text: /**
   * Copyright 2013 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 ReactCompositeComponent
   */
  
  "use strict";
  
  var ReactComponent = require('ReactComponent');
  var ReactContext = require('ReactContext');
  var ReactCurrentOwner = require('ReactCurrentOwner');
  var ReactErrorUtils = require('ReactErrorUtils');
  var ReactOwner = require('ReactOwner');
  var ReactPerf = require('ReactPerf');
  var ReactPropTransferer = require('ReactPropTransferer');
  var ReactPropTypeLocations = require('ReactPropTypeLocations');
  var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames');
  var ReactUpdates = require('ReactUpdates');
  
  var invariant = require('invariant');
  var keyMirror = require('keyMirror');
  var merge = require('merge');
  var mixInto = require('mixInto');
  var objMap = require('objMap');
  var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
  
  /**
   * Policies that describe methods in `ReactCompositeComponentInterface`.
   */
  var SpecPolicy = keyMirror({
    /**
     * These methods may be defined only once by the class specification or mixin.
     */
    DEFINE_ONCE: null,
    /**
     * These methods may be defined by both the class specification and mixins.
     * Subsequent definitions will be chained. These methods must return void.
     */
    DEFINE_MANY: null,
    /**
     * These methods are overriding the base ReactCompositeComponent class.
     */
    OVERRIDE_BASE: null,
    /**
     * These methods are similar to DEFINE_MANY, except we assume they return
     * objects. We try to merge the keys of the return values of all the mixed in
     * functions. If there is a key conflict we throw.
     */
    DEFINE_MANY_MERGED: null
  });
  
  /**
   * Composite components are higher-level components that compose other composite
   * or native components.
   *
   * To create a new type of `ReactCompositeComponent`, pass a specification of
   * your new class to `React.createClass`. The only requirement of your class
   * specification is that you implement a `render` method.
   *
   *   var MyComponent = React.createClass({
   *     render: function() {
   *       return <div>Hello World</div>;
   *     }
   *   });
   *
   * The class specification supports a specific protocol of methods that have
   * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
   * more the comprehensive protocol. Any other properties and methods in the
   * class specification will available on the prototype.
   *
   * @interface ReactCompositeComponentInterface
   * @internal
   */
  var ReactCompositeComponentInterface = {
  
    /**
     * An array of Mixin objects to include when defining your component.
     *
     * @type {array}
     * @optional
     */
    mixins: SpecPolicy.DEFINE_MANY,
  
    /**
     * An object containing properties and methods that should be defined on
     * the component's constructor instead of its prototype (static methods).
     *
     * @type {object}
     * @optional
     */
    statics: SpecPolicy.DEFINE_MANY,
  
    /**
     * Definition of prop types for this component.
     *
     * @type {object}
     * @optional
     */
    propTypes: SpecPolicy.DEFINE_MANY,
  
    /**
     * Definition of context types for this component.
     *
     * @type {object}
     * @optional
     */
    contextTypes: SpecPolicy.DEFINE_MANY,
  
    /**
     * Definition of context types this component sets for its children.
     *
     * @type {object}
     * @optional
     */
    childContextTypes: SpecPolicy.DEFINE_MANY,
  
    // ==== Definition methods ====
  
    /**
     * Invoked when the component is mounted. Values in the mapping will be set on
     * `this.props` if that prop is not specified (i.e. using an `in` check).
     *
     * This method is invoked before `getInitialState` and therefore cannot rely
     * on `this.state` or use `this.setState`.
     *
     * @return {object}
     * @optional
     */
    getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
  
    /**
     * Invoked once before the component is mounted. The return value will be used
     * as the initial value of `this.state`.
     *
     *   getInitialState: function() {
     *     return {
     *       isOn: false,
     *       fooBaz: new BazFoo()
     *     }
     *   }
     *
     * @return {object}
     * @optional
     */
    getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
  
    /**
     * @return {object}
     * @optional
     */
    getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
  
    /**
     * Uses props from `this.props` and state from `this.state` to render the
     * structure of the component.
     *
     * No guarantees are made about when or how often this method is invoked, so
     * it must not have side effects.
     *
     *   render: function() {
     *     var name = this.props.name;
     *     return <div>Hello, {name}!</div>;
     *   }
     *
     * @return {ReactComponent}
     * @nosideeffects
     * @required
     */
    render: SpecPolicy.DEFINE_ONCE,
  
  
  
    // ==== Delegate methods ====
  
    /**
     * Invoked when the component is initially created and about to be mounted.
     * This may have side effects, but any external subscriptions or data created
     * by this method must be cleaned up in `componentWillUnmount`.
     *
     * @optional
     */
    componentWillMount: SpecPolicy.DEFINE_MANY,
  
    /**
     * Invoked when the component has been mounted and has a DOM representation.
     * However, there is no guarantee that the DOM node is in the document.
     *
     * Use this as an opportunity to operate on the DOM when the component has
     * been mounted (initialized and rendered) for the first time.
     *
     * @param {DOMElement} rootNode DOM element representing the component.
     * @optional
     */
    componentDidMount: SpecPolicy.DEFINE_MANY,
  
    /**
     * Invoked before the component receives new props.
     *
     * Use this as an opportunity to react to a prop transition by updating the
     * state using `this.setState`. Current props are accessed via `this.props`.
     *
     *   componentWillReceiveProps: function(nextProps, nextContext) {
     *     this.setState({
     *       likesIncreasing: nextProps.likeCount > this.props.likeCount
     *     });
     *   }
     *
     * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
     * transition may cause a state change, but the opposite is not true. If you
     * need it, you are probably looking for `componentWillUpdate`.
     *
     * @param {object} nextProps
     * @optional
     */
    componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
  
    /**
     * Invoked while deciding if the component should be updated as a result of
     * receiving new props, state and/or context.
     *
     * Use this as an opportunity to `return false` when you're certain that the
     * transition to the new props/state/context will not require a component
     * update.
     *
     *   shouldComponentUpdate: function(nextProps, nextState, nextContext) {
     *     return !equal(nextProps, this.props) ||
     *       !equal(nextState, this.state) ||
     *       !equal(nextContext, this.context);
     *   }
     *
     * @param {object} nextProps
     * @param {?object} nextState
     * @param {?object} nextContext
     * @return {boolean} True if the component should update.
     * @optional
     */
    shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
  
    /**
     * Invoked when the component is about to update due to a transition from
     * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
     * and `nextContext`.
     *
     * Use this as an opportunity to perform preparation before an update occurs.
     *
     * NOTE: You **cannot** use `this.setState()` in this method.
     *
     * @param {object} nextProps
     * @param {?object} nextState
     * @param {?object} nextContext
     * @param {ReactReconcileTransaction} transaction
     * @optional
     */
    componentWillUpdate: SpecPolicy.DEFINE_MANY,
  
    /**
     * Invoked when the component's DOM representation has been updated.
     *
     * Use this as an opportunity to operate on the DOM when the component has
     * been updated.
     *
     * @param {object} prevProps
     * @param {?object} prevState
     * @param {?object} prevContext
     * @param {DOMElement} rootNode DOM element representing the component.
     * @optional
     */
    componentDidUpdate: SpecPolicy.DEFINE_MANY,
  
    /**
     * Invoked when the component is about to be removed from its parent and have
     * its DOM representation destroyed.
     *
     * Use this as an opportunity to deallocate any external resources.
     *
     * NOTE: There is no `componentDidUnmount` since your component will have been
     * destroyed by that point.
     *
     * @optional
     */
    componentWillUnmount: SpecPolicy.DEFINE_MANY,
  
  
  
    // ==== Advanced methods ====
  
    /**
     * Updates the component's currently mounted DOM representation.
     *
     * By default, this implements React's rendering and reconciliation algorithm.
     * Sophisticated clients may wish to override this.
     *
     * @param {ReactReconcileTransaction} transaction
     * @internal
     * @overridable
     */
    updateComponent: SpecPolicy.OVERRIDE_BASE
  
  };
  
  /**
   * Mapping from class specification keys to special processing functions.
   *
   * Although these are declared like instance properties in the specification
   * when defining classes using `React.createClass`, they are actually static
   * and are accessible on the constructor instead of the prototype. Despite
   * being static, they must be defined outside of the "statics" key under
   * which all other static methods are defined.
   */
  var RESERVED_SPEC_KEYS = {
    displayName: function(ConvenienceConstructor, displayName) {
      ConvenienceConstructor.componentConstructor.displayName = displayName;
    },
    mixins: function(ConvenienceConstructor, mixins) {
      if (mixins) {
        for (var i = 0; i < mixins.length; i++) {
          mixSpecIntoComponent(ConvenienceConstructor, mixins[i]);
        }
      }
    },
    childContextTypes: function(ConvenienceConstructor, childContextTypes) {
      var Constructor = ConvenienceConstructor.componentConstructor;
      validateTypeDef(
        Constructor,
        childContextTypes,
        ReactPropTypeLocations.childContext
      );
      Constructor.childContextTypes = merge(
        Constructor.childContextTypes,
        childContextTypes
      );
    },
    contextTypes: function(ConvenienceConstructor, contextTypes) {
      var Constructor = ConvenienceConstructor.componentConstructor;
      validateTypeDef(
        Constructor,
        contextTypes,
        ReactPropTypeLocations.context
      );
      Constructor.contextTypes = merge(Constructor.contextTypes, contextTypes);
    },
    propTypes: function(ConvenienceConstructor, propTypes) {
      var Constructor = ConvenienceConstructor.componentConstructor;
      validateTypeDef(
        Constructor,
        propTypes,
        ReactPropTypeLocations.prop
      );
      Constructor.propTypes = merge(Constructor.propTypes, propTypes);
    },
    statics: function(ConvenienceConstructor, statics) {
      mixStaticSpecIntoComponent(ConvenienceConstructor, statics);
    }
  };
  
  function validateTypeDef(Constructor, typeDef, location) {
    for (var propName in typeDef) {
      if (typeDef.hasOwnProperty(propName)) {
        invariant(
          typeof typeDef[propName] == 'function',
          '%s: %s type `%s` is invalid; it must be a function, usually from ' +
          'React.PropTypes.',
          Constructor.displayName || 'ReactCompositeComponent',
          ReactPropTypeLocationNames[location],
          propName
        );
      }
    }
  }
  
  function validateMethodOverride(proto, name) {
    var specPolicy = ReactCompositeComponentInterface[name];
  
    // Disallow overriding of base class methods unless explicitly allowed.
    if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
      invariant(
        specPolicy === SpecPolicy.OVERRIDE_BASE,
        'ReactCompositeComponentInterface: You are attempting to override ' +
        '`%s` from your class specification. Ensure that your method names ' +
        'do not overlap with React methods.',
        name
      );
    }
  
    // Disallow defining methods more than once unless explicitly allowed.
    if (proto.hasOwnProperty(name)) {
      invariant(
        specPolicy === SpecPolicy.DEFINE_MANY ||
        specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
        'ReactCompositeComponentInterface: You are attempting to define ' +
        '`%s` on your component more than once. This conflict may be due ' +
        'to a mixin.',
        name
      );
    }
  }
  
  function validateLifeCycleOnReplaceState(instance) {
    var compositeLifeCycleState = instance._compositeLifeCycleState;
    invariant(
      instance.isMounted() ||
        compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
      'replaceState(...): Can only update a mounted or mounting component.'
    );
    invariant(compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE,
      'replaceState(...): Cannot update during an existing state transition ' +
      '(such as within `render`). This could potentially cause an infinite ' +
      'loop so it is forbidden.'
    );
    invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
      'replaceState(...): Cannot update while unmounting component. This ' +
      'usually means you called setState() on an unmounted component.'
    );
  }
  
  /**
   * Custom version of `mixInto` which handles policy validation and reserved
   * specification keys when building `ReactCompositeComponent` classses.
   */
  function mixSpecIntoComponent(ConvenienceConstructor, spec) {
    invariant(
      !isValidClass(spec),
      'ReactCompositeComponent: You\'re attempting to ' +
      'use a component class as a mixin. Instead, just use a regular object.'
    );
    invariant(
      !ReactComponent.isValidComponent(spec),
      'ReactCompositeComponent: You\'re attempting to ' +
      'use a component as a mixin. Instead, just use a regular object.'
    );
  
    var Constructor = ConvenienceConstructor.componentConstructor;
    var proto = Constructor.prototype;
    for (var name in spec) {
      var property = spec[name];
      if (!spec.hasOwnProperty(name) || !property) {
        continue;
      }
  
      validateMethodOverride(proto, name);
  
      if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
        RESERVED_SPEC_KEYS[name](ConvenienceConstructor, property);
      } else {
        // Setup methods on prototype:
        // The following member methods should not be automatically bound:
        // 1. Expected ReactCompositeComponent methods (in the "interface").
        // 2. Overridden methods (that were mixed in).
        var isCompositeComponentMethod = name in ReactCompositeComponentInterface;
        var isInherited = name in proto;
        var markedDontBind = property.__reactDontBind;
        var isFunction = typeof property === 'function';
        var shouldAutoBind =
          isFunction &&
          !isCompositeComponentMethod &&
          !isInherited &&
          !markedDontBind;
  
        if (shouldAutoBind) {
          if (!proto.__reactAutoBindMap) {
            proto.__reactAutoBindMap = {};
          }
          proto.__reactAutoBindMap[name] = property;
          proto[name] = property;
        } else {
          if (isInherited) {
            // For methods which are defined more than once, call the existing
            // methods before calling the new property.
            if (ReactCompositeComponentInterface[name] ===
                SpecPolicy.DEFINE_MANY_MERGED) {
              proto[name] = createMergedResultFunction(proto[name], property);
            } else {
              proto[name] = createChainedFunction(proto[name], property);
            }
          } else {
            proto[name] = property;
          }
        }
      }
    }
  }
  
  function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) {
    if (!statics) {
      return;
    }
    for (var name in statics) {
      var property = statics[name];
      if (!statics.hasOwnProperty(name) || !property) {
        return;
      }
  
      var isInherited = name in ConvenienceConstructor;
      var result = property;
      if (isInherited) {
        var existingProperty = ConvenienceConstructor[name];
        var existingType = typeof existingProperty;
        var propertyType = typeof property;
        invariant(
          existingType === 'function' && propertyType === 'function',
          'ReactCompositeComponent: You are attempting to define ' +
          '`%s` on your component more than once, but that is only supported ' +
          'for functions, which are chained together. This conflict may be ' +
          'due to a mixin.',
          name
        );
        result = createChainedFunction(existingProperty, property);
      }
      ConvenienceConstructor[name] = result;
      ConvenienceConstructor.componentConstructor[name] = result;
    }
  }
  
  /**
   * Merge two objects, but throw if both contain the same key.
   *
   * @param {object} one The first object, which is mutated.
   * @param {object} two The second object
   * @return {object} one after it has been mutated to contain everything in two.
   */
  function mergeObjectsWithNoDuplicateKeys(one, two) {
    invariant(
      one && two && typeof one === 'object' && typeof two === 'object',
      'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
    );
  
    objMap(two, function(value, key) {
      invariant(
        one[key] === undefined,
        'mergeObjectsWithNoDuplicateKeys(): ' +
        'Tried to merge two objects with the same key: %s',
        key
      );
      one[key] = value;
    });
    return one;
  }
  
  /**
   * Creates a function that invokes two functions and merges their return values.
   *
   * @param {function} one Function to invoke first.
   * @param {function} two Function to invoke second.
   * @return {function} Function that invokes the two argument functions.
   * @private
   */
  function createMergedResultFunction(one, two) {
    return function mergedResult() {
      var a = one.apply(this, arguments);
      var b = two.apply(this, arguments);
      if (a == null) {
        return b;
      } else if (b == null) {
        return a;
      }
      return mergeObjectsWithNoDuplicateKeys(a, b);
    };
  }
  
  /**
   * Creates a function that invokes two functions and ignores their return vales.
   *
   * @param {function} one Function to invoke first.
   * @param {function} two Function to invoke second.
   * @return {function} Function that invokes the two argument functions.
   * @private
   */
  function createChainedFunction(one, two) {
    return function chainedFunction() {
      one.apply(this, arguments);
      two.apply(this, arguments);
    };
  }
  
  /**
   * `ReactCompositeComponent` maintains an auxiliary life cycle state in
   * `this._compositeLifeCycleState` (which can be null).
   *
   * This is different from the life cycle state maintained by `ReactComponent` in
   * `this._lifeCycleState`. The following diagram shows how the states overlap in
   * time. There are times when the CompositeLifeCycle is null - at those times it
   * is only meaningful to look at ComponentLifeCycle alone.
   *
   * Top Row: ReactComponent.ComponentLifeCycle
   * Low Row: ReactComponent.CompositeLifeCycle
   *
   * +-------+------------------------------------------------------+--------+
   * |  UN   |                    MOUNTED                           |   UN   |
   * |MOUNTED|                                                      | MOUNTED|
   * +-------+------------------------------------------------------+--------+
   * |       ^--------+   +------+   +------+   +------+   +--------^        |
   * |       |        |   |      |   |      |   |      |   |        |        |
   * |    0--|MOUNTING|-0-|RECEIV|-0-|RECEIV|-0-|RECEIV|-0-|   UN   |--->0   |
   * |       |        |   |PROPS |   | PROPS|   | STATE|   |MOUNTING|        |
   * |       |        |   |      |   |      |   |      |   |        |        |
   * |       |        |   |      |   |      |   |      |   |        |        |
   * |       +--------+   +------+   +------+   +------+   +--------+        |
   * |       |                                                      |        |
   * +-------+------------------------------------------------------+--------+
   */
  var CompositeLifeCycle = keyMirror({
    /**
     * Components in the process of being mounted respond to state changes
     * differently.
     */
    MOUNTING: null,
    /**
     * Components in the process of being unmounted are guarded against state
     * changes.
     */
    UNMOUNTING: null,
    /**
     * Components that are mounted and receiving new props respond to state
     * changes differently.
     */
    RECEIVING_PROPS: null,
    /**
     * Components that are mounted and receiving new state are guarded against
     * additional state changes.
     */
    RECEIVING_STATE: null
  });
  
  /**
   * @lends {ReactCompositeComponent.prototype}
   */
  var ReactCompositeComponentMixin = {
  
    /**
     * Base constructor for all composite component.
     *
     * @param {?object} initialProps
     * @param {*} children
     * @final
     * @internal
     */
    construct: function(initialProps, children) {
      // Children can be either an array or more than one argument
      ReactComponent.Mixin.construct.apply(this, arguments);
  
      this.state = null;
      this._pendingState = null;
  
      this.context = this._processContext(ReactContext.current);
      this._currentContext = ReactContext.current;
      this._pendingContext = null;
  
      this._compositeLifeCycleState = null;
    },
  
    /**
     * Checks whether or not this composite component is mounted.
     * @return {boolean} True if mounted, false otherwise.
     * @protected
     * @final
     */
    isMounted: function() {
      return ReactComponent.Mixin.isMounted.call(this) &&
        this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
    },
  
    /**
     * Initializes the component, renders markup, and registers event listeners.
     *
     * @param {string} rootID DOM ID of the root node.
     * @param {ReactReconcileTransaction} transaction
     * @param {number} mountDepth number of components in the owner hierarchy
     * @return {?string} Rendered markup to be inserted into the DOM.
     * @final
     * @internal
     */
    mountComponent: ReactPerf.measure(
      'ReactCompositeComponent',
      'mountComponent',
      function(rootID, transaction, mountDepth) {
        ReactComponent.Mixin.mountComponent.call(
          this,
          rootID,
          transaction,
          mountDepth
        );
        this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
  
        this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
        this.props = this._processProps(this.props);
  
        if (this.__reactAutoBindMap) {
          this._bindAutoBindMethods();
        }
  
        this.state = this.getInitialState ? this.getInitialState() : null;
        invariant(
          typeof this.state === 'object' && !Array.isArray(this.state),
          '%s.getInitialState(): must return an object or null',
          this.constructor.displayName || 'ReactCompositeComponent'
        );
  
        this._pendingState = null;
        this._pendingForceUpdate = false;
  
        if (this.componentWillMount) {
          this.componentWillMount();
          // When mounting, calls to `setState` by `componentWillMount` will set
          // `this._pendingState` without triggering a re-render.
          if (this._pendingState) {
            this.state = this._pendingState;
            this._pendingState = null;
          }
        }
  
        this._renderedComponent = this._renderValidatedComponent();
  
        // Done with mounting, `setState` will now trigger UI changes.
        this._compositeLifeCycleState = null;
        var markup = this._renderedComponent.mountComponent(
          rootID,
          transaction,
          mountDepth + 1
        );
        if (this.componentDidMount) {
          transaction.getReactMountReady().enqueue(this, this.componentDidMount);
        }
        return markup;
      }
    ),
  
    /**
     * Releases any resources allocated by `mountComponent`.
     *
     * @final
     * @internal
     */
    unmountComponent: function() {
      this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
      if (this.componentWillUnmount) {
        this.componentWillUnmount();
      }
      this._compositeLifeCycleState = null;
  
      this._defaultProps = null;
  
      this._renderedComponent.unmountComponent();
      this._renderedComponent = null;
  
      ReactComponent.Mixin.unmountComponent.call(this);
  
      if (this.refs) {
        this.refs = null;
      }
  
      // Some existing components rely on this.props even after they've been
      // destroyed (in event handlers).
      // TODO: this.props = null;
      // TODO: this.state = null;
    },
  
    /**
     * Sets a subset of the state. Always use this or `replaceState` to mutate
     * state. You should treat `this.state` as immutable.
     *
     * There is no guarantee that `this.state` will be immediately updated, so
     * accessing `this.state` after calling this method may return the old value.
     *
     * There is no guarantee that calls to `setState` will run synchronously,
     * as they may eventually be batched together.  You can provide an optional
     * callback that will be executed when the call to setState is actually
     * completed.
     *
     * @param {object} partialState Next partial state to be merged with state.
     * @param {?function} callback Called after state is updated.
     * @final
     * @protected
     */
    setState: function(partialState, callback) {
      invariant(
        typeof partialState === 'object' || partialState == null,
        'setState(...): takes an object of state variables to update.'
      );
      if (__DEV__){
        if (partialState == null) {
          console.warn(
            'setState(...): You passed an undefined or null state object; ' +
            'instead, use forceUpdate().'
          );
        }
      }
      // Merge with `_pendingState` if it exists, otherwise with existing state.
      this.replaceState(
        merge(this._pendingState || this.state, partialState),
        callback
      );
    },
  
    /**
     * Replaces all of the state. Always use this or `setState` to mutate state.
     * You should treat `this.state` as immutable.
     *
     * There is no guarantee that `this.state` will be immediately updated, so
     * accessing `this.state` after calling this method may return the old value.
     *
     * @param {object} completeState Next state.
     * @param {?function} callback Called after state is updated.
     * @final
     * @protected
     */
    replaceState: function(completeState, callback) {
      validateLifeCycleOnReplaceState(this);
      this._pendingState = completeState;
      ReactUpdates.enqueueUpdate(this, callback);
    },
  
    /**
     * Filters the context object to only contain keys specified in
     * `contextTypes`, and asserts that they are valid.
     *
     * @param {object} context
     * @return {?object}
     * @private
     */
    _processContext: function(context) {
      var maskedContext = null;
      var contextTypes = this.constructor.contextTypes;
      if (contextTypes) {
        maskedContext = {};
        for (var contextName in contextTypes) {
          maskedContext[contextName] = context[contextName];
        }
        if (__DEV__) {
          this._checkPropTypes(
            contextTypes,
            maskedContext,
            ReactPropTypeLocations.context
          );
        }
      }
      return maskedContext;
    },
  
    /**
     * @param {object} currentContext
     * @return {object}
     * @private
     */
    _processChildContext: function(currentContext) {
      var childContext = this.getChildContext && this.getChildContext();
      var displayName = this.constructor.displayName || 'ReactCompositeComponent';
      if (childContext) {
        invariant(
          typeof this.constructor.childContextTypes === 'object',
          '%s.getChildContext(): childContextTypes must be defined in order to ' +
          'use getChildContext().',
          displayName
        );
        if (__DEV__) {
          this._checkPropTypes(
            this.constructor.childContextTypes,
            childContext,
            ReactPropTypeLocations.childContext
          );
        }
        for (var name in childContext) {
          invariant(
            name in this.constructor.childContextTypes,
            '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
            displayName,
            name
          );
        }
        return merge(currentContext, childContext);
      }
      return currentContext;
    },
  
    /**
     * Processes props by setting default values for unspecified props and
     * asserting that the props are valid. Does not mutate its argument; returns
     * a new props object with defaults merged in.
     *
     * @param {object} newProps
     * @return {object}
     * @private
     */
    _processProps: function(newProps) {
      var props = merge(newProps);
      var defaultProps = this._defaultProps;
      for (var propName in defaultProps) {
        if (typeof props[propName] === 'undefined') {
          props[propName] = defaultProps[propName];
        }
      }
      if (__DEV__) {
        var propTypes = this.constructor.propTypes;
        if (propTypes) {
          this._checkPropTypes(propTypes, props, ReactPropTypeLocations.prop);
        }
      }
      return props;
    },
  
    /**
     * Assert that the props are valid
     *
     * @param {object} propTypes Map of prop name to a ReactPropType
     * @param {object} props
     * @param {string} location e.g. "prop", "context", "child context"
     * @private
     */
    _checkPropTypes: function(propTypes, props, location) {
      var componentName = this.constructor.displayName;
      for (var propName in propTypes) {
        if (propTypes.hasOwnProperty(propName)) {
          propTypes[propName](props, propName, componentName, location);
        }
      }
    },
  
    performUpdateIfNecessary: function() {
      var compositeLifeCycleState = this._compositeLifeCycleState;
      // Do not trigger a state transition if we are in the middle of mounting or
      // receiving props because both of those will already be doing this.
      if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
          compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
        return;
      }
      ReactComponent.Mixin.performUpdateIfNecessary.call(this);
    },
  
    /**
     * If any of `_pendingProps`, `_pendingState`, or `_pendingForceUpdate` is
     * set, update the component.
     *
     * @param {ReactReconcileTransaction} transaction
     * @internal
     */
    _performUpdateIfNecessary: function(transaction) {
      if (this._pendingProps == null &&
          this._pendingState == null &&
          this._pendingContext == null &&
          !this._pendingForceUpdate) {
        return;
      }
  
      var nextFullContext = this._pendingContext || this._currentContext;
      var nextContext = this._processContext(nextFullContext);
      this._pendingContext = null;
  
      var nextProps = this.props;
      if (this._pendingProps != null) {
        nextProps = this._processProps(this._pendingProps);
        this._pendingProps = null;
  
        this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
        if (this.componentWillReceiveProps) {
          this.componentWillReceiveProps(nextProps, nextContext);
        }
      }
  
      this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_STATE;
  
      // Unlike props, state, and context, we specifically don't want to set
      // _pendingOwner to null here because it's possible for a component to have
      // a null owner, so we instead make `this._owner === this._pendingOwner`
      // mean that there's no owner change pending.
      var nextOwner = this._pendingOwner;
  
      var nextState = this._pendingState || this.state;
      this._pendingState = null;
  
      try {
        if (this._pendingForceUpdate ||
            !this.shouldComponentUpdate ||
            this.shouldComponentUpdate(nextProps, nextState, nextContext)) {
          this._pendingForceUpdate = false;
          // Will set `this.props`, `this.state` and `this.context`.
          this._performComponentUpdate(
            nextProps,
            nextOwner,
            nextState,
            nextFullContext,
            nextContext,
            transaction
          );
        } else {
          // If it's determined that a component should not update, we still want
          // to set props and state.
          this.props = nextProps;
          this._owner = nextOwner;
          this.state = nextState;
          this._currentContext = nextFullContext;
          this.context = nextContext;
        }
      } finally {
        this._compositeLifeCycleState = null;
      }
    },
  
    /**
     * Merges new props and state, notifies delegate methods of update and
     * performs update.
     *
     * @param {object} nextProps Next object to set as properties.
     * @param {?ReactComponent} nextOwner Next component to set as owner
     * @param {?object} nextState Next object to set as state.
     * @param {?object} nextFullContext Next object to set as _currentContext.
     * @param {?object} nextContext Next object to set as context.
     * @param {ReactReconcileTransaction} transaction
     * @private
     */
    _performComponentUpdate: function(
      nextProps,
      nextOwner,
      nextState,
      nextFullContext,
      nextContext,
      transaction
    ) {
      var prevProps = this.props;
      var prevOwner = this._owner;
      var prevState = this.state;
      var prevContext = this.context;
  
      if (this.componentWillUpdate) {
        this.componentWillUpdate(nextProps, nextState, nextContext);
      }
  
      this.props = nextProps;
      this._owner = nextOwner;
      this.state = nextState;
      this._currentContext = nextFullContext;
      this.context = nextContext;
  
      this.updateComponent(
        transaction,
        prevProps,
        prevOwner,
        prevState,
        prevContext
      );
  
      if (this.componentDidUpdate) {
        transaction.getReactMountReady().enqueue(
          this,
          this.componentDidUpdate.bind(this, prevProps, prevState, prevContext)
        );
      }
    },
  
    receiveComponent: function(nextComponent, transaction) {
      if (nextComponent === this) {
        // Since props and context are immutable after the component is
        // mounted, we can do a cheap identity compare here to determine
        // if this is a superfluous reconcile.
        return;
      }
  
      this._pendingContext = nextComponent._currentContext;
      ReactComponent.Mixin.receiveComponent.call(
        this,
        nextComponent,
        transaction
      );
    },
  
    /**
     * Updates the component's currently mounted DOM representation.
     *
     * By default, this implements React's rendering and reconciliation algorithm.
     * Sophisticated clients may wish to override this.
     *
     * @param {ReactReconcileTransaction} transaction
     * @param {object} prevProps
     * @param {?ReactComponent} prevOwner
     * @param {?object} prevState
     * @param {?object} prevContext
     * @internal
     * @overridable
     */
    updateComponent: ReactPerf.measure(
      'ReactCompositeComponent',
      'updateComponent',
      function(transaction, prevProps, prevOwner, prevState, prevContext) {
        ReactComponent.Mixin.updateComponent.call(
          this,
          transaction,
          prevProps,
          prevOwner
        );
        var prevComponent = this._renderedComponent;
        var nextComponent = this._renderValidatedComponent();
        if (shouldUpdateReactComponent(prevComponent, nextComponent)) {
          prevComponent.receiveComponent(nextComponent, transaction);
        } else {
          // These two IDs are actually the same! But nothing should rely on that.
          var thisID = this._rootNodeID;
          var prevComponentID = prevComponent._rootNodeID;
          prevComponent.unmountComponent();
          this._renderedComponent = nextComponent;
          var nextMarkup = nextComponent.mountComponent(
            thisID,
            transaction,
            this._mountDepth + 1
          );
          ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
            prevComponentID,
            nextMarkup
          );
        }
      }
    ),
  
    /**
     * Forces an update. This should only be invoked when it is known with
     * certainty that we are **not** in a DOM transaction.
     *
     * You may want to call this when you know that some deeper aspect of the
     * component's state has changed but `setState` was not called.
     *
     * This will not invoke `shouldUpdateComponent`, but it will invoke
     * `componentWillUpdate` and `componentDidUpdate`.
     *
     * @param {?function} callback Called after update is complete.
     * @final
     * @protected
     */
    forceUpdate: function(callback) {
      var compositeLifeCycleState = this._compositeLifeCycleState;
      invariant(
        this.isMounted() ||
          compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
        'forceUpdate(...): Can only force an update on mounted or mounting ' +
          'components.'
      );
      invariant(
        compositeLifeCycleState !== CompositeLifeCycle.RECEIVING_STATE &&
        compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
        'forceUpdate(...): Cannot force an update while unmounting component ' +
        'or during an existing state transition (such as within `render`).'
      );
      this._pendingForceUpdate = true;
      ReactUpdates.enqueueUpdate(this, callback);
    },
  
    /**
     * @private
     */
    _renderValidatedComponent: function() {
      var renderedComponent;
      var previousContext = ReactContext.current;
      ReactContext.current = this._processChildContext(this._currentContext);
      ReactCurrentOwner.current = this;
      try {
        renderedComponent = this.render();
      } finally {
        ReactContext.current = previousContext;
        ReactCurrentOwner.current = null;
      }
      invariant(
        ReactComponent.isValidComponent(renderedComponent),
        '%s.render(): A valid ReactComponent must be returned. You may have ' +
        'returned null, undefined, an array, or some other invalid object.',
        this.constructor.displayName || 'ReactCompositeComponent'
      );
      return renderedComponent;
    },
  
    /**
     * @private
     */
    _bindAutoBindMethods: function() {
      for (var autoBindKey in this.__reactAutoBindMap) {
        if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
          continue;
        }
        var method = this.__reactAutoBindMap[autoBindKey];
        this[autoBindKey] = this._bindAutoBindMethod(ReactErrorUtils.guard(
          method,
          this.constructor.displayName + '.' + autoBindKey
        ));
      }
    },
  
    /**
     * Binds a method to the component.
     *
     * @param {function} method Method to be bound.
     * @private
     */
    _bindAutoBindMethod: function(method) {
      var component = this;
      var boundMethod = function() {
        return method.apply(component, arguments);
      };
      if (__DEV__) {
        boundMethod.__reactBoundContext = component;
        boundMethod.__reactBoundMethod = method;
        boundMethod.__reactBoundArguments = null;
        var componentName = component.constructor.displayName;
        var _bind = boundMethod.bind;
        boundMethod.bind = function(newThis, ...args) {
          // User is trying to bind() an autobound method; we effectively will
          // ignore the value of "this" that the user is trying to use, so
          // let's warn.
          if (newThis !== component && newThis !== null) {
            console.warn(
              'bind(): React component methods may only be bound to the ' +
              'component instance. See ' + componentName
            );
          } else if (!args.length) {
            console.warn(
              'bind(): You are binding a component method to the component. ' +
              'React does this for you automatically in a high-performance ' +
              'way, so you can safely remove this call. See ' + componentName
            );
            return boundMethod;
          }
          var reboundMethod = _bind.apply(boundMethod, arguments);
          reboundMethod.__reactBoundContext = component;
          reboundMethod.__reactBoundMethod = method;
          reboundMethod.__reactBoundArguments = args;
          return reboundMethod;
        };
      }
      return boundMethod;
    }
  };
  
  var ReactCompositeComponentBase = function() {};
  mixInto(ReactCompositeComponentBase, ReactComponent.Mixin);
  mixInto(ReactCompositeComponentBase, ReactOwner.Mixin);
  mixInto(ReactCompositeComponentBase, ReactPropTransferer.Mixin);
  mixInto(ReactCompositeComponentBase, ReactCompositeComponentMixin);
  
  /**
   * Checks if a value is a valid component constructor.
   *
   * @param {*}
   * @return {boolean}
   * @public
   */
  function isValidClass(componentClass) {
    return componentClass instanceof Function &&
           'componentConstructor' in componentClass &&
           componentClass.componentConstructor instanceof Function;
  }
  /**
   * Module for creating composite components.
   *
   * @class ReactCompositeComponent
   * @extends ReactComponent
   * @extends ReactOwner
   * @extends ReactPropTransferer
   */
  var ReactCompositeComponent = {
  
    LifeCycle: CompositeLifeCycle,
  
    Base: ReactCompositeComponentBase,
  
    /**
     * Creates a composite component class given a class specification.
     *
     * @param {object} spec Class specification (which must define `render`).
     * @return {function} Component constructor function.
     * @public
     */
    createClass: function(spec) {
      var Constructor = function() {};
      Constructor.prototype = new ReactCompositeComponentBase();
      Constructor.prototype.constructor = Constructor;
  
      var ConvenienceConstructor = function(props, children) {
        var instance = new Constructor();
        instance.construct.apply(instance, arguments);
        return instance;
      };
      ConvenienceConstructor.componentConstructor = Constructor;
      Constructor.ConvenienceConstructor = ConvenienceConstructor;
      ConvenienceConstructor.originalSpec = spec;
  
      mixSpecIntoComponent(ConvenienceConstructor, spec);
  
      invariant(
        Constructor.prototype.render,
        'createClass(...): Class specification must implement a `render` method.'
      );
  
      if (__DEV__) {
        if (Constructor.prototype.componentShouldUpdate) {
          console.warn(
            (spec.displayName || 'A component') + ' has a method called ' +
            'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
            'The name is phrased as a question because the function is ' +
            'expected to return a value.'
           );
        }
      }
  
      // Reduce time spent doing lookups by setting these on the prototype.
      for (var methodName in ReactCompositeComponentInterface) {
        if (!Constructor.prototype[methodName]) {
          Constructor.prototype[methodName] = null;
        }
      }
  
      return ConvenienceConstructor;
    },
  
    isValidClass: isValidClass
  };
  
  module.exports = ReactCompositeComponent;
  