diff options
| -rw-r--r-- | mitmproxy/web/static/app.js | 1025 | ||||
| -rw-r--r-- | mitmproxy/web/static/vendor.js | 1359 | ||||
| -rw-r--r-- | web/.babelrc | 3 | ||||
| -rw-r--r-- | web/.eslintrc.yml | 8 | ||||
| -rw-r--r-- | web/package.json | 6 | ||||
| -rw-r--r-- | web/src/js/components/common.js | 31 | ||||
| -rw-r--r-- | web/src/js/components/eventlog.js | 231 | ||||
| -rw-r--r-- | web/src/js/components/flowtable.js | 340 | ||||
| -rw-r--r-- | web/src/js/components/helpers/AutoScroll.js | 25 | ||||
| -rw-r--r-- | web/src/js/components/helpers/VirtualScroll.js | 70 | ||||
| -rw-r--r-- | web/src/js/components/mainview.js | 14 | ||||
| -rw-r--r-- | web/src/js/components/virtualscroll.js | 84 | 
12 files changed, 2150 insertions, 1046 deletions
| diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js index bb06970e..e318d1ac 100644 --- a/mitmproxy/web/static/app.js +++ b/mitmproxy/web/static/app.js @@ -442,7 +442,7 @@ var Query = exports.Query = {      SHOW_EVENTLOG: "e"  }; -},{"./dispatcher.js":21,"jquery":"jquery","lodash":"lodash"}],3:[function(require,module,exports){ +},{"./dispatcher.js":22,"jquery":"jquery","lodash":"lodash"}],3:[function(require,module,exports){  "use strict";  var _react = require("react"); @@ -475,13 +475,13 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de      (0, _reactDom.render)(_proxyapp.app, document.getElementById("mitmproxy"));  }); -},{"./actions.js":2,"./components/proxyapp.js":18,"./connection":20,"jquery":"jquery","react":"react","react-dom":"react-dom"}],4:[function(require,module,exports){ +},{"./actions.js":2,"./components/proxyapp.js":20,"./connection":21,"jquery":"jquery","react":"react","react-dom":"react-dom"}],4:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", {      value: true  }); -exports.Splitter = exports.Router = exports.StickyHeadMixin = exports.AutoScrollMixin = undefined; +exports.Splitter = exports.Router = undefined;  var _react = require("react"); @@ -497,29 +497,6 @@ var _lodash2 = _interopRequireDefault(_lodash);  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example) -var AutoScrollMixin = exports.AutoScrollMixin = { -    componentWillUpdate: function componentWillUpdate() { -        var node = _reactDom2.default.findDOMNode(this); -        this._shouldScrollBottom = node.scrollTop !== 0 && node.scrollTop + node.clientHeight === node.scrollHeight; -    }, -    componentDidUpdate: function componentDidUpdate() { -        if (this._shouldScrollBottom) { -            var node = _reactDom2.default.findDOMNode(this); -            node.scrollTop = node.scrollHeight; -        } -    } -}; - -var StickyHeadMixin = exports.StickyHeadMixin = { -    adjustHead: function adjustHead() { -        // Abusing CSS transforms to set the element -        // referenced as head into some kind of position:sticky. -        var head = _reactDom2.default.findDOMNode(this.refs.head); -        head.style.transform = "translate(0," + _reactDom2.default.findDOMNode(this).scrollTop + "px)"; -    } -}; -  var Router = exports.Router = {      contextTypes: {          location: _react2.default.PropTypes.object, @@ -543,9 +520,6 @@ var Router = exports.Router = {          // For whatever reason, react-router always returns the same object, which makes comparing          // the current props with nextProps impossible. As a workaround, we just clone the query object.          return _lodash2.default.clone(this.context.location.query); -    }, -    getParams: function getParams() { -        return this.props.routeParams;      }  }; @@ -915,22 +889,36 @@ var ValueEditor = exports.ValueEditor = _react2.default.createClass({      }  }); -},{"../utils.js":26,"react":"react","react-dom":"react-dom"}],6:[function(require,module,exports){ +},{"../utils.js":27,"react":"react","react-dom":"react-dom"}],6:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", {      value: true  }); +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +  var _react = require("react");  var _react2 = _interopRequireDefault(_react); +var _reactDom = require("react-dom"); + +var _reactDom2 = _interopRequireDefault(_reactDom); + +var _shallowequal = require("shallowequal"); + +var _shallowequal2 = _interopRequireDefault(_shallowequal); +  var _common = require("./common.js");  var _actions = require("../actions.js"); -var _virtualscroll = require("./virtualscroll.js"); +var _AutoScroll = require("./helpers/AutoScroll"); + +var _AutoScroll2 = _interopRequireDefault(_AutoScroll); + +var _VirtualScroll = require("./helpers/VirtualScroll");  var _view = require("../store/view.js"); @@ -940,117 +928,174 @@ var _lodash2 = _interopRequireDefault(_lodash);  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var LogMessage = _react2.default.createClass({ -    displayName: "LogMessage", +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -    render: function render() { -        var entry = this.props.entry; -        var indicator; -        switch (entry.level) { -            case "web": -                indicator = _react2.default.createElement("i", { className: "fa fa-fw fa-html5" }); -                break; -            case "debug": -                indicator = _react2.default.createElement("i", { className: "fa fa-fw fa-bug" }); -                break; -            default: -                indicator = _react2.default.createElement("i", { className: "fa fa-fw fa-info" }); -        } -        return _react2.default.createElement( -            "div", -            null, -            indicator, -            " ", -            entry.message -        ); -    }, -    shouldComponentUpdate: function shouldComponentUpdate() { -        return false; // log entries are immutable. -    } -}); +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } -var EventLogContents = _react2.default.createClass({ -    displayName: "EventLogContents", +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } -    contextTypes: { -        eventStore: _react2.default.PropTypes.object.isRequired -    }, -    mixins: [_common.AutoScrollMixin, _virtualscroll.VirtualScrollMixin], -    getInitialState: function getInitialState() { -        var filterFn = function filterFn(entry) { -            return this.props.filter[entry.level]; -        }; -        var view = new _view.StoreView(this.context.eventStore, filterFn.bind(this)); -        view.addListener("add", this.onEventLogChange); -        view.addListener("recalculate", this.onEventLogChange); +var EventLogContents = function (_React$Component) { +    _inherits(EventLogContents, _React$Component); -        return { -            view: view -        }; -    }, -    componentWillUnmount: function componentWillUnmount() { -        this.state.view.close(); -    }, -    filter: function filter(entry) { -        return this.props.filter[entry.level]; -    }, -    onEventLogChange: function onEventLogChange() { -        this.forceUpdate(); -    }, -    componentWillReceiveProps: function componentWillReceiveProps(nextProps) { -        if (nextProps.filter !== this.props.filter) { -            this.props.filter = nextProps.filter; // Dirty: Make sure that view filter sees the update. -            this.state.view.recalculate(); +    function EventLogContents(props, context) { +        _classCallCheck(this, EventLogContents); + +        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(EventLogContents).call(this, props, context)); + +        _this.view = new _view.StoreView(_this.context.eventStore, function (entry) { +            return _this.props.filter[entry.level]; +        }); + +        _this.heights = {}; +        _this.state = { entries: _this.view.list, vScroll: (0, _VirtualScroll.calcVScroll)() }; + +        _this.onChange = _this.onChange.bind(_this); +        _this.onViewportUpdate = _this.onViewportUpdate.bind(_this); +        return _this; +    } + +    _createClass(EventLogContents, [{ +        key: "componentDidMount", +        value: function componentDidMount() { +            window.addEventListener("resize", this.onViewportUpdate); +            this.view.addListener("add", this.onChange); +            this.view.addListener("recalculate", this.onChange); +            this.onViewportUpdate(); +        } +    }, { +        key: "componentWillUnmount", +        value: function componentWillUnmount() { +            window.removeEventListener("resize", this.onViewportUpdate); +            this.view.removeListener("add", this.onChange); +            this.view.removeListener("recalculate", this.onChange); +            this.view.close(); +        } +    }, { +        key: "componentDidUpdate", +        value: function componentDidUpdate() { +            this.onViewportUpdate(); +        } +    }, { +        key: "componentWillReceiveProps", +        value: function componentWillReceiveProps(nextProps) { +            if (nextProps.filter !== this.props.filter) { +                this.view.recalculate(function (entry) { +                    return nextProps.filter[entry.level]; +                }); +            }          } -    }, -    getDefaultProps: function getDefaultProps() { -        return { -            rowHeight: 45, -            rowHeightMin: 15, -            placeholderTagName: "div" -        }; -    }, -    renderRow: function renderRow(elem) { -        return _react2.default.createElement(LogMessage, { key: elem.id, entry: elem }); -    }, -    render: function render() { -        var entries = this.state.view.list; -        var rows = this.renderRows(entries); +    }, { +        key: "onViewportUpdate", +        value: function onViewportUpdate() { +            var _this2 = this; + +            var viewport = _reactDom2.default.findDOMNode(this); + +            var vScroll = (0, _VirtualScroll.calcVScroll)({ +                itemCount: this.state.entries.length, +                rowHeight: this.props.rowHeight, +                viewportTop: viewport.scrollTop, +                viewportHeight: viewport.offsetHeight, +                itemHeights: this.state.entries.map(function (entry) { +                    return _this2.heights[entry.id]; +                }) +            }); -        return _react2.default.createElement( -            "pre", -            { onScroll: this.onScroll }, -            this.getPlaceholderTop(entries.length), -            rows, -            this.getPlaceholderBottom(entries.length) -        ); -    } -}); +            if (!(0, _shallowequal2.default)(this.state.vScroll, vScroll)) { +                this.setState({ vScroll: vScroll }); +            } +        } +    }, { +        key: "onChange", +        value: function onChange() { +            this.setState({ entries: this.view.list }); +        } +    }, { +        key: "setHeight", +        value: function setHeight(id, ref) { +            if (ref && !this.heights[id]) { +                var height = _reactDom2.default.findDOMNode(ref).offsetHeight; +                if (this.heights[id] !== height) { +                    this.heights[id] = height; +                    this.onViewportUpdate(); +                } +            } +        } +    }, { +        key: "getIcon", +        value: function getIcon(level) { +            return { web: "html5", debug: "bug" }[level] || "info"; +        } +    }, { +        key: "render", +        value: function render() { +            var _this3 = this; -var ToggleFilter = _react2.default.createClass({ -    displayName: "ToggleFilter", +            var vScroll = this.state.vScroll; +            var entries = this.state.entries.slice(vScroll.start, vScroll.end); -    toggle: function toggle(e) { -        e.preventDefault(); -        return this.props.toggleLevel(this.props.name); -    }, -    render: function render() { -        var className = "label "; -        if (this.props.active) { -            className += "label-primary"; -        } else { -            className += "label-default"; +            return _react2.default.createElement( +                "pre", +                { onScroll: this.onViewportUpdate }, +                _react2.default.createElement("div", { style: { height: vScroll.paddingTop } }), +                entries.map(function (entry, index) { +                    return _react2.default.createElement( +                        "div", +                        { key: entry.id, ref: _this3.setHeight.bind(_this3, entry.id) }, +                        _react2.default.createElement("i", { className: "fa fa-fw fa-" + _this3.getIcon(entry.level) }), +                        entry.message +                    ); +                }), +                _react2.default.createElement("div", { style: { height: vScroll.paddingBottom } }) +            );          } -        return _react2.default.createElement( -            "a", -            { -                href: "#", -                className: className, -                onClick: this.toggle }, -            this.props.name -        ); +    }]); + +    return EventLogContents; +}(_react2.default.Component); + +EventLogContents.contextTypes = { +    eventStore: _react2.default.PropTypes.object.isRequired +}; +EventLogContents.defaultProps = { +    rowHeight: 18 +}; + + +ToggleFilter.propTypes = { +    name: _react2.default.PropTypes.string.isRequired, +    toggleLevel: _react2.default.PropTypes.func.isRequired, +    active: _react2.default.PropTypes.bool +}; + +function ToggleFilter(_ref) { +    var name = _ref.name; +    var active = _ref.active; +    var toggleLevel = _ref.toggleLevel; + +    var className = "label "; +    if (active) { +        className += "label-primary"; +    } else { +        className += "label-default";      } -}); + +    function onClick(event) { +        event.preventDefault(); +        toggleLevel(name); +    } + +    return _react2.default.createElement( +        "a", +        { +            href: "#", +            className: className, +            onClick: onClick }, +        name +    ); +} + +var AutoScrollEventLog = (0, _AutoScroll2.default)(EventLogContents);  var EventLog = _react2.default.createClass({      displayName: "EventLog", @@ -1068,7 +1113,6 @@ var EventLog = _react2.default.createClass({      close: function close() {          var d = {};          d[_actions.Query.SHOW_EVENTLOG] = undefined; -          this.updateLocation(undefined, d);      },      toggleLevel: function toggleLevel(level) { @@ -1093,14 +1137,14 @@ var EventLog = _react2.default.createClass({                      _react2.default.createElement("i", { onClick: this.close, className: "fa fa-close" })                  )              ), -            _react2.default.createElement(EventLogContents, { filter: this.state.filter }) +            _react2.default.createElement(AutoScrollEventLog, { filter: this.state.filter })          );      }  });  exports.default = EventLog; -},{"../actions.js":2,"../store/view.js":25,"./common.js":4,"./virtualscroll.js":19,"lodash":"lodash","react":"react"}],7:[function(require,module,exports){ +},{"../actions.js":2,"../store/view.js":26,"./common.js":4,"./helpers/AutoScroll":16,"./helpers/VirtualScroll":17,"lodash":"lodash","react":"react","react-dom":"react-dom","shallowequal":"shallowequal"}],7:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -1369,13 +1413,15 @@ var all_columns = [TLSColumn, IconColumn, PathColumn, MethodColumn, StatusColumn  exports.default = all_columns; -},{"../flow/utils.js":23,"../utils.js":26,"react":"react"}],8:[function(require,module,exports){ +},{"../flow/utils.js":24,"../utils.js":27,"react":"react"}],8:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", {      value: true  }); +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); +  var _react = require("react");  var _react2 = _interopRequireDefault(_react); @@ -1384,7 +1430,9 @@ var _reactDom = require("react-dom");  var _reactDom2 = _interopRequireDefault(_reactDom); -var _common = require("./common.js"); +var _classnames = require("classnames"); + +var _classnames2 = _interopRequireDefault(_classnames);  var _utils = require("../utils.js"); @@ -1392,7 +1440,15 @@ var _lodash = require("lodash");  var _lodash2 = _interopRequireDefault(_lodash); -var _virtualscroll = require("./virtualscroll.js"); +var _shallowequal = require("shallowequal"); + +var _shallowequal2 = _interopRequireDefault(_shallowequal); + +var _AutoScroll = require("./helpers/AutoScroll"); + +var _AutoScroll2 = _interopRequireDefault(_AutoScroll); + +var _VirtualScroll = require("./helpers/VirtualScroll");  var _flowtableColumns = require("./flowtable-columns.js"); @@ -1400,196 +1456,256 @@ var _flowtableColumns2 = _interopRequireDefault(_flowtableColumns);  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var FlowRow = _react2.default.createClass({ -    displayName: "FlowRow", +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -    render: function render() { -        var flow = this.props.flow; -        var columns = this.props.columns.map(function (Column) { +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +FlowRow.propTypes = { +    selectFlow: _react2.default.PropTypes.func.isRequired, +    columns: _react2.default.PropTypes.array.isRequired, +    flow: _react2.default.PropTypes.object.isRequired, +    highlighted: _react2.default.PropTypes.bool, +    selected: _react2.default.PropTypes.bool +}; + +function FlowRow(props) { +    var flow = props.flow; + +    var className = (0, _classnames2.default)({ +        "selected": props.selected, +        "highlighted": props.highlighted, +        "intercepted": flow.intercepted, +        "has-request": flow.request, +        "has-response": flow.response +    }); + +    return _react2.default.createElement( +        "tr", +        { className: className, onClick: function onClick() { +                return props.selectFlow(flow); +            } }, +        props.columns.map(function (Column) {              return _react2.default.createElement(Column, { key: Column.displayName, flow: flow }); -        }.bind(this)); -        var className = ""; -        if (this.props.selected) { -            className += " selected"; -        } -        if (this.props.highlighted) { -            className += " highlighted"; -        } -        if (flow.intercepted) { -            className += " intercepted"; -        } -        if (flow.request) { -            className += " has-request"; -        } -        if (flow.response) { -            className += " has-response"; -        } +        }) +    ); +} -        return _react2.default.createElement( -            "tr", -            { className: className, onClick: this.props.selectFlow.bind(null, flow) }, -            columns -        ); -    }, -    shouldComponentUpdate: function shouldComponentUpdate(nextProps) { -        return true; -        // Further optimization could be done here -        // by calling forceUpdate on flow updates, selection changes and column changes. -        //return ( -        //(this.props.columns.length !== nextProps.columns.length) || -        //(this.props.selected !== nextProps.selected) -        //); +var FlowTableHead = function (_React$Component) { +    _inherits(FlowTableHead, _React$Component); + +    function FlowTableHead(props, context) { +        _classCallCheck(this, FlowTableHead); + +        var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(FlowTableHead).call(this, props, context)); + +        _this.state = { sortColumn: undefined, sortDesc: false }; +        return _this;      } -}); -var FlowTableHead = _react2.default.createClass({ -    displayName: "FlowTableHead", +    _createClass(FlowTableHead, [{ +        key: "onClick", +        value: function onClick(Column) { +            var hasSort = Column.sortKeyFun; -    getInitialState: function getInitialState() { -        return { -            sortColumn: undefined, -            sortDesc: false -        }; -    }, -    onClick: function onClick(Column) { -        var sortDesc = this.state.sortDesc; -        var hasSort = Column.sortKeyFun; -        if (Column === this.state.sortColumn) { -            sortDesc = !sortDesc; -            this.setState({ -                sortDesc: sortDesc -            }); -        } else { -            this.setState({ -                sortColumn: hasSort && Column, -                sortDesc: false -            }); -        } -        var sortKeyFun; -        if (!sortDesc) { -            sortKeyFun = Column.sortKeyFun; -        } else { -            sortKeyFun = hasSort && function () { -                var k = Column.sortKeyFun.apply(this, arguments); -                if (_lodash2.default.isString(k)) { -                    return (0, _utils.reverseString)("" + k); -                } else { +            var sortDesc = this.state.sortDesc; + +            if (Column === this.state.sortColumn) { +                sortDesc = !sortDesc; +                this.setState({ sortDesc: sortDesc }); +            } else { +                this.setState({ sortColumn: hasSort && Column, sortDesc: false }); +            } + +            var sortKeyFun = Column.sortKeyFun; +            if (sortDesc) { +                sortKeyFun = hasSort && function () { +                    var k = Column.sortKeyFun.apply(this, arguments); +                    if (_lodash2.default.isString(k)) { +                        return (0, _utils.reverseString)("" + k); +                    }                      return -k; -                } -            }; -        } -        this.props.setSortKeyFun(sortKeyFun); -    }, -    render: function render() { -        var columns = this.props.columns.map(function (Column) { -            var onClick = this.onClick.bind(this, Column); -            var className; -            if (this.state.sortColumn === Column) { -                if (this.state.sortDesc) { -                    className = "sort-desc"; -                } else { -                    className = "sort-asc"; -                } +                };              } -            return _react2.default.createElement(Column.Title, { -                key: Column.displayName, -                onClick: onClick, -                className: className }); -        }.bind(this)); -        return _react2.default.createElement( -            "thead", -            null, -            _react2.default.createElement( + +            this.props.setSortKeyFun(sortKeyFun); +        } +    }, { +        key: "render", +        value: function render() { +            var _this2 = this; + +            var sortColumn = this.state.sortColumn; +            var sortType = this.state.sortDesc ? "sort-desc" : "sort-asc"; +            return _react2.default.createElement(                  "tr",                  null, -                columns -            ) -        ); -    } -}); +                this.props.columns.map(function (Column) { +                    return _react2.default.createElement(Column.Title, { +                        key: Column.displayName, +                        onClick: function onClick() { +                            return _this2.onClick(Column); +                        }, +                        className: sortColumn === Column && sortType +                    }); +                }) +            ); +        } +    }]); -var ROW_HEIGHT = 32; +    return FlowTableHead; +}(_react2.default.Component); -var FlowTable = _react2.default.createClass({ -    displayName: "FlowTable", +FlowTableHead.propTypes = { +    setSortKeyFun: _react2.default.PropTypes.func.isRequired, +    columns: _react2.default.PropTypes.array.isRequired +}; -    mixins: [_common.StickyHeadMixin, _common.AutoScrollMixin, _virtualscroll.VirtualScrollMixin], -    contextTypes: { -        view: _react2.default.PropTypes.object.isRequired -    }, -    getInitialState: function getInitialState() { -        return { -            columns: _flowtableColumns2.default -        }; -    }, -    componentWillMount: function componentWillMount() { -        this.context.view.addListener("add", this.onChange); -        this.context.view.addListener("update", this.onChange); -        this.context.view.addListener("remove", this.onChange); -        this.context.view.addListener("recalculate", this.onChange); -    }, -    componentWillUnmount: function componentWillUnmount() { -        this.context.view.removeListener("add", this.onChange); -        this.context.view.removeListener("update", this.onChange); -        this.context.view.removeListener("remove", this.onChange); -        this.context.view.removeListener("recalculate", this.onChange); -    }, -    getDefaultProps: function getDefaultProps() { -        return { -            rowHeight: ROW_HEIGHT -        }; -    }, -    onScrollFlowTable: function onScrollFlowTable() { -        this.adjustHead(); -        this.onScroll(); -    }, -    onChange: function onChange() { -        this.forceUpdate(); -    }, -    scrollIntoView: function scrollIntoView(flow) { -        this.scrollRowIntoView(this.context.view.indexOf(flow), _reactDom2.default.findDOMNode(this.refs.body).offsetTop); -    }, -    renderRow: function renderRow(flow) { -        var selected = flow === this.props.selected; -        var highlighted = this.context.view._highlight && this.context.view._highlight[flow.id]; +var FlowTable = function (_React$Component2) { +    _inherits(FlowTable, _React$Component2); + +    function FlowTable(props, context) { +        _classCallCheck(this, FlowTable); + +        var _this3 = _possibleConstructorReturn(this, Object.getPrototypeOf(FlowTable).call(this, props, context)); + +        _this3.state = { flows: [], vScroll: (0, _VirtualScroll.calcVScroll)() }; + +        _this3.onChange = _this3.onChange.bind(_this3); +        _this3.onViewportUpdate = _this3.onViewportUpdate.bind(_this3); +        return _this3; +    } + +    _createClass(FlowTable, [{ +        key: "componentWillMount", +        value: function componentWillMount() { +            window.addEventListener("resize", this.onViewportUpdate); +            this.context.view.addListener("add", this.onChange); +            this.context.view.addListener("update", this.onChange); +            this.context.view.addListener("remove", this.onChange); +            this.context.view.addListener("recalculate", this.onChange); +        } +    }, { +        key: "componentWillUnmount", +        value: function componentWillUnmount() { +            window.removeEventListener("resize", this.onViewportUpdate); +            this.context.view.removeListener("add", this.onChange); +            this.context.view.removeListener("update", this.onChange); +            this.context.view.removeListener("remove", this.onChange); +            this.context.view.removeListener("recalculate", this.onChange); +        } +    }, { +        key: "componentDidUpdate", +        value: function componentDidUpdate() { +            this.onViewportUpdate(); +        } +    }, { +        key: "onViewportUpdate", +        value: function onViewportUpdate() { +            var viewport = _reactDom2.default.findDOMNode(this); +            var viewportTop = viewport.scrollTop; + +            var vScroll = (0, _VirtualScroll.calcVScroll)({ +                viewportTop: viewportTop, +                viewportHeight: viewport.offsetHeight, +                itemCount: this.state.flows.length, +                rowHeight: this.props.rowHeight +            }); -        return _react2.default.createElement(FlowRow, { key: flow.id, -            ref: flow.id, -            flow: flow, -            columns: this.state.columns, -            selected: selected, -            highlighted: highlighted, -            selectFlow: this.props.selectFlow -        }); -    }, -    render: function render() { -        var flows = this.context.view.list; -        var rows = this.renderRows(flows); +            if (!(0, _shallowequal2.default)(this.state.vScroll, vScroll) || this.state.viewportTop !== viewportTop) { +                this.setState({ vScroll: vScroll, viewportTop: viewportTop }); +            } +        } +    }, { +        key: "onChange", +        value: function onChange() { +            this.setState({ flows: this.context.view.list }); +        } +    }, { +        key: "scrollIntoView", +        value: function scrollIntoView(flow) { +            var viewport = _reactDom2.default.findDOMNode(this); +            var index = this.context.view.indexOf(flow); +            var rowHeight = this.props.rowHeight; +            var head = _reactDom2.default.findDOMNode(this.refs.head); -        return _react2.default.createElement( -            "div", -            { className: "flow-table", onScroll: this.onScrollFlowTable }, -            _react2.default.createElement( -                "table", -                null, -                _react2.default.createElement(FlowTableHead, { ref: "head", -                    columns: this.state.columns, -                    setSortKeyFun: this.props.setSortKeyFun }), +            var headHeight = head ? head.offsetHeight : 0; + +            var rowTop = index * rowHeight + headHeight; +            var rowBottom = rowTop + rowHeight; + +            var viewportTop = viewport.scrollTop; +            var viewportHeight = viewport.offsetHeight; + +            // Account for pinned thead +            if (rowTop - headHeight < viewportTop) { +                viewport.scrollTop = rowTop - headHeight; +            } else if (rowBottom > viewportTop + viewportHeight) { +                viewport.scrollTop = rowBottom - viewportHeight; +            } +        } +    }, { +        key: "render", +        value: function render() { +            var _this4 = this; + +            var vScroll = this.state.vScroll; +            var highlight = this.context.view._highlight; +            var flows = this.state.flows.slice(vScroll.start, vScroll.end); + +            var transform = "translate(0," + this.state.viewportTop + "px)"; + +            return _react2.default.createElement( +                "div", +                { className: "flow-table", onScroll: this.onViewportUpdate },                  _react2.default.createElement( -                    "tbody", -                    { ref: "body" }, -                    this.getPlaceholderTop(flows.length), -                    rows, -                    this.getPlaceholderBottom(flows.length) +                    "table", +                    null, +                    _react2.default.createElement( +                        "thead", +                        { ref: "head", style: { transform: transform } }, +                        _react2.default.createElement(FlowTableHead, { +                            columns: _flowtableColumns2.default, +                            setSortKeyFun: this.props.setSortKeyFun +                        }) +                    ), +                    _react2.default.createElement( +                        "tbody", +                        null, +                        _react2.default.createElement("tr", { style: { height: vScroll.paddingTop } }), +                        flows.map(function (flow) { +                            return _react2.default.createElement(FlowRow, { +                                key: flow.id, +                                flow: flow, +                                columns: _flowtableColumns2.default, +                                selected: flow === _this4.props.selected, +                                highlighted: highlight && highlight[flow.id], +                                selectFlow: _this4.props.selectFlow +                            }); +                        }), +                        _react2.default.createElement("tr", { style: { height: vScroll.paddingBottom } }) +                    )                  ) -            ) -        ); -    } -}); +            ); +        } +    }]); + +    return FlowTable; +}(_react2.default.Component); -exports.default = FlowTable; +FlowTable.contextTypes = { +    view: _react2.default.PropTypes.object.isRequired +}; +FlowTable.propTypes = { +    rowHeight: _react2.default.PropTypes.number +}; +FlowTable.defaultProps = { +    rowHeight: 32 +}; +exports.default = (0, _AutoScroll2.default)(FlowTable); -},{"../utils.js":26,"./common.js":4,"./flowtable-columns.js":7,"./virtualscroll.js":19,"lodash":"lodash","react":"react","react-dom":"react-dom"}],9:[function(require,module,exports){ +},{"../utils.js":27,"./flowtable-columns.js":7,"./helpers/AutoScroll":16,"./helpers/VirtualScroll":17,"classnames":"classnames","lodash":"lodash","react":"react","react-dom":"react-dom","shallowequal":"shallowequal"}],9:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -1899,7 +2015,7 @@ var ContentView = _react2.default.createClass({  exports.default = ContentView; -},{"../../flow/utils.js":23,"../../utils.js":26,"lodash":"lodash","react":"react"}],10:[function(require,module,exports){ +},{"../../flow/utils.js":24,"../../utils.js":27,"lodash":"lodash","react":"react"}],10:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -2167,7 +2283,7 @@ var Details = _react2.default.createClass({  exports.default = Details; -},{"../../utils.js":26,"lodash":"lodash","react":"react"}],11:[function(require,module,exports){ +},{"../../utils.js":27,"lodash":"lodash","react":"react"}],11:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -2299,7 +2415,7 @@ var FlowView = _react2.default.createClass({  exports.default = FlowView; -},{"../common.js":4,"../prompt.js":17,"./details.js":10,"./messages.js":12,"./nav.js":13,"react":"react"}],12:[function(require,module,exports){ +},{"../common.js":4,"../prompt.js":19,"./details.js":10,"./messages.js":12,"./nav.js":13,"react":"react"}],12:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -2664,7 +2780,7 @@ var Error = exports.Error = _react2.default.createClass({      }  }); -},{"../../actions.js":2,"../../flow/utils.js":23,"../../utils.js":26,"../editor.js":5,"./contentview.js":9,"lodash":"lodash","react":"react","react-dom":"react-dom"}],13:[function(require,module,exports){ +},{"../../actions.js":2,"../../flow/utils.js":24,"../../utils.js":27,"../editor.js":5,"./contentview.js":9,"lodash":"lodash","react":"react","react-dom":"react-dom"}],13:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -2757,8 +2873,6 @@ var _react = require("react");  var _react2 = _interopRequireDefault(_react); -var _common = require("./common.js"); -  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }  Footer.propTypes = { @@ -2788,7 +2902,7 @@ function Footer(_ref) {      );  } -},{"./common.js":4,"react":"react"}],15:[function(require,module,exports){ +},{"react":"react"}],15:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -3257,7 +3371,152 @@ var Header = exports.Header = _react2.default.createClass({      }  }); -},{"../actions.js":2,"../filt/filt.js":22,"../utils.js":26,"./common.js":4,"jquery":"jquery","react":"react","react-dom":"react-dom"}],16:[function(require,module,exports){ +},{"../actions.js":2,"../filt/filt.js":23,"../utils.js":27,"./common.js":4,"jquery":"jquery","react":"react","react-dom":"react-dom"}],16:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { +    value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _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 (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _react = require("react"); + +var _react2 = _interopRequireDefault(_react); + +var _reactDom = require("react-dom"); + +var _reactDom2 = _interopRequireDefault(_reactDom); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var symShouldStick = Symbol("shouldStick"); +var isAtBottom = function isAtBottom(v) { +    return v.scrollTop + v.clientHeight === v.scrollHeight; +}; + +exports.default = function (Component) { +    var _class, _temp; + +    return Object.assign((_temp = _class = function (_Component) { +        _inherits(AutoScrollWrapper, _Component); + +        function AutoScrollWrapper() { +            _classCallCheck(this, AutoScrollWrapper); + +            return _possibleConstructorReturn(this, Object.getPrototypeOf(AutoScrollWrapper).apply(this, arguments)); +        } + +        _createClass(AutoScrollWrapper, [{ +            key: "componentWillUpdate", +            value: function componentWillUpdate() { +                var viewport = _reactDom2.default.findDOMNode(this); +                this[symShouldStick] = viewport.scrollTop && isAtBottom(viewport); +                _get(Object.getPrototypeOf(AutoScrollWrapper.prototype), "componentWillUpdate", this) && _get(Object.getPrototypeOf(AutoScrollWrapper.prototype), "componentWillUpdate", this).call(this); +            } +        }, { +            key: "componentDidUpdate", +            value: function componentDidUpdate() { +                var viewport = _reactDom2.default.findDOMNode(this); +                if (this[symShouldStick] && !isAtBottom(viewport)) { +                    viewport.scrollTop = viewport.scrollHeight; +                } +                _get(Object.getPrototypeOf(AutoScrollWrapper.prototype), "componentDidUpdate", this) && _get(Object.getPrototypeOf(AutoScrollWrapper.prototype), "componentDidUpdate", this).call(this); +            } +        }]); + +        return AutoScrollWrapper; +    }(Component), _class.displayName = Component.name, _temp), Component); +}; + +},{"react":"react","react-dom":"react-dom"}],17:[function(require,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { +    value: true +}); +exports.calcVScroll = calcVScroll; +/** + * Calculate virtual scroll stuffs + * + * @param {?Object} opts Options for calculation + * + * @returns {Object} result + * + * __opts__ should have following properties: + * - {number}         itemCount + * - {number}         rowHeight + * - {number}         viewportTop + * - {number}         viewportHeight + * - {Array<?number>} [itemHeights] + * + * __result__ have following properties: + * - {number} start + * - {number} end + * - {number} paddingTop + * - {number} paddingBottom + */ +function calcVScroll(opts) { +    if (!opts) { +        return { start: 0, end: 0, paddingTop: 0, paddingBottom: 0 }; +    } + +    var itemCount = opts.itemCount; +    var rowHeight = opts.rowHeight; +    var viewportTop = opts.viewportTop; +    var viewportHeight = opts.viewportHeight; +    var itemHeights = opts.itemHeights; + +    var viewportBottom = viewportTop + viewportHeight; + +    var start = 0; +    var end = 0; + +    var paddingTop = 0; +    var paddingBottom = 0; + +    if (itemHeights) { + +        for (var i = 0, pos = 0; i < itemCount; i++) { +            var height = itemHeights[i] || rowHeight; + +            if (pos <= viewportTop && i % 2 === 0) { +                paddingTop = pos; +                start = i; +            } + +            if (pos <= viewportBottom) { +                end = i + 1; +            } else { +                paddingBottom += height; +            } + +            pos += height; +        } +    } else { + +        // Make sure that we start at an even row so that CSS `:nth-child(even)` is preserved +        start = Math.max(0, Math.floor(viewportTop / rowHeight) - 1) & ~1; +        end = Math.min(itemCount, start + Math.ceil(viewportHeight / rowHeight) + 1); + +        // When a large trunk of elements is removed from the button, start may be far off the viewport. +        // To make this issue less severe, limit the top placeholder to the total number of rows. +        paddingTop = Math.min(start, itemCount) * rowHeight; +        paddingBottom = Math.max(0, itemCount - end) * rowHeight; +    } + +    return { start: start, end: end, paddingTop: paddingTop, paddingBottom: paddingBottom }; +} + +},{}],18:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -3362,12 +3621,12 @@ var MainView = _react2.default.createClass({          }      },      onUpdate: function onUpdate(flow) { -        if (flow.id === this.getParams().flowId) { +        if (flow.id === this.props.routeParams.flowId) {              this.forceUpdate();          }      },      onRemove: function onRemove(flow_id, index) { -        if (flow_id === this.getParams().flowId) { +        if (flow_id === this.props.routeParams.flowId) {              var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length - 1)];              this.selectFlow(flow_to_select);          } @@ -3380,7 +3639,7 @@ var MainView = _react2.default.createClass({      },      selectFlow: function selectFlow(flow) {          if (flow) { -            var tab = this.getParams().detailTab || "request"; +            var tab = this.props.routeParams.detailTab || "request";              this.updateLocation("/flows/" + flow.id + "/" + tab);              this.refs.flowTable.scrollIntoView(flow);          } else { @@ -3390,14 +3649,14 @@ var MainView = _react2.default.createClass({      selectFlowRelative: function selectFlowRelative(shift) {          var flows = this.state.view.list;          var index; -        if (!this.getParams().flowId) { +        if (!this.props.routeParams.flowId) {              if (shift < 0) {                  index = flows.length - 1;              } else {                  index = 0;              }          } else { -            var currFlowId = this.getParams().flowId; +            var currFlowId = this.props.routeParams.flowId;              var i = flows.length;              while (i--) {                  if (flows[i].id === currFlowId) { @@ -3497,7 +3756,7 @@ var MainView = _react2.default.createClass({          e.preventDefault();      },      getSelected: function getSelected() { -        return this.context.flowStore.get(this.getParams().flowId); +        return this.context.flowStore.get(this.props.routeParams.flowId);      },      render: function render() {          var selected = this.getSelected(); @@ -3507,7 +3766,7 @@ var MainView = _react2.default.createClass({              details = [_react2.default.createElement(_common.Splitter, { key: "splitter" }), _react2.default.createElement(_index2.default, {                  key: "flowDetails",                  ref: "flowDetails", -                tab: this.getParams().detailTab, +                tab: this.props.routeParams.detailTab,                  flow: selected })];          } else {              details = null; @@ -3527,7 +3786,7 @@ var MainView = _react2.default.createClass({  exports.default = MainView; -},{"../actions.js":2,"../filt/filt.js":22,"../store/view.js":25,"../utils.js":26,"./common.js":4,"./flowtable.js":8,"./flowview/index.js":11,"react":"react"}],17:[function(require,module,exports){ +},{"../actions.js":2,"../filt/filt.js":23,"../store/view.js":26,"../utils.js":27,"./common.js":4,"./flowtable.js":8,"./flowview/index.js":11,"react":"react"}],19:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -3663,7 +3922,7 @@ var Prompt = _react2.default.createClass({  exports.default = Prompt; -},{"../utils.js":26,"lodash":"lodash","react":"react","react-dom":"react-dom"}],18:[function(require,module,exports){ +},{"../utils.js":27,"lodash":"lodash","react":"react","react-dom":"react-dom"}],20:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -3832,107 +4091,7 @@ var app = exports.app = _react2.default.createElement(      )  ); -},{"../actions.js":2,"../store/store.js":24,"../utils.js":26,"./common.js":4,"./eventlog.js":6,"./footer.js":14,"./header.js":15,"./mainview.js":16,"lodash":"lodash","react":"react","react-dom":"react-dom","react-router":"react-router"}],19:[function(require,module,exports){ -"use strict"; - -Object.defineProperty(exports, "__esModule", { -    value: true -}); -exports.VirtualScrollMixin = undefined; - -var _react = require("react"); - -var _react2 = _interopRequireDefault(_react); - -var _reactDom = require("react-dom"); - -var _reactDom2 = _interopRequireDefault(_reactDom); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var VirtualScrollMixin = exports.VirtualScrollMixin = { -    getInitialState: function getInitialState() { -        return { -            start: 0, -            stop: 0 -        }; -    }, -    componentWillMount: function componentWillMount() { -        if (!this.props.rowHeight) { -            console.warn("VirtualScrollMixin: No rowHeight specified", this); -        } -    }, -    getPlaceholderTop: function getPlaceholderTop(total) { -        var Tag = this.props.placeholderTagName || "tr"; -        // When a large trunk of elements is removed from the button, start may be far off the viewport. -        // To make this issue less severe, limit the top placeholder to the total number of rows. -        var style = { -            height: Math.min(this.state.start, total) * this.props.rowHeight -        }; -        var spacer = _react2.default.createElement(Tag, { key: "placeholder-top", style: style }); - -        if (this.state.start % 2 === 1) { -            // fix even/odd rows -            return [spacer, _react2.default.createElement(Tag, { key: "placeholder-top-2" })]; -        } else { -            return spacer; -        } -    }, -    getPlaceholderBottom: function getPlaceholderBottom(total) { -        var Tag = this.props.placeholderTagName || "tr"; -        var style = { -            height: Math.max(0, total - this.state.stop) * this.props.rowHeight -        }; -        return _react2.default.createElement(Tag, { key: "placeholder-bottom", style: style }); -    }, -    componentDidMount: function componentDidMount() { -        this.onScroll(); -        window.addEventListener('resize', this.onScroll); -    }, -    componentWillUnmount: function componentWillUnmount() { -        window.removeEventListener('resize', this.onScroll); -    }, -    onScroll: function onScroll() { -        var viewport = _reactDom2.default.findDOMNode(this); -        var top = viewport.scrollTop; -        var height = viewport.offsetHeight; -        var start = Math.floor(top / this.props.rowHeight); -        var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight)); - -        this.setState({ -            start: start, -            stop: stop -        }); -    }, -    renderRows: function renderRows(elems) { -        var rows = []; -        var max = Math.min(elems.length, this.state.stop); - -        for (var i = this.state.start; i < max; i++) { -            var elem = elems[i]; -            rows.push(this.renderRow(elem)); -        } -        return rows; -    }, -    scrollRowIntoView: function scrollRowIntoView(index, head_height) { - -        var row_top = index * this.props.rowHeight + head_height; -        var row_bottom = row_top + this.props.rowHeight; - -        var viewport = _reactDom2.default.findDOMNode(this); -        var viewport_top = viewport.scrollTop; -        var viewport_bottom = viewport_top + viewport.offsetHeight; - -        // Account for pinned thead -        if (row_top - head_height < viewport_top) { -            viewport.scrollTop = row_top - head_height; -        } else if (row_bottom > viewport_bottom) { -            viewport.scrollTop = row_bottom - viewport.offsetHeight; -        } -    } -}; - -},{"react":"react","react-dom":"react-dom"}],20:[function(require,module,exports){ +},{"../actions.js":2,"../store/store.js":25,"../utils.js":27,"./common.js":4,"./eventlog.js":6,"./footer.js":14,"./header.js":15,"./mainview.js":18,"lodash":"lodash","react":"react","react-dom":"react-dom","react-router":"react-router"}],21:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -3969,7 +4128,7 @@ function Connection(url) {  exports.default = Connection; -},{"./actions.js":2,"./dispatcher.js":21}],21:[function(require,module,exports){ +},{"./actions.js":2,"./dispatcher.js":22}],22:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -3998,7 +4157,7 @@ AppDispatcher.dispatchServerAction = function (action) {      this.dispatch(action);  }; -},{"flux":"flux"}],22:[function(require,module,exports){ +},{"flux":"flux"}],23:[function(require,module,exports){  "use strict";  module.exports = function () { @@ -5902,7 +6061,7 @@ module.exports = function () {    };  }(); -},{"../flow/utils.js":23}],23:[function(require,module,exports){ +},{"../flow/utils.js":24}],24:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -6036,7 +6195,7 @@ var parseHttpVersion = exports.parseHttpVersion = function parseHttpVersion(http      });  }; -},{"jquery":"jquery","lodash":"lodash"}],24:[function(require,module,exports){ +},{"jquery":"jquery","lodash":"lodash"}],25:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -6223,7 +6382,7 @@ _lodash2.default.extend(EventLogStore.prototype, LiveListStore.prototype, {      }  }); -},{"../actions.js":2,"../dispatcher.js":21,"events":1,"jquery":"jquery","lodash":"lodash"}],25:[function(require,module,exports){ +},{"../actions.js":2,"../dispatcher.js":22,"events":1,"jquery":"jquery","lodash":"lodash"}],26:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { @@ -6353,7 +6512,7 @@ _lodash2.default.extend(StoreView.prototype, _events.EventEmitter.prototype, {      }  }); -},{"../utils.js":26,"events":1,"lodash":"lodash"}],26:[function(require,module,exports){ +},{"../utils.js":27,"events":1,"lodash":"lodash"}],27:[function(require,module,exports){  "use strict";  Object.defineProperty(exports, "__esModule", { diff --git a/mitmproxy/web/static/vendor.js b/mitmproxy/web/static/vendor.js index 6bb4b947..0f6ec987 100644 --- a/mitmproxy/web/static/vendor.js +++ b/mitmproxy/web/static/vendor.js @@ -180,7 +180,7 @@ var invariant = function (condition, format, a, b, c, d, e, f) {  module.exports = invariant;  }).call(this,require('_process')) -},{"_process":23}],5:[function(require,module,exports){ +},{"_process":27}],5:[function(require,module,exports){  (function (process){  /**   * Copyright (c) 2014-2015, Facebook, Inc. @@ -415,7 +415,7 @@ var Dispatcher = (function () {  module.exports = Dispatcher;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/invariant":4}],6:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/invariant":4}],6:[function(require,module,exports){  /**   * Indicates that navigation was caused by a call to history.push.   */ @@ -551,7 +551,7 @@ function readState(key) {  }  }).call(this,require('_process')) -},{"_process":23,"warning":232}],9:[function(require,module,exports){ +},{"_process":27,"warning":236}],9:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -684,7 +684,7 @@ function parsePath(path) {  }  }).call(this,require('_process')) -},{"_process":23,"warning":232}],12:[function(require,module,exports){ +},{"_process":27,"warning":236}],12:[function(require,module,exports){  (function (process){  'use strict'; @@ -864,7 +864,7 @@ exports['default'] = createBrowserHistory;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./Actions":6,"./DOMStateStorage":8,"./DOMUtils":9,"./ExecutionEnvironment":10,"./PathUtils":11,"./createDOMHistory":13,"_process":23,"invariant":22}],13:[function(require,module,exports){ +},{"./Actions":6,"./DOMStateStorage":8,"./DOMUtils":9,"./ExecutionEnvironment":10,"./PathUtils":11,"./createDOMHistory":13,"_process":27,"invariant":22}],13:[function(require,module,exports){  (function (process){  'use strict'; @@ -908,7 +908,7 @@ exports['default'] = createDOMHistory;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./DOMUtils":9,"./ExecutionEnvironment":10,"./createHistory":15,"_process":23,"invariant":22}],14:[function(require,module,exports){ +},{"./DOMUtils":9,"./ExecutionEnvironment":10,"./createHistory":15,"_process":27,"invariant":22}],14:[function(require,module,exports){  (function (process){  'use strict'; @@ -1158,7 +1158,7 @@ exports['default'] = createHashHistory;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./Actions":6,"./DOMStateStorage":8,"./DOMUtils":9,"./ExecutionEnvironment":10,"./PathUtils":11,"./createDOMHistory":13,"_process":23,"invariant":22,"warning":232}],15:[function(require,module,exports){ +},{"./Actions":6,"./DOMStateStorage":8,"./DOMUtils":9,"./ExecutionEnvironment":10,"./PathUtils":11,"./createDOMHistory":13,"_process":27,"invariant":22,"warning":236}],15:[function(require,module,exports){  (function (process){  'use strict'; @@ -1450,7 +1450,7 @@ exports['default'] = createHistory;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./Actions":6,"./AsyncUtils":7,"./PathUtils":11,"./createLocation":16,"./deprecate":18,"./runTransitionHook":19,"_process":23,"deep-equal":1,"warning":232}],16:[function(require,module,exports){ +},{"./Actions":6,"./AsyncUtils":7,"./PathUtils":11,"./createLocation":16,"./deprecate":18,"./runTransitionHook":19,"_process":27,"deep-equal":1,"warning":236}],16:[function(require,module,exports){  (function (process){  'use strict'; @@ -1505,7 +1505,7 @@ exports['default'] = createLocation;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./Actions":6,"./PathUtils":11,"_process":23,"warning":232}],17:[function(require,module,exports){ +},{"./Actions":6,"./PathUtils":11,"_process":27,"warning":236}],17:[function(require,module,exports){  (function (process){  'use strict'; @@ -1662,7 +1662,7 @@ exports['default'] = createMemoryHistory;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./Actions":6,"./PathUtils":11,"./createHistory":15,"_process":23,"invariant":22,"warning":232}],18:[function(require,module,exports){ +},{"./Actions":6,"./PathUtils":11,"./createHistory":15,"_process":27,"invariant":22,"warning":236}],18:[function(require,module,exports){  (function (process){  'use strict'; @@ -1685,7 +1685,7 @@ exports['default'] = deprecate;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"_process":23,"warning":232}],19:[function(require,module,exports){ +},{"_process":27,"warning":236}],19:[function(require,module,exports){  (function (process){  'use strict'; @@ -1713,7 +1713,7 @@ exports['default'] = runTransitionHook;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"_process":23,"warning":232}],20:[function(require,module,exports){ +},{"_process":27,"warning":236}],20:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -2035,7 +2035,7 @@ exports['default'] = useQueries;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./PathUtils":11,"./deprecate":18,"./runTransitionHook":19,"_process":23,"query-string":24,"warning":232}],22:[function(require,module,exports){ +},{"./PathUtils":11,"./deprecate":18,"./runTransitionHook":19,"_process":27,"query-string":28,"warning":236}],22:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -2091,7 +2091,811 @@ module.exports = invariant;  }).call(this,require('_process')) -},{"_process":23}],23:[function(require,module,exports){ +},{"_process":27}],23:[function(require,module,exports){ +/** + * lodash 3.9.1 (Custom Build) <https://lodash.com/> + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/> + * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license <https://lodash.com/license> + */ + +/** `Object#toString` result references. */ +var funcTag = '[object Function]'; + +/** Used to detect host constructors (Safari > 5). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { +  return !!value && typeof value == 'object'; +} + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + +  fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') +  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { +  var value = object == null ? undefined : object[key]; +  return isNative(value) ? value : undefined; +} + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { +  // The use of `Object#toString` avoids issues with the `typeof` operator +  // in older versions of Chrome and Safari which return 'function' for regexes +  // and Safari 8 equivalents which return 'object' for typed array constructors. +  return isObject(value) && objToString.call(value) == funcTag; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { +  // Avoid a V8 JIT bug in Chrome 19-20. +  // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. +  var type = typeof value; +  return !!value && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ +function isNative(value) { +  if (value == null) { +    return false; +  } +  if (isFunction(value)) { +    return reIsNative.test(fnToString.call(value)); +  } +  return isObjectLike(value) && reIsHostCtor.test(value); +} + +module.exports = getNative; + +},{}],24:[function(require,module,exports){ +/** + * lodash 3.0.8 (Custom Build) <https://lodash.com/> + * Build: `lodash modularize exports="npm" -o ./` + * Copyright 2012-2016 The Dojo Foundation <http://dojofoundation.org/> + * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> + * Copyright 2009-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license <https://lodash.com/license> + */ + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]', +    funcTag = '[object Function]', +    genTag = '[object GeneratorFunction]'; + +/** Used for built-in method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ +var objectToString = objectProto.toString; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto.propertyIsEnumerable; + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { +  return function(object) { +    return object == null ? undefined : object[key]; +  }; +} + +/** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ +var getLength = baseProperty('length'); + +/** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ +function isArguments(value) { +  // Safari 8.1 incorrectly makes `arguments.callee` enumerable in strict mode. +  return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && +    (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); +} + +/** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ +function isArrayLike(value) { +  return value != null && isLength(getLength(value)) && !isFunction(value); +} + +/** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ +function isArrayLikeObject(value) { +  return isObjectLike(value) && isArrayLike(value); +} + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { +  // The use of `Object#toString` avoids issues with the `typeof` operator +  // in Safari 8 which returns 'object' for typed array and weak map constructors, +  // and PhantomJS 1.9 which returns 'function' for `NodeList` instances. +  var tag = isObject(value) ? objectToString.call(value) : ''; +  return tag == funcTag || tag == genTag; +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is loosely based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ +function isLength(value) { +  return typeof value == 'number' && +    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ +function isObject(value) { +  var type = typeof value; +  return !!value && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value) { +  return !!value && typeof value == 'object'; +} + +module.exports = isArguments; + +},{}],25:[function(require,module,exports){ +/** + * lodash 3.0.4 (Custom Build) <https://lodash.com/> + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/> + * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license <https://lodash.com/license> + */ + +/** `Object#toString` result references. */ +var arrayTag = '[object Array]', +    funcTag = '[object Function]'; + +/** Used to detect host constructors (Safari > 5). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; + +/** + * Checks if `value` is object-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + */ +function isObjectLike(value) { +  return !!value && typeof value == 'object'; +} + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to resolve the decompiled source of functions. */ +var fnToString = Function.prototype.toString; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) + * of values. + */ +var objToString = objectProto.toString; + +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + +  fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') +  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeIsArray = getNative(Array, 'isArray'); + +/** + * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ +function getNative(object, key) { +  var value = object == null ? undefined : object[key]; +  return isNative(value) ? value : undefined; +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { +  return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(function() { return arguments; }()); + * // => false + */ +var isArray = nativeIsArray || function(value) { +  return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; +}; + +/** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { +  // The use of `Object#toString` avoids issues with the `typeof` operator +  // in older versions of Chrome and Safari which return 'function' for regexes +  // and Safari 8 equivalents which return 'object' for typed array constructors. +  return isObject(value) && objToString.call(value) == funcTag; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { +  // Avoid a V8 JIT bug in Chrome 19-20. +  // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. +  var type = typeof value; +  return !!value && (type == 'object' || type == 'function'); +} + +/** + * Checks if `value` is a native function. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ +function isNative(value) { +  if (value == null) { +    return false; +  } +  if (isFunction(value)) { +    return reIsNative.test(fnToString.call(value)); +  } +  return isObjectLike(value) && reIsHostCtor.test(value); +} + +module.exports = isArray; + +},{}],26:[function(require,module,exports){ +/** + * lodash 3.1.2 (Custom Build) <https://lodash.com/> + * Build: `lodash modern modularize exports="npm" -o ./` + * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/> + * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license <https://lodash.com/license> + */ +var getNative = require('lodash._getnative'), +    isArguments = require('lodash.isarguments'), +    isArray = require('lodash.isarray'); + +/** Used to detect unsigned integer values. */ +var reIsUint = /^\d+$/; + +/** Used for native method references. */ +var objectProto = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/* Native method references for those with the same name as other `lodash` methods. */ +var nativeKeys = getNative(Object, 'keys'); + +/** + * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * of an array-like value. + */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. + */ +function baseProperty(key) { +  return function(object) { +    return object == null ? undefined : object[key]; +  }; +} + +/** + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. + * + * @private + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. + */ +var getLength = baseProperty('length'); + +/** + * Checks if `value` is array-like. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + */ +function isArrayLike(value) { +  return value != null && isLength(getLength(value)); +} + +/** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ +function isIndex(value, length) { +  value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; +  length = length == null ? MAX_SAFE_INTEGER : length; +  return value > -1 && value % 1 == 0 && value < length; +} + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + */ +function isLength(value) { +  return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; +} + +/** + * A fallback implementation of `Object.keys` which creates an array of the + * own enumerable property names of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ +function shimKeys(object) { +  var props = keysIn(object), +      propsLength = props.length, +      length = propsLength && object.length; + +  var allowIndexes = !!length && isLength(length) && +    (isArray(object) || isArguments(object)); + +  var index = -1, +      result = []; + +  while (++index < propsLength) { +    var key = props[index]; +    if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { +      result.push(key); +    } +  } +  return result; +} + +/** + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { +  // Avoid a V8 JIT bug in Chrome 19-20. +  // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. +  var type = typeof value; +  return !!value && (type == 'object' || type == 'function'); +} + +/** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) + * for more details. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + *   this.a = 1; + *   this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ +var keys = !nativeKeys ? shimKeys : function(object) { +  var Ctor = object == null ? undefined : object.constructor; +  if ((typeof Ctor == 'function' && Ctor.prototype === object) || +      (typeof object != 'function' && isArrayLike(object))) { +    return shimKeys(object); +  } +  return isObject(object) ? nativeKeys(object) : []; +}; + +/** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + *   this.a = 1; + *   this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ +function keysIn(object) { +  if (object == null) { +    return []; +  } +  if (!isObject(object)) { +    object = Object(object); +  } +  var length = object.length; +  length = (length && isLength(length) && +    (isArray(object) || isArguments(object)) && length) || 0; + +  var Ctor = object.constructor, +      index = -1, +      isProto = typeof Ctor == 'function' && Ctor.prototype === object, +      result = Array(length), +      skipIndexes = length > 0; + +  while (++index < length) { +    result[index] = (index + ''); +  } +  for (var key in object) { +    if (!(skipIndexes && isIndex(key, length)) && +        !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { +      result.push(key); +    } +  } +  return result; +} + +module.exports = keys; + +},{"lodash._getnative":23,"lodash.isarguments":24,"lodash.isarray":25}],27:[function(require,module,exports){  // shim for using process in browser  var process = module.exports = {}; @@ -2184,7 +2988,7 @@ process.chdir = function (dir) {  };  process.umask = function() { return 0; }; -},{}],24:[function(require,module,exports){ +},{}],28:[function(require,module,exports){  'use strict';  var strictUriEncode = require('strict-uri-encode'); @@ -2252,7 +3056,7 @@ exports.stringify = function (obj) {  	}).join('&') : '';  }; -},{"strict-uri-encode":231}],25:[function(require,module,exports){ +},{"strict-uri-encode":235}],29:[function(require,module,exports){  "use strict";  exports.__esModule = true; @@ -2343,7 +3147,7 @@ function mapAsync(array, work, callback) {      });    });  } -},{}],26:[function(require,module,exports){ +},{}],30:[function(require,module,exports){  (function (process){  'use strict'; @@ -2377,7 +3181,7 @@ exports['default'] = History;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./PropTypes":33,"./routerWarning":55,"_process":23}],27:[function(require,module,exports){ +},{"./PropTypes":37,"./routerWarning":59,"_process":27}],31:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -2408,7 +3212,7 @@ var IndexLink = _react2['default'].createClass({  exports['default'] = IndexLink;  module.exports = exports['default']; -},{"./Link":31,"react":"react"}],28:[function(require,module,exports){ +},{"./Link":35,"react":"react"}],32:[function(require,module,exports){  (function (process){  'use strict'; @@ -2476,7 +3280,7 @@ exports['default'] = IndexRedirect;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./PropTypes":33,"./Redirect":34,"./routerWarning":55,"_process":23,"invariant":22,"react":"react"}],29:[function(require,module,exports){ +},{"./PropTypes":37,"./Redirect":38,"./routerWarning":59,"_process":27,"invariant":22,"react":"react"}],33:[function(require,module,exports){  (function (process){  'use strict'; @@ -2541,7 +3345,7 @@ exports['default'] = IndexRoute;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./PropTypes":33,"./RouteUtils":37,"./routerWarning":55,"_process":23,"invariant":22,"react":"react"}],30:[function(require,module,exports){ +},{"./PropTypes":37,"./RouteUtils":41,"./routerWarning":59,"_process":27,"invariant":22,"react":"react"}],34:[function(require,module,exports){  (function (process){  'use strict'; @@ -2614,7 +3418,7 @@ exports['default'] = Lifecycle;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./routerWarning":55,"_process":23,"invariant":22,"react":"react"}],31:[function(require,module,exports){ +},{"./routerWarning":59,"_process":27,"invariant":22,"react":"react"}],35:[function(require,module,exports){  (function (process){  'use strict'; @@ -2782,7 +3586,7 @@ exports['default'] = Link;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./routerWarning":55,"_process":23,"react":"react"}],32:[function(require,module,exports){ +},{"./routerWarning":59,"_process":27,"react":"react"}],36:[function(require,module,exports){  (function (process){  'use strict'; @@ -3013,7 +3817,7 @@ function formatPattern(pattern, params) {  }  }).call(this,require('_process')) -},{"_process":23,"invariant":22}],33:[function(require,module,exports){ +},{"_process":27,"invariant":22}],37:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -3067,7 +3871,7 @@ exports['default'] = {    components: components,    route: route  }; -},{"react":"react"}],34:[function(require,module,exports){ +},{"react":"react"}],38:[function(require,module,exports){  (function (process){  'use strict'; @@ -3174,7 +3978,7 @@ exports['default'] = Redirect;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./PatternUtils":32,"./PropTypes":33,"./RouteUtils":37,"_process":23,"invariant":22,"react":"react"}],35:[function(require,module,exports){ +},{"./PatternUtils":36,"./PropTypes":37,"./RouteUtils":41,"_process":27,"invariant":22,"react":"react"}],39:[function(require,module,exports){  (function (process){  'use strict'; @@ -3234,7 +4038,7 @@ exports['default'] = Route;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./PropTypes":33,"./RouteUtils":37,"_process":23,"invariant":22,"react":"react"}],36:[function(require,module,exports){ +},{"./PropTypes":37,"./RouteUtils":41,"_process":27,"invariant":22,"react":"react"}],40:[function(require,module,exports){  (function (process){  'use strict'; @@ -3284,7 +4088,7 @@ exports['default'] = RouteContext;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./routerWarning":55,"_process":23,"react":"react"}],37:[function(require,module,exports){ +},{"./routerWarning":59,"_process":27,"react":"react"}],41:[function(require,module,exports){  (function (process){  'use strict'; @@ -3402,7 +4206,7 @@ function createRoutes(routes) {  }  }).call(this,require('_process')) -},{"./routerWarning":55,"_process":23,"react":"react"}],38:[function(require,module,exports){ +},{"./routerWarning":59,"_process":27,"react":"react"}],42:[function(require,module,exports){  (function (process){  'use strict'; @@ -3616,7 +4420,7 @@ exports['default'] = Router;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./PropTypes":33,"./RouteUtils":37,"./RouterContext":39,"./RouterUtils":40,"./createTransitionManager":47,"./routerWarning":55,"_process":23,"history/lib/createHashHistory":14,"history/lib/useQueries":21,"react":"react"}],39:[function(require,module,exports){ +},{"./PropTypes":37,"./RouteUtils":41,"./RouterContext":43,"./RouterUtils":44,"./createTransitionManager":51,"./routerWarning":59,"_process":27,"history/lib/createHashHistory":14,"history/lib/useQueries":21,"react":"react"}],43:[function(require,module,exports){  (function (process){  'use strict'; @@ -3774,7 +4578,7 @@ exports['default'] = RouterContext;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./RouteUtils":37,"./deprecateObjectProperties":48,"./getRouteParams":50,"./routerWarning":55,"_process":23,"invariant":22,"react":"react"}],40:[function(require,module,exports){ +},{"./RouteUtils":41,"./deprecateObjectProperties":52,"./getRouteParams":54,"./routerWarning":59,"_process":27,"invariant":22,"react":"react"}],44:[function(require,module,exports){  (function (process){  'use strict'; @@ -3811,7 +4615,7 @@ function createRoutingHistory(history, transitionManager) {  }  }).call(this,require('_process')) -},{"./deprecateObjectProperties":48,"_process":23}],41:[function(require,module,exports){ +},{"./deprecateObjectProperties":52,"_process":27}],45:[function(require,module,exports){  (function (process){  'use strict'; @@ -3847,7 +4651,7 @@ exports['default'] = RoutingContext;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./RouterContext":39,"./routerWarning":55,"_process":23,"react":"react"}],42:[function(require,module,exports){ +},{"./RouterContext":43,"./routerWarning":59,"_process":27,"react":"react"}],46:[function(require,module,exports){  (function (process){  'use strict'; @@ -3940,7 +4744,7 @@ function runLeaveHooks(routes) {  }  }).call(this,require('_process')) -},{"./AsyncUtils":25,"./routerWarning":55,"_process":23}],43:[function(require,module,exports){ +},{"./AsyncUtils":29,"./routerWarning":59,"_process":27}],47:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -3957,7 +4761,7 @@ var _createRouterHistory2 = _interopRequireDefault(_createRouterHistory);  exports['default'] = _createRouterHistory2['default'](_historyLibCreateBrowserHistory2['default']);  module.exports = exports['default']; -},{"./createRouterHistory":46,"history/lib/createBrowserHistory":12}],44:[function(require,module,exports){ +},{"./createRouterHistory":50,"history/lib/createBrowserHistory":12}],48:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -4014,7 +4818,7 @@ function computeChangedRoutes(prevState, nextState) {  exports['default'] = computeChangedRoutes;  module.exports = exports['default']; -},{"./PatternUtils":32}],45:[function(require,module,exports){ +},{"./PatternUtils":36}],49:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -4048,7 +4852,7 @@ function createMemoryHistory(options) {  }  module.exports = exports['default']; -},{"history/lib/createMemoryHistory":17,"history/lib/useBasename":20,"history/lib/useQueries":21}],46:[function(require,module,exports){ +},{"history/lib/createMemoryHistory":17,"history/lib/useBasename":20,"history/lib/useQueries":21}],50:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -4068,7 +4872,7 @@ exports['default'] = function (createHistory) {  };  module.exports = exports['default']; -},{"./useRouterHistory":56}],47:[function(require,module,exports){ +},{"./useRouterHistory":60}],51:[function(require,module,exports){  (function (process){  'use strict'; @@ -4368,7 +5172,7 @@ function createTransitionManager(history, routes) {  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./TransitionUtils":42,"./computeChangedRoutes":44,"./getComponents":49,"./isActive":52,"./matchRoutes":54,"./routerWarning":55,"_process":23,"history/lib/Actions":6}],48:[function(require,module,exports){ +},{"./TransitionUtils":46,"./computeChangedRoutes":48,"./getComponents":53,"./isActive":56,"./matchRoutes":58,"./routerWarning":59,"_process":27,"history/lib/Actions":6}],52:[function(require,module,exports){  (function (process){  /*eslint no-empty: 0*/  'use strict'; @@ -4429,7 +5233,7 @@ function deprecateObjectProperties(object, message) {  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./routerWarning":55,"_process":23}],49:[function(require,module,exports){ +},{"./routerWarning":59,"_process":27}],53:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -4463,7 +5267,7 @@ function getComponents(nextState, callback) {  exports['default'] = getComponents;  module.exports = exports['default']; -},{"./AsyncUtils":25}],50:[function(require,module,exports){ +},{"./AsyncUtils":29}],54:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -4488,7 +5292,7 @@ function getRouteParams(route, params) {  exports['default'] = getRouteParams;  module.exports = exports['default']; -},{"./PatternUtils":32}],51:[function(require,module,exports){ +},{"./PatternUtils":36}],55:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -4505,7 +5309,7 @@ var _createRouterHistory2 = _interopRequireDefault(_createRouterHistory);  exports['default'] = _createRouterHistory2['default'](_historyLibCreateHashHistory2['default']);  module.exports = exports['default']; -},{"./createRouterHistory":46,"history/lib/createHashHistory":14}],52:[function(require,module,exports){ +},{"./createRouterHistory":50,"history/lib/createHashHistory":14}],56:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -4633,7 +5437,7 @@ function isActive(_ref, indexOnly, currentLocation, routes, params) {  }  module.exports = exports['default']; -},{"./PatternUtils":32}],53:[function(require,module,exports){ +},{"./PatternUtils":36}],57:[function(require,module,exports){  (function (process){  'use strict'; @@ -4718,7 +5522,7 @@ exports['default'] = match;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./RouteUtils":37,"./RouterUtils":40,"./createMemoryHistory":45,"./createTransitionManager":47,"_process":23,"invariant":22}],54:[function(require,module,exports){ +},{"./RouteUtils":41,"./RouterUtils":44,"./createMemoryHistory":49,"./createTransitionManager":51,"_process":27,"invariant":22}],58:[function(require,module,exports){  (function (process){  'use strict'; @@ -4928,7 +5732,7 @@ exports['default'] = matchRoutes;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./AsyncUtils":25,"./PatternUtils":32,"./RouteUtils":37,"./routerWarning":55,"_process":23}],55:[function(require,module,exports){ +},{"./AsyncUtils":29,"./PatternUtils":36,"./RouteUtils":41,"./routerWarning":59,"_process":27}],59:[function(require,module,exports){  (function (process){  'use strict'; @@ -4954,7 +5758,7 @@ function routerWarning(falseToWarn, message) {  module.exports = exports['default'];  }).call(this,require('_process')) -},{"_process":23,"warning":232}],56:[function(require,module,exports){ +},{"_process":27,"warning":236}],60:[function(require,module,exports){  'use strict';  exports.__esModule = true; @@ -4979,7 +5783,7 @@ function useRouterHistory(createHistory) {  }  module.exports = exports['default']; -},{"history/lib/useBasename":20,"history/lib/useQueries":21}],57:[function(require,module,exports){ +},{"history/lib/useBasename":20,"history/lib/useQueries":21}],61:[function(require,module,exports){  (function (process){  'use strict'; @@ -5034,7 +5838,7 @@ exports['default'] = useRoutes;  module.exports = exports['default'];  }).call(this,require('_process')) -},{"./createTransitionManager":47,"./routerWarning":55,"_process":23,"history/lib/useQueries":21}],58:[function(require,module,exports){ +},{"./createTransitionManager":51,"./routerWarning":59,"_process":27,"history/lib/useQueries":21}],62:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -5071,7 +5875,7 @@ var AutoFocusUtils = {  };  module.exports = AutoFocusUtils; -},{"./ReactMount":128,"./findDOMNode":179,"fbjs/lib/focusNode":212}],59:[function(require,module,exports){ +},{"./ReactMount":132,"./findDOMNode":183,"fbjs/lib/focusNode":216}],63:[function(require,module,exports){  /**   * Copyright 2013-2015 Facebook, Inc.   * All rights reserved. @@ -5477,7 +6281,7 @@ var BeforeInputEventPlugin = {  };  module.exports = BeforeInputEventPlugin; -},{"./EventConstants":71,"./EventPropagators":75,"./FallbackCompositionState":76,"./SyntheticCompositionEvent":160,"./SyntheticInputEvent":164,"fbjs/lib/ExecutionEnvironment":204,"fbjs/lib/keyOf":223}],60:[function(require,module,exports){ +},{"./EventConstants":75,"./EventPropagators":79,"./FallbackCompositionState":80,"./SyntheticCompositionEvent":164,"./SyntheticInputEvent":168,"fbjs/lib/ExecutionEnvironment":208,"fbjs/lib/keyOf":227}],64:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -5617,7 +6421,7 @@ var CSSProperty = {  };  module.exports = CSSProperty; -},{}],61:[function(require,module,exports){ +},{}],65:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -5796,7 +6600,7 @@ ReactPerf.measureMethods(CSSPropertyOperations, 'CSSPropertyOperations', {  module.exports = CSSPropertyOperations;  }).call(this,require('_process')) -},{"./CSSProperty":60,"./ReactPerf":134,"./dangerousStyleValue":176,"_process":23,"fbjs/lib/ExecutionEnvironment":204,"fbjs/lib/camelizeStyleName":206,"fbjs/lib/hyphenateStyleName":217,"fbjs/lib/memoizeStringOnly":225,"fbjs/lib/warning":230}],62:[function(require,module,exports){ +},{"./CSSProperty":64,"./ReactPerf":138,"./dangerousStyleValue":180,"_process":27,"fbjs/lib/ExecutionEnvironment":208,"fbjs/lib/camelizeStyleName":210,"fbjs/lib/hyphenateStyleName":221,"fbjs/lib/memoizeStringOnly":229,"fbjs/lib/warning":234}],66:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -5893,7 +6697,7 @@ PooledClass.addPoolingTo(CallbackQueue);  module.exports = CallbackQueue;  }).call(this,require('_process')) -},{"./Object.assign":80,"./PooledClass":81,"_process":23,"fbjs/lib/invariant":218}],63:[function(require,module,exports){ +},{"./Object.assign":84,"./PooledClass":85,"_process":27,"fbjs/lib/invariant":222}],67:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -6215,7 +7019,7 @@ var ChangeEventPlugin = {  };  module.exports = ChangeEventPlugin; -},{"./EventConstants":71,"./EventPluginHub":72,"./EventPropagators":75,"./ReactUpdates":152,"./SyntheticEvent":162,"./getEventTarget":185,"./isEventSupported":190,"./isTextInputElement":191,"fbjs/lib/ExecutionEnvironment":204,"fbjs/lib/keyOf":223}],64:[function(require,module,exports){ +},{"./EventConstants":75,"./EventPluginHub":76,"./EventPropagators":79,"./ReactUpdates":156,"./SyntheticEvent":166,"./getEventTarget":189,"./isEventSupported":194,"./isTextInputElement":195,"fbjs/lib/ExecutionEnvironment":208,"fbjs/lib/keyOf":227}],68:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -6239,7 +7043,7 @@ var ClientReactRootIndex = {  };  module.exports = ClientReactRootIndex; -},{}],65:[function(require,module,exports){ +},{}],69:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -6372,7 +7176,7 @@ ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', {  module.exports = DOMChildrenOperations;  }).call(this,require('_process')) -},{"./Danger":68,"./ReactMultiChildUpdateTypes":130,"./ReactPerf":134,"./setInnerHTML":195,"./setTextContent":196,"_process":23,"fbjs/lib/invariant":218}],66:[function(require,module,exports){ +},{"./Danger":72,"./ReactMultiChildUpdateTypes":134,"./ReactPerf":138,"./setInnerHTML":199,"./setTextContent":200,"_process":27,"fbjs/lib/invariant":222}],70:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -6610,7 +7414,7 @@ var DOMProperty = {  module.exports = DOMProperty;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/invariant":218}],67:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/invariant":222}],71:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -6839,7 +7643,7 @@ ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', {  module.exports = DOMPropertyOperations;  }).call(this,require('_process')) -},{"./DOMProperty":66,"./ReactPerf":134,"./quoteAttributeValueForBrowser":193,"_process":23,"fbjs/lib/warning":230}],68:[function(require,module,exports){ +},{"./DOMProperty":70,"./ReactPerf":138,"./quoteAttributeValueForBrowser":197,"_process":27,"fbjs/lib/warning":234}],72:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -6988,7 +7792,7 @@ var Danger = {  module.exports = Danger;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/ExecutionEnvironment":204,"fbjs/lib/createNodesFromMarkup":209,"fbjs/lib/emptyFunction":210,"fbjs/lib/getMarkupWrap":214,"fbjs/lib/invariant":218}],69:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/ExecutionEnvironment":208,"fbjs/lib/createNodesFromMarkup":213,"fbjs/lib/emptyFunction":214,"fbjs/lib/getMarkupWrap":218,"fbjs/lib/invariant":222}],73:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -7016,7 +7820,7 @@ var keyOf = require('fbjs/lib/keyOf');  var DefaultEventPluginOrder = [keyOf({ ResponderEventPlugin: null }), keyOf({ SimpleEventPlugin: null }), keyOf({ TapEventPlugin: null }), keyOf({ EnterLeaveEventPlugin: null }), keyOf({ ChangeEventPlugin: null }), keyOf({ SelectEventPlugin: null }), keyOf({ BeforeInputEventPlugin: null })];  module.exports = DefaultEventPluginOrder; -},{"fbjs/lib/keyOf":223}],70:[function(require,module,exports){ +},{"fbjs/lib/keyOf":227}],74:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -7141,7 +7945,7 @@ var EnterLeaveEventPlugin = {  };  module.exports = EnterLeaveEventPlugin; -},{"./EventConstants":71,"./EventPropagators":75,"./ReactMount":128,"./SyntheticMouseEvent":166,"fbjs/lib/keyOf":223}],71:[function(require,module,exports){ +},{"./EventConstants":75,"./EventPropagators":79,"./ReactMount":132,"./SyntheticMouseEvent":170,"fbjs/lib/keyOf":227}],75:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -7234,7 +8038,7 @@ var EventConstants = {  };  module.exports = EventConstants; -},{"fbjs/lib/keyMirror":222}],72:[function(require,module,exports){ +},{"fbjs/lib/keyMirror":226}],76:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -7517,7 +8321,7 @@ var EventPluginHub = {  module.exports = EventPluginHub;  }).call(this,require('_process')) -},{"./EventPluginRegistry":73,"./EventPluginUtils":74,"./ReactErrorUtils":117,"./accumulateInto":172,"./forEachAccumulated":181,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],73:[function(require,module,exports){ +},{"./EventPluginRegistry":77,"./EventPluginUtils":78,"./ReactErrorUtils":121,"./accumulateInto":176,"./forEachAccumulated":185,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],77:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -7741,7 +8545,7 @@ var EventPluginRegistry = {  module.exports = EventPluginRegistry;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/invariant":218}],74:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/invariant":222}],78:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -7947,7 +8751,7 @@ var EventPluginUtils = {  module.exports = EventPluginUtils;  }).call(this,require('_process')) -},{"./EventConstants":71,"./ReactErrorUtils":117,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],75:[function(require,module,exports){ +},{"./EventConstants":75,"./ReactErrorUtils":121,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],79:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -8086,7 +8890,7 @@ var EventPropagators = {  module.exports = EventPropagators;  }).call(this,require('_process')) -},{"./EventConstants":71,"./EventPluginHub":72,"./accumulateInto":172,"./forEachAccumulated":181,"_process":23,"fbjs/lib/warning":230}],76:[function(require,module,exports){ +},{"./EventConstants":75,"./EventPluginHub":76,"./accumulateInto":176,"./forEachAccumulated":185,"_process":27,"fbjs/lib/warning":234}],80:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -8182,7 +8986,7 @@ assign(FallbackCompositionState.prototype, {  PooledClass.addPoolingTo(FallbackCompositionState);  module.exports = FallbackCompositionState; -},{"./Object.assign":80,"./PooledClass":81,"./getTextContentAccessor":188}],77:[function(require,module,exports){ +},{"./Object.assign":84,"./PooledClass":85,"./getTextContentAccessor":192}],81:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -8413,7 +9217,7 @@ var HTMLDOMPropertyConfig = {  };  module.exports = HTMLDOMPropertyConfig; -},{"./DOMProperty":66,"fbjs/lib/ExecutionEnvironment":204}],78:[function(require,module,exports){ +},{"./DOMProperty":70,"fbjs/lib/ExecutionEnvironment":208}],82:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -8450,7 +9254,7 @@ var LinkedStateMixin = {  };  module.exports = LinkedStateMixin; -},{"./ReactLink":126,"./ReactStateSetters":146}],79:[function(require,module,exports){ +},{"./ReactLink":130,"./ReactStateSetters":150}],83:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -8588,7 +9392,7 @@ var LinkedValueUtils = {  module.exports = LinkedValueUtils;  }).call(this,require('_process')) -},{"./ReactPropTypeLocations":137,"./ReactPropTypes":138,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],80:[function(require,module,exports){ +},{"./ReactPropTypeLocations":141,"./ReactPropTypes":142,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],84:[function(require,module,exports){  /**   * Copyright 2014-2015, Facebook, Inc.   * All rights reserved. @@ -8636,7 +9440,7 @@ function assign(target, sources) {  }  module.exports = assign; -},{}],81:[function(require,module,exports){ +},{}],85:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -8759,7 +9563,7 @@ var PooledClass = {  module.exports = PooledClass;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/invariant":218}],82:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/invariant":222}],86:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -8800,7 +9604,7 @@ React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOM;  React.__SECRET_DOM_SERVER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOMServer;  module.exports = React; -},{"./Object.assign":80,"./ReactDOM":96,"./ReactDOMServer":106,"./ReactIsomorphic":125,"./deprecated":177}],83:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactDOM":100,"./ReactDOMServer":110,"./ReactIsomorphic":129,"./deprecated":181}],87:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -8840,7 +9644,7 @@ var ReactBrowserComponentMixin = {  module.exports = ReactBrowserComponentMixin;  }).call(this,require('_process')) -},{"./ReactInstanceMap":124,"./findDOMNode":179,"_process":23,"fbjs/lib/warning":230}],84:[function(require,module,exports){ +},{"./ReactInstanceMap":128,"./findDOMNode":183,"_process":27,"fbjs/lib/warning":234}],88:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -9165,7 +9969,7 @@ ReactPerf.measureMethods(ReactBrowserEventEmitter, 'ReactBrowserEventEmitter', {  });  module.exports = ReactBrowserEventEmitter; -},{"./EventConstants":71,"./EventPluginHub":72,"./EventPluginRegistry":73,"./Object.assign":80,"./ReactEventEmitterMixin":118,"./ReactPerf":134,"./ViewportMetrics":171,"./isEventSupported":190}],85:[function(require,module,exports){ +},{"./EventConstants":75,"./EventPluginHub":76,"./EventPluginRegistry":77,"./Object.assign":84,"./ReactEventEmitterMixin":122,"./ReactPerf":138,"./ViewportMetrics":175,"./isEventSupported":194}],89:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -9249,7 +10053,7 @@ var ReactCSSTransitionGroup = React.createClass({  });  module.exports = ReactCSSTransitionGroup; -},{"./Object.assign":80,"./React":82,"./ReactCSSTransitionGroupChild":86,"./ReactTransitionGroup":150}],86:[function(require,module,exports){ +},{"./Object.assign":84,"./React":86,"./ReactCSSTransitionGroupChild":90,"./ReactTransitionGroup":154}],90:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -9415,7 +10219,7 @@ var ReactCSSTransitionGroupChild = React.createClass({  });  module.exports = ReactCSSTransitionGroupChild; -},{"./React":82,"./ReactDOM":96,"./ReactTransitionEvents":149,"./onlyChild":192,"fbjs/lib/CSSCore":202}],87:[function(require,module,exports){ +},{"./React":86,"./ReactDOM":100,"./ReactTransitionEvents":153,"./onlyChild":196,"fbjs/lib/CSSCore":206}],91:[function(require,module,exports){  (function (process){  /**   * Copyright 2014-2015, Facebook, Inc. @@ -9541,7 +10345,7 @@ var ReactChildReconciler = {  module.exports = ReactChildReconciler;  }).call(this,require('_process')) -},{"./ReactReconciler":140,"./instantiateReactComponent":189,"./shouldUpdateReactComponent":198,"./traverseAllChildren":199,"_process":23,"fbjs/lib/warning":230}],88:[function(require,module,exports){ +},{"./ReactReconciler":144,"./instantiateReactComponent":193,"./shouldUpdateReactComponent":202,"./traverseAllChildren":203,"_process":27,"fbjs/lib/warning":234}],92:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -9724,7 +10528,7 @@ var ReactChildren = {  };  module.exports = ReactChildren; -},{"./PooledClass":81,"./ReactElement":113,"./traverseAllChildren":199,"fbjs/lib/emptyFunction":210}],89:[function(require,module,exports){ +},{"./PooledClass":85,"./ReactElement":117,"./traverseAllChildren":203,"fbjs/lib/emptyFunction":214}],93:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -10499,7 +11303,7 @@ var ReactClass = {  module.exports = ReactClass;  }).call(this,require('_process')) -},{"./Object.assign":80,"./ReactComponent":90,"./ReactElement":113,"./ReactNoopUpdateQueue":132,"./ReactPropTypeLocationNames":136,"./ReactPropTypeLocations":137,"_process":23,"fbjs/lib/emptyObject":211,"fbjs/lib/invariant":218,"fbjs/lib/keyMirror":222,"fbjs/lib/keyOf":223,"fbjs/lib/warning":230}],90:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactComponent":94,"./ReactElement":117,"./ReactNoopUpdateQueue":136,"./ReactPropTypeLocationNames":140,"./ReactPropTypeLocations":141,"_process":27,"fbjs/lib/emptyObject":215,"fbjs/lib/invariant":222,"fbjs/lib/keyMirror":226,"fbjs/lib/keyOf":227,"fbjs/lib/warning":234}],94:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -10625,7 +11429,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = ReactComponent;  }).call(this,require('_process')) -},{"./ReactNoopUpdateQueue":132,"./canDefineProperty":174,"_process":23,"fbjs/lib/emptyObject":211,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],91:[function(require,module,exports){ +},{"./ReactNoopUpdateQueue":136,"./canDefineProperty":178,"_process":27,"fbjs/lib/emptyObject":215,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],95:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -10667,7 +11471,7 @@ var ReactComponentBrowserEnvironment = {  };  module.exports = ReactComponentBrowserEnvironment; -},{"./ReactDOMIDOperations":101,"./ReactMount":128}],92:[function(require,module,exports){ +},{"./ReactDOMIDOperations":105,"./ReactMount":132}],96:[function(require,module,exports){  (function (process){  /**   * Copyright 2014-2015, Facebook, Inc. @@ -10722,7 +11526,7 @@ var ReactComponentEnvironment = {  module.exports = ReactComponentEnvironment;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/invariant":218}],93:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/invariant":222}],97:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -10769,7 +11573,7 @@ var ReactComponentWithPureRenderMixin = {  };  module.exports = ReactComponentWithPureRenderMixin; -},{"./shallowCompare":197}],94:[function(require,module,exports){ +},{"./shallowCompare":201}],98:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -11467,7 +12271,7 @@ var ReactCompositeComponent = {  module.exports = ReactCompositeComponent;  }).call(this,require('_process')) -},{"./Object.assign":80,"./ReactComponentEnvironment":92,"./ReactCurrentOwner":95,"./ReactElement":113,"./ReactInstanceMap":124,"./ReactPerf":134,"./ReactPropTypeLocationNames":136,"./ReactPropTypeLocations":137,"./ReactReconciler":140,"./ReactUpdateQueue":151,"./shouldUpdateReactComponent":198,"_process":23,"fbjs/lib/emptyObject":211,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],95:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactComponentEnvironment":96,"./ReactCurrentOwner":99,"./ReactElement":117,"./ReactInstanceMap":128,"./ReactPerf":138,"./ReactPropTypeLocationNames":140,"./ReactPropTypeLocations":141,"./ReactReconciler":144,"./ReactUpdateQueue":155,"./shouldUpdateReactComponent":202,"_process":27,"fbjs/lib/emptyObject":215,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],99:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -11498,7 +12302,7 @@ var ReactCurrentOwner = {  };  module.exports = ReactCurrentOwner; -},{}],96:[function(require,module,exports){ +},{}],100:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -11594,7 +12398,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = React;  }).call(this,require('_process')) -},{"./ReactCurrentOwner":95,"./ReactDOMTextComponent":107,"./ReactDefaultInjection":110,"./ReactInstanceHandles":123,"./ReactMount":128,"./ReactPerf":134,"./ReactReconciler":140,"./ReactUpdates":152,"./ReactVersion":153,"./findDOMNode":179,"./renderSubtreeIntoContainer":194,"_process":23,"fbjs/lib/ExecutionEnvironment":204,"fbjs/lib/warning":230}],97:[function(require,module,exports){ +},{"./ReactCurrentOwner":99,"./ReactDOMTextComponent":111,"./ReactDefaultInjection":114,"./ReactInstanceHandles":127,"./ReactMount":132,"./ReactPerf":138,"./ReactReconciler":144,"./ReactUpdates":156,"./ReactVersion":157,"./findDOMNode":183,"./renderSubtreeIntoContainer":198,"_process":27,"fbjs/lib/ExecutionEnvironment":208,"fbjs/lib/warning":234}],101:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -11645,7 +12449,7 @@ var ReactDOMButton = {  };  module.exports = ReactDOMButton; -},{}],98:[function(require,module,exports){ +},{}],102:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -12611,7 +13415,7 @@ assign(ReactDOMComponent.prototype, ReactDOMComponent.Mixin, ReactMultiChild.Mix  module.exports = ReactDOMComponent;  }).call(this,require('_process')) -},{"./AutoFocusUtils":58,"./CSSPropertyOperations":61,"./DOMProperty":66,"./DOMPropertyOperations":67,"./EventConstants":71,"./Object.assign":80,"./ReactBrowserEventEmitter":84,"./ReactComponentBrowserEnvironment":91,"./ReactDOMButton":97,"./ReactDOMInput":102,"./ReactDOMOption":103,"./ReactDOMSelect":104,"./ReactDOMTextarea":108,"./ReactMount":128,"./ReactMultiChild":129,"./ReactPerf":134,"./ReactUpdateQueue":151,"./canDefineProperty":174,"./escapeTextContentForBrowser":178,"./isEventSupported":190,"./setInnerHTML":195,"./setTextContent":196,"./validateDOMNesting":201,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/keyOf":223,"fbjs/lib/shallowEqual":228,"fbjs/lib/warning":230}],99:[function(require,module,exports){ +},{"./AutoFocusUtils":62,"./CSSPropertyOperations":65,"./DOMProperty":70,"./DOMPropertyOperations":71,"./EventConstants":75,"./Object.assign":84,"./ReactBrowserEventEmitter":88,"./ReactComponentBrowserEnvironment":95,"./ReactDOMButton":101,"./ReactDOMInput":106,"./ReactDOMOption":107,"./ReactDOMSelect":108,"./ReactDOMTextarea":112,"./ReactMount":132,"./ReactMultiChild":133,"./ReactPerf":138,"./ReactUpdateQueue":155,"./canDefineProperty":178,"./escapeTextContentForBrowser":182,"./isEventSupported":194,"./setInnerHTML":199,"./setTextContent":200,"./validateDOMNesting":205,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/keyOf":227,"fbjs/lib/shallowEqual":232,"fbjs/lib/warning":234}],103:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -12792,7 +13596,7 @@ var ReactDOMFactories = mapObject({  module.exports = ReactDOMFactories;  }).call(this,require('_process')) -},{"./ReactElement":113,"./ReactElementValidator":114,"_process":23,"fbjs/lib/mapObject":224}],100:[function(require,module,exports){ +},{"./ReactElement":117,"./ReactElementValidator":118,"_process":27,"fbjs/lib/mapObject":228}],104:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -12811,7 +13615,7 @@ var ReactDOMFeatureFlags = {  };  module.exports = ReactDOMFeatureFlags; -},{}],101:[function(require,module,exports){ +},{}],105:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -12909,7 +13713,7 @@ ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {  module.exports = ReactDOMIDOperations;  }).call(this,require('_process')) -},{"./DOMChildrenOperations":65,"./DOMPropertyOperations":67,"./ReactMount":128,"./ReactPerf":134,"_process":23,"fbjs/lib/invariant":218}],102:[function(require,module,exports){ +},{"./DOMChildrenOperations":69,"./DOMPropertyOperations":71,"./ReactMount":132,"./ReactPerf":138,"_process":27,"fbjs/lib/invariant":222}],106:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -13066,7 +13870,7 @@ function _handleChange(event) {  module.exports = ReactDOMInput;  }).call(this,require('_process')) -},{"./LinkedValueUtils":79,"./Object.assign":80,"./ReactDOMIDOperations":101,"./ReactMount":128,"./ReactUpdates":152,"_process":23,"fbjs/lib/invariant":218}],103:[function(require,module,exports){ +},{"./LinkedValueUtils":83,"./Object.assign":84,"./ReactDOMIDOperations":105,"./ReactMount":132,"./ReactUpdates":156,"_process":27,"fbjs/lib/invariant":222}],107:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -13159,7 +13963,7 @@ var ReactDOMOption = {  module.exports = ReactDOMOption;  }).call(this,require('_process')) -},{"./Object.assign":80,"./ReactChildren":88,"./ReactDOMSelect":104,"_process":23,"fbjs/lib/warning":230}],104:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactChildren":92,"./ReactDOMSelect":108,"_process":27,"fbjs/lib/warning":234}],108:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -13351,7 +14155,7 @@ function _handleChange(event) {  module.exports = ReactDOMSelect;  }).call(this,require('_process')) -},{"./LinkedValueUtils":79,"./Object.assign":80,"./ReactMount":128,"./ReactUpdates":152,"_process":23,"fbjs/lib/warning":230}],105:[function(require,module,exports){ +},{"./LinkedValueUtils":83,"./Object.assign":84,"./ReactMount":132,"./ReactUpdates":156,"_process":27,"fbjs/lib/warning":234}],109:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -13564,7 +14368,7 @@ var ReactDOMSelection = {  };  module.exports = ReactDOMSelection; -},{"./getNodeForCharacterOffset":187,"./getTextContentAccessor":188,"fbjs/lib/ExecutionEnvironment":204}],106:[function(require,module,exports){ +},{"./getNodeForCharacterOffset":191,"./getTextContentAccessor":192,"fbjs/lib/ExecutionEnvironment":208}],110:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -13591,7 +14395,7 @@ var ReactDOMServer = {  };  module.exports = ReactDOMServer; -},{"./ReactDefaultInjection":110,"./ReactServerRendering":144,"./ReactVersion":153}],107:[function(require,module,exports){ +},{"./ReactDefaultInjection":114,"./ReactServerRendering":148,"./ReactVersion":157}],111:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -13722,7 +14526,7 @@ assign(ReactDOMTextComponent.prototype, {  module.exports = ReactDOMTextComponent;  }).call(this,require('_process')) -},{"./DOMChildrenOperations":65,"./DOMPropertyOperations":67,"./Object.assign":80,"./ReactComponentBrowserEnvironment":91,"./ReactMount":128,"./escapeTextContentForBrowser":178,"./setTextContent":196,"./validateDOMNesting":201,"_process":23}],108:[function(require,module,exports){ +},{"./DOMChildrenOperations":69,"./DOMPropertyOperations":71,"./Object.assign":84,"./ReactComponentBrowserEnvironment":95,"./ReactMount":132,"./escapeTextContentForBrowser":182,"./setTextContent":200,"./validateDOMNesting":205,"_process":27}],112:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -13839,7 +14643,7 @@ function _handleChange(event) {  module.exports = ReactDOMTextarea;  }).call(this,require('_process')) -},{"./LinkedValueUtils":79,"./Object.assign":80,"./ReactDOMIDOperations":101,"./ReactUpdates":152,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],109:[function(require,module,exports){ +},{"./LinkedValueUtils":83,"./Object.assign":84,"./ReactDOMIDOperations":105,"./ReactUpdates":156,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],113:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -13907,7 +14711,7 @@ var ReactDefaultBatchingStrategy = {  };  module.exports = ReactDefaultBatchingStrategy; -},{"./Object.assign":80,"./ReactUpdates":152,"./Transaction":170,"fbjs/lib/emptyFunction":210}],110:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactUpdates":156,"./Transaction":174,"fbjs/lib/emptyFunction":214}],114:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -14008,7 +14812,7 @@ module.exports = {  };  }).call(this,require('_process')) -},{"./BeforeInputEventPlugin":59,"./ChangeEventPlugin":63,"./ClientReactRootIndex":64,"./DefaultEventPluginOrder":69,"./EnterLeaveEventPlugin":70,"./HTMLDOMPropertyConfig":77,"./ReactBrowserComponentMixin":83,"./ReactComponentBrowserEnvironment":91,"./ReactDOMComponent":98,"./ReactDOMTextComponent":107,"./ReactDefaultBatchingStrategy":109,"./ReactDefaultPerf":111,"./ReactEventListener":119,"./ReactInjection":121,"./ReactInstanceHandles":123,"./ReactMount":128,"./ReactReconcileTransaction":139,"./SVGDOMPropertyConfig":155,"./SelectEventPlugin":156,"./ServerReactRootIndex":157,"./SimpleEventPlugin":158,"_process":23,"fbjs/lib/ExecutionEnvironment":204}],111:[function(require,module,exports){ +},{"./BeforeInputEventPlugin":63,"./ChangeEventPlugin":67,"./ClientReactRootIndex":68,"./DefaultEventPluginOrder":73,"./EnterLeaveEventPlugin":74,"./HTMLDOMPropertyConfig":81,"./ReactBrowserComponentMixin":87,"./ReactComponentBrowserEnvironment":95,"./ReactDOMComponent":102,"./ReactDOMTextComponent":111,"./ReactDefaultBatchingStrategy":113,"./ReactDefaultPerf":115,"./ReactEventListener":123,"./ReactInjection":125,"./ReactInstanceHandles":127,"./ReactMount":132,"./ReactReconcileTransaction":143,"./SVGDOMPropertyConfig":159,"./SelectEventPlugin":160,"./ServerReactRootIndex":161,"./SimpleEventPlugin":162,"_process":27,"fbjs/lib/ExecutionEnvironment":208}],115:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -14246,7 +15050,7 @@ var ReactDefaultPerf = {  };  module.exports = ReactDefaultPerf; -},{"./DOMProperty":66,"./ReactDefaultPerfAnalysis":112,"./ReactMount":128,"./ReactPerf":134,"fbjs/lib/performanceNow":227}],112:[function(require,module,exports){ +},{"./DOMProperty":70,"./ReactDefaultPerfAnalysis":116,"./ReactMount":132,"./ReactPerf":138,"fbjs/lib/performanceNow":231}],116:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -14448,7 +15252,7 @@ var ReactDefaultPerfAnalysis = {  };  module.exports = ReactDefaultPerfAnalysis; -},{"./Object.assign":80}],113:[function(require,module,exports){ +},{"./Object.assign":84}],117:[function(require,module,exports){  (function (process){  /**   * Copyright 2014-2015, Facebook, Inc. @@ -14699,7 +15503,7 @@ ReactElement.isValidElement = function (object) {  module.exports = ReactElement;  }).call(this,require('_process')) -},{"./Object.assign":80,"./ReactCurrentOwner":95,"./canDefineProperty":174,"_process":23}],114:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactCurrentOwner":99,"./canDefineProperty":178,"_process":27}],118:[function(require,module,exports){  (function (process){  /**   * Copyright 2014-2015, Facebook, Inc. @@ -14984,7 +15788,7 @@ var ReactElementValidator = {  module.exports = ReactElementValidator;  }).call(this,require('_process')) -},{"./ReactCurrentOwner":95,"./ReactElement":113,"./ReactPropTypeLocationNames":136,"./ReactPropTypeLocations":137,"./canDefineProperty":174,"./getIteratorFn":186,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],115:[function(require,module,exports){ +},{"./ReactCurrentOwner":99,"./ReactElement":117,"./ReactPropTypeLocationNames":140,"./ReactPropTypeLocations":141,"./canDefineProperty":178,"./getIteratorFn":190,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],119:[function(require,module,exports){  /**   * Copyright 2014-2015, Facebook, Inc.   * All rights reserved. @@ -15036,7 +15840,7 @@ assign(ReactEmptyComponent.prototype, {  ReactEmptyComponent.injection = ReactEmptyComponentInjection;  module.exports = ReactEmptyComponent; -},{"./Object.assign":80,"./ReactElement":113,"./ReactEmptyComponentRegistry":116,"./ReactReconciler":140}],116:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactElement":117,"./ReactEmptyComponentRegistry":120,"./ReactReconciler":144}],120:[function(require,module,exports){  /**   * Copyright 2014-2015, Facebook, Inc.   * All rights reserved. @@ -15085,7 +15889,7 @@ var ReactEmptyComponentRegistry = {  };  module.exports = ReactEmptyComponentRegistry; -},{}],117:[function(require,module,exports){ +},{}],121:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -15166,7 +15970,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = ReactErrorUtils;  }).call(this,require('_process')) -},{"_process":23}],118:[function(require,module,exports){ +},{"_process":27}],122:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -15205,7 +16009,7 @@ var ReactEventEmitterMixin = {  };  module.exports = ReactEventEmitterMixin; -},{"./EventPluginHub":72}],119:[function(require,module,exports){ +},{"./EventPluginHub":76}],123:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -15417,7 +16221,7 @@ var ReactEventListener = {  };  module.exports = ReactEventListener; -},{"./Object.assign":80,"./PooledClass":81,"./ReactInstanceHandles":123,"./ReactMount":128,"./ReactUpdates":152,"./getEventTarget":185,"fbjs/lib/EventListener":203,"fbjs/lib/ExecutionEnvironment":204,"fbjs/lib/getUnboundedScrollPosition":215}],120:[function(require,module,exports){ +},{"./Object.assign":84,"./PooledClass":85,"./ReactInstanceHandles":127,"./ReactMount":132,"./ReactUpdates":156,"./getEventTarget":189,"fbjs/lib/EventListener":207,"fbjs/lib/ExecutionEnvironment":208,"fbjs/lib/getUnboundedScrollPosition":219}],124:[function(require,module,exports){  (function (process){  /**   * Copyright 2015, Facebook, Inc. @@ -15485,7 +16289,7 @@ var ReactFragment = {  module.exports = ReactFragment;  }).call(this,require('_process')) -},{"./ReactChildren":88,"./ReactElement":113,"_process":23,"fbjs/lib/emptyFunction":210,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],121:[function(require,module,exports){ +},{"./ReactChildren":92,"./ReactElement":117,"_process":27,"fbjs/lib/emptyFunction":214,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],125:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -15524,7 +16328,7 @@ var ReactInjection = {  };  module.exports = ReactInjection; -},{"./DOMProperty":66,"./EventPluginHub":72,"./ReactBrowserEventEmitter":84,"./ReactClass":89,"./ReactComponentEnvironment":92,"./ReactEmptyComponent":115,"./ReactNativeComponent":131,"./ReactPerf":134,"./ReactRootIndex":142,"./ReactUpdates":152}],122:[function(require,module,exports){ +},{"./DOMProperty":70,"./EventPluginHub":76,"./ReactBrowserEventEmitter":88,"./ReactClass":93,"./ReactComponentEnvironment":96,"./ReactEmptyComponent":119,"./ReactNativeComponent":135,"./ReactPerf":138,"./ReactRootIndex":146,"./ReactUpdates":156}],126:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -15649,7 +16453,7 @@ var ReactInputSelection = {  };  module.exports = ReactInputSelection; -},{"./ReactDOMSelection":105,"fbjs/lib/containsNode":207,"fbjs/lib/focusNode":212,"fbjs/lib/getActiveElement":213}],123:[function(require,module,exports){ +},{"./ReactDOMSelection":109,"fbjs/lib/containsNode":211,"fbjs/lib/focusNode":216,"fbjs/lib/getActiveElement":217}],127:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -15955,7 +16759,7 @@ var ReactInstanceHandles = {  module.exports = ReactInstanceHandles;  }).call(this,require('_process')) -},{"./ReactRootIndex":142,"_process":23,"fbjs/lib/invariant":218}],124:[function(require,module,exports){ +},{"./ReactRootIndex":146,"_process":27,"fbjs/lib/invariant":222}],128:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -16003,7 +16807,7 @@ var ReactInstanceMap = {  };  module.exports = ReactInstanceMap; -},{}],125:[function(require,module,exports){ +},{}],129:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -16081,7 +16885,7 @@ var React = {  module.exports = React;  }).call(this,require('_process')) -},{"./Object.assign":80,"./ReactChildren":88,"./ReactClass":89,"./ReactComponent":90,"./ReactDOMFactories":99,"./ReactElement":113,"./ReactElementValidator":114,"./ReactPropTypes":138,"./ReactVersion":153,"./onlyChild":192,"_process":23}],126:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactChildren":92,"./ReactClass":93,"./ReactComponent":94,"./ReactDOMFactories":103,"./ReactElement":117,"./ReactElementValidator":118,"./ReactPropTypes":142,"./ReactVersion":157,"./onlyChild":196,"_process":27}],130:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -16151,7 +16955,7 @@ ReactLink.PropTypes = {  };  module.exports = ReactLink; -},{"./React":82}],127:[function(require,module,exports){ +},{"./React":86}],131:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -16197,7 +17001,7 @@ var ReactMarkupChecksum = {  };  module.exports = ReactMarkupChecksum; -},{"./adler32":173}],128:[function(require,module,exports){ +},{"./adler32":177}],132:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -17051,7 +17855,7 @@ ReactPerf.measureMethods(ReactMount, 'ReactMount', {  module.exports = ReactMount;  }).call(this,require('_process')) -},{"./DOMProperty":66,"./Object.assign":80,"./ReactBrowserEventEmitter":84,"./ReactCurrentOwner":95,"./ReactDOMFeatureFlags":100,"./ReactElement":113,"./ReactEmptyComponentRegistry":116,"./ReactInstanceHandles":123,"./ReactInstanceMap":124,"./ReactMarkupChecksum":127,"./ReactPerf":134,"./ReactReconciler":140,"./ReactUpdateQueue":151,"./ReactUpdates":152,"./instantiateReactComponent":189,"./setInnerHTML":195,"./shouldUpdateReactComponent":198,"./validateDOMNesting":201,"_process":23,"fbjs/lib/containsNode":207,"fbjs/lib/emptyObject":211,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],129:[function(require,module,exports){ +},{"./DOMProperty":70,"./Object.assign":84,"./ReactBrowserEventEmitter":88,"./ReactCurrentOwner":99,"./ReactDOMFeatureFlags":104,"./ReactElement":117,"./ReactEmptyComponentRegistry":120,"./ReactInstanceHandles":127,"./ReactInstanceMap":128,"./ReactMarkupChecksum":131,"./ReactPerf":138,"./ReactReconciler":144,"./ReactUpdateQueue":155,"./ReactUpdates":156,"./instantiateReactComponent":193,"./setInnerHTML":199,"./shouldUpdateReactComponent":202,"./validateDOMNesting":205,"_process":27,"fbjs/lib/containsNode":211,"fbjs/lib/emptyObject":215,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],133:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -17551,7 +18355,7 @@ var ReactMultiChild = {  module.exports = ReactMultiChild;  }).call(this,require('_process')) -},{"./ReactChildReconciler":87,"./ReactComponentEnvironment":92,"./ReactCurrentOwner":95,"./ReactMultiChildUpdateTypes":130,"./ReactReconciler":140,"./flattenChildren":180,"_process":23}],130:[function(require,module,exports){ +},{"./ReactChildReconciler":91,"./ReactComponentEnvironment":96,"./ReactCurrentOwner":99,"./ReactMultiChildUpdateTypes":134,"./ReactReconciler":144,"./flattenChildren":184,"_process":27}],134:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -17584,7 +18388,7 @@ var ReactMultiChildUpdateTypes = keyMirror({  });  module.exports = ReactMultiChildUpdateTypes; -},{"fbjs/lib/keyMirror":222}],131:[function(require,module,exports){ +},{"fbjs/lib/keyMirror":226}],135:[function(require,module,exports){  (function (process){  /**   * Copyright 2014-2015, Facebook, Inc. @@ -17682,7 +18486,7 @@ var ReactNativeComponent = {  module.exports = ReactNativeComponent;  }).call(this,require('_process')) -},{"./Object.assign":80,"_process":23,"fbjs/lib/invariant":218}],132:[function(require,module,exports){ +},{"./Object.assign":84,"_process":27,"fbjs/lib/invariant":222}],136:[function(require,module,exports){  (function (process){  /**   * Copyright 2015, Facebook, Inc. @@ -17804,7 +18608,7 @@ var ReactNoopUpdateQueue = {  module.exports = ReactNoopUpdateQueue;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/warning":230}],133:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/warning":234}],137:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -17899,7 +18703,7 @@ var ReactOwner = {  module.exports = ReactOwner;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/invariant":218}],134:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/invariant":222}],138:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -17999,7 +18803,7 @@ function _noMeasure(objName, fnName, func) {  module.exports = ReactPerf;  }).call(this,require('_process')) -},{"_process":23}],135:[function(require,module,exports){ +},{"_process":27}],139:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -18108,7 +18912,7 @@ var ReactPropTransferer = {  };  module.exports = ReactPropTransferer; -},{"./Object.assign":80,"fbjs/lib/emptyFunction":210,"fbjs/lib/joinClasses":221}],136:[function(require,module,exports){ +},{"./Object.assign":84,"fbjs/lib/emptyFunction":214,"fbjs/lib/joinClasses":225}],140:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -18136,7 +18940,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = ReactPropTypeLocationNames;  }).call(this,require('_process')) -},{"_process":23}],137:[function(require,module,exports){ +},{"_process":27}],141:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -18159,7 +18963,7 @@ var ReactPropTypeLocations = keyMirror({  });  module.exports = ReactPropTypeLocations; -},{"fbjs/lib/keyMirror":222}],138:[function(require,module,exports){ +},{"fbjs/lib/keyMirror":226}],142:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -18516,7 +19320,7 @@ function getClassName(propValue) {  }  module.exports = ReactPropTypes; -},{"./ReactElement":113,"./ReactPropTypeLocationNames":136,"./getIteratorFn":186,"fbjs/lib/emptyFunction":210}],139:[function(require,module,exports){ +},{"./ReactElement":117,"./ReactPropTypeLocationNames":140,"./getIteratorFn":190,"fbjs/lib/emptyFunction":214}],143:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -18668,7 +19472,7 @@ assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin);  PooledClass.addPoolingTo(ReactReconcileTransaction);  module.exports = ReactReconcileTransaction; -},{"./CallbackQueue":62,"./Object.assign":80,"./PooledClass":81,"./ReactBrowserEventEmitter":84,"./ReactDOMFeatureFlags":100,"./ReactInputSelection":122,"./Transaction":170}],140:[function(require,module,exports){ +},{"./CallbackQueue":66,"./Object.assign":84,"./PooledClass":85,"./ReactBrowserEventEmitter":88,"./ReactDOMFeatureFlags":104,"./ReactInputSelection":126,"./Transaction":174}],144:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -18776,7 +19580,7 @@ var ReactReconciler = {  };  module.exports = ReactReconciler; -},{"./ReactRef":141}],141:[function(require,module,exports){ +},{"./ReactRef":145}],145:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -18855,7 +19659,7 @@ ReactRef.detachRefs = function (instance, element) {  };  module.exports = ReactRef; -},{"./ReactOwner":133}],142:[function(require,module,exports){ +},{"./ReactOwner":137}],146:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -18885,7 +19689,7 @@ var ReactRootIndex = {  };  module.exports = ReactRootIndex; -},{}],143:[function(require,module,exports){ +},{}],147:[function(require,module,exports){  /**   * Copyright 2014-2015, Facebook, Inc.   * All rights reserved. @@ -18909,7 +19713,7 @@ var ReactServerBatchingStrategy = {  };  module.exports = ReactServerBatchingStrategy; -},{}],144:[function(require,module,exports){ +},{}],148:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -18996,7 +19800,7 @@ module.exports = {  };  }).call(this,require('_process')) -},{"./ReactDefaultBatchingStrategy":109,"./ReactElement":113,"./ReactInstanceHandles":123,"./ReactMarkupChecksum":127,"./ReactServerBatchingStrategy":143,"./ReactServerRenderingTransaction":145,"./ReactUpdates":152,"./instantiateReactComponent":189,"_process":23,"fbjs/lib/emptyObject":211,"fbjs/lib/invariant":218}],145:[function(require,module,exports){ +},{"./ReactDefaultBatchingStrategy":113,"./ReactElement":117,"./ReactInstanceHandles":127,"./ReactMarkupChecksum":131,"./ReactServerBatchingStrategy":147,"./ReactServerRenderingTransaction":149,"./ReactUpdates":156,"./instantiateReactComponent":193,"_process":27,"fbjs/lib/emptyObject":215,"fbjs/lib/invariant":222}],149:[function(require,module,exports){  /**   * Copyright 2014-2015, Facebook, Inc.   * All rights reserved. @@ -19084,7 +19888,7 @@ assign(ReactServerRenderingTransaction.prototype, Transaction.Mixin, Mixin);  PooledClass.addPoolingTo(ReactServerRenderingTransaction);  module.exports = ReactServerRenderingTransaction; -},{"./CallbackQueue":62,"./Object.assign":80,"./PooledClass":81,"./Transaction":170,"fbjs/lib/emptyFunction":210}],146:[function(require,module,exports){ +},{"./CallbackQueue":66,"./Object.assign":84,"./PooledClass":85,"./Transaction":174,"fbjs/lib/emptyFunction":214}],150:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -19189,7 +19993,7 @@ ReactStateSetters.Mixin = {  };  module.exports = ReactStateSetters; -},{}],147:[function(require,module,exports){ +},{}],151:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -19670,7 +20474,7 @@ Object.keys(topLevelTypes).forEach(function (eventType) {  module.exports = ReactTestUtils;  }).call(this,require('_process')) -},{"./EventConstants":71,"./EventPluginHub":72,"./EventPropagators":75,"./Object.assign":80,"./React":82,"./ReactBrowserEventEmitter":84,"./ReactCompositeComponent":94,"./ReactDOM":96,"./ReactElement":113,"./ReactInstanceHandles":123,"./ReactInstanceMap":124,"./ReactMount":128,"./ReactUpdates":152,"./SyntheticEvent":162,"./findDOMNode":179,"_process":23,"fbjs/lib/emptyObject":211,"fbjs/lib/invariant":218}],148:[function(require,module,exports){ +},{"./EventConstants":75,"./EventPluginHub":76,"./EventPropagators":79,"./Object.assign":84,"./React":86,"./ReactBrowserEventEmitter":88,"./ReactCompositeComponent":98,"./ReactDOM":100,"./ReactElement":117,"./ReactInstanceHandles":127,"./ReactInstanceMap":128,"./ReactMount":132,"./ReactUpdates":156,"./SyntheticEvent":166,"./findDOMNode":183,"_process":27,"fbjs/lib/emptyObject":215,"fbjs/lib/invariant":222}],152:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -19769,7 +20573,7 @@ var ReactTransitionChildMapping = {  };  module.exports = ReactTransitionChildMapping; -},{"./flattenChildren":180}],149:[function(require,module,exports){ +},{"./flattenChildren":184}],153:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -19879,7 +20683,7 @@ var ReactTransitionEvents = {  };  module.exports = ReactTransitionEvents; -},{"fbjs/lib/ExecutionEnvironment":204}],150:[function(require,module,exports){ +},{"fbjs/lib/ExecutionEnvironment":208}],154:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -20085,7 +20889,7 @@ var ReactTransitionGroup = React.createClass({  });  module.exports = ReactTransitionGroup; -},{"./Object.assign":80,"./React":82,"./ReactTransitionChildMapping":148,"fbjs/lib/emptyFunction":210}],151:[function(require,module,exports){ +},{"./Object.assign":84,"./React":86,"./ReactTransitionChildMapping":152,"fbjs/lib/emptyFunction":214}],155:[function(require,module,exports){  (function (process){  /**   * Copyright 2015, Facebook, Inc. @@ -20346,7 +21150,7 @@ var ReactUpdateQueue = {  module.exports = ReactUpdateQueue;  }).call(this,require('_process')) -},{"./Object.assign":80,"./ReactCurrentOwner":95,"./ReactElement":113,"./ReactInstanceMap":124,"./ReactUpdates":152,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],152:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactCurrentOwner":99,"./ReactElement":117,"./ReactInstanceMap":128,"./ReactUpdates":156,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],156:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -20573,7 +21377,7 @@ var ReactUpdates = {  module.exports = ReactUpdates;  }).call(this,require('_process')) -},{"./CallbackQueue":62,"./Object.assign":80,"./PooledClass":81,"./ReactPerf":134,"./ReactReconciler":140,"./Transaction":170,"_process":23,"fbjs/lib/invariant":218}],153:[function(require,module,exports){ +},{"./CallbackQueue":66,"./Object.assign":84,"./PooledClass":85,"./ReactPerf":138,"./ReactReconciler":144,"./Transaction":174,"_process":27,"fbjs/lib/invariant":222}],157:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -20588,7 +21392,7 @@ module.exports = ReactUpdates;  'use strict';  module.exports = '0.14.7'; -},{}],154:[function(require,module,exports){ +},{}],158:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -20652,7 +21456,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = React;  }).call(this,require('_process')) -},{"./LinkedStateMixin":78,"./React":82,"./ReactCSSTransitionGroup":85,"./ReactComponentWithPureRenderMixin":93,"./ReactDefaultPerf":111,"./ReactFragment":120,"./ReactTestUtils":147,"./ReactTransitionGroup":150,"./ReactUpdates":152,"./cloneWithProps":175,"./shallowCompare":197,"./update":200,"_process":23,"fbjs/lib/warning":230}],155:[function(require,module,exports){ +},{"./LinkedStateMixin":82,"./React":86,"./ReactCSSTransitionGroup":89,"./ReactComponentWithPureRenderMixin":97,"./ReactDefaultPerf":115,"./ReactFragment":124,"./ReactTestUtils":151,"./ReactTransitionGroup":154,"./ReactUpdates":156,"./cloneWithProps":179,"./shallowCompare":201,"./update":204,"_process":27,"fbjs/lib/warning":234}],159:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -20780,7 +21584,7 @@ var SVGDOMPropertyConfig = {  };  module.exports = SVGDOMPropertyConfig; -},{"./DOMProperty":66}],156:[function(require,module,exports){ +},{"./DOMProperty":70}],160:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -20982,7 +21786,7 @@ var SelectEventPlugin = {  };  module.exports = SelectEventPlugin; -},{"./EventConstants":71,"./EventPropagators":75,"./ReactInputSelection":122,"./SyntheticEvent":162,"./isTextInputElement":191,"fbjs/lib/ExecutionEnvironment":204,"fbjs/lib/getActiveElement":213,"fbjs/lib/keyOf":223,"fbjs/lib/shallowEqual":228}],157:[function(require,module,exports){ +},{"./EventConstants":75,"./EventPropagators":79,"./ReactInputSelection":126,"./SyntheticEvent":166,"./isTextInputElement":195,"fbjs/lib/ExecutionEnvironment":208,"fbjs/lib/getActiveElement":217,"fbjs/lib/keyOf":227,"fbjs/lib/shallowEqual":232}],161:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -21012,7 +21816,7 @@ var ServerReactRootIndex = {  };  module.exports = ServerReactRootIndex; -},{}],158:[function(require,module,exports){ +},{}],162:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -21603,7 +22407,7 @@ var SimpleEventPlugin = {  module.exports = SimpleEventPlugin;  }).call(this,require('_process')) -},{"./EventConstants":71,"./EventPropagators":75,"./ReactMount":128,"./SyntheticClipboardEvent":159,"./SyntheticDragEvent":161,"./SyntheticEvent":162,"./SyntheticFocusEvent":163,"./SyntheticKeyboardEvent":165,"./SyntheticMouseEvent":166,"./SyntheticTouchEvent":167,"./SyntheticUIEvent":168,"./SyntheticWheelEvent":169,"./getEventCharCode":182,"_process":23,"fbjs/lib/EventListener":203,"fbjs/lib/emptyFunction":210,"fbjs/lib/invariant":218,"fbjs/lib/keyOf":223}],159:[function(require,module,exports){ +},{"./EventConstants":75,"./EventPropagators":79,"./ReactMount":132,"./SyntheticClipboardEvent":163,"./SyntheticDragEvent":165,"./SyntheticEvent":166,"./SyntheticFocusEvent":167,"./SyntheticKeyboardEvent":169,"./SyntheticMouseEvent":170,"./SyntheticTouchEvent":171,"./SyntheticUIEvent":172,"./SyntheticWheelEvent":173,"./getEventCharCode":186,"_process":27,"fbjs/lib/EventListener":207,"fbjs/lib/emptyFunction":214,"fbjs/lib/invariant":222,"fbjs/lib/keyOf":227}],163:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -21643,7 +22447,7 @@ function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent, na  SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);  module.exports = SyntheticClipboardEvent; -},{"./SyntheticEvent":162}],160:[function(require,module,exports){ +},{"./SyntheticEvent":166}],164:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -21681,7 +22485,7 @@ function SyntheticCompositionEvent(dispatchConfig, dispatchMarker, nativeEvent,  SyntheticEvent.augmentClass(SyntheticCompositionEvent, CompositionEventInterface);  module.exports = SyntheticCompositionEvent; -},{"./SyntheticEvent":162}],161:[function(require,module,exports){ +},{"./SyntheticEvent":166}],165:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -21719,7 +22523,7 @@ function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeE  SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);  module.exports = SyntheticDragEvent; -},{"./SyntheticMouseEvent":166}],162:[function(require,module,exports){ +},{"./SyntheticMouseEvent":170}],166:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -21903,7 +22707,7 @@ PooledClass.addPoolingTo(SyntheticEvent, PooledClass.fourArgumentPooler);  module.exports = SyntheticEvent;  }).call(this,require('_process')) -},{"./Object.assign":80,"./PooledClass":81,"_process":23,"fbjs/lib/emptyFunction":210,"fbjs/lib/warning":230}],163:[function(require,module,exports){ +},{"./Object.assign":84,"./PooledClass":85,"_process":27,"fbjs/lib/emptyFunction":214,"fbjs/lib/warning":234}],167:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -21941,7 +22745,7 @@ function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent, native  SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);  module.exports = SyntheticFocusEvent; -},{"./SyntheticUIEvent":168}],164:[function(require,module,exports){ +},{"./SyntheticUIEvent":172}],168:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -21980,7 +22784,7 @@ function SyntheticInputEvent(dispatchConfig, dispatchMarker, nativeEvent, native  SyntheticEvent.augmentClass(SyntheticInputEvent, InputEventInterface);  module.exports = SyntheticInputEvent; -},{"./SyntheticEvent":162}],165:[function(require,module,exports){ +},{"./SyntheticEvent":166}],169:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22066,7 +22870,7 @@ function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent, nat  SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);  module.exports = SyntheticKeyboardEvent; -},{"./SyntheticUIEvent":168,"./getEventCharCode":182,"./getEventKey":183,"./getEventModifierState":184}],166:[function(require,module,exports){ +},{"./SyntheticUIEvent":172,"./getEventCharCode":186,"./getEventKey":187,"./getEventModifierState":188}],170:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22140,7 +22944,7 @@ function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent, native  SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);  module.exports = SyntheticMouseEvent; -},{"./SyntheticUIEvent":168,"./ViewportMetrics":171,"./getEventModifierState":184}],167:[function(require,module,exports){ +},{"./SyntheticUIEvent":172,"./ViewportMetrics":175,"./getEventModifierState":188}],171:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22187,7 +22991,7 @@ function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent, native  SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);  module.exports = SyntheticTouchEvent; -},{"./SyntheticUIEvent":168,"./getEventModifierState":184}],168:[function(require,module,exports){ +},{"./SyntheticUIEvent":172,"./getEventModifierState":188}],172:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22248,7 +23052,7 @@ function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent, nativeEve  SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);  module.exports = SyntheticUIEvent; -},{"./SyntheticEvent":162,"./getEventTarget":185}],169:[function(require,module,exports){ +},{"./SyntheticEvent":166,"./getEventTarget":189}],173:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22304,7 +23108,7 @@ function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent, native  SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);  module.exports = SyntheticWheelEvent; -},{"./SyntheticMouseEvent":166}],170:[function(require,module,exports){ +},{"./SyntheticMouseEvent":170}],174:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -22539,7 +23343,7 @@ var Transaction = {  module.exports = Transaction;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/invariant":218}],171:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/invariant":222}],175:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22567,7 +23371,7 @@ var ViewportMetrics = {  };  module.exports = ViewportMetrics; -},{}],172:[function(require,module,exports){ +},{}],176:[function(require,module,exports){  (function (process){  /**   * Copyright 2014-2015, Facebook, Inc. @@ -22630,7 +23434,7 @@ function accumulateInto(current, next) {  module.exports = accumulateInto;  }).call(this,require('_process')) -},{"_process":23,"fbjs/lib/invariant":218}],173:[function(require,module,exports){ +},{"_process":27,"fbjs/lib/invariant":222}],177:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22673,7 +23477,7 @@ function adler32(data) {  }  module.exports = adler32; -},{}],174:[function(require,module,exports){ +},{}],178:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -22701,7 +23505,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = canDefineProperty;  }).call(this,require('_process')) -},{"_process":23}],175:[function(require,module,exports){ +},{"_process":27}],179:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -22759,7 +23563,7 @@ function cloneWithProps(child, props) {  module.exports = cloneWithProps;  }).call(this,require('_process')) -},{"./ReactElement":113,"./ReactPropTransferer":135,"_process":23,"fbjs/lib/keyOf":223,"fbjs/lib/warning":230}],176:[function(require,module,exports){ +},{"./ReactElement":117,"./ReactPropTransferer":139,"_process":27,"fbjs/lib/keyOf":227,"fbjs/lib/warning":234}],180:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22815,7 +23619,7 @@ function dangerousStyleValue(name, value) {  }  module.exports = dangerousStyleValue; -},{"./CSSProperty":60}],177:[function(require,module,exports){ +},{"./CSSProperty":64}],181:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -22867,7 +23671,7 @@ function deprecated(fnName, newModule, newPackage, ctx, fn) {  module.exports = deprecated;  }).call(this,require('_process')) -},{"./Object.assign":80,"_process":23,"fbjs/lib/warning":230}],178:[function(require,module,exports){ +},{"./Object.assign":84,"_process":27,"fbjs/lib/warning":234}],182:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -22906,7 +23710,7 @@ function escapeTextContentForBrowser(text) {  }  module.exports = escapeTextContentForBrowser; -},{}],179:[function(require,module,exports){ +},{}],183:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -22959,7 +23763,7 @@ function findDOMNode(componentOrElement) {  module.exports = findDOMNode;  }).call(this,require('_process')) -},{"./ReactCurrentOwner":95,"./ReactInstanceMap":124,"./ReactMount":128,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],180:[function(require,module,exports){ +},{"./ReactCurrentOwner":99,"./ReactInstanceMap":128,"./ReactMount":132,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],184:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -23011,7 +23815,7 @@ function flattenChildren(children) {  module.exports = flattenChildren;  }).call(this,require('_process')) -},{"./traverseAllChildren":199,"_process":23,"fbjs/lib/warning":230}],181:[function(require,module,exports){ +},{"./traverseAllChildren":203,"_process":27,"fbjs/lib/warning":234}],185:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23041,7 +23845,7 @@ var forEachAccumulated = function (arr, cb, scope) {  };  module.exports = forEachAccumulated; -},{}],182:[function(require,module,exports){ +},{}],186:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23092,7 +23896,7 @@ function getEventCharCode(nativeEvent) {  }  module.exports = getEventCharCode; -},{}],183:[function(require,module,exports){ +},{}],187:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23196,7 +24000,7 @@ function getEventKey(nativeEvent) {  }  module.exports = getEventKey; -},{"./getEventCharCode":182}],184:[function(require,module,exports){ +},{"./getEventCharCode":186}],188:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23241,7 +24045,7 @@ function getEventModifierState(nativeEvent) {  }  module.exports = getEventModifierState; -},{}],185:[function(require,module,exports){ +},{}],189:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23271,7 +24075,7 @@ function getEventTarget(nativeEvent) {  }  module.exports = getEventTarget; -},{}],186:[function(require,module,exports){ +},{}],190:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23312,7 +24116,7 @@ function getIteratorFn(maybeIterable) {  }  module.exports = getIteratorFn; -},{}],187:[function(require,module,exports){ +},{}],191:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23386,7 +24190,7 @@ function getNodeForCharacterOffset(root, offset) {  }  module.exports = getNodeForCharacterOffset; -},{}],188:[function(require,module,exports){ +},{}],192:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23420,7 +24224,7 @@ function getTextContentAccessor() {  }  module.exports = getTextContentAccessor; -},{"fbjs/lib/ExecutionEnvironment":204}],189:[function(require,module,exports){ +},{"fbjs/lib/ExecutionEnvironment":208}],193:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -23536,7 +24340,7 @@ function instantiateReactComponent(node) {  module.exports = instantiateReactComponent;  }).call(this,require('_process')) -},{"./Object.assign":80,"./ReactCompositeComponent":94,"./ReactEmptyComponent":115,"./ReactNativeComponent":131,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],190:[function(require,module,exports){ +},{"./Object.assign":84,"./ReactCompositeComponent":98,"./ReactEmptyComponent":119,"./ReactNativeComponent":135,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],194:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23597,7 +24401,7 @@ function isEventSupported(eventNameSuffix, capture) {  }  module.exports = isEventSupported; -},{"fbjs/lib/ExecutionEnvironment":204}],191:[function(require,module,exports){ +},{"fbjs/lib/ExecutionEnvironment":208}],195:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23638,7 +24442,7 @@ function isTextInputElement(elem) {  }  module.exports = isTextInputElement; -},{}],192:[function(require,module,exports){ +},{}],196:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -23675,7 +24479,7 @@ function onlyChild(children) {  module.exports = onlyChild;  }).call(this,require('_process')) -},{"./ReactElement":113,"_process":23,"fbjs/lib/invariant":218}],193:[function(require,module,exports){ +},{"./ReactElement":117,"_process":27,"fbjs/lib/invariant":222}],197:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23702,7 +24506,7 @@ function quoteAttributeValueForBrowser(value) {  }  module.exports = quoteAttributeValueForBrowser; -},{"./escapeTextContentForBrowser":178}],194:[function(require,module,exports){ +},{"./escapeTextContentForBrowser":182}],198:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23719,7 +24523,7 @@ module.exports = quoteAttributeValueForBrowser;  var ReactMount = require('./ReactMount');  module.exports = ReactMount.renderSubtreeIntoContainer; -},{"./ReactMount":128}],195:[function(require,module,exports){ +},{"./ReactMount":132}],199:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23810,7 +24614,7 @@ if (ExecutionEnvironment.canUseDOM) {  }  module.exports = setInnerHTML; -},{"fbjs/lib/ExecutionEnvironment":204}],196:[function(require,module,exports){ +},{"fbjs/lib/ExecutionEnvironment":208}],200:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23851,7 +24655,7 @@ if (ExecutionEnvironment.canUseDOM) {  }  module.exports = setTextContent; -},{"./escapeTextContentForBrowser":178,"./setInnerHTML":195,"fbjs/lib/ExecutionEnvironment":204}],197:[function(require,module,exports){ +},{"./escapeTextContentForBrowser":182,"./setInnerHTML":199,"fbjs/lib/ExecutionEnvironment":208}],201:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23876,7 +24680,7 @@ function shallowCompare(instance, nextProps, nextState) {  }  module.exports = shallowCompare; -},{"fbjs/lib/shallowEqual":228}],198:[function(require,module,exports){ +},{"fbjs/lib/shallowEqual":232}],202:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -23920,7 +24724,7 @@ function shouldUpdateReactComponent(prevElement, nextElement) {  }  module.exports = shouldUpdateReactComponent; -},{}],199:[function(require,module,exports){ +},{}],203:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -24113,7 +24917,7 @@ function traverseAllChildren(children, callback, traverseContext) {  module.exports = traverseAllChildren;  }).call(this,require('_process')) -},{"./ReactCurrentOwner":95,"./ReactElement":113,"./ReactInstanceHandles":123,"./getIteratorFn":186,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/warning":230}],200:[function(require,module,exports){ +},{"./ReactCurrentOwner":99,"./ReactElement":117,"./ReactInstanceHandles":127,"./getIteratorFn":190,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/warning":234}],204:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -24224,7 +25028,7 @@ function update(value, spec) {  module.exports = update;  }).call(this,require('_process')) -},{"./Object.assign":80,"_process":23,"fbjs/lib/invariant":218,"fbjs/lib/keyOf":223}],201:[function(require,module,exports){ +},{"./Object.assign":84,"_process":27,"fbjs/lib/invariant":222,"fbjs/lib/keyOf":227}],205:[function(require,module,exports){  (function (process){  /**   * Copyright 2015, Facebook, Inc. @@ -24591,7 +25395,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = validateDOMNesting;  }).call(this,require('_process')) -},{"./Object.assign":80,"_process":23,"fbjs/lib/emptyFunction":210,"fbjs/lib/warning":230}],202:[function(require,module,exports){ +},{"./Object.assign":84,"_process":27,"fbjs/lib/emptyFunction":214,"fbjs/lib/warning":234}],206:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -24692,7 +25496,7 @@ var CSSCore = {  module.exports = CSSCore;  }).call(this,require('_process')) -},{"./invariant":218,"_process":23}],203:[function(require,module,exports){ +},{"./invariant":222,"_process":27}],207:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -24780,7 +25584,7 @@ var EventListener = {  module.exports = EventListener;  }).call(this,require('_process')) -},{"./emptyFunction":210,"_process":23}],204:[function(require,module,exports){ +},{"./emptyFunction":214,"_process":27}],208:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -24817,7 +25621,7 @@ var ExecutionEnvironment = {  };  module.exports = ExecutionEnvironment; -},{}],205:[function(require,module,exports){ +},{}],209:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -24850,7 +25654,7 @@ function camelize(string) {  }  module.exports = camelize; -},{}],206:[function(require,module,exports){ +},{}],210:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -24891,7 +25695,7 @@ function camelizeStyleName(string) {  }  module.exports = camelizeStyleName; -},{"./camelize":205}],207:[function(require,module,exports){ +},{"./camelize":209}],211:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -24947,7 +25751,7 @@ function containsNode(_x, _x2) {  }  module.exports = containsNode; -},{"./isTextNode":220}],208:[function(require,module,exports){ +},{"./isTextNode":224}],212:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25033,7 +25837,7 @@ function createArrayFromMixed(obj) {  }  module.exports = createArrayFromMixed; -},{"./toArray":229}],209:[function(require,module,exports){ +},{"./toArray":233}],213:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -25121,7 +25925,7 @@ function createNodesFromMarkup(markup, handleScript) {  module.exports = createNodesFromMarkup;  }).call(this,require('_process')) -},{"./ExecutionEnvironment":204,"./createArrayFromMixed":208,"./getMarkupWrap":214,"./invariant":218,"_process":23}],210:[function(require,module,exports){ +},{"./ExecutionEnvironment":208,"./createArrayFromMixed":212,"./getMarkupWrap":218,"./invariant":222,"_process":27}],214:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25160,7 +25964,7 @@ emptyFunction.thatReturnsArgument = function (arg) {  };  module.exports = emptyFunction; -},{}],211:[function(require,module,exports){ +},{}],215:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -25184,7 +25988,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = emptyObject;  }).call(this,require('_process')) -},{"_process":23}],212:[function(require,module,exports){ +},{"_process":27}],216:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25211,7 +26015,7 @@ function focusNode(node) {  }  module.exports = focusNode; -},{}],213:[function(require,module,exports){ +},{}],217:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25247,7 +26051,7 @@ function getActiveElement() /*?DOMElement*/{  }  module.exports = getActiveElement; -},{}],214:[function(require,module,exports){ +},{}],218:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -25346,7 +26150,7 @@ function getMarkupWrap(nodeName) {  module.exports = getMarkupWrap;  }).call(this,require('_process')) -},{"./ExecutionEnvironment":204,"./invariant":218,"_process":23}],215:[function(require,module,exports){ +},{"./ExecutionEnvironment":208,"./invariant":222,"_process":27}],219:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25385,7 +26189,7 @@ function getUnboundedScrollPosition(scrollable) {  }  module.exports = getUnboundedScrollPosition; -},{}],216:[function(require,module,exports){ +},{}],220:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25419,7 +26223,7 @@ function hyphenate(string) {  }  module.exports = hyphenate; -},{}],217:[function(require,module,exports){ +},{}],221:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25459,7 +26263,7 @@ function hyphenateStyleName(string) {  }  module.exports = hyphenateStyleName; -},{"./hyphenate":216}],218:[function(require,module,exports){ +},{"./hyphenate":220}],222:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -25513,7 +26317,7 @@ function invariant(condition, format, a, b, c, d, e, f) {  module.exports = invariant;  }).call(this,require('_process')) -},{"_process":23}],219:[function(require,module,exports){ +},{"_process":27}],223:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25537,7 +26341,7 @@ function isNode(object) {  }  module.exports = isNode; -},{}],220:[function(require,module,exports){ +},{}],224:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25563,7 +26367,7 @@ function isTextNode(object) {  }  module.exports = isTextNode; -},{"./isNode":219}],221:[function(require,module,exports){ +},{"./isNode":223}],225:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25603,7 +26407,7 @@ function joinClasses(className /*, ... */) {  }  module.exports = joinClasses; -},{}],222:[function(require,module,exports){ +},{}],226:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -25655,7 +26459,7 @@ var keyMirror = function (obj) {  module.exports = keyMirror;  }).call(this,require('_process')) -},{"./invariant":218,"_process":23}],223:[function(require,module,exports){ +},{"./invariant":222,"_process":27}],227:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25691,7 +26495,7 @@ var keyOf = function (oneKeyObj) {  };  module.exports = keyOf; -},{}],224:[function(require,module,exports){ +},{}],228:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25743,7 +26547,7 @@ function mapObject(object, callback, context) {  }  module.exports = mapObject; -},{}],225:[function(require,module,exports){ +},{}],229:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25775,7 +26579,7 @@ function memoizeStringOnly(callback) {  }  module.exports = memoizeStringOnly; -},{}],226:[function(require,module,exports){ +},{}],230:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25799,7 +26603,7 @@ if (ExecutionEnvironment.canUseDOM) {  }  module.exports = performance || {}; -},{"./ExecutionEnvironment":204}],227:[function(require,module,exports){ +},{"./ExecutionEnvironment":208}],231:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25834,7 +26638,7 @@ if (performance.now) {  }  module.exports = performanceNow; -},{"./performance":226}],228:[function(require,module,exports){ +},{"./performance":230}],232:[function(require,module,exports){  /**   * Copyright 2013-2015, Facebook, Inc.   * All rights reserved. @@ -25885,7 +26689,7 @@ function shallowEqual(objA, objB) {  }  module.exports = shallowEqual; -},{}],229:[function(require,module,exports){ +},{}],233:[function(require,module,exports){  (function (process){  /**   * Copyright 2013-2015, Facebook, Inc. @@ -25946,7 +26750,7 @@ function toArray(obj) {  module.exports = toArray;  }).call(this,require('_process')) -},{"./invariant":218,"_process":23}],230:[function(require,module,exports){ +},{"./invariant":222,"_process":27}],234:[function(require,module,exports){  (function (process){  /**   * Copyright 2014-2015, Facebook, Inc. @@ -26007,7 +26811,7 @@ if (process.env.NODE_ENV !== 'production') {  module.exports = warning;  }).call(this,require('_process')) -},{"./emptyFunction":210,"_process":23}],231:[function(require,module,exports){ +},{"./emptyFunction":214,"_process":27}],235:[function(require,module,exports){  'use strict';  module.exports = function (str) {  	return encodeURIComponent(str).replace(/[!'()*]/g, function (c) { @@ -26015,7 +26819,7 @@ module.exports = function (str) {  	});  }; -},{}],232:[function(require,module,exports){ +},{}],236:[function(require,module,exports){  (function (process){  /**   * Copyright 2014-2015, Facebook, Inc. @@ -26080,7 +26884,57 @@ module.exports = warning;  }).call(this,require('_process')) -},{"_process":23}],"flux":[function(require,module,exports){ +},{"_process":27}],"classnames":[function(require,module,exports){ +/*! +  Copyright (c) 2016 Jed Watson. +  Licensed under the MIT License (MIT), see +  http://jedwatson.github.io/classnames +*/ +/* global define */ + +(function () { +	'use strict'; + +	var hasOwn = {}.hasOwnProperty; + +	function classNames () { +		var classes = []; + +		for (var i = 0; i < arguments.length; i++) { +			var arg = arguments[i]; +			if (!arg) continue; + +			var argType = typeof arg; + +			if (argType === 'string' || argType === 'number') { +				classes.push(arg); +			} else if (Array.isArray(arg)) { +				classes.push(classNames.apply(null, arg)); +			} else if (argType === 'object') { +				for (var key in arg) { +					if (hasOwn.call(arg, key) && arg[key]) { +						classes.push(key); +					} +				} +			} +		} + +		return classes.join(' '); +	} + +	if (typeof module !== 'undefined' && module.exports) { +		module.exports = classNames; +	} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { +		// register as 'classnames', consistent with npm package name +		define('classnames', [], function () { +			return classNames; +		}); +	} else { +		window.classNames = classNames; +	} +}()); + +},{}],"flux":[function(require,module,exports){  /**   * Copyright (c) 2014-2015, Facebook, Inc.   * All rights reserved. @@ -50868,7 +51722,7 @@ return jQuery;  module.exports = require('react/lib/ReactDOM'); -},{"react/lib/ReactDOM":96}],"react-router":[function(require,module,exports){ +},{"react/lib/ReactDOM":100}],"react-router":[function(require,module,exports){  /* components */  'use strict'; @@ -51005,7 +51859,7 @@ var _createMemoryHistory2 = require('./createMemoryHistory');  var _createMemoryHistory3 = _interopRequireDefault(_createMemoryHistory2);  exports.createMemoryHistory = _createMemoryHistory3['default']; -},{"./History":26,"./IndexLink":27,"./IndexRedirect":28,"./IndexRoute":29,"./Lifecycle":30,"./Link":31,"./PatternUtils":32,"./PropTypes":33,"./Redirect":34,"./Route":35,"./RouteContext":36,"./RouteUtils":37,"./Router":38,"./RouterContext":39,"./RoutingContext":41,"./browserHistory":43,"./createMemoryHistory":45,"./hashHistory":51,"./match":53,"./useRouterHistory":56,"./useRoutes":57}],"react/addons":[function(require,module,exports){ +},{"./History":30,"./IndexLink":31,"./IndexRedirect":32,"./IndexRoute":33,"./Lifecycle":34,"./Link":35,"./PatternUtils":36,"./PropTypes":37,"./Redirect":38,"./Route":39,"./RouteContext":40,"./RouteUtils":41,"./Router":42,"./RouterContext":43,"./RoutingContext":45,"./browserHistory":47,"./createMemoryHistory":49,"./hashHistory":55,"./match":57,"./useRouterHistory":60,"./useRoutes":61}],"react/addons":[function(require,module,exports){  'use strict';  var warning = require('fbjs/lib/warning'); @@ -51020,12 +51874,61 @@ warning(  module.exports = require('./lib/ReactWithAddons'); -},{"./lib/ReactWithAddons":154,"fbjs/lib/warning":230}],"react":[function(require,module,exports){ +},{"./lib/ReactWithAddons":158,"fbjs/lib/warning":234}],"react":[function(require,module,exports){  'use strict';  module.exports = require('./lib/React'); -},{"./lib/React":82}]},{},[]) +},{"./lib/React":86}],"shallowequal":[function(require,module,exports){ +'use strict'; + +var fetchKeys = require('lodash.keys'); + +module.exports = function shallowEqual(objA, objB, compare, compareContext) { + +    var ret = compare ? compare.call(compareContext, objA, objB) : void 0; + +    if (ret !== void 0) { +        return !!ret; +    } + +    if (objA === objB) { +        return true; +    } + +    if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { +        return false; +    } + +    var keysA = fetchKeys(objA); +    var keysB = fetchKeys(objB); + +    var len = keysA.length; +    if (len !== keysB.length) { +        return false; +    } + +    compareContext = compareContext || null; + +    // Test for A's keys different from B. +    var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB); +    for (var i = 0; i < len; i++) { +        var key = keysA[i]; +        if (!bHasOwnProperty(key)) { +            return false; +        } +        var valueA = objA[key]; +        var valueB = objB[key]; + +        var _ret = compare ? compare.call(compareContext, valueA, valueB, key) : void 0; +        if (_ret === false || _ret === void 0 && valueA !== valueB) { +            return false; +        } +    } + +    return true; +}; +},{"lodash.keys":26}]},{},[])  //# sourceMappingURL=vendor.js.map diff --git a/web/.babelrc b/web/.babelrc index facd1809..5dd7708c 100644 --- a/web/.babelrc +++ b/web/.babelrc @@ -1,3 +1,4 @@  { -  "presets": ["es2015", "react"] +  "presets": ["es2015", "react"], +  "plugins": ["transform-class-properties"]  }
\ No newline at end of file diff --git a/web/.eslintrc.yml b/web/.eslintrc.yml index 319fa67c..60028c97 100644 --- a/web/.eslintrc.yml +++ b/web/.eslintrc.yml @@ -1,9 +1,3 @@  { -    "parserOptions": { -        "ecmaVersion": 6, -        "sourceType": "module", -        "ecmaFeatures": { -            "jsx": true -        } -    } +    "parser": "babel-eslint"  }
\ No newline at end of file diff --git a/web/package.json b/web/package.json index 63a664ae..e489a0b1 100644 --- a/web/package.json +++ b/web/package.json @@ -17,16 +17,20 @@    },    "dependencies": {      "bootstrap": "^3.3.6", +    "classnames": "^2.2.3",      "flux": "^2.1.1",      "jquery": "^2.2.1",      "lodash": "^4.5.1",      "react": "^0.14.7",      "react-dom": "^0.14.7", -    "react-router": "^2.0.0" +    "react-router": "^2.0.0", +    "shallowequal": "^0.2.2"    },    "devDependencies": {      "babel-core": "^6.5.2", +    "babel-eslint": "^5.0.0",      "babel-jest": "^6.0.1", +    "babel-plugin-transform-class-properties": "^6.6.0",      "babel-preset-es2015": "^6.5.0",      "babel-preset-react": "^6.5.0",      "babelify": "^7.2.0", diff --git a/web/src/js/components/common.js b/web/src/js/components/common.js index 447e6eec..ad97ab38 100644 --- a/web/src/js/components/common.js +++ b/web/src/js/components/common.js @@ -2,34 +2,6 @@ import React from "react"  import ReactDOM from "react-dom"  import _ from "lodash" -// http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html (also contains inverse example) -export var AutoScrollMixin = { -    componentWillUpdate: function () { -        var node = ReactDOM.findDOMNode(this); -        this._shouldScrollBottom = ( -            node.scrollTop !== 0 && -            node.scrollTop + node.clientHeight === node.scrollHeight -        ); -    }, -    componentDidUpdate: function () { -        if (this._shouldScrollBottom) { -            var node = ReactDOM.findDOMNode(this); -            node.scrollTop = node.scrollHeight; -        } -    } -}; - - -export var StickyHeadMixin = { -    adjustHead: function () { -        // Abusing CSS transforms to set the element -        // referenced as head into some kind of position:sticky. -        var head = ReactDOM.findDOMNode(this.refs.head); -        head.style.transform = "translate(0," + ReactDOM.findDOMNode(this).scrollTop + "px)"; -    } -}; - -  export var Router = {      contextTypes: {          location: React.PropTypes.object, @@ -53,9 +25,6 @@ export var Router = {          // For whatever reason, react-router always returns the same object, which makes comparing          // the current props with nextProps impossible. As a workaround, we just clone the query object.          return _.clone(this.context.location.query); -    }, -    getParams: function() { -        return this.props.routeParams;      }  }; diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js index 650f7cd3..d1b23ace 100644 --- a/web/src/js/components/eventlog.js +++ b/web/src/js/components/eventlog.js @@ -1,115 +1,151 @@  import React from "react" -import {AutoScrollMixin, Router} from "./common.js" +import ReactDOM from "react-dom" +import shallowEqual from "shallowequal" +import {Router} from "./common.js"  import {Query} from "../actions.js" -import { VirtualScrollMixin } from "./virtualscroll.js" +import AutoScroll from "./helpers/AutoScroll"; +import {calcVScroll} from "./helpers/VirtualScroll"  import {StoreView} from "../store/view.js"  import _ from "lodash" -var LogMessage = React.createClass({ -    render: function () { -        var entry = this.props.entry; -        var indicator; -        switch (entry.level) { -            case "web": -                indicator = <i className="fa fa-fw fa-html5"></i>; -                break; -            case "debug": -                indicator = <i className="fa fa-fw fa-bug"></i>; -                break; -            default: -                indicator = <i className="fa fa-fw fa-info"></i>; -        } -        return ( -            <div> -                { indicator } {entry.message} -            </div> +class EventLogContents extends React.Component { + +    static contextTypes = { +        eventStore: React.PropTypes.object.isRequired, +    }; + +    static defaultProps = { +        rowHeight: 18, +    }; + +    constructor(props, context) { +        super(props, context); + +        this.view = new StoreView( +            this.context.eventStore, +            entry => this.props.filter[entry.level]          ); -    }, -    shouldComponentUpdate: function () { -        return false; // log entries are immutable. + +        this.heights = {}; +        this.state = { entries: this.view.list, vScroll: calcVScroll() }; + +        this.onChange = this.onChange.bind(this); +        this.onViewportUpdate = this.onViewportUpdate.bind(this);      } -}); -var EventLogContents = React.createClass({ -    contextTypes: { -        eventStore: React.PropTypes.object.isRequired -    }, -    mixins: [AutoScrollMixin, VirtualScrollMixin], -    getInitialState: function () { -        var filterFn = function (entry) { -            return this.props.filter[entry.level]; -        }; -        var view = new StoreView(this.context.eventStore, filterFn.bind(this)); -        view.addListener("add", this.onEventLogChange); -        view.addListener("recalculate", this.onEventLogChange); +    componentDidMount() { +        window.addEventListener("resize", this.onViewportUpdate); +        this.view.addListener("add", this.onChange); +        this.view.addListener("recalculate", this.onChange); +        this.onViewportUpdate(); +    } -        return { -            view: view -        }; -    }, -    componentWillUnmount: function () { -        this.state.view.close(); -    }, -    filter: function (entry) { -        return this.props.filter[entry.level]; -    }, -    onEventLogChange: function () { -        this.forceUpdate(); -    }, -    componentWillReceiveProps: function (nextProps) { +    componentWillUnmount() { +        window.removeEventListener("resize", this.onViewportUpdate); +        this.view.removeListener("add", this.onChange); +        this.view.removeListener("recalculate", this.onChange); +        this.view.close(); +    } + +    componentDidUpdate() { +        this.onViewportUpdate(); +    } + +    componentWillReceiveProps(nextProps) {          if (nextProps.filter !== this.props.filter) { -            this.props.filter = nextProps.filter; // Dirty: Make sure that view filter sees the update. -            this.state.view.recalculate(); +            this.view.recalculate( +                entry => nextProps.filter[entry.level] +            );          } -    }, -    getDefaultProps: function () { -        return { -            rowHeight: 45, -            rowHeightMin: 15, -            placeholderTagName: "div" -        }; -    }, -    renderRow: function (elem) { -        return <LogMessage key={elem.id} entry={elem}/>; -    }, -    render: function () { -        var entries = this.state.view.list; -        var rows = this.renderRows(entries); - -        return <pre onScroll={this.onScroll}> -            { this.getPlaceholderTop(entries.length) } -            {rows} -            { this.getPlaceholderBottom(entries.length) } -        </pre>;      } -}); -var ToggleFilter = React.createClass({ -    toggle: function (e) { -        e.preventDefault(); -        return this.props.toggleLevel(this.props.name); -    }, -    render: function () { -        var className = "label "; -        if (this.props.active) { -            className += "label-primary"; -        } else { -            className += "label-default"; +    onViewportUpdate() { +        const viewport = ReactDOM.findDOMNode(this); + +        const vScroll = calcVScroll({ +            itemCount: this.state.entries.length, +            rowHeight: this.props.rowHeight, +            viewportTop: viewport.scrollTop, +            viewportHeight: viewport.offsetHeight, +            itemHeights: this.state.entries.map(entry => this.heights[entry.id]), +        }); + +        if (!shallowEqual(this.state.vScroll, vScroll)) { +            this.setState({ vScroll }); +        } +    } + +    onChange() { +        this.setState({ entries: this.view.list }); +    } + +    setHeight(id, ref) { +        if (ref && !this.heights[id]) { +            const height = ReactDOM.findDOMNode(ref).offsetHeight; +            if (this.heights[id] !== height) { +                this.heights[id] = height; +                this.onViewportUpdate(); +            }          } +    } + +    getIcon(level) { +        return { web: "html5", debug: "bug" }[level] || "info"; +    } + +    render() { +        const vScroll = this.state.vScroll; +        const entries = this.state.entries.slice(vScroll.start, vScroll.end); +          return ( -            <a -                href="#" -                className={className} -                onClick={this.toggle}> -                {this.props.name} -            </a> +            <pre onScroll={this.onViewportUpdate}> +                <div style={{ height: vScroll.paddingTop }}></div> +                {entries.map((entry, index) => ( +                    <div key={entry.id} ref={this.setHeight.bind(this, entry.id)}> +                        <i className={`fa fa-fw fa-${this.getIcon(entry.level)}`}></i> +                        {entry.message} +                    </div> +                ))} +                <div style={{ height: vScroll.paddingBottom }}></div> +            </pre>          );      } -}); +} + +ToggleFilter.propTypes = { +    name: React.PropTypes.string.isRequired, +    toggleLevel: React.PropTypes.func.isRequired, +    active: React.PropTypes.bool, +}; + +function ToggleFilter ({ name, active, toggleLevel }) { +    let className = "label "; +    if (active) { +        className += "label-primary"; +    } else { +        className += "label-default"; +    } + +    function onClick(event) { +        event.preventDefault(); +        toggleLevel(name); +    } + +    return ( +        <a +            href="#" +            className={className} +            onClick={onClick}> +            {name} +        </a> +    ); +} + +const AutoScrollEventLog = AutoScroll(EventLogContents);  var EventLog = React.createClass({      mixins: [Router], -    getInitialState: function () { +    getInitialState() {          return {              filter: {                  "debug": false, @@ -118,18 +154,17 @@ var EventLog = React.createClass({              }          };      }, -    close: function () { +    close() {          var d = {};          d[Query.SHOW_EVENTLOG] = undefined; -          this.updateLocation(undefined, d);      }, -    toggleLevel: function (level) { +    toggleLevel(level) {          var filter = _.extend({}, this.state.filter);          filter[level] = !filter[level];          this.setState({filter: filter});      }, -    render: function () { +    render() {          return (              <div className="eventlog">                  <div> @@ -142,10 +177,10 @@ var EventLog = React.createClass({                      </div>                  </div> -                <EventLogContents filter={this.state.filter}/> +                <AutoScrollEventLog filter={this.state.filter}/>              </div>          );      }  }); -export default EventLog;
\ No newline at end of file +export default EventLog; diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js index 988d1895..f03b8ec0 100644 --- a/web/src/js/components/flowtable.js +++ b/web/src/js/components/flowtable.js @@ -1,188 +1,216 @@  import React from "react"; -import ReactDOM from 'react-dom'; -import {StickyHeadMixin, AutoScrollMixin} from "./common.js"; +import ReactDOM from "react-dom"; +import classNames from "classnames";  import {reverseString} from "../utils.js";  import _ from "lodash"; - -import { VirtualScrollMixin } from "./virtualscroll.js" +import shallowEqual from "shallowequal"; +import AutoScroll from "./helpers/AutoScroll"; +import {calcVScroll} from "./helpers/VirtualScroll";  import flowtable_columns from "./flowtable-columns.js"; -var FlowRow = React.createClass({ -    render: function () { -        var flow = this.props.flow; -        var columns = this.props.columns.map(function (Column) { -            return <Column key={Column.displayName} flow={flow}/>; -        }.bind(this)); -        var className = ""; -        if (this.props.selected) { -            className += " selected"; -        } -        if (this.props.highlighted) { -            className += " highlighted"; -        } -        if (flow.intercepted) { -            className += " intercepted"; -        } -        if (flow.request) { -            className += " has-request"; -        } -        if (flow.response) { -            className += " has-response"; -        } +FlowRow.propTypes = { +    selectFlow: React.PropTypes.func.isRequired, +    columns: React.PropTypes.array.isRequired, +    flow: React.PropTypes.object.isRequired, +    highlighted: React.PropTypes.bool, +    selected: React.PropTypes.bool, +}; -        return ( -            <tr className={className} onClick={this.props.selectFlow.bind(null, flow)}> -                {columns} -            </tr>); -    }, -    shouldComponentUpdate: function (nextProps) { -        return true; -        // Further optimization could be done here -        // by calling forceUpdate on flow updates, selection changes and column changes. -        //return ( -        //(this.props.columns.length !== nextProps.columns.length) || -        //(this.props.selected !== nextProps.selected) -        //); +function FlowRow(props) { +    const flow = props.flow; + +    const className = classNames({ +        "selected": props.selected, +        "highlighted": props.highlighted, +        "intercepted": flow.intercepted, +        "has-request": flow.request, +        "has-response": flow.response, +    }); + +    return ( +        <tr className={className} onClick={() => props.selectFlow(flow)}> +            {props.columns.map(Column => ( +                <Column key={Column.displayName} flow={flow}/> +            ))} +        </tr> +    ); +} + +class FlowTableHead extends React.Component { + +    static propTypes = { +        setSortKeyFun: React.PropTypes.func.isRequired, +        columns: React.PropTypes.array.isRequired, +    }; + +    constructor(props, context) { +        super(props, context); +        this.state = { sortColumn: undefined, sortDesc: false };      } -}); - -var FlowTableHead = React.createClass({ -    getInitialState: function(){ -        return { -            sortColumn: undefined, -            sortDesc: false -        }; -    }, -    onClick: function(Column){ -        var sortDesc = this.state.sortDesc; -        var hasSort = Column.sortKeyFun; -        if(Column === this.state.sortColumn){ + +    onClick(Column) { +        const hasSort = Column.sortKeyFun; + +        let sortDesc = this.state.sortDesc; + +        if (Column === this.state.sortColumn) {              sortDesc = !sortDesc; -            this.setState({ -                sortDesc: sortDesc -            }); +            this.setState({ sortDesc });          } else { -            this.setState({ -                sortColumn: hasSort && Column, -                sortDesc: false -            }) +            this.setState({ sortColumn: hasSort && Column, sortDesc: false });          } -        var sortKeyFun; -        if(!sortDesc){ -            sortKeyFun = Column.sortKeyFun; -        } else { -            sortKeyFun = hasSort && function(){ -                var k = Column.sortKeyFun.apply(this, arguments); -                if(_.isString(k)){ -                    return reverseString(""+k); -                } else { -                    return -k; + +        let sortKeyFun = Column.sortKeyFun; +        if (sortDesc) { +            sortKeyFun = hasSort && function() { +                const k = Column.sortKeyFun.apply(this, arguments); +                if (_.isString(k)) { +                    return reverseString("" + k);                  } -            } +                return -k; +            };          } +          this.props.setSortKeyFun(sortKeyFun); -    }, -    render: function () { -        var columns = this.props.columns.map(function (Column) { -            var onClick = this.onClick.bind(this, Column); -            var className; -            if(this.state.sortColumn === Column) { -                if(this.state.sortDesc){ -                    className = "sort-desc"; -                } else { -                    className = "sort-asc"; -                } -            } -            return <Column.Title +    } + +    render() { +        const sortColumn = this.state.sortColumn; +        const sortType = this.state.sortDesc ? "sort-desc" : "sort-asc"; +        return ( +            <tr> +                {this.props.columns.map(Column => ( +                    <Column.Title                          key={Column.displayName} -                        onClick={onClick} -                        className={className} />; -        }.bind(this)); -        return <thead> -            <tr>{columns}</tr> -        </thead>; +                        onClick={() => this.onClick(Column)} +                        className={sortColumn === Column && sortType} +                    /> +                ))} +            </tr> +        ); +    } +} + +class FlowTable extends React.Component { + +    static contextTypes = { +        view: React.PropTypes.object.isRequired, +    }; + +    static propTypes = { +        rowHeight: React.PropTypes.number, +    }; + +    static defaultProps = { +        rowHeight: 32, +    }; + +    constructor(props, context) { +        super(props, context); + +        this.state = { flows: [], vScroll: calcVScroll() }; + +        this.onChange = this.onChange.bind(this); +        this.onViewportUpdate = this.onViewportUpdate.bind(this);      } -}); - - -var ROW_HEIGHT = 32; - -var FlowTable = React.createClass({ -    mixins: [StickyHeadMixin, AutoScrollMixin, VirtualScrollMixin], -    contextTypes: { -        view: React.PropTypes.object.isRequired -    }, -    getInitialState: function () { -        return { -            columns: flowtable_columns -        }; -    }, -    componentWillMount: function () { + +    componentWillMount() { +        window.addEventListener("resize", this.onViewportUpdate);          this.context.view.addListener("add", this.onChange);          this.context.view.addListener("update", this.onChange);          this.context.view.addListener("remove", this.onChange);          this.context.view.addListener("recalculate", this.onChange); -    }, -    componentWillUnmount: function(){ +    } + +    componentWillUnmount() { +        window.removeEventListener("resize", this.onViewportUpdate);          this.context.view.removeListener("add", this.onChange);          this.context.view.removeListener("update", this.onChange);          this.context.view.removeListener("remove", this.onChange);          this.context.view.removeListener("recalculate", this.onChange); -    }, -    getDefaultProps: function () { -        return { -            rowHeight: ROW_HEIGHT -        }; -    }, -    onScrollFlowTable: function () { -        this.adjustHead(); -        this.onScroll(); -    }, -    onChange: function () { -        this.forceUpdate(); -    }, -    scrollIntoView: function (flow) { -        this.scrollRowIntoView( -            this.context.view.indexOf(flow), -            ReactDOM.findDOMNode(this.refs.body).offsetTop -        ); -    }, -    renderRow: function (flow) { -        var selected = (flow === this.props.selected); -        var highlighted = -            ( -            this.context.view._highlight && -            this.context.view._highlight[flow.id] -            ); - -        return <FlowRow key={flow.id} -            ref={flow.id} -            flow={flow} -            columns={this.state.columns} -            selected={selected} -            highlighted={highlighted} -            selectFlow={this.props.selectFlow} -        />; -    }, -    render: function () { -        var flows = this.context.view.list; -        var rows = this.renderRows(flows); +    } + +    componentDidUpdate() { +        this.onViewportUpdate(); +    } + +    onViewportUpdate() { +        const viewport = ReactDOM.findDOMNode(this); +        const viewportTop = viewport.scrollTop; + +        const vScroll = calcVScroll({ +            viewportTop, +            viewportHeight: viewport.offsetHeight, +            itemCount: this.state.flows.length, +            rowHeight: this.props.rowHeight, +        }); + +        if (!shallowEqual(this.state.vScroll, vScroll) || +            this.state.viewportTop !== viewportTop) { +            this.setState({ vScroll, viewportTop }); +        } +    } + +    onChange() { +        this.setState({ flows: this.context.view.list }); +    } + +    scrollIntoView(flow) { +        const viewport = ReactDOM.findDOMNode(this); +        const index = this.context.view.indexOf(flow); +        const rowHeight = this.props.rowHeight; +        const head = ReactDOM.findDOMNode(this.refs.head); + +        const headHeight = head ? head.offsetHeight : 0; + +        const rowTop = (index * rowHeight) + headHeight; +        const rowBottom = rowTop + rowHeight; + +        const viewportTop = viewport.scrollTop; +        const viewportHeight = viewport.offsetHeight; + +        // Account for pinned thead +        if (rowTop - headHeight < viewportTop) { +            viewport.scrollTop = rowTop - headHeight; +        } else if (rowBottom > viewportTop + viewportHeight) { +            viewport.scrollTop = rowBottom - viewportHeight; +        } +    } + +    render() { +        const vScroll = this.state.vScroll; +        const highlight = this.context.view._highlight; +        const flows = this.state.flows.slice(vScroll.start, vScroll.end); + +        const transform = `translate(0,${this.state.viewportTop}px)`;          return ( -            <div className="flow-table" onScroll={this.onScrollFlowTable}> +            <div className="flow-table" onScroll={this.onViewportUpdate}>                  <table> -                    <FlowTableHead ref="head" -                        columns={this.state.columns} -                        setSortKeyFun={this.props.setSortKeyFun}/> -                    <tbody ref="body"> -                        { this.getPlaceholderTop(flows.length) } -                        {rows} -                        { this.getPlaceholderBottom(flows.length) } +                    <thead ref="head" style={{ transform }}> +                        <FlowTableHead +                            columns={flowtable_columns} +                            setSortKeyFun={this.props.setSortKeyFun} +                        /> +                    </thead> +                    <tbody> +                        <tr style={{ height: vScroll.paddingTop }}></tr> +                        {flows.map(flow => ( +                            <FlowRow +                                key={flow.id} +                                flow={flow} +                                columns={flowtable_columns} +                                selected={flow === this.props.selected} +                                highlighted={highlight && highlight[flow.id]} +                                selectFlow={this.props.selectFlow} +                            /> +                        ))} +                        <tr style={{ height: vScroll.paddingBottom }}></tr>                      </tbody>                  </table>              </div>          );      } -}); +} -export default FlowTable; +export default AutoScroll(FlowTable); diff --git a/web/src/js/components/helpers/AutoScroll.js b/web/src/js/components/helpers/AutoScroll.js new file mode 100644 index 00000000..d37b9f37 --- /dev/null +++ b/web/src/js/components/helpers/AutoScroll.js @@ -0,0 +1,25 @@ +import React from "react"; +import ReactDOM from "react-dom"; + +const symShouldStick = Symbol("shouldStick"); +const isAtBottom = v => v.scrollTop + v.clientHeight === v.scrollHeight; + +export default Component => Object.assign(class AutoScrollWrapper extends Component { + +    static displayName = Component.name; + +    componentWillUpdate() { +        const viewport = ReactDOM.findDOMNode(this); +        this[symShouldStick] = viewport.scrollTop && isAtBottom(viewport); +        super.componentWillUpdate && super.componentWillUpdate(); +    } + +    componentDidUpdate() { +        const viewport = ReactDOM.findDOMNode(this); +        if (this[symShouldStick] && !isAtBottom(viewport)) { +            viewport.scrollTop = viewport.scrollHeight; +        } +        super.componentDidUpdate && super.componentDidUpdate(); +    } + +}, Component); diff --git a/web/src/js/components/helpers/VirtualScroll.js b/web/src/js/components/helpers/VirtualScroll.js new file mode 100644 index 00000000..5d4cf796 --- /dev/null +++ b/web/src/js/components/helpers/VirtualScroll.js @@ -0,0 +1,70 @@ +/** + * Calculate virtual scroll stuffs + * + * @param {?Object} opts Options for calculation + * + * @returns {Object} result + * + * __opts__ should have following properties: + * - {number}         itemCount + * - {number}         rowHeight + * - {number}         viewportTop + * - {number}         viewportHeight + * - {Array<?number>} [itemHeights] + * + * __result__ have following properties: + * - {number} start + * - {number} end + * - {number} paddingTop + * - {number} paddingBottom + */ +export function calcVScroll(opts) { +    if (!opts) { +        return { start: 0, end: 0, paddingTop: 0, paddingBottom: 0 }; +    } + +    const { itemCount, rowHeight, viewportTop, viewportHeight, itemHeights } = opts; +    const viewportBottom = viewportTop + viewportHeight; + +    let start = 0; +    let end = 0; + +    let paddingTop = 0; +    let paddingBottom = 0; + +    if (itemHeights) { + +        for (let i = 0, pos = 0; i < itemCount; i++) { +            const height = itemHeights[i] || rowHeight; + +            if (pos <= viewportTop && i % 2 === 0) { +                paddingTop = pos; +                start = i; +            } + +            if (pos <= viewportBottom) { +                end = i + 1; +            } else { +                paddingBottom += height; +            } + +            pos += height; +        } + +    } else { + +        // Make sure that we start at an even row so that CSS `:nth-child(even)` is preserved +        start = Math.max(0, Math.floor(viewportTop / rowHeight) - 1) & ~1; +        end = Math.min( +            itemCount, +            start + Math.ceil(viewportHeight / rowHeight) + 1 +        ); + +        // When a large trunk of elements is removed from the button, start may be far off the viewport. +        // To make this issue less severe, limit the top placeholder to the total number of rows. +        paddingTop = Math.min(start, itemCount) * rowHeight; +        paddingBottom = Math.max(0, itemCount - end) * rowHeight; +    } + +    return { start, end, paddingTop, paddingBottom }; +} diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js index cc1f05ae..87c0c4bd 100644 --- a/web/src/js/components/mainview.js +++ b/web/src/js/components/mainview.js @@ -75,12 +75,12 @@ var MainView = React.createClass({          }      },      onUpdate: function (flow) { -        if (flow.id === this.getParams().flowId) { +        if (flow.id === this.props.routeParams.flowId) {              this.forceUpdate();          }      },      onRemove: function (flow_id, index) { -        if (flow_id === this.getParams().flowId) { +        if (flow_id === this.props.routeParams.flowId) {              var flow_to_select = this.state.view.list[Math.min(index, this.state.view.list.length - 1)];              this.selectFlow(flow_to_select);          } @@ -93,7 +93,7 @@ var MainView = React.createClass({      },      selectFlow: function (flow) {          if (flow) { -            var tab = this.getParams().detailTab || "request"; +            var tab = this.props.routeParams.detailTab || "request";              this.updateLocation(`/flows/${flow.id}/${tab}`);              this.refs.flowTable.scrollIntoView(flow);          } else { @@ -103,14 +103,14 @@ var MainView = React.createClass({      selectFlowRelative: function (shift) {          var flows = this.state.view.list;          var index; -        if (!this.getParams().flowId) { +        if (!this.props.routeParams.flowId) {              if (shift < 0) {                  index = flows.length - 1;              } else {                  index = 0;              }          } else { -            var currFlowId = this.getParams().flowId; +            var currFlowId = this.props.routeParams.flowId;              var i = flows.length;              while (i--) {                  if (flows[i].id === currFlowId) { @@ -212,7 +212,7 @@ var MainView = React.createClass({          e.preventDefault();      },      getSelected: function () { -        return this.context.flowStore.get(this.getParams().flowId); +        return this.context.flowStore.get(this.props.routeParams.flowId);      },      render: function () {          var selected = this.getSelected(); @@ -224,7 +224,7 @@ var MainView = React.createClass({                  <FlowView                      key="flowDetails"                      ref="flowDetails" -                    tab={this.getParams().detailTab} +                    tab={this.props.routeParams.detailTab}                      flow={selected}/>              ];          } else { diff --git a/web/src/js/components/virtualscroll.js b/web/src/js/components/virtualscroll.js deleted file mode 100644 index f462fdcc..00000000 --- a/web/src/js/components/virtualscroll.js +++ /dev/null @@ -1,84 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; - -export var VirtualScrollMixin = { -    getInitialState: function () { -        return { -            start: 0, -            stop: 0 -        }; -    }, -    componentWillMount: function () { -        if (!this.props.rowHeight) { -            console.warn("VirtualScrollMixin: No rowHeight specified", this); -        } -    }, -    getPlaceholderTop: function (total) { -        var Tag = this.props.placeholderTagName || "tr"; -        // When a large trunk of elements is removed from the button, start may be far off the viewport. -        // To make this issue less severe, limit the top placeholder to the total number of rows. -        var style = { -            height: Math.min(this.state.start, total) * this.props.rowHeight -        }; -        var spacer = <Tag key="placeholder-top" style={style}></Tag>; - -        if (this.state.start % 2 === 1) { -            // fix even/odd rows -            return [spacer, <Tag key="placeholder-top-2"></Tag>]; -        } else { -            return spacer; -        } -    }, -    getPlaceholderBottom: function (total) { -        var Tag = this.props.placeholderTagName || "tr"; -        var style = { -            height: Math.max(0, total - this.state.stop) * this.props.rowHeight -        }; -        return <Tag key="placeholder-bottom" style={style}></Tag>; -    }, -    componentDidMount: function () { -        this.onScroll(); -        window.addEventListener('resize', this.onScroll); -    }, -    componentWillUnmount: function(){ -        window.removeEventListener('resize', this.onScroll); -    }, -    onScroll: function () { -        var viewport = ReactDOM.findDOMNode(this); -        var top = viewport.scrollTop; -        var height = viewport.offsetHeight; -        var start = Math.floor(top / this.props.rowHeight); -        var stop = start + Math.ceil(height / (this.props.rowHeightMin || this.props.rowHeight)); - -        this.setState({ -            start: start, -            stop: stop -        }); -    }, -    renderRows: function (elems) { -        var rows = []; -        var max = Math.min(elems.length, this.state.stop); - -        for (var i = this.state.start; i < max; i++) { -            var elem = elems[i]; -            rows.push(this.renderRow(elem)); -        } -        return rows; -    }, -    scrollRowIntoView: function (index, head_height) { - -        var row_top = (index * this.props.rowHeight) + head_height; -        var row_bottom = row_top + this.props.rowHeight; - -        var viewport = ReactDOM.findDOMNode(this); -        var viewport_top = viewport.scrollTop; -        var viewport_bottom = viewport_top + viewport.offsetHeight; - -        // Account for pinned thead -        if (row_top - head_height < viewport_top) { -            viewport.scrollTop = row_top - head_height; -        } else if (row_bottom > viewport_bottom) { -            viewport.scrollTop = row_bottom - viewport.offsetHeight; -        } -    }, -}; | 
