From ac2d8549e5cf6efaac78de8acc0c4967e63adcf9 Mon Sep 17 00:00:00 2001 From: Clemens Date: Mon, 6 Jun 2016 23:27:04 +0200 Subject: [PATCH 1/6] moved sort state to redux, missing apply sort --- mitmproxy/web/static/app.js | 160 +-- mitmproxy/web/static/vendor.js | 1573 ++++++++++++++++------------ web/src/js/components/flowtable.js | 83 +- web/src/js/components/mainview.js | 7 +- web/src/js/ducks/flows.js | 13 + 5 files changed, 1051 insertions(+), 785 deletions(-) diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js index b37365829..b46e24322 100644 --- a/mitmproxy/web/static/app.js +++ b/mitmproxy/web/static/app.js @@ -1530,88 +1530,77 @@ var FlowRowContainer = (0, _reactRedux.connect)(function (state, ownProps) { }; })(FlowRow); -var FlowTableHead = function (_React$Component) { - _inherits(FlowTableHead, _React$Component); +function FlowTableHead(_ref2) { + var setSort = _ref2.setSort; + var columns = _ref2.columns; + var sort = _ref2.sort; - function FlowTableHead(props, context) { - _classCallCheck(this, FlowTableHead); - var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(FlowTableHead).call(this, props, context)); + //const hasSort = Column.sortKeyFun; - _this.state = { sortColumn: undefined, sortDesc: false }; - return _this; - } + // let sortDesc = this.props.sort.sortDesc; + // + // if (Column === this.props.sort.sortColumn) { + // sortDesc = !sortDesc; + // this.props.setSort(sortColumn, sortDesc); + // } else { + // this.props.setSort({sortColumn: hasSort && Column, sortDesc: false}); + // } + // + // 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); - _createClass(FlowTableHead, [{ - key: "onClick", - value: function onClick(Column) { - var hasSort = Column.sortKeyFun; + var sortColumn = sort.sortColumn; + var sortType = sort.sortDesc ? "sort-desc" : "sort-asc"; - 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); - } - }, { - 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, - this.props.columns.map(function (Column) { - return _react2.default.createElement(Column.Title, { - key: Column.name, - onClick: function onClick() { - return _this2.onClick(Column); - }, - className: sortColumn === Column ? sortType : undefined - }); - }) - ); - } - }]); - - return FlowTableHead; -}(_react2.default.Component); + return _react2.default.createElement( + "tr", + null, + columns.map(function (Column) { + return _react2.default.createElement(Column.Title, { + key: Column.name, + onClick: function onClick() { + return setSort({ sortColumn: Column.name, sortDesc: Column.name != sort.sortColumn ? false : !sort.sortDesc }); + }, + className: sortColumn === Column.name ? sortType : undefined + }); + }) + ); +} FlowTableHead.propTypes = { - setSortKeyFun: _react2.default.PropTypes.func.isRequired, + setSort: _react2.default.PropTypes.func.isRequired, + sort: _react2.default.PropTypes.object.isRequired, columns: _react2.default.PropTypes.array.isRequired }; -var FlowTable = function (_React$Component2) { - _inherits(FlowTable, _React$Component2); +var FlowTableHeadContainer = (0, _reactRedux.connect)(function (state, ownProps) { + return { + sort: state.flows.sort + }; +})(FlowTableHead); + +var FlowTable = function (_React$Component) { + _inherits(FlowTable, _React$Component); function FlowTable(props, context) { _classCallCheck(this, FlowTable); - var _this3 = _possibleConstructorReturn(this, Object.getPrototypeOf(FlowTable).call(this, props, context)); + var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(FlowTable).call(this, props, context)); - _this3.state = { vScroll: (0, _VirtualScroll.calcVScroll)() }; + _this.state = { vScroll: (0, _VirtualScroll.calcVScroll)() }; - _this3.onViewportUpdate = _this3.onViewportUpdate.bind(_this3); - return _this3; + _this.onViewportUpdate = _this.onViewportUpdate.bind(_this); + return _this; } _createClass(FlowTable, [{ @@ -1627,11 +1616,11 @@ var FlowTable = function (_React$Component2) { }, { key: "componentWillReceiveProps", value: function componentWillReceiveProps(nextProps) { - var _this4 = this; + var _this2 = this; if (nextProps.selected && nextProps.selected !== this.props.selected) { window.setTimeout(function () { - return _this4.scrollIntoView(nextProps.selected); + return _this2.scrollIntoView(nextProps.selected); }, 1); } } @@ -1683,7 +1672,7 @@ var FlowTable = function (_React$Component2) { }, { key: "render", value: function render() { - var _this5 = this; + var _this3 = this; var vScroll = this.state.vScroll; var flows = this.props.flows.slice(vScroll.start, vScroll.end); @@ -1699,9 +1688,10 @@ var FlowTable = function (_React$Component2) { _react2.default.createElement( "thead", { ref: "head", style: { transform: transform } }, - _react2.default.createElement(FlowTableHead, { + _react2.default.createElement(FlowTableHeadContainer, { columns: _flowtableColumns2.default, - setSortKeyFun: this.props.setSortKeyFun + setSortKeyFun: this.props.setSortKeyFun, + setSort: this.props.setSort }) ), _react2.default.createElement( @@ -1713,7 +1703,7 @@ var FlowTable = function (_React$Component2) { key: flow.id, flowId: flow.id, columns: _flowtableColumns2.default, - selectFlow: _this5.props.selectFlow + selectFlow: _this3.props.selectFlow }); }), _react2.default.createElement("tr", { style: { height: vScroll.paddingBottom } }) @@ -3944,7 +3934,10 @@ var MainView = _react2.default.createClass({ { className: "main-view" }, _react2.default.createElement(_flowtable2.default, { ref: "flowTable", selectFlow: this.selectFlow, - setSortKeyFun: this.setSortKeyFun, + setSortKeyFun: function setSortKeyFun(f) { + return console.log("asdf"); + }, + setSort: this.props.setSort, selected: this.props.selectedFlow }), details ); @@ -3955,6 +3948,7 @@ var MainViewContainer = (0, _reactRedux.connect)(function (state) { return { flows: state.flows.view, filter: state.flows.filter, + sort: state.flows.sort, highlight: state.flows.highlight, selectedFlow: state.flows.all.byId[state.flows.selected[0]] }; @@ -3966,6 +3960,9 @@ var MainViewContainer = (0, _reactRedux.connect)(function (state) { setFilter: function setFilter(filter) { return dispatch((0, _flows.setFilter)(filter)); }, + setSort: function setSort(sort) { + return dispatch((0, _flows.setSort)(sort)); + }, setHighlight: function setHighlight(highlight) { return dispatch((0, _flows.setHighlight)(highlight)); } @@ -4496,13 +4493,14 @@ exports.fetchLogEntries = fetchList; Object.defineProperty(exports, "__esModule", { value: true }); -exports.fetchFlows = exports.updateFlows = exports.SELECT_FLOW = exports.SET_HIGHLIGHT = exports.SET_FILTER = exports.UPDATE_FLOWS = undefined; +exports.fetchFlows = exports.updateFlows = exports.SELECT_FLOW = exports.SET_SORT = exports.SET_HIGHLIGHT = exports.SET_FILTER = exports.UPDATE_FLOWS = undefined; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; exports.default = reducer; exports.setFilter = setFilter; exports.setHighlight = setHighlight; +exports.setSort = setSort; exports.selectFlow = selectFlow; var _list = require("./utils/list"); @@ -4520,6 +4518,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de var UPDATE_FLOWS = exports.UPDATE_FLOWS = "UPDATE_FLOWS"; var SET_FILTER = exports.SET_FILTER = "SET_FLOW_FILTER"; var SET_HIGHLIGHT = exports.SET_HIGHLIGHT = "SET_FLOW_HIGHLIGHT"; +var SET_SORT = exports.SET_SORT = "SET_FLOW_SORT"; var SELECT_FLOW = exports.SELECT_FLOW = "SELECT_FLOW"; var _makeList = (0, _list2.default)(UPDATE_FLOWS, "/flows"); @@ -4534,7 +4533,8 @@ var defaultState = { selected: [], view: [], filter: undefined, - highlight: undefined + highlight: undefined, + sort: { sortColumn: undefined, sortDesc: false } }; function makeFilterFn(filter) { @@ -4563,6 +4563,10 @@ function reducer() { return _extends({}, state, { highlight: action.highlight }); + case SET_SORT: + return _extends({}, state, { + sort: action.sort + }); case SELECT_FLOW: return _extends({}, state, { selected: [action.flowId] @@ -4584,6 +4588,12 @@ function setHighlight(highlight) { highlight: highlight }; } +function setSort(sort) { + return { + type: SET_SORT, + sort: sort + }; +} function selectFlow(flowId) { return { type: SELECT_FLOW, diff --git a/mitmproxy/web/static/vendor.js b/mitmproxy/web/static/vendor.js index b2e490436..caf49f63f 100644 --- a/mitmproxy/web/static/vendor.js +++ b/mitmproxy/web/static/vendor.js @@ -764,7 +764,11 @@ function createBrowserHistory() { var useRefresh = !isSupported || forceRefresh; function getCurrentLocation(historyState) { - historyState = historyState || window.history.state || {}; + try { + historyState = historyState || window.history.state || {}; + } catch (e) { + historyState = {}; + } var path = _DOMUtils.getWindowPath(); var _historyState = historyState; @@ -2116,13 +2120,15 @@ var KNOWN_STATICS = { }; module.exports = function hoistNonReactStatics(targetComponent, sourceComponent) { - var keys = Object.getOwnPropertyNames(sourceComponent); - for (var i=0; i - * Build: `lodash -d -o ./foo/lodash.js` + * lodash * Copyright jQuery Foundation and other contributors * Released under MIT license * Based on Underscore.js 1.8.3 @@ -37205,7 +37190,7 @@ return jQuery; var undefined; /** Used as the semantic version number. */ - var VERSION = '4.11.2'; + var VERSION = '4.13.1'; /** Used as the size to enable large array optimizations. */ var LARGE_ARRAY_SIZE = 200; @@ -37309,7 +37294,7 @@ return jQuery; /** Used to match property names within property paths. */ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]/g; + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(\.|\[\])(?:\4|$))/g; /** * Used to match `RegExp` @@ -37442,7 +37427,7 @@ return jQuery; 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', 'Promise', 'Reflect', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', - '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' + '_', 'isFinite', 'parseInt', 'setTimeout' ]; /** Used to make template sourceURLs easier to identify. */ @@ -37521,12 +37506,6 @@ return jQuery; '`': '`' }; - /** Used to determine if values are of the language type `Object`. */ - var objectTypes = { - 'function': true, - 'object': true - }; - /** Used to escape characters for inclusion in compiled string literals. */ var stringEscapes = { '\\': '\\', @@ -37542,41 +37521,25 @@ return jQuery; freeParseInt = parseInt; /** Detect free variable `exports`. */ - var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType) - ? exports - : undefined; + var freeExports = typeof exports == 'object' && exports; /** Detect free variable `module`. */ - var freeModule = (objectTypes[typeof module] && module && !module.nodeType) - ? module - : undefined; + var freeModule = freeExports && typeof module == 'object' && module; /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = (freeModule && freeModule.exports === freeExports) - ? freeExports - : undefined; + var moduleExports = freeModule && freeModule.exports === freeExports; /** Detect free variable `global` from Node.js. */ - var freeGlobal = checkGlobal(freeExports && freeModule && typeof global == 'object' && global); + var freeGlobal = checkGlobal(typeof global == 'object' && global); /** Detect free variable `self`. */ - var freeSelf = checkGlobal(objectTypes[typeof self] && self); - - /** Detect free variable `window`. */ - var freeWindow = checkGlobal(objectTypes[typeof window] && window); + var freeSelf = checkGlobal(typeof self == 'object' && self); /** Detect `this` as the global object. */ - var thisGlobal = checkGlobal(objectTypes[typeof this] && this); + var thisGlobal = checkGlobal(typeof this == 'object' && this); - /** - * Used as a reference to the global object. - * - * The `this` value is used if it's the global object to avoid Greasemonkey's - * restricted `window` object, otherwise the `window` object is used. - */ - var root = freeGlobal || - ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) || - freeSelf || thisGlobal || Function('return this')(); + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || thisGlobal || Function('return this')(); /*--------------------------------------------------------------------------*/ @@ -37632,7 +37595,7 @@ return jQuery; * A specialized version of `baseAggregator` for arrays. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} setter The function to set `accumulator` values. * @param {Function} iteratee The iteratee to transform keys. * @param {Object} accumulator The initial aggregated object. @@ -37640,7 +37603,7 @@ return jQuery; */ function arrayAggregator(array, setter, iteratee, accumulator) { var index = -1, - length = array.length; + length = array ? array.length : 0; while (++index < length) { var value = array[index]; @@ -37649,42 +37612,18 @@ return jQuery; return accumulator; } - /** - * Creates a new array concatenating `array` with `other`. - * - * @private - * @param {Array} array The first array to concatenate. - * @param {Array} other The second array to concatenate. - * @returns {Array} Returns the new concatenated array. - */ - function arrayConcat(array, other) { - var index = -1, - length = array.length, - othIndex = -1, - othLength = other.length, - result = Array(length + othLength); - - while (++index < length) { - result[index] = array[index]; - } - while (++othIndex < othLength) { - result[index++] = other[othIndex]; - } - return result; - } - /** * A specialized version of `_.forEach` for arrays without support for * iteratee shorthands. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns `array`. */ function arrayEach(array, iteratee) { var index = -1, - length = array.length; + length = array ? array.length : 0; while (++index < length) { if (iteratee(array[index], index, array) === false) { @@ -37699,12 +37638,12 @@ return jQuery; * iteratee shorthands. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns `array`. */ function arrayEachRight(array, iteratee) { - var length = array.length; + var length = array ? array.length : 0; while (length--) { if (iteratee(array[length], length, array) === false) { @@ -37719,14 +37658,14 @@ return jQuery; * iteratee shorthands. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if all elements pass the predicate check, * else `false`. */ function arrayEvery(array, predicate) { var index = -1, - length = array.length; + length = array ? array.length : 0; while (++index < length) { if (!predicate(array[index], index, array)) { @@ -37741,13 +37680,13 @@ return jQuery; * iteratee shorthands. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {Array} Returns the new filtered array. */ function arrayFilter(array, predicate) { var index = -1, - length = array.length, + length = array ? array.length : 0, resIndex = 0, result = []; @@ -37765,26 +37704,27 @@ return jQuery; * specifying an index to search from. * * @private - * @param {Array} array The array to search. + * @param {Array} [array] The array to search. * @param {*} target The value to search for. * @returns {boolean} Returns `true` if `target` is found, else `false`. */ function arrayIncludes(array, value) { - return !!array.length && baseIndexOf(array, value, 0) > -1; + var length = array ? array.length : 0; + return !!length && baseIndexOf(array, value, 0) > -1; } /** * This function is like `arrayIncludes` except that it accepts a comparator. * * @private - * @param {Array} array The array to search. + * @param {Array} [array] The array to search. * @param {*} target The value to search for. * @param {Function} comparator The comparator invoked per element. * @returns {boolean} Returns `true` if `target` is found, else `false`. */ function arrayIncludesWith(array, value, comparator) { var index = -1, - length = array.length; + length = array ? array.length : 0; while (++index < length) { if (comparator(value, array[index])) { @@ -37799,13 +37739,13 @@ return jQuery; * shorthands. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the new mapped array. */ function arrayMap(array, iteratee) { var index = -1, - length = array.length, + length = array ? array.length : 0, result = Array(length); while (++index < length) { @@ -37838,7 +37778,7 @@ return jQuery; * iteratee shorthands. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @param {boolean} [initAccum] Specify using the first element of `array` as @@ -37847,7 +37787,7 @@ return jQuery; */ function arrayReduce(array, iteratee, accumulator, initAccum) { var index = -1, - length = array.length; + length = array ? array.length : 0; if (initAccum && length) { accumulator = array[++index]; @@ -37863,7 +37803,7 @@ return jQuery; * iteratee shorthands. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {*} [accumulator] The initial value. * @param {boolean} [initAccum] Specify using the last element of `array` as @@ -37871,7 +37811,7 @@ return jQuery; * @returns {*} Returns the accumulated value. */ function arrayReduceRight(array, iteratee, accumulator, initAccum) { - var length = array.length; + var length = array ? array.length : 0; if (initAccum && length) { accumulator = array[--length]; } @@ -37886,14 +37826,14 @@ return jQuery; * shorthands. * * @private - * @param {Array} array The array to iterate over. + * @param {Array} [array] The array to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if any element passes the predicate check, * else `false`. */ function arraySome(array, predicate) { var index = -1, - length = array.length; + length = array ? array.length : 0; while (++index < length) { if (predicate(array[index], index, array)) { @@ -37904,23 +37844,21 @@ return jQuery; } /** - * The base implementation of methods like `_.find` and `_.findKey`, without - * support for iteratee shorthands, which iterates over `collection` using - * `eachFunc`. + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. * * @private * @param {Array|Object} collection The collection to search. * @param {Function} predicate The function invoked per iteration. * @param {Function} eachFunc The function to iterate over `collection`. - * @param {boolean} [retKey] Specify returning the key of the found element - * instead of the element itself. * @returns {*} Returns the found element or its key, else `undefined`. */ - function baseFind(collection, predicate, eachFunc, retKey) { + function baseFindKey(collection, predicate, eachFunc) { var result; eachFunc(collection, function(value, key, collection) { if (predicate(value, key, collection)) { - result = retKey ? key : value; + result = key; return false; } }); @@ -37934,12 +37872,13 @@ return jQuery; * @private * @param {Array} array The array to search. * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {number} Returns the index of the matched value, else `-1`. */ - function baseFindIndex(array, predicate, fromRight) { + function baseFindIndex(array, predicate, fromIndex, fromRight) { var length = array.length, - index = fromRight ? length : -1; + index = fromIndex + (fromRight ? 1 : -1); while ((fromRight ? index-- : ++index < length)) { if (predicate(array[index], index, array)) { @@ -38100,7 +38039,7 @@ return jQuery; * @private * @param {Object} object The object to query. * @param {Array} props The property names to get values for. - * @returns {Object} Returns the new array of key-value pairs. + * @returns {Object} Returns the key-value pairs. */ function baseToPairs(object, props) { return arrayMap(props, function(key) { @@ -38113,7 +38052,7 @@ return jQuery; * * @private * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new capped function. */ function baseUnary(func) { return function(value) { @@ -38137,6 +38076,18 @@ return jQuery; }); } + /** + * Checks if a cache value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function cacheHas(cache, key) { + return cache.has(key); + } + /** * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol * that is not found in the character symbols. @@ -38234,6 +38185,18 @@ return jQuery; return '\\' + stringEscapes[chr]; } + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue(object, key) { + return object == null ? undefined : object[key]; + } + /** * Gets the index at which the first occurrence of `NaN` is found in `array`. * @@ -38245,7 +38208,7 @@ return jQuery; */ function indexOfNaN(array, fromIndex, fromRight) { var length = array.length, - index = fromIndex + (fromRight ? 0 : -1); + index = fromIndex + (fromRight ? 1 : -1); while ((fromRight ? index-- : ++index < length)) { var other = array[index]; @@ -38293,11 +38256,11 @@ return jQuery; } /** - * Converts `map` to an array. + * Converts `map` to its key-value pairs. * * @private * @param {Object} map The map to convert. - * @returns {Array} Returns the converted array. + * @returns {Array} Returns the key-value pairs. */ function mapToArray(map) { var index = -1, @@ -38335,11 +38298,11 @@ return jQuery; } /** - * Converts `set` to an array. + * Converts `set` to an array of its values. * * @private * @param {Object} set The set to convert. - * @returns {Array} Returns the converted array. + * @returns {Array} Returns the values. */ function setToArray(set) { var index = -1, @@ -38351,6 +38314,23 @@ return jQuery; return result; } + /** + * Converts `set` to its value-value pairs. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the value-value pairs. + */ + function setToPairs(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = [value, value]; + }); + return result; + } + /** * Gets the number of symbols in `string`. * @@ -38419,10 +38399,10 @@ return jQuery; * lodash.isFunction(lodash.bar); * // => true * - * // Use `context` to mock `Date#getTime` use in `_.now`. - * var mock = _.runInContext({ + * // Use `context` to stub `Date#getTime` use in `_.now`. + * var stubbed = _.runInContext({ * 'Date': function() { - * return { 'getTime': getTimeMock }; + * return { 'getTime': stubGetTime }; * } * }); * @@ -38444,6 +38424,15 @@ return jQuery; objectProto = context.Object.prototype, stringProto = context.String.prototype; + /** Used to detect overreaching core-js shims. */ + var coreJsData = context['__core-js_shared__']; + + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); + /** Used to resolve the decompiled source of functions. */ var funcToString = context.Function.prototype.toString; @@ -38477,15 +38466,16 @@ return jQuery; Reflect = context.Reflect, Symbol = context.Symbol, Uint8Array = context.Uint8Array, - clearTimeout = context.clearTimeout, enumerate = Reflect ? Reflect.enumerate : undefined, getOwnPropertySymbols = Object.getOwnPropertySymbols, iteratorSymbol = typeof (iteratorSymbol = Symbol && Symbol.iterator) == 'symbol' ? iteratorSymbol : undefined, objectCreate = Object.create, propertyIsEnumerable = objectProto.propertyIsEnumerable, - setTimeout = context.setTimeout, splice = arrayProto.splice; + /** Built-in method references that are mockable. */ + var setTimeout = function(func, wait) { return context.setTimeout.call(root, func, wait); }; + /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeCeil = Math.ceil, nativeFloor = Math.floor, @@ -38604,22 +38594,24 @@ return jQuery; * `floor`, `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, * `forOwnRight`, `get`, `gt`, `gte`, `has`, `hasIn`, `head`, `identity`, * `includes`, `indexOf`, `inRange`, `invoke`, `isArguments`, `isArray`, - * `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, `isBoolean`, `isBuffer`, - * `isDate`, `isElement`, `isEmpty`, `isEqual`, `isEqualWith`, `isError`, - * `isFinite`, `isFunction`, `isInteger`, `isLength`, `isMap`, `isMatch`, - * `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, `isNumber`, - * `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, `isSafeInteger`, - * `isSet`, `isString`, `isUndefined`, `isTypedArray`, `isWeakMap`, `isWeakSet`, - * `join`, `kebabCase`, `last`, `lastIndexOf`, `lowerCase`, `lowerFirst`, - * `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, `min`, `minBy`, `multiply`, - * `noConflict`, `noop`, `now`, `nth`, `pad`, `padEnd`, `padStart`, `parseInt`, - * `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, `round`, - * `runInContext`, `sample`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, - * `sortedIndexBy`, `sortedLastIndex`, `sortedLastIndexBy`, `startCase`, - * `startsWith`, `subtract`, `sum`, `sumBy`, `template`, `times`, `toInteger`, - * `toJSON`, `toLength`, `toLower`, `toNumber`, `toSafeInteger`, `toString`, - * `toUpper`, `trim`, `trimEnd`, `trimStart`, `truncate`, `unescape`, - * `uniqueId`, `upperCase`, `upperFirst`, `value`, and `words` + * `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, `isBoolean`, + * `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isEqualWith`, + * `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, `isMap`, + * `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, + * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, + * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, + * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, + * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, + * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, + * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, + * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, + * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, + * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, + * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, + * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, + * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, + * `upperFirst`, `value`, and `words` * * @name _ * @constructor @@ -38878,64 +38870,212 @@ return jQuery; * * @private * @constructor - * @returns {Object} Returns the new hash object. + * @param {Array} [entries] The key-value pairs to cache. */ - function Hash() {} + function Hash(entries) { + var index = -1, + length = entries ? entries.length : 0; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + } /** * Removes `key` and its value from the hash. * * @private + * @name delete + * @memberOf Hash * @param {Object} hash The hash to modify. * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ - function hashDelete(hash, key) { - return hashHas(hash, key) && delete hash[key]; + function hashDelete(key) { + return this.has(key) && delete this.__data__[key]; } /** * Gets the hash value for `key`. * * @private - * @param {Object} hash The hash to query. + * @name get + * @memberOf Hash * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ - function hashGet(hash, key) { + function hashGet(key) { + var data = this.__data__; if (nativeCreate) { - var result = hash[key]; + var result = data[key]; return result === HASH_UNDEFINED ? undefined : result; } - return hasOwnProperty.call(hash, key) ? hash[key] : undefined; + return hasOwnProperty.call(data, key) ? data[key] : undefined; } /** * Checks if a hash value for `key` exists. * * @private - * @param {Object} hash The hash to query. + * @name has + * @memberOf Hash * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ - function hashHas(hash, key) { - return nativeCreate ? hash[key] !== undefined : hasOwnProperty.call(hash, key); + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); } /** * Sets the hash `key` to `value`. * * @private - * @param {Object} hash The hash to modify. + * @name set + * @memberOf Hash * @param {string} key The key of the value to set. * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. */ - function hashSet(hash, key, value) { - hash[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + function hashSet(key, value) { + var data = this.__data__; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; } - // Avoid inheriting from `Object.prototype` when possible. - Hash.prototype = nativeCreate ? nativeCreate(null) : objectProto; + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries ? entries.length : 0; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + } + + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + return true; + } + + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; + } + + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } + + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; /*------------------------------------------------------------------------*/ @@ -38944,15 +39084,15 @@ return jQuery; * * @private * @constructor - * @param {Array} [values] The values to cache. + * @param {Array} [entries] The key-value pairs to cache. */ - function MapCache(values) { + function MapCache(entries) { var index = -1, - length = values ? values.length : 0; + length = entries ? entries.length : 0; this.clear(); while (++index < length) { - var entry = values[index]; + var entry = entries[index]; this.set(entry[0], entry[1]); } } @@ -38964,10 +39104,10 @@ return jQuery; * @name clear * @memberOf MapCache */ - function mapClear() { + function mapCacheClear() { this.__data__ = { 'hash': new Hash, - 'map': Map ? new Map : [], + 'map': new (Map || ListCache), 'string': new Hash }; } @@ -38981,12 +39121,8 @@ return jQuery; * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ - function mapDelete(key) { - var data = this.__data__; - if (isKeyable(key)) { - return hashDelete(typeof key == 'string' ? data.string : data.hash, key); - } - return Map ? data.map['delete'](key) : assocDelete(data.map, key); + function mapCacheDelete(key) { + return getMapData(this, key)['delete'](key); } /** @@ -38998,12 +39134,8 @@ return jQuery; * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ - function mapGet(key) { - var data = this.__data__; - if (isKeyable(key)) { - return hashGet(typeof key == 'string' ? data.string : data.hash, key); - } - return Map ? data.map.get(key) : assocGet(data.map, key); + function mapCacheGet(key) { + return getMapData(this, key).get(key); } /** @@ -39015,12 +39147,8 @@ return jQuery; * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ - function mapHas(key) { - var data = this.__data__; - if (isKeyable(key)) { - return hashHas(typeof key == 'string' ? data.string : data.hash, key); - } - return Map ? data.map.has(key) : assocHas(data.map, key); + function mapCacheHas(key) { + return getMapData(this, key).has(key); } /** @@ -39033,30 +39161,23 @@ return jQuery; * @param {*} value The value to set. * @returns {Object} Returns the map cache instance. */ - function mapSet(key, value) { - var data = this.__data__; - if (isKeyable(key)) { - hashSet(typeof key == 'string' ? data.string : data.hash, key, value); - } else if (Map) { - data.map.set(key, value); - } else { - assocSet(data.map, key, value); - } + function mapCacheSet(key, value) { + getMapData(this, key).set(key, value); return this; } // Add methods to `MapCache`. - MapCache.prototype.clear = mapClear; - MapCache.prototype['delete'] = mapDelete; - MapCache.prototype.get = mapGet; - MapCache.prototype.has = mapHas; - MapCache.prototype.set = mapSet; + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; /*------------------------------------------------------------------------*/ /** * - * Creates a set cache object to store unique values. + * Creates an array cache object to store unique values. * * @private * @constructor @@ -39068,52 +39189,41 @@ return jQuery; this.__data__ = new MapCache; while (++index < length) { - this.push(values[index]); + this.add(values[index]); } } /** - * Checks if `value` is in `cache`. + * Adds `value` to the array cache. * * @private - * @param {Object} cache The set cache to search. + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; + } + + /** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache * @param {*} value The value to search for. * @returns {number} Returns `true` if `value` is found, else `false`. */ - function cacheHas(cache, value) { - var map = cache.__data__; - if (isKeyable(value)) { - var data = map.__data__, - hash = typeof value == 'string' ? data.string : data.hash; - - return hash[value] === HASH_UNDEFINED; - } - return map.has(value); - } - - /** - * Adds `value` to the set cache. - * - * @private - * @name push - * @memberOf SetCache - * @param {*} value The value to cache. - */ - function cachePush(value) { - var map = this.__data__; - if (isKeyable(value)) { - var data = map.__data__, - hash = typeof value == 'string' ? data.string : data.hash; - - hash[value] = HASH_UNDEFINED; - } - else { - map.set(value, HASH_UNDEFINED); - } + function setCacheHas(value) { + return this.__data__.has(value); } // Add methods to `SetCache`. - SetCache.prototype.push = cachePush; + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; /*------------------------------------------------------------------------*/ @@ -39122,17 +39232,10 @@ return jQuery; * * @private * @constructor - * @param {Array} [values] The values to cache. + * @param {Array} [entries] The key-value pairs to cache. */ - function Stack(values) { - var index = -1, - length = values ? values.length : 0; - - this.clear(); - while (++index < length) { - var entry = values[index]; - this.set(entry[0], entry[1]); - } + function Stack(entries) { + this.__data__ = new ListCache(entries); } /** @@ -39143,7 +39246,7 @@ return jQuery; * @memberOf Stack */ function stackClear() { - this.__data__ = { 'array': [], 'map': null }; + this.__data__ = new ListCache; } /** @@ -39156,10 +39259,7 @@ return jQuery; * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ function stackDelete(key) { - var data = this.__data__, - array = data.array; - - return array ? assocDelete(array, key) : data.map['delete'](key); + return this.__data__['delete'](key); } /** @@ -39172,10 +39272,7 @@ return jQuery; * @returns {*} Returns the entry value. */ function stackGet(key) { - var data = this.__data__, - array = data.array; - - return array ? assocGet(array, key) : data.map.get(key); + return this.__data__.get(key); } /** @@ -39188,10 +39285,7 @@ return jQuery; * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ function stackHas(key) { - var data = this.__data__, - array = data.array; - - return array ? assocHas(array, key) : data.map.has(key); + return this.__data__.has(key); } /** @@ -39205,21 +39299,11 @@ return jQuery; * @returns {Object} Returns the stack cache instance. */ function stackSet(key, value) { - var data = this.__data__, - array = data.array; - - if (array) { - if (array.length < (LARGE_ARRAY_SIZE - 1)) { - assocSet(array, key, value); - } else { - data.array = null; - data.map = new MapCache(array); - } - } - var map = data.map; - if (map) { - map.set(key, value); + var cache = this.__data__; + if (cache instanceof ListCache && cache.__data__.length == LARGE_ARRAY_SIZE) { + cache = this.__data__ = new MapCache(cache.__data__); } + cache.set(key, value); return this; } @@ -39232,90 +39316,6 @@ return jQuery; /*------------------------------------------------------------------------*/ - /** - * Removes `key` and its value from the associative array. - * - * @private - * @param {Array} array The array to modify. - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function assocDelete(array, key) { - var index = assocIndexOf(array, key); - if (index < 0) { - return false; - } - var lastIndex = array.length - 1; - if (index == lastIndex) { - array.pop(); - } else { - splice.call(array, index, 1); - } - return true; - } - - /** - * Gets the associative array value for `key`. - * - * @private - * @param {Array} array The array to query. - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function assocGet(array, key) { - var index = assocIndexOf(array, key); - return index < 0 ? undefined : array[index][1]; - } - - /** - * Checks if an associative array value for `key` exists. - * - * @private - * @param {Array} array The array to query. - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function assocHas(array, key) { - return assocIndexOf(array, key) > -1; - } - - /** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to search. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; - } - } - return -1; - } - - /** - * Sets the associative array `key` to `value`. - * - * @private - * @param {Array} array The array to modify. - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - */ - function assocSet(array, key, value) { - var index = assocIndexOf(array, key); - if (index < 0) { - array.push([key, value]); - } else { - array[index][1] = value; - } - } - - /*------------------------------------------------------------------------*/ - /** * Used by `_.defaults` to customize its `_.assignIn` use. * @@ -39368,6 +39368,24 @@ return jQuery; } } + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to search. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; + } + /** * Aggregates elements of `collection` on `accumulator` with keys transformed * by `iteratee` and values set by `setter`. @@ -39405,7 +39423,7 @@ return jQuery; * @private * @param {Object} object The object to iterate over. * @param {string[]} paths The property paths of elements to pick. - * @returns {Array} Returns the new array of picked elements. + * @returns {Array} Returns the picked elements. */ function baseAt(object, paths) { var index = -1, @@ -39520,7 +39538,7 @@ return jQuery; * * @private * @param {Object} source The object of property predicates to conform to. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new spec function. */ function baseConforms(source) { var props = keys(source), @@ -39833,7 +39851,7 @@ return jQuery; * @private * @param {Object} object The object to inspect. * @param {Array} props The property names to filter. - * @returns {Array} Returns the new array of filtered property names. + * @returns {Array} Returns the function names. */ function baseFunctions(object, props) { return arrayFilter(props, function(key) { @@ -39874,9 +39892,7 @@ return jQuery; */ function baseGetAllKeys(object, keysFunc, symbolsFunc) { var result = keysFunc(object); - return isArray(object) - ? result - : arrayPush(result, symbolsFunc(object)); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); } /** @@ -39896,7 +39912,7 @@ return jQuery; * The base implementation of `_.has` without support for deep paths. * * @private - * @param {Object} object The object to query. + * @param {Object} [object] The object to query. * @param {Array|string} key The key to check. * @returns {boolean} Returns `true` if `key` exists, else `false`. */ @@ -39904,20 +39920,21 @@ return jQuery; // Avoid a bug in IE 10-11 where objects with a [[Prototype]] of `null`, // that are composed entirely of index properties, return `false` for // `hasOwnProperty` checks of them. - return hasOwnProperty.call(object, key) || - (typeof object == 'object' && key in object && getPrototype(object) === null); + return object != null && + (hasOwnProperty.call(object, key) || + (typeof object == 'object' && key in object && getPrototype(object) === null)); } /** * The base implementation of `_.hasIn` without support for deep paths. * * @private - * @param {Object} object The object to query. + * @param {Object} [object] The object to query. * @param {Array|string} key The key to check. * @returns {boolean} Returns `true` if `key` exists, else `false`. */ function baseHasIn(object, key) { - return key in Object(object); + return object != null && key in Object(object); } /** @@ -40171,6 +40188,22 @@ return jQuery; return true; } + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); + } + /** * The base implementation of `_.iteratee`. * @@ -40268,7 +40301,7 @@ return jQuery; * * @private * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new spec function. */ function baseMatches(source) { var matchData = getMatchData(source); @@ -40286,7 +40319,7 @@ return jQuery; * @private * @param {string} path The path of the property to get. * @param {*} srcValue The value to match. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new spec function. */ function baseMatchesProperty(path, srcValue) { if (isKey(path) && isStrictComparable(srcValue)) { @@ -40501,7 +40534,7 @@ return jQuery; * * @private * @param {string} key The key of the property to get. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new accessor function. */ function baseProperty(key) { return function(object) { @@ -40514,7 +40547,7 @@ return jQuery; * * @private * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new accessor function. */ function basePropertyDeep(path) { return function(object) { @@ -40539,6 +40572,9 @@ return jQuery; length = values.length, seen = array; + if (array === values) { + values = copyArray(values); + } if (iteratee) { seen = arrayMap(array, baseUnary(iteratee)); } @@ -40615,7 +40651,7 @@ return jQuery; * @param {number} end The end of the range. * @param {number} step The value to increment or decrement by. * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the new array of numbers. + * @returns {Array} Returns the range of numbers. */ function baseRange(start, end, step, fromRight) { var index = -1, @@ -41329,7 +41365,7 @@ return jQuery; * placeholders, and provided arguments into a single array of arguments. * * @private - * @param {Array|Object} args The provided arguments. + * @param {Array} args The provided arguments. * @param {Array} partials The arguments to prepend to those provided. * @param {Array} holders The `partials` placeholder indexes. * @params {boolean} [isCurried] Specify composing for a curried function. @@ -41364,7 +41400,7 @@ return jQuery; * is tailored for `_.partialRight`. * * @private - * @param {Array|Object} args The provided arguments. + * @param {Array} args The provided arguments. * @param {Array} partials The arguments to append to those provided. * @param {Array} holders The `partials` placeholder indexes. * @params {boolean} [isCurried] Specify composing for a curried function. @@ -41486,7 +41522,7 @@ return jQuery; customizer = length > 1 ? sources[length - 1] : undefined, guard = length > 2 ? sources[2] : undefined; - customizer = typeof customizer == 'function' + customizer = (assigner.length > 3 && typeof customizer == 'function') ? (length--, customizer) : undefined; @@ -41585,7 +41621,7 @@ return jQuery; * * @private * @param {string} methodName The name of the `String` case method to use. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new case function. */ function createCaseFirst(methodName) { return function(string) { @@ -41670,7 +41706,7 @@ return jQuery; var length = arguments.length, args = Array(length), index = length, - placeholder = getPlaceholder(wrapper); + placeholder = getHolder(wrapper); while (index--) { args[index] = arguments[index]; @@ -41691,6 +41727,31 @@ return jQuery; return wrapper; } + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} findIndexFunc The function to find the collection index. + * @returns {Function} Returns the new find function. + */ + function createFind(findIndexFunc) { + return function(collection, predicate, fromIndex) { + var iterable = Object(collection); + predicate = getIteratee(predicate, 3); + if (!isArrayLike(collection)) { + var props = keys(collection); + } + var index = findIndexFunc(props || collection, function(value, key) { + if (props) { + key = value; + value = iterable[key]; + } + return predicate(value, key, iterable); + }, fromIndex); + return index > -1 ? collection[props ? props[index] : index] : undefined; + }; + } + /** * Creates a `_.flow` or `_.flowRight` function. * @@ -41785,14 +41846,14 @@ return jQuery; function wrapper() { var length = arguments.length, - index = length, - args = Array(length); + args = Array(length), + index = length; while (index--) { args[index] = arguments[index]; } if (isCurried) { - var placeholder = getPlaceholder(wrapper), + var placeholder = getHolder(wrapper), holdersCount = countHolders(args, placeholder); } if (partials) { @@ -41881,7 +41942,7 @@ return jQuery; * * @private * @param {Function} arrayFunc The function to iterate over iteratees. - * @returns {Function} Returns the new invoker function. + * @returns {Function} Returns the new over function. */ function createOver(arrayFunc) { return rest(function(iteratees) { @@ -42054,7 +42115,7 @@ return jQuery; var func = Math[methodName]; return function(number, precision) { number = toNumber(number); - precision = toInteger(precision); + precision = nativeMin(toInteger(precision), 292); if (precision) { // Shift with exponential notation to avoid floating-point issues. // See [MDN](https://mdn.io/round#Examples) for more details. @@ -42079,6 +42140,26 @@ return jQuery; return new Set(values); }; + /** + * Creates a `_.toPairs` or `_.toPairsIn` function. + * + * @private + * @param {Function} keysFunc The function to get the keys of a given object. + * @returns {Function} Returns the new pairs function. + */ + function createToPairs(keysFunc) { + return function(object) { + var tag = getTag(object); + if (tag == mapTag) { + return mapToArray(object); + } + if (tag == setTag) { + return setToPairs(object); + } + return baseToPairs(object, keysFunc(object)); + }; + } + /** * Creates a function that either curries or invokes `func` with optional * `this` binding and partially applied arguments. @@ -42096,6 +42177,7 @@ return jQuery; * 64 - `_.partialRight` * 128 - `_.rearg` * 256 - `_.ary` + * 512 - `_.flip` * @param {*} [thisArg] The `this` binding of `func`. * @param {Array} [partials] The arguments to be partially applied. * @param {Array} [holders] The `partials` placeholder indexes. @@ -42174,9 +42256,7 @@ return jQuery; * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. */ function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { - var index = -1, - isPartial = bitmask & PARTIAL_COMPARE_FLAG, - isUnordered = bitmask & UNORDERED_COMPARE_FLAG, + var isPartial = bitmask & PARTIAL_COMPARE_FLAG, arrLength = array.length, othLength = other.length; @@ -42188,7 +42268,10 @@ return jQuery; if (stacked) { return stacked == other; } - var result = true; + var index = -1, + result = true, + seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined; + stack.set(array, other); // Ignore non-index properties. @@ -42209,10 +42292,12 @@ return jQuery; break; } // Recursively compare arrays (susceptible to call stack limits). - if (isUnordered) { - if (!arraySome(other, function(othValue) { - return arrValue === othValue || - equalFunc(arrValue, othValue, customizer, bitmask, stack); + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!seen.has(othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) { + return seen.add(othIndex); + } })) { result = false; break; @@ -42446,6 +42531,18 @@ return jQuery; return result; } + /** + * Gets the argument placeholder value for `func`. + * + * @private + * @param {Function} func The function to inspect. + * @returns {*} Returns the placeholder value. + */ + function getHolder(func) { + var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; + return object.placeholder; + } + /** * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, * this function returns the custom method, otherwise it returns `baseIteratee`. @@ -42476,6 +42573,21 @@ return jQuery; */ var getLength = baseProperty('length'); + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } + /** * Gets the property names, values, and compare flags of `object`. * @@ -42484,11 +42596,14 @@ return jQuery; * @returns {Array} Returns the match data of `object`. */ function getMatchData(object) { - var result = toPairs(object), + var result = keys(object), length = result.length; while (length--) { - result[length][2] = isStrictComparable(result[length][1]); + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; } return result; } @@ -42502,20 +42617,8 @@ return jQuery; * @returns {*} Returns the function if it's native, else `undefined`. */ function getNative(object, key) { - var value = object[key]; - return isNative(value) ? value : undefined; - } - - /** - * Gets the argument placeholder value for `func`. - * - * @private - * @param {Function} func The function to inspect. - * @returns {*} Returns the placeholder value. - */ - function getPlaceholder(func) { - var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; - return object.placeholder; + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; } /** @@ -42544,9 +42647,7 @@ return jQuery; // Fallback for IE < 11. if (!getOwnPropertySymbols) { - getSymbols = function() { - return []; - }; + getSymbols = stubArray; } /** @@ -42767,7 +42868,7 @@ return jQuery; * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. */ function isFlattenable(value) { - return isArrayLikeObject(value) && (isArray(value) || isArguments(value)); + return isArray(value) || isArguments(value); } /** @@ -42878,6 +42979,26 @@ return jQuery; return !!data && func === data[0]; } + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } + + /** + * Checks if `func` is capable of being masked. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `func` is maskable, else `false`. + */ + var isMaskable = coreJsData ? isFunction : stubFalse; + /** * Checks if `value` is likely a prototype object. * @@ -42911,7 +43032,7 @@ return jQuery; * @private * @param {string} key The key of the property to get. * @param {*} srcValue The value to match. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new spec function. */ function matchesStrictComparable(key, srcValue) { return function(object) { @@ -43163,7 +43284,7 @@ return jQuery; * @param {Array} array The array to process. * @param {number} [size=1] The length of each chunk * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the new array containing chunks. + * @returns {Array} Returns the new array of chunks. * @example * * _.chunk(['a', 'b', 'c', 'd'], 2); @@ -43246,16 +43367,16 @@ return jQuery; */ function concat() { var length = arguments.length, - array = castArray(arguments[0]); + args = Array(length ? length - 1 : 0), + array = arguments[0], + index = length; - if (length < 2) { - return length ? copyArray(array) : []; + while (index--) { + args[index - 1] = arguments[index]; } - var args = Array(length - 1); - while (length--) { - args[length - 1] = arguments[length]; - } - return arrayConcat(array, baseFlatten(args, 1)); + return length + ? arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)) + : []; } /** @@ -43274,8 +43395,8 @@ return jQuery; * @see _.without, _.xor * @example * - * _.difference([3, 2, 1], [4, 2]); - * // => [3, 1] + * _.difference([2, 1], [2, 3]); + * // => [1] */ var difference = rest(function(array, values) { return isArrayLikeObject(array) @@ -43300,8 +43421,8 @@ return jQuery; * @returns {Array} Returns the new array of filtered values. * @example * - * _.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor); - * // => [3.1, 1.3] + * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2] * * // The `_.property` iteratee shorthand. * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); @@ -43553,6 +43674,7 @@ return jQuery; * @param {Array} array The array to search. * @param {Array|Function|Object|string} [predicate=_.identity] * The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. * @returns {number} Returns the index of the found element, else `-1`. * @example * @@ -43577,10 +43699,16 @@ return jQuery; * _.findIndex(users, 'active'); * // => 2 */ - function findIndex(array, predicate) { - return (array && array.length) - ? baseFindIndex(array, getIteratee(predicate, 3)) - : -1; + function findIndex(array, predicate, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseFindIndex(array, getIteratee(predicate, 3), index); } /** @@ -43594,6 +43722,7 @@ return jQuery; * @param {Array} array The array to search. * @param {Array|Function|Object|string} [predicate=_.identity] * The function invoked per iteration. + * @param {number} [fromIndex=array.length-1] The index to search from. * @returns {number} Returns the index of the found element, else `-1`. * @example * @@ -43618,10 +43747,19 @@ return jQuery; * _.findLastIndex(users, 'active'); * // => 0 */ - function findLastIndex(array, predicate) { - return (array && array.length) - ? baseFindIndex(array, getIteratee(predicate, 3), true) - : -1; + function findLastIndex(array, predicate, fromIndex) { + var length = array ? array.length : 0; + if (!length) { + return -1; + } + var index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 + ? nativeMax(length + index, 0) + : nativeMin(index, length - 1); + } + return baseFindIndex(array, getIteratee(predicate, 3), index, true); } /** @@ -43768,11 +43906,11 @@ return jQuery; if (!length) { return -1; } - fromIndex = toInteger(fromIndex); - if (fromIndex < 0) { - fromIndex = nativeMax(length + fromIndex, 0); + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); } - return baseIndexOf(array, value, fromIndex); + return baseIndexOf(array, value, index); } /** @@ -43807,7 +43945,7 @@ return jQuery; * @returns {Array} Returns the new array of intersecting values. * @example * - * _.intersection([2, 1], [4, 2], [1, 2]); + * _.intersection([2, 1], [2, 3]); * // => [2] */ var intersection = rest(function(arrays) { @@ -43833,7 +43971,7 @@ return jQuery; * @returns {Array} Returns the new array of intersecting values. * @example * - * _.intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor); + * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); * // => [2.1] * * // The `_.property` iteratee shorthand. @@ -43963,7 +44101,7 @@ return jQuery; ) + 1; } if (value !== value) { - return indexOfNaN(array, index, true); + return indexOfNaN(array, index - 1, true); } while (index--) { if (array[index] === value) { @@ -43974,8 +44112,8 @@ return jQuery; } /** - * Gets the nth element of `array`. If `n` is negative, the nth element - * from the end is returned. + * Gets the element at index `n` of `array`. If `n` is negative, the nth + * element from the end is returned. * * @static * @memberOf _ @@ -44015,11 +44153,11 @@ return jQuery; * @returns {Array} Returns `array`. * @example * - * var array = [1, 2, 3, 1, 2, 3]; + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; * - * _.pull(array, 2, 3); + * _.pull(array, 'a', 'c'); * console.log(array); - * // => [1, 1] + * // => ['b', 'b'] */ var pull = rest(pullAll); @@ -44037,11 +44175,11 @@ return jQuery; * @returns {Array} Returns `array`. * @example * - * var array = [1, 2, 3, 1, 2, 3]; + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; * - * _.pullAll(array, [2, 3]); + * _.pullAll(array, ['a', 'c']); * console.log(array); - * // => [1, 1] + * // => ['b', 'b'] */ function pullAll(array, values) { return (array && array.length && values && values.length) @@ -44123,14 +44261,14 @@ return jQuery; * @returns {Array} Returns the new array of removed elements. * @example * - * var array = [5, 10, 15, 20]; - * var evens = _.pullAt(array, 1, 3); + * var array = ['a', 'b', 'c', 'd']; + * var pulled = _.pullAt(array, [1, 3]); * * console.log(array); - * // => [5, 15] + * // => ['a', 'c'] * - * console.log(evens); - * // => [10, 20] + * console.log(pulled); + * // => ['b', 'd'] */ var pullAt = rest(function(array, indexes) { indexes = baseFlatten(indexes, 1); @@ -44270,9 +44408,6 @@ return jQuery; * * _.sortedIndex([30, 50], 40); * // => 1 - * - * _.sortedIndex([4, 5], 4); - * // => 0 */ function sortedIndex(array, value) { return baseSortedIndex(array, value); @@ -44295,13 +44430,13 @@ return jQuery; * into `array`. * @example * - * var dict = { 'thirty': 30, 'forty': 40, 'fifty': 50 }; + * var objects = [{ 'x': 4 }, { 'x': 5 }]; * - * _.sortedIndexBy(['thirty', 'fifty'], 'forty', _.propertyOf(dict)); - * // => 1 + * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 0 * * // The `_.property` iteratee shorthand. - * _.sortedIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x'); + * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); * // => 0 */ function sortedIndexBy(array, value, iteratee) { @@ -44321,8 +44456,8 @@ return jQuery; * @returns {number} Returns the index of the matched value, else `-1`. * @example * - * _.sortedIndexOf([1, 1, 2, 2], 2); - * // => 2 + * _.sortedIndexOf([4, 5, 5, 5, 6], 5); + * // => 1 */ function sortedIndexOf(array, value) { var length = array ? array.length : 0; @@ -44350,8 +44485,8 @@ return jQuery; * into `array`. * @example * - * _.sortedLastIndex([4, 5], 4); - * // => 1 + * _.sortedLastIndex([4, 5, 5, 5, 6], 5); + * // => 4 */ function sortedLastIndex(array, value) { return baseSortedIndex(array, value, true); @@ -44374,8 +44509,13 @@ return jQuery; * into `array`. * @example * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 1 + * * // The `_.property` iteratee shorthand. - * _.sortedLastIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x'); + * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); * // => 1 */ function sortedLastIndexBy(array, value, iteratee) { @@ -44395,7 +44535,7 @@ return jQuery; * @returns {number} Returns the index of the matched value, else `-1`. * @example * - * _.sortedLastIndexOf([1, 1, 2, 2], 2); + * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); * // => 3 */ function sortedLastIndexOf(array, value) { @@ -44635,8 +44775,8 @@ return jQuery; * @returns {Array} Returns the new array of combined values. * @example * - * _.union([2, 1], [4, 2], [1, 2]); - * // => [2, 1, 4] + * _.union([2], [1, 2]); + * // => [2, 1] */ var union = rest(function(arrays) { return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); @@ -44658,8 +44798,8 @@ return jQuery; * @returns {Array} Returns the new array of combined values. * @example * - * _.unionBy([2.1, 1.2], [4.3, 2.4], Math.floor); - * // => [2.1, 1.2, 4.3] + * _.unionBy([2.1], [1.2, 2.3], Math.floor); + * // => [2.1, 1.2] * * // The `_.property` iteratee shorthand. * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); @@ -44766,7 +44906,7 @@ return jQuery; * @returns {Array} Returns the new duplicate free array. * @example * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; * * _.uniqWith(objects, _.isEqual); * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] @@ -44855,13 +44995,13 @@ return jQuery; * @memberOf _ * @since 0.1.0 * @category Array - * @param {Array} array The array to filter. + * @param {Array} array The array to inspect. * @param {...*} [values] The values to exclude. * @returns {Array} Returns the new array of filtered values. * @see _.difference, _.xor * @example * - * _.without([1, 2, 1, 3], 1, 2); + * _.without([2, 1, 2, 3], 1, 2); * // => [3] */ var without = rest(function(array, values) { @@ -44881,12 +45021,12 @@ return jQuery; * @since 2.4.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of values. + * @returns {Array} Returns the new array of filtered values. * @see _.difference, _.without * @example * - * _.xor([2, 1], [4, 2]); - * // => [1, 4] + * _.xor([2, 1], [2, 3]); + * // => [1, 3] */ var xor = rest(function(arrays) { return baseXor(arrayFilter(arrays, isArrayLikeObject)); @@ -44905,11 +45045,11 @@ return jQuery; * @param {...Array} [arrays] The arrays to inspect. * @param {Array|Function|Object|string} [iteratee=_.identity] * The iteratee invoked per element. - * @returns {Array} Returns the new array of values. + * @returns {Array} Returns the new array of filtered values. * @example * - * _.xorBy([2.1, 1.2], [4.3, 2.4], Math.floor); - * // => [1.2, 4.3] + * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2, 3.4] * * // The `_.property` iteratee shorthand. * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); @@ -44934,7 +45074,7 @@ return jQuery; * @category Array * @param {...Array} [arrays] The arrays to inspect. * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of values. + * @returns {Array} Returns the new array of filtered values. * @example * * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; @@ -45142,9 +45282,6 @@ return jQuery; * * _(object).at(['a[0].b.c', 'a[1]']).value(); * // => [3, 4] - * - * _(['a', 'b', 'c']).at(0, 2).value(); - * // => ['a', 'c'] */ var wrapperAt = rest(function(paths) { paths = baseFlatten(paths, 1); @@ -45407,6 +45544,7 @@ return jQuery; * _.countBy([6.1, 4.2, 6.3], Math.floor); * // => { '4': 1, '6': 2 } * + * // The `_.property` iteratee shorthand. * _.countBy(['one', 'two', 'three'], 'length'); * // => { '3': 2, '5': 1 } */ @@ -45512,6 +45650,7 @@ return jQuery; * @param {Array|Object} collection The collection to search. * @param {Array|Function|Object|string} [predicate=_.identity] * The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. * @returns {*} Returns the matched element, else `undefined`. * @example * @@ -45536,14 +45675,7 @@ return jQuery; * _.find(users, 'active'); * // => object for 'barney' */ - function find(collection, predicate) { - predicate = getIteratee(predicate, 3); - if (isArray(collection)) { - var index = baseFindIndex(collection, predicate); - return index > -1 ? collection[index] : undefined; - } - return baseFind(collection, predicate, baseEach); - } + var find = createFind(findIndex); /** * This method is like `_.find` except that it iterates over elements of @@ -45556,6 +45688,7 @@ return jQuery; * @param {Array|Object} collection The collection to search. * @param {Array|Function|Object|string} [predicate=_.identity] * The function invoked per iteration. + * @param {number} [fromIndex=collection.length-1] The index to search from. * @returns {*} Returns the matched element, else `undefined`. * @example * @@ -45564,14 +45697,7 @@ return jQuery; * }); * // => 3 */ - function findLast(collection, predicate) { - predicate = getIteratee(predicate, 3); - if (isArray(collection)) { - var index = baseFindIndex(collection, predicate, true); - return index > -1 ? collection[index] : undefined; - } - return baseFind(collection, predicate, baseEachRight); - } + var findLast = createFind(findLastIndex); /** * Creates a flattened array of values by running each element in `collection` @@ -45682,9 +45808,8 @@ return jQuery; * // => Logs 'a' then 'b' (iteration order is not guaranteed). */ function forEach(collection, iteratee) { - return (typeof iteratee == 'function' && isArray(collection)) - ? arrayEach(collection, iteratee) - : baseEach(collection, getIteratee(iteratee)); + var func = isArray(collection) ? arrayEach : baseEach; + return func(collection, getIteratee(iteratee, 3)); } /** @@ -45708,9 +45833,8 @@ return jQuery; * // => Logs `2` then `1`. */ function forEachRight(collection, iteratee) { - return (typeof iteratee == 'function' && isArray(collection)) - ? arrayEachRight(collection, iteratee) - : baseEachRight(collection, getIteratee(iteratee)); + var func = isArray(collection) ? arrayEachRight : baseEachRight; + return func(collection, getIteratee(iteratee, 3)); } /** @@ -46330,7 +46454,6 @@ return jQuery; * @static * @memberOf _ * @since 2.4.0 - * @type {Function} * @category Date * @returns {number} Returns the timestamp. * @example @@ -46338,9 +46461,11 @@ return jQuery; * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred function to be invoked. + * // => Logs the number of milliseconds it took for the deferred invocation. */ - var now = Date.now; + function now() { + return Date.now(); + } /*------------------------------------------------------------------------*/ @@ -46391,7 +46516,7 @@ return jQuery; * @param {Function} func The function to cap arguments for. * @param {number} [n=func.length] The arity cap. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new capped function. * @example * * _.map(['6', '8', '10'], _.ary(parseInt, 1)); @@ -46444,7 +46569,7 @@ return jQuery; * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, * may be used as a placeholder for partially applied arguments. * - * **Note:** Unlike native `Function#bind` this method doesn't set the "length" + * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" * property of bound functions. * * @static @@ -46475,7 +46600,7 @@ return jQuery; var bind = rest(function(func, thisArg, partials) { var bitmask = BIND_FLAG; if (partials.length) { - var holders = replaceHolders(partials, getPlaceholder(bind)); + var holders = replaceHolders(partials, getHolder(bind)); bitmask |= PARTIAL_FLAG; } return createWrapper(func, bitmask, thisArg, partials, holders); @@ -46529,7 +46654,7 @@ return jQuery; var bindKey = rest(function(object, key, partials) { var bitmask = BIND_FLAG | BIND_KEY_FLAG; if (partials.length) { - var holders = replaceHolders(partials, getPlaceholder(bindKey)); + var holders = replaceHolders(partials, getHolder(bindKey)); bitmask |= PARTIAL_FLAG; } return createWrapper(key, bitmask, object, partials, holders); @@ -46684,7 +46809,7 @@ return jQuery; maxWait, result, timerId, - lastCallTime = 0, + lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, @@ -46735,7 +46860,7 @@ return jQuery; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. - return (!lastCallTime || (timeSinceLastCall >= wait) || + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); } @@ -46749,7 +46874,6 @@ return jQuery; } function trailingEdge(time) { - clearTimeout(timerId); timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been @@ -46762,11 +46886,8 @@ return jQuery; } function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastCallTime = lastInvokeTime = 0; - lastArgs = lastThis = timerId = undefined; + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { @@ -46787,7 +46908,6 @@ return jQuery; } if (maxing) { // Handle invocations in a tight loop. - clearTimeout(timerId); timerId = setTimeout(timerExpired, wait); return invokeFunc(lastCallTime); } @@ -46855,7 +46975,7 @@ return jQuery; * @since 4.0.0 * @category Function * @param {Function} func The function to flip arguments for. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new flipped function. * @example * * var flipped = _.flip(function() { @@ -46888,7 +47008,7 @@ return jQuery; * @category Function * @param {Function} func The function to have its output memoized. * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoizing function. + * @returns {Function} Returns the new memoized function. * @example * * var object = { 'a': 1, 'b': 2 }; @@ -46946,7 +47066,7 @@ return jQuery; * @since 3.0.0 * @category Function * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new negated function. * @example * * function isEven(n) { @@ -47011,7 +47131,7 @@ return jQuery; * * var func = _.overArgs(function(x, y) { * return [x, y]; - * }, square, doubled); + * }, [square, doubled]); * * func(9, 3); * // => [81, 6] @@ -47070,7 +47190,7 @@ return jQuery; * // => 'hi fred' */ var partial = rest(function(func, partials) { - var holders = replaceHolders(partials, getPlaceholder(partial)); + var holders = replaceHolders(partials, getHolder(partial)); return createWrapper(func, PARTIAL_FLAG, undefined, partials, holders); }); @@ -47107,7 +47227,7 @@ return jQuery; * // => 'hello fred' */ var partialRight = rest(function(func, partials) { - var holders = replaceHolders(partials, getPlaceholder(partialRight)); + var holders = replaceHolders(partials, getHolder(partialRight)); return createWrapper(func, PARTIAL_RIGHT_FLAG, undefined, partials, holders); }); @@ -47128,7 +47248,7 @@ return jQuery; * * var rearged = _.rearg(function(a, b, c) { * return [a, b, c]; - * }, 2, 0, 1); + * }, [2, 0, 1]); * * rearged('b', 'c', 'a') * // => ['a', 'b', 'c'] @@ -47309,7 +47429,7 @@ return jQuery; * @since 4.0.0 * @category Function * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new capped function. * @example * * _.map(['6', '8', '10'], _.unary(parseInt)); @@ -47767,7 +47887,7 @@ return jQuery; * _.isBuffer(new Uint8Array(2)); * // => false */ - var isBuffer = !Buffer ? constant(false) : function(value) { + var isBuffer = !Buffer ? stubFalse : function(value) { return value instanceof Buffer; }; @@ -47985,14 +48105,14 @@ return jQuery; * _.isFinite(3); * // => true * - * _.isFinite(Number.MAX_VALUE); - * // => true - * - * _.isFinite(3.14); + * _.isFinite(Number.MIN_VALUE); * // => true * * _.isFinite(Infinity); * // => false + * + * _.isFinite('3'); + * // => false */ function isFinite(value) { return typeof value == 'number' && nativeIsFinite(value); @@ -48267,7 +48387,15 @@ return jQuery; } /** - * Checks if `value` is a native function. + * Checks if `value` is a pristine native function. + * + * **Note:** This method can't reliably detect native functions in the + * presence of the `core-js` package because `core-js` circumvents this kind + * of detection. Despite multiple requests, the `core-js` maintainer has made + * it clear: any attempt to fix the detection will be obstructed. As a result, + * we're left with little choice but to throw an error. Unfortunately, this + * also affects packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), + * which rely on `core-js`. * * @static * @memberOf _ @@ -48285,11 +48413,10 @@ return jQuery; * // => false */ function isNative(value) { - if (!isObject(value)) { - return false; + if (isMaskable(value)) { + throw new Error('This method is not supported with `core-js`. Try https://github.com/es-shims.'); } - var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); + return baseIsNative(value); } /** @@ -48713,10 +48840,45 @@ return jQuery; return func(value); } + /** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ + function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; + } + /** * Converts `value` to an integer. * - * **Note:** This function is loosely based on + * **Note:** This method is loosely based on * [`ToInteger`](http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger). * * @static @@ -48727,7 +48889,7 @@ return jQuery; * @returns {number} Returns the converted integer. * @example * - * _.toInteger(3); + * _.toInteger(3.2); * // => 3 * * _.toInteger(Number.MIN_VALUE); @@ -48736,20 +48898,14 @@ return jQuery; * _.toInteger(Infinity); * // => 1.7976931348623157e+308 * - * _.toInteger('3'); + * _.toInteger('3.2'); * // => 3 */ function toInteger(value) { - if (!value) { - return value === 0 ? value : 0; - } - value = toNumber(value); - if (value === INFINITY || value === -INFINITY) { - var sign = (value < 0 ? -1 : 1); - return sign * MAX_INTEGER; - } - var remainder = value % 1; - return value === value ? (remainder ? value - remainder : value) : 0; + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; } /** @@ -48767,7 +48923,7 @@ return jQuery; * @returns {number} Returns the converted integer. * @example * - * _.toLength(3); + * _.toLength(3.2); * // => 3 * * _.toLength(Number.MIN_VALUE); @@ -48776,7 +48932,7 @@ return jQuery; * _.toLength(Infinity); * // => 4294967295 * - * _.toLength('3'); + * _.toLength('3.2'); * // => 3 */ function toLength(value) { @@ -48794,8 +48950,8 @@ return jQuery; * @returns {number} Returns the number. * @example * - * _.toNumber(3); - * // => 3 + * _.toNumber(3.2); + * // => 3.2 * * _.toNumber(Number.MIN_VALUE); * // => 5e-324 @@ -48803,8 +48959,8 @@ return jQuery; * _.toNumber(Infinity); * // => Infinity * - * _.toNumber('3'); - * // => 3 + * _.toNumber('3.2'); + * // => 3.2 */ function toNumber(value) { if (typeof value == 'number') { @@ -48867,7 +49023,7 @@ return jQuery; * @returns {number} Returns the converted integer. * @example * - * _.toSafeInteger(3); + * _.toSafeInteger(3.2); * // => 3 * * _.toSafeInteger(Number.MIN_VALUE); @@ -48876,7 +49032,7 @@ return jQuery; * _.toSafeInteger(Infinity); * // => 9007199254740991 * - * _.toSafeInteger('3'); + * _.toSafeInteger('3.2'); * // => 3 */ function toSafeInteger(value) { @@ -49069,16 +49225,13 @@ return jQuery; * @category Object * @param {Object} object The object to iterate over. * @param {...(string|string[])} [paths] The property paths of elements to pick. - * @returns {Array} Returns the new array of picked elements. + * @returns {Array} Returns the picked values. * @example * * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; * * _.at(object, ['a[0].b.c', 'a[1]']); * // => [3, 4] - * - * _.at(['a', 'b', 'c'], 0, 2); - * // => ['a', 'c'] */ var at = rest(function(object, paths) { return baseAt(object, baseFlatten(paths, 1)); @@ -49211,7 +49364,7 @@ return jQuery; * // => 'barney' */ function findKey(object, predicate) { - return baseFind(object, getIteratee(predicate, 3), baseForOwn, true); + return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); } /** @@ -49251,7 +49404,7 @@ return jQuery; * // => 'pebbles' */ function findLastKey(object, predicate) { - return baseFind(object, getIteratee(predicate, 3), baseForOwnRight, true); + return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); } /** @@ -49285,7 +49438,7 @@ return jQuery; function forIn(object, iteratee) { return object == null ? object - : baseFor(object, getIteratee(iteratee), keysIn); + : baseFor(object, getIteratee(iteratee, 3), keysIn); } /** @@ -49317,7 +49470,7 @@ return jQuery; function forInRight(object, iteratee) { return object == null ? object - : baseForRight(object, getIteratee(iteratee), keysIn); + : baseForRight(object, getIteratee(iteratee, 3), keysIn); } /** @@ -49349,7 +49502,7 @@ return jQuery; * // => Logs 'a' then 'b' (iteration order is not guaranteed). */ function forOwn(object, iteratee) { - return object && baseForOwn(object, getIteratee(iteratee)); + return object && baseForOwn(object, getIteratee(iteratee, 3)); } /** @@ -49379,7 +49532,7 @@ return jQuery; * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. */ function forOwnRight(object, iteratee) { - return object && baseForOwnRight(object, getIteratee(iteratee)); + return object && baseForOwnRight(object, getIteratee(iteratee, 3)); } /** @@ -49391,7 +49544,7 @@ return jQuery; * @memberOf _ * @category Object * @param {Object} object The object to inspect. - * @returns {Array} Returns the new array of property names. + * @returns {Array} Returns the function names. * @see _.functionsIn * @example * @@ -49418,7 +49571,7 @@ return jQuery; * @since 4.0.0 * @category Object * @param {Object} object The object to inspect. - * @returns {Array} Returns the new array of property names. + * @returns {Array} Returns the function names. * @see _.functions * @example * @@ -49771,7 +49924,7 @@ return jQuery; * inherited enumerable string keyed properties of source objects into the * destination object. Source properties that resolve to `undefined` are * skipped if a destination value exists. Array and plain object properties - * are merged recursively.Other objects and value types are overridden by + * are merged recursively. Other objects and value types are overridden by * assignment. Source objects are applied from left to right. Subsequent * sources overwrite property assignments of previous sources. * @@ -50056,7 +50209,8 @@ return jQuery; /** * Creates an array of own enumerable string keyed-value pairs for `object` - * which can be consumed by `_.fromPairs`. + * which can be consumed by `_.fromPairs`. If `object` is a map or set, its + * entries are returned. * * @static * @memberOf _ @@ -50064,7 +50218,7 @@ return jQuery; * @alias entries * @category Object * @param {Object} object The object to query. - * @returns {Array} Returns the new array of key-value pairs. + * @returns {Array} Returns the key-value pairs. * @example * * function Foo() { @@ -50077,13 +50231,12 @@ return jQuery; * _.toPairs(new Foo); * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) */ - function toPairs(object) { - return baseToPairs(object, keys(object)); - } + var toPairs = createToPairs(keys); /** * Creates an array of own and inherited enumerable string keyed-value pairs - * for `object` which can be consumed by `_.fromPairs`. + * for `object` which can be consumed by `_.fromPairs`. If `object` is a map + * or set, its entries are returned. * * @static * @memberOf _ @@ -50091,7 +50244,7 @@ return jQuery; * @alias entriesIn * @category Object * @param {Object} object The object to query. - * @returns {Array} Returns the new array of key-value pairs. + * @returns {Array} Returns the key-value pairs. * @example * * function Foo() { @@ -50102,25 +50255,24 @@ return jQuery; * Foo.prototype.c = 3; * * _.toPairsIn(new Foo); - * // => [['a', 1], ['b', 2], ['c', 1]] (iteration order is not guaranteed) + * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) */ - function toPairsIn(object) { - return baseToPairs(object, keysIn(object)); - } + var toPairsIn = createToPairs(keysIn); /** * An alternative to `_.reduce`; this method transforms `object` to a new * `accumulator` object which is the result of running each of its own * enumerable string keyed properties thru `iteratee`, with each invocation - * potentially mutating the `accumulator` object. The iteratee is invoked - * with four arguments: (accumulator, value, key, object). Iteratee functions - * may exit iteration early by explicitly returning `false`. + * potentially mutating the `accumulator` object. If `accumulator` is not + * provided, a new object with the same `[[Prototype]]` will be used. The + * iteratee is invoked with four arguments: (accumulator, value, key, object). + * Iteratee functions may exit iteration early by explicitly returning `false`. * * @static * @memberOf _ * @since 1.3.0 * @category Object - * @param {Array|Object} object The object to iterate over. + * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The custom accumulator value. * @returns {*} Returns the accumulated value. @@ -50542,7 +50694,7 @@ return jQuery; * @category String * @param {string} [string=''] The string to search. * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search from. + * @param {number} [position=string.length] The position to search up to. * @returns {boolean} Returns `true` if `string` ends with `target`, * else `false`. * @example @@ -50936,7 +51088,7 @@ return jQuery; * @param {string} [string=''] The string to split. * @param {RegExp|string} separator The separator pattern to split by. * @param {number} [limit] The length to truncate results to. - * @returns {Array} Returns the new array of string segments. + * @returns {Array} Returns the string segments. * @example * * _.split('a-b-c', '-', 2); @@ -51081,12 +51233,6 @@ return jQuery; * compiled({ 'user': 'pebbles' }); * // => 'hello pebbles!' * - * // Use custom template delimiters. - * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g; - * var compiled = _.template('hello {{ user }}!'); - * compiled({ 'user': 'mustache' }); - * // => 'hello mustache!' - * * // Use backslashes to treat delimiters as plain text. * var compiled = _.template('<%= "\\<%- value %\\>" %>'); * compiled({ 'value': 'ignored' }); @@ -51112,9 +51258,15 @@ return jQuery; * // return __p; * // } * + * // Use custom template delimiters. + * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g; + * var compiled = _.template('hello {{ user }}!'); + * compiled({ 'user': 'mustache' }); + * // => 'hello mustache!' + * * // Use the `source` property to inline compiled templates for meaningful * // line numbers in error messages and stack traces. - * fs.writeFileSync(path.join(cwd, 'jst.js'), '\ + * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\ * var JST = {\ * "main": ' + _.template(mainText).source + '\ * };\ @@ -51627,7 +51779,7 @@ return jQuery; * } * }; * - * _.bindAll(view, 'onClick'); + * _.bindAll(view, ['onClick']); * jQuery(element).on('click', view.onClick); * // => Logs 'clicked docs' when clicked. */ @@ -51650,7 +51802,7 @@ return jQuery; * @since 4.0.0 * @category Util * @param {Array} pairs The predicate-function pairs. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new composite function. * @example * * var func = _.cond([ @@ -51700,7 +51852,7 @@ return jQuery; * @since 4.0.0 * @category Util * @param {Object} source The object of property predicates to conform to. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new spec function. * @example * * var users = [ @@ -51708,7 +51860,7 @@ return jQuery; * { 'user': 'fred', 'age': 40 } * ]; * - * _.filter(users, _.conforms({ 'age': _.partial(_.gt, _, 38) })); + * _.filter(users, _.conforms({ 'age': function(n) { return n > 38; } })); * // => [{ 'user': 'fred', 'age': 40 }] */ function conforms(source) { @@ -51723,13 +51875,15 @@ return jQuery; * @since 2.4.0 * @category Util * @param {*} value The value to return from the new function. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new constant function. * @example * - * var object = { 'user': 'fred' }; - * var getter = _.constant(object); + * var objects = _.times(2, _.constant({ 'a': 1 })); * - * getter() === object; + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); * // => true */ function constant(value) { @@ -51748,7 +51902,7 @@ return jQuery; * @since 3.0.0 * @category Util * @param {...(Function|Function[])} [funcs] Functions to invoke. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new composite function. * @see _.flowRight * @example * @@ -51756,7 +51910,7 @@ return jQuery; * return n * n; * } * - * var addSquare = _.flow(_.add, square); + * var addSquare = _.flow([_.add, square]); * addSquare(1, 2); * // => 9 */ @@ -51771,7 +51925,7 @@ return jQuery; * @memberOf _ * @category Util * @param {...(Function|Function[])} [funcs] Functions to invoke. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new composite function. * @see _.flow * @example * @@ -51779,7 +51933,7 @@ return jQuery; * return n * n; * } * - * var addSquare = _.flowRight(square, _.add); + * var addSquare = _.flowRight([square, _.add]); * addSquare(1, 2); * // => 9 */ @@ -51798,7 +51952,7 @@ return jQuery; * * var object = { 'user': 'fred' }; * - * _.identity(object) === object; + * console.log(_.identity(object) === object); * // => true */ function identity(value) { @@ -51864,7 +52018,7 @@ return jQuery; * @since 3.0.0 * @category Util * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new spec function. * @example * * var users = [ @@ -51892,7 +52046,7 @@ return jQuery; * @category Util * @param {Array|string} path The path of the property to get. * @param {*} srcValue The value to match. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new spec function. * @example * * var users = [ @@ -51917,7 +52071,7 @@ return jQuery; * @category Util * @param {Array|string} path The path of the method to invoke. * @param {...*} [args] The arguments to invoke the method with. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new invoker function. * @example * * var objects = [ @@ -51948,7 +52102,7 @@ return jQuery; * @category Util * @param {Object} object The object to query. * @param {...*} [args] The arguments to invoke the method with. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new invoker function. * @example * * var array = _.times(3, _.constant), @@ -52059,8 +52213,7 @@ return jQuery; } /** - * A no-operation function that returns `undefined` regardless of the - * arguments it receives. + * A method that returns `undefined`. * * @static * @memberOf _ @@ -52068,17 +52221,15 @@ return jQuery; * @category Util * @example * - * var object = { 'user': 'fred' }; - * - * _.noop(object) === undefined; - * // => true + * _.times(2, _.noop); + * // => [undefined, undefined] */ function noop() { // No operation performed. } /** - * Creates a function that returns its nth argument. If `n` is negative, + * Creates a function that gets the argument at index `n`. If `n` is negative, * the nth argument from the end is returned. * * @static @@ -52086,7 +52237,7 @@ return jQuery; * @since 4.0.0 * @category Util * @param {number} [n=0] The index of the argument to return. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new pass-thru function. * @example * * var func = _.nthArg(1); @@ -52117,7 +52268,7 @@ return jQuery; * @returns {Function} Returns the new function. * @example * - * var func = _.over(Math.max, Math.min); + * var func = _.over([Math.max, Math.min]); * * func(1, 2, 3, 4); * // => [4, 1] @@ -52137,7 +52288,7 @@ return jQuery; * @returns {Function} Returns the new function. * @example * - * var func = _.overEvery(Boolean, isFinite); + * var func = _.overEvery([Boolean, isFinite]); * * func('1'); * // => true @@ -52163,7 +52314,7 @@ return jQuery; * @returns {Function} Returns the new function. * @example * - * var func = _.overSome(Boolean, isFinite); + * var func = _.overSome([Boolean, isFinite]); * * func('1'); * // => true @@ -52184,7 +52335,7 @@ return jQuery; * @since 2.4.0 * @category Util * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new accessor function. * @example * * var objects = [ @@ -52211,7 +52362,7 @@ return jQuery; * @since 3.0.0 * @category Util * @param {Object} object The object to query. - * @returns {Function} Returns the new function. + * @returns {Function} Returns the new accessor function. * @example * * var array = [0, 1, 2], @@ -52245,7 +52396,7 @@ return jQuery; * @param {number} [start=0] The start of the range. * @param {number} end The end of the range. * @param {number} [step=1] The value to increment or decrement by. - * @returns {Array} Returns the new array of numbers. + * @returns {Array} Returns the range of numbers. * @see _.inRange, _.rangeRight * @example * @@ -52283,7 +52434,7 @@ return jQuery; * @param {number} [start=0] The start of the range. * @param {number} end The end of the range. * @param {number} [step=1] The value to increment or decrement by. - * @returns {Array} Returns the new array of numbers. + * @returns {Array} Returns the range of numbers. * @see _.inRange, _.range * @example * @@ -52310,6 +52461,101 @@ return jQuery; */ var rangeRight = createRange(true); + /** + * A method that returns a new empty array. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Array} Returns the new empty array. + * @example + * + * var arrays = _.times(2, _.stubArray); + * + * console.log(arrays); + * // => [[], []] + * + * console.log(arrays[0] === arrays[1]); + * // => false + */ + function stubArray() { + return []; + } + + /** + * A method that returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ + function stubFalse() { + return false; + } + + /** + * A method that returns a new empty object. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Object} Returns the new empty object. + * @example + * + * var objects = _.times(2, _.stubObject); + * + * console.log(objects); + * // => [{}, {}] + * + * console.log(objects[0] === objects[1]); + * // => false + */ + function stubObject() { + return {}; + } + + /** + * A method that returns an empty string. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {string} Returns the empty string. + * @example + * + * _.times(2, _.stubString); + * // => ['', ''] + */ + function stubString() { + return ''; + } + + /** + * A method that returns `true`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `true`. + * @example + * + * _.times(2, _.stubTrue); + * // => [true, true] + */ + function stubTrue() { + return true; + } + /** * Invokes the iteratee `n` times, returning an array of the results of * each invocation. The iteratee is invoked with one argument; (index). @@ -52326,8 +52572,8 @@ return jQuery; * _.times(3, String); * // => ['0', '1', '2'] * - * _.times(4, _.constant(true)); - * // => [true, true, true, true] + * _.times(4, _.constant(0)); + * // => [0, 0, 0, 0] */ function times(n, iteratee) { n = toInteger(n); @@ -52363,15 +52609,6 @@ return jQuery; * * _.toPath('a[0].b.c'); * // => ['a', '0', 'b', 'c'] - * - * var path = ['a', 'b', 'c'], - * newPath = _.toPath(path); - * - * console.log(newPath); - * // => ['a', 'b', 'c'] - * - * console.log(path === newPath); - * // => false */ function toPath(value) { if (isArray(value)) { @@ -53010,6 +53247,11 @@ return jQuery; lodash.meanBy = meanBy; lodash.min = min; lodash.minBy = minBy; + lodash.stubArray = stubArray; + lodash.stubFalse = stubFalse; + lodash.stubObject = stubObject; + lodash.stubString = stubString; + lodash.stubTrue = stubTrue; lodash.multiply = multiply; lodash.nth = nth; lodash.noConflict = noConflict; @@ -53044,6 +53286,7 @@ return jQuery; lodash.sumBy = sumBy; lodash.template = template; lodash.times = times; + lodash.toFinite = toFinite; lodash.toInteger = toInteger; lodash.toLength = toLength; lodash.toLower = toLower; @@ -53315,7 +53558,7 @@ return jQuery; // also prevents errors in cases where Lodash is loaded by a script tag in the // presence of an AMD loader. See http://requirejs.org/docs/errors.html#mismatch // for more details. Use `_.noConflict` to remove Lodash from the global object. - (freeWindow || freeSelf || {})._ = _; + (freeSelf || {})._ = _; // Some AMD build optimizers like r.js check for condition patterns like the following: if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { @@ -53326,11 +53569,9 @@ return jQuery; }); } // Check for `exports` after `define` in case a build optimizer adds an `exports` object. - else if (freeExports && freeModule) { + else if (freeModule) { // Export for Node.js. - if (moduleExports) { - (freeModule.exports = _)._ = _; - } + (freeModule.exports = _)._ = _; // Export for CommonJS support. freeExports._ = _; } diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js index d621387cc..642ded17f 100644 --- a/web/src/js/components/flowtable.js +++ b/web/src/js/components/flowtable.js @@ -46,61 +46,59 @@ const FlowRowContainer = connect( }) )(FlowRow) -class FlowTableHead extends React.Component { +function FlowTableHead({setSort, columns, sort}) { - static propTypes = { - setSortKeyFun: React.PropTypes.func.isRequired, - columns: React.PropTypes.array.isRequired, - }; + //const hasSort = Column.sortKeyFun; - constructor(props, context) { - super(props, context); - this.state = {sortColumn: undefined, sortDesc: false}; - } + // let sortDesc = this.props.sort.sortDesc; + // + // if (Column === this.props.sort.sortColumn) { + // sortDesc = !sortDesc; + // this.props.setSort(sortColumn, sortDesc); + // } else { + // this.props.setSort({sortColumn: hasSort && Column, sortDesc: false}); + // } + // + // 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); - onClick(Column) { - const hasSort = Column.sortKeyFun; + const sortColumn = sort.sortColumn; + const sortType = sort.sortDesc ? "sort-desc" : "sort-asc"; - let sortDesc = this.state.sortDesc; - - if (Column === this.state.sortColumn) { - sortDesc = !sortDesc; - this.setState({sortDesc}); - } else { - this.setState({sortColumn: hasSort && Column, sortDesc: false}); - } - - 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() { - const sortColumn = this.state.sortColumn; - const sortType = this.state.sortDesc ? "sort-desc" : "sort-asc"; return ( - {this.props.columns.map(Column => ( + {columns.map(Column => ( this.onClick(Column)} - className={sortColumn === Column ? sortType : undefined} + onClick={() => setSort({sortColumn: Column.name, sortDesc: Column.name != sort.sortColumn ? false : !sort.sortDesc})} + className={sortColumn === Column.name ? sortType : undefined} /> ))} ); - } } +FlowTableHead.propTypes = { + setSort: React.PropTypes.func.isRequired, + sort: React.PropTypes.object.isRequired, + columns: React.PropTypes.array.isRequired +}; + +const FlowTableHeadContainer = connect( + (state, ownProps) => ({ + sort: state.flows.sort + }) +)(FlowTableHead) + class FlowTable extends React.Component { static propTypes = { @@ -186,9 +184,10 @@ class FlowTable extends React.Component {
- diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js index 228959917..99cdeb3ca 100644 --- a/web/src/js/components/mainview.js +++ b/web/src/js/components/mainview.js @@ -7,7 +7,7 @@ import {Splitter} from "./common.js" import FlowTable from "./flowtable.js"; import FlowView from "./flowview/index.js"; import {connect} from 'react-redux' -import {selectFlow, setFilter, setHighlight} from "../ducks/flows"; +import {selectFlow, setFilter, setHighlight, setSort} from "../ducks/flows"; var MainView = React.createClass({ @@ -161,7 +161,8 @@ var MainView = React.createClass({
console.log("asdf")} + setSort={this.props.setSort} selected={this.props.selectedFlow} /> {details}
@@ -173,12 +174,14 @@ const MainViewContainer = connect( state => ({ flows: state.flows.view, filter: state.flows.filter, + sort: state.flows.sort, highlight: state.flows.highlight, selectedFlow: state.flows.all.byId[state.flows.selected[0]] }), dispatch => ({ selectFlow: flowId => dispatch(selectFlow(flowId)), setFilter: filter => dispatch(setFilter(filter)), + setSort: (sort) => dispatch(setSort(sort)), setHighlight: highlight => dispatch(setHighlight(highlight)) }), undefined, diff --git a/web/src/js/ducks/flows.js b/web/src/js/ducks/flows.js index fdbc42ee1..bde531790 100644 --- a/web/src/js/ducks/flows.js +++ b/web/src/js/ducks/flows.js @@ -5,6 +5,7 @@ import {updateViewFilter, updateViewList} from "./utils/view" export const UPDATE_FLOWS = "UPDATE_FLOWS" export const SET_FILTER = "SET_FLOW_FILTER" export const SET_HIGHLIGHT = "SET_FLOW_HIGHLIGHT" +export const SET_SORT = "SET_FLOW_SORT" export const SELECT_FLOW = "SELECT_FLOW" const { @@ -20,6 +21,7 @@ const defaultState = { view: [], filter: undefined, highlight: undefined, + sort: {sortColumn: undefined, sortDesc: false}, } function makeFilterFn(filter) { @@ -46,6 +48,11 @@ export default function reducer(state = defaultState, action) { ...state, highlight: action.highlight } + case SET_SORT: + return { + ...state, + sort: action.sort + } case SELECT_FLOW: return { ...state, @@ -69,6 +76,12 @@ export function setHighlight(highlight) { highlight } } +export function setSort(sort){ + return { + type: SET_SORT, + sort + } +} export function selectFlow(flowId) { return { type: SELECT_FLOW, From ff2129773fba4cbcaca93f2c604a2fa72955868f Mon Sep 17 00:00:00 2001 From: Clemens Date: Tue, 7 Jun 2016 00:17:09 +0200 Subject: [PATCH 2/6] start with sort, continue tomorrow --- mitmproxy/web/static/app.js | 41 ++++++++---------------------- web/src/js/components/flowtable.js | 5 ++-- web/src/js/components/mainview.js | 4 --- 3 files changed, 14 insertions(+), 36 deletions(-) diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js index b46e24322..ccf4eba98 100644 --- a/mitmproxy/web/static/app.js +++ b/mitmproxy/web/static/app.js @@ -1536,28 +1536,13 @@ function FlowTableHead(_ref2) { var sort = _ref2.sort; - //const hasSort = Column.sortKeyFun; - - // let sortDesc = this.props.sort.sortDesc; - // - // if (Column === this.props.sort.sortColumn) { - // sortDesc = !sortDesc; - // this.props.setSort(sortColumn, sortDesc); - // } else { - // this.props.setSort({sortColumn: hasSort && Column, sortDesc: false}); - // } - // - // 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); + /* function () { + const k = Column.sortKeyFun.apply(this, arguments); + if (_.isString(k)) { + return reverseString("" + k); + } + return -k; + };*/ var sortColumn = sort.sortColumn; var sortType = sort.sortDesc ? "sort-desc" : "sort-asc"; @@ -1583,7 +1568,7 @@ FlowTableHead.propTypes = { columns: _react2.default.PropTypes.array.isRequired }; -var FlowTableHeadContainer = (0, _reactRedux.connect)(function (state, ownProps) { +var FlowTableHeadContainer = (0, _reactRedux.connect)(function (state) { return { sort: state.flows.sort }; @@ -1730,7 +1715,9 @@ var parseFilter = _lodash2.default.memoize(_filt2.default.parse); var FlowTableContainer = (0, _reactRedux.connect)(function (state) { return { - flows: state.flows.view + flows: state.flows.view.sort(function (a, b) { + return state.flows.sort.sortColumn ? a.response.status_code > b.response.status_code : 0; + }) }; })(FlowTable); @@ -3801,9 +3788,6 @@ var MainView = _react2.default.createClass({ this.props.setHighlight(nextProps.location.query[_actions.Query.HIGHLIGHT], false); } }, - setSortKeyFun: function setSortKeyFun(sortKeyFun) { - // FIXME: Move to redux. This requires that sortKeyFun is not a function anymore. - }, selectFlow: function selectFlow(flow) { // TODO: This belongs into redux if (flow) { @@ -3934,9 +3918,6 @@ var MainView = _react2.default.createClass({ { className: "main-view" }, _react2.default.createElement(_flowtable2.default, { ref: "flowTable", selectFlow: this.selectFlow, - setSortKeyFun: function setSortKeyFun(f) { - return console.log("asdf"); - }, setSort: this.props.setSort, selected: this.props.selectedFlow }), details diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js index 642ded17f..89bcfc39c 100644 --- a/web/src/js/components/flowtable.js +++ b/web/src/js/components/flowtable.js @@ -94,7 +94,7 @@ FlowTableHead.propTypes = { }; const FlowTableHeadContainer = connect( - (state, ownProps) => ({ + (state) => ({ sort: state.flows.sort }) )(FlowTableHead) @@ -215,7 +215,8 @@ const parseFilter = _.memoize(Filt.parse) const FlowTableContainer = connect( state => ({ - flows: state.flows.view, + // first idea to sort here, but i think thats not good enough ( and not working yet)... + flows: state.flows.view.sort((a,b) => state.flows.sort.sortColumn ? a.response.status_code > b.response.status_code : 0), }) )(FlowTable) diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js index 99cdeb3ca..5237bddbd 100644 --- a/web/src/js/components/mainview.js +++ b/web/src/js/components/mainview.js @@ -23,9 +23,6 @@ var MainView = React.createClass({ this.props.setHighlight(nextProps.location.query[Query.HIGHLIGHT], false) } }, - setSortKeyFun: function (sortKeyFun) { - // FIXME: Move to redux. This requires that sortKeyFun is not a function anymore. - }, selectFlow: function (flow) { // TODO: This belongs into redux if (flow) { @@ -161,7 +158,6 @@ var MainView = React.createClass({
console.log("asdf")} setSort={this.props.setSort} selected={this.props.selectedFlow} /> {details} From 1aac283e2309339877907d2e08e79a06fbea1898 Mon Sep 17 00:00:00 2001 From: Clemens Date: Tue, 7 Jun 2016 00:40:36 +0200 Subject: [PATCH 3/6] moved redux state injection closer to child --- mitmproxy/web/static/app.js | 44 ++++++++++++++++++++++-------- web/src/js/components/flowtable.js | 6 +++- web/src/js/components/mainview.js | 4 +-- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js index ccf4eba98..a214d2aa7 100644 --- a/mitmproxy/web/static/app.js +++ b/mitmproxy/web/static/app.js @@ -1479,6 +1479,8 @@ var _filt = require("../filt/filt"); var _filt2 = _interopRequireDefault(_filt); +var _flows = require("../ducks/flows"); + 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"); } } @@ -1536,13 +1538,28 @@ function FlowTableHead(_ref2) { var sort = _ref2.sort; - /* function () { - const k = Column.sortKeyFun.apply(this, arguments); - if (_.isString(k)) { - return reverseString("" + k); - } - return -k; - };*/ + //const hasSort = Column.sortKeyFun; + + // let sortDesc = this.props.sort.sortDesc; + // + // if (Column === this.props.sort.sortColumn) { + // sortDesc = !sortDesc; + // this.props.setSort(sortColumn, sortDesc); + // } else { + // this.props.setSort({sortColumn: hasSort && Column, sortDesc: false}); + // } + // + // 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); var sortColumn = sort.sortColumn; var sortType = sort.sortDesc ? "sort-desc" : "sort-asc"; @@ -1572,6 +1589,12 @@ var FlowTableHeadContainer = (0, _reactRedux.connect)(function (state) { return { sort: state.flows.sort }; +}, function (dispatch) { + return { + setSort: function setSort(sort) { + return dispatch((0, _flows.setSort)(sort)); + } + }; })(FlowTableHead); var FlowTable = function (_React$Component) { @@ -1715,6 +1738,7 @@ var parseFilter = _lodash2.default.memoize(_filt2.default.parse); var FlowTableContainer = (0, _reactRedux.connect)(function (state) { return { + // first idea to sort here, but i think thats not good enough ( and not working yet)... flows: state.flows.view.sort(function (a, b) { return state.flows.sort.sortColumn ? a.response.status_code > b.response.status_code : 0; }) @@ -1723,7 +1747,7 @@ var FlowTableContainer = (0, _reactRedux.connect)(function (state) { exports.default = FlowTableContainer; -},{"../filt/filt":29,"../utils.js":32,"./flowtable-columns.js":7,"./helpers/AutoScroll":16,"./helpers/VirtualScroll":17,"classnames":"classnames","lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux","shallowequal":"shallowequal"}],9:[function(require,module,exports){ +},{"../ducks/flows":24,"../filt/filt":29,"../utils.js":32,"./flowtable-columns.js":7,"./helpers/AutoScroll":16,"./helpers/VirtualScroll":17,"classnames":"classnames","lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux","shallowequal":"shallowequal"}],9:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { @@ -3918,7 +3942,6 @@ var MainView = _react2.default.createClass({ { className: "main-view" }, _react2.default.createElement(_flowtable2.default, { ref: "flowTable", selectFlow: this.selectFlow, - setSort: this.props.setSort, selected: this.props.selectedFlow }), details ); @@ -3941,9 +3964,6 @@ var MainViewContainer = (0, _reactRedux.connect)(function (state) { setFilter: function setFilter(filter) { return dispatch((0, _flows.setFilter)(filter)); }, - setSort: function setSort(sort) { - return dispatch((0, _flows.setSort)(sort)); - }, setHighlight: function setHighlight(highlight) { return dispatch((0, _flows.setHighlight)(highlight)); } diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js index 89bcfc39c..234698271 100644 --- a/web/src/js/components/flowtable.js +++ b/web/src/js/components/flowtable.js @@ -9,6 +9,7 @@ import AutoScroll from "./helpers/AutoScroll"; import {calcVScroll} from "./helpers/VirtualScroll"; import flowtable_columns from "./flowtable-columns.js"; import Filt from "../filt/filt"; +import {setSort} from "../ducks/flows"; FlowRow.propTypes = { @@ -94,8 +95,11 @@ FlowTableHead.propTypes = { }; const FlowTableHeadContainer = connect( - (state) => ({ + state => ({ sort: state.flows.sort + }), + dispatch => ({ + loc: (sort) => dispatch(setSort(sort)), }) )(FlowTableHead) diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js index 5237bddbd..dae2856e7 100644 --- a/web/src/js/components/mainview.js +++ b/web/src/js/components/mainview.js @@ -7,7 +7,7 @@ import {Splitter} from "./common.js" import FlowTable from "./flowtable.js"; import FlowView from "./flowview/index.js"; import {connect} from 'react-redux' -import {selectFlow, setFilter, setHighlight, setSort} from "../ducks/flows"; +import {selectFlow, setFilter, setHighlight} from "../ducks/flows"; var MainView = React.createClass({ @@ -158,7 +158,6 @@ var MainView = React.createClass({
{details}
@@ -177,7 +176,6 @@ const MainViewContainer = connect( dispatch => ({ selectFlow: flowId => dispatch(selectFlow(flowId)), setFilter: filter => dispatch(setFilter(filter)), - setSort: (sort) => dispatch(setSort(sort)), setHighlight: highlight => dispatch(setHighlight(highlight)) }), undefined, From fa3ad2382bd13a76b38e1567d82636d349708371 Mon Sep 17 00:00:00 2001 From: Clemens Date: Tue, 7 Jun 2016 11:02:46 +0200 Subject: [PATCH 4/6] sorting done, ready to review --- mitmproxy/web/static/app.js | 70 ++++++++++++++---------------- web/src/js/components/flowtable.js | 30 +------------ web/src/js/ducks/flows.js | 26 +++++++++-- web/src/js/ducks/utils/view.js | 4 +- 4 files changed, 58 insertions(+), 72 deletions(-) diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js index a214d2aa7..e1f877365 100644 --- a/mitmproxy/web/static/app.js +++ b/mitmproxy/web/static/app.js @@ -1455,8 +1455,6 @@ var _classnames = require("classnames"); var _classnames2 = _interopRequireDefault(_classnames); -var _utils = require("../utils.js"); - var _lodash = require("lodash"); var _lodash2 = _interopRequireDefault(_lodash); @@ -1537,30 +1535,6 @@ function FlowTableHead(_ref2) { var columns = _ref2.columns; var sort = _ref2.sort; - - //const hasSort = Column.sortKeyFun; - - // let sortDesc = this.props.sort.sortDesc; - // - // if (Column === this.props.sort.sortColumn) { - // sortDesc = !sortDesc; - // this.props.setSort(sortColumn, sortDesc); - // } else { - // this.props.setSort({sortColumn: hasSort && Column, sortDesc: false}); - // } - // - // 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); - var sortColumn = sort.sortColumn; var sortType = sort.sortDesc ? "sort-desc" : "sort-asc"; @@ -1738,16 +1712,13 @@ var parseFilter = _lodash2.default.memoize(_filt2.default.parse); var FlowTableContainer = (0, _reactRedux.connect)(function (state) { return { - // first idea to sort here, but i think thats not good enough ( and not working yet)... - flows: state.flows.view.sort(function (a, b) { - return state.flows.sort.sortColumn ? a.response.status_code > b.response.status_code : 0; - }) + flows: state.flows.view }; })(FlowTable); exports.default = FlowTableContainer; -},{"../ducks/flows":24,"../filt/filt":29,"../utils.js":32,"./flowtable-columns.js":7,"./helpers/AutoScroll":16,"./helpers/VirtualScroll":17,"classnames":"classnames","lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux","shallowequal":"shallowequal"}],9:[function(require,module,exports){ +},{"../ducks/flows":24,"../filt/filt":29,"./flowtable-columns.js":7,"./helpers/AutoScroll":16,"./helpers/VirtualScroll":17,"classnames":"classnames","lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux","shallowequal":"shallowequal"}],9:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { @@ -4514,6 +4485,12 @@ var _filt2 = _interopRequireDefault(_filt); var _view = require("./utils/view"); +var _utils = require("../utils.js"); + +var _flowtableColumns = require("../components/flowtable-columns.js"); + +var _flowtableColumns2 = _interopRequireDefault(_flowtableColumns); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var UPDATE_FLOWS = exports.UPDATE_FLOWS = "UPDATE_FLOWS"; @@ -4544,6 +4521,22 @@ function makeFilterFn(filter) { }; } +function makeSortFn(sort) { + var column = _.find(_flowtableColumns2.default, function (c) { + return c.name == sort.sortColumn; + }); + if (!column) return; + + var sortKeyFun = column.sortKeyFun; + if (sort.sortDesc) { + sortKeyFun = function sortKeyFun() { + var k = column.sortKeyFun.apply(this, arguments); + return _.isString(k) ? (0, _utils.reverseString)("" + k) : -k; + }; + } + return sortKeyFun; +} + function reducer() { var state = arguments.length <= 0 || arguments[0] === undefined ? defaultState : arguments[0]; var action = arguments[1]; @@ -4553,12 +4546,12 @@ function reducer() { var all = reduceList(state.all, action); return _extends({}, state, { all: all, - view: (0, _view.updateViewList)(state.view, state.all, all, action, makeFilterFn(action.filter)) + view: (0, _view.updateViewList)(state.view, state.all, all, action, makeFilterFn(action.filter), makeSortFn(state.sort)) }); case SET_FILTER: return _extends({}, state, { filter: action.filter, - view: (0, _view.updateViewFilter)(state.all, makeFilterFn(action.filter)) + view: (0, _view.updateViewFilterSort)(state.all, makeFilterFn(action.filter), makeSortFn(state.sort)) }); case SET_HIGHLIGHT: return _extends({}, state, { @@ -4566,7 +4559,8 @@ function reducer() { }); case SET_SORT: return _extends({}, state, { - sort: action.sort + sort: action.sort, + view: (0, _view.updateViewFilterSort)(state.all, makeFilterFn(state.filter), makeSortFn(action.sort)) }); case SELECT_FLOW: return _extends({}, state, { @@ -4605,7 +4599,7 @@ function selectFlow(flowId) { exports.updateFlows = updateList; exports.fetchFlows = fetchList; -},{"../filt/filt":29,"./utils/list":26,"./utils/view":27}],25:[function(require,module,exports){ +},{"../components/flowtable-columns.js":7,"../filt/filt":29,"../utils.js":32,"./utils/list":26,"./utils/view":27}],25:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, "__esModule", { @@ -4849,7 +4843,7 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol exports.sortedIndexOf = sortedIndexOf; exports.updateViewList = updateViewList; -exports.updateViewFilter = updateViewFilter; +exports.updateViewFilterSort = updateViewFilterSort; var _list = require("./list"); @@ -4945,7 +4939,7 @@ function updateViewList(currentView, currentList, nextList, action) { case _list.REQUEST_LIST: return currentView; case _list.RECEIVE_LIST: - return updateViewFilter(nextList, filterFn, sortFn); + return updateViewFilterSort(nextList, filterFn, sortFn); case _list.ADD: if (filterFn(action.item)) { return sortedInsert(currentView, sortFn, action.item); @@ -4988,7 +4982,7 @@ function updateViewList(currentView, currentList, nextList, action) { } } -function updateViewFilter(list) { +function updateViewFilterSort(list) { var filterFn = arguments.length <= 1 || arguments[1] === undefined ? defaultFilterFn : arguments[1]; var sortFn = arguments.length <= 2 || arguments[2] === undefined ? defaultSortFn : arguments[2]; diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js index 234698271..5a0793bac 100644 --- a/web/src/js/components/flowtable.js +++ b/web/src/js/components/flowtable.js @@ -2,7 +2,6 @@ import React from "react"; import ReactDOM from "react-dom"; import {connect} from 'react-redux' import classNames from "classnames"; -import {reverseString} from "../utils.js"; import _ from "lodash"; import shallowEqual from "shallowequal"; import AutoScroll from "./helpers/AutoScroll"; @@ -48,30 +47,6 @@ const FlowRowContainer = connect( )(FlowRow) function FlowTableHead({setSort, columns, sort}) { - - //const hasSort = Column.sortKeyFun; - - // let sortDesc = this.props.sort.sortDesc; - // - // if (Column === this.props.sort.sortColumn) { - // sortDesc = !sortDesc; - // this.props.setSort(sortColumn, sortDesc); - // } else { - // this.props.setSort({sortColumn: hasSort && Column, sortDesc: false}); - // } - // - // 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); - const sortColumn = sort.sortColumn; const sortType = sort.sortDesc ? "sort-desc" : "sort-asc"; @@ -99,7 +74,7 @@ const FlowTableHeadContainer = connect( sort: state.flows.sort }), dispatch => ({ - loc: (sort) => dispatch(setSort(sort)), + setSort: (sort) => dispatch(setSort(sort)), }) )(FlowTableHead) @@ -219,8 +194,7 @@ const parseFilter = _.memoize(Filt.parse) const FlowTableContainer = connect( state => ({ - // first idea to sort here, but i think thats not good enough ( and not working yet)... - flows: state.flows.view.sort((a,b) => state.flows.sort.sortColumn ? a.response.status_code > b.response.status_code : 0), + flows: state.flows.view }) )(FlowTable) diff --git a/web/src/js/ducks/flows.js b/web/src/js/ducks/flows.js index bde531790..c4444a9ff 100644 --- a/web/src/js/ducks/flows.js +++ b/web/src/js/ducks/flows.js @@ -1,6 +1,8 @@ import makeList from "./utils/list" import Filt from "../filt/filt" -import {updateViewFilter, updateViewList} from "./utils/view" +import {updateViewFilterSort, updateViewList} from "./utils/view" +import {reverseString} from "../utils.js"; +import flowtable_columns from "../components/flowtable-columns.js"; export const UPDATE_FLOWS = "UPDATE_FLOWS" export const SET_FILTER = "SET_FLOW_FILTER" @@ -28,6 +30,21 @@ function makeFilterFn(filter) { return filter ? Filt.parse(filter) : () => true; } + +function makeSortFn(sort){ + let column = _.find(flowtable_columns, c => c.name == sort.sortColumn); + if (!column) return; + + let sortKeyFun = column.sortKeyFun; + if (sort.sortDesc) { + sortKeyFun = function () { + const k = column.sortKeyFun.apply(this, arguments); + return _.isString(k) ? reverseString("" + k) : -k; + }; + } + return sortKeyFun; +} + export default function reducer(state = defaultState, action) { switch (action.type) { case UPDATE_FLOWS: @@ -35,13 +52,13 @@ export default function reducer(state = defaultState, action) { return { ...state, all, - view: updateViewList(state.view, state.all, all, action, makeFilterFn(action.filter)) + view: updateViewList(state.view, state.all, all, action, makeFilterFn(action.filter), makeSortFn(state.sort)) } case SET_FILTER: return { ...state, filter: action.filter, - view: updateViewFilter(state.all, makeFilterFn(action.filter)) + view: updateViewFilterSort(state.all, makeFilterFn(action.filter), makeSortFn(state.sort)) } case SET_HIGHLIGHT: return { @@ -51,7 +68,8 @@ export default function reducer(state = defaultState, action) { case SET_SORT: return { ...state, - sort: action.sort + sort: action.sort, + view: updateViewFilterSort(state.all, makeFilterFn(state.filter), makeSortFn(action.sort)) } case SELECT_FLOW: return { diff --git a/web/src/js/ducks/utils/view.js b/web/src/js/ducks/utils/view.js index fa23efcd2..712c4d99a 100644 --- a/web/src/js/ducks/utils/view.js +++ b/web/src/js/ducks/utils/view.js @@ -75,7 +75,7 @@ export function updateViewList(currentView, currentList, nextList, action, filte case REQUEST_LIST: return currentView case RECEIVE_LIST: - return updateViewFilter(nextList, filterFn, sortFn) + return updateViewFilterSort(nextList, filterFn, sortFn) case ADD: if (filterFn(action.item)) { return sortedInsert(currentView, sortFn, action.item) @@ -113,7 +113,7 @@ export function updateViewList(currentView, currentList, nextList, action, filte } } -export function updateViewFilter(list, filterFn = defaultFilterFn, sortFn = defaultSortFn) { +export function updateViewFilterSort(list, filterFn = defaultFilterFn, sortFn = defaultSortFn) { let filtered = list.list.filter(filterFn) if (sortFn){ filtered.sort(makeCompareFn(sortFn)) From dbbda030200e50768c92f48cf4189d96775b0684 Mon Sep 17 00:00:00 2001 From: Clemens Date: Tue, 7 Jun 2016 11:22:52 +0200 Subject: [PATCH 5/6] sorting done, ready to review --- mitmproxy/web/static/app.js | 10 ++++------ web/src/js/ducks/flows.js | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js index e1f877365..7d6f5ce0a 100644 --- a/mitmproxy/web/static/app.js +++ b/mitmproxy/web/static/app.js @@ -4900,12 +4900,10 @@ var sortedRemove = function sortedRemove(list, sortFn, item) { }; function sortedIndexOf(list, value, sortFn) { - if (sortFn === false) { - var i = 0; - while (i < list.length && list[i].id !== value.id) { - i++; - } - return i; + if (!sortFn) { + sortFn = function sortFn(x) { + return 0; + }; // This triggers the linear search for flows that have the same sort value. } var low = 0, diff --git a/web/src/js/ducks/flows.js b/web/src/js/ducks/flows.js index c4444a9ff..83a7b12c1 100644 --- a/web/src/js/ducks/flows.js +++ b/web/src/js/ducks/flows.js @@ -37,7 +37,7 @@ function makeSortFn(sort){ let sortKeyFun = column.sortKeyFun; if (sort.sortDesc) { - sortKeyFun = function () { + sortKeyFun = sortKeyFun && function () { const k = column.sortKeyFun.apply(this, arguments); return _.isString(k) ? reverseString("" + k) : -k; }; From ad84d650ded555213452e4a69c1dbea1bc771b3a Mon Sep 17 00:00:00 2001 From: Clemens Date: Wed, 8 Jun 2016 10:29:33 +0200 Subject: [PATCH 6/6] sorting add pr review changes --- mitmproxy/web/static/app.js | 46 ++++++++++++++++------ web/src/js/components/flowtable-columns.js | 14 +++---- web/src/js/components/mainview.js | 1 - web/src/js/ducks/flows.js | 14 +++---- web/src/js/ducks/utils/view.js | 14 ++++++- 5 files changed, 60 insertions(+), 29 deletions(-) diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js index 7d6f5ce0a..fb591e318 100644 --- a/mitmproxy/web/static/app.js +++ b/mitmproxy/web/static/app.js @@ -1202,6 +1202,14 @@ Object.defineProperty(exports, "__esModule", { var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +exports.TLSColumn = TLSColumn; +exports.IconColumn = IconColumn; +exports.PathColumn = PathColumn; +exports.MethodColumn = MethodColumn; +exports.StatusColumn = StatusColumn; +exports.SizeColumn = SizeColumn; +exports.TimeColumn = TimeColumn; + var _react = require("react"); var _react2 = _interopRequireDefault(_react); @@ -3923,7 +3931,6 @@ var MainViewContainer = (0, _reactRedux.connect)(function (state) { return { flows: state.flows.view, filter: state.flows.filter, - sort: state.flows.sort, highlight: state.flows.highlight, selectedFlow: state.flows.all.byId[state.flows.selected[0]] }; @@ -4489,7 +4496,9 @@ var _utils = require("../utils.js"); var _flowtableColumns = require("../components/flowtable-columns.js"); -var _flowtableColumns2 = _interopRequireDefault(_flowtableColumns); +var flow_table_columns = _interopRequireWildcard(_flowtableColumns); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -4522,15 +4531,13 @@ function makeFilterFn(filter) { } function makeSortFn(sort) { - var column = _.find(_flowtableColumns2.default, function (c) { - return c.name == sort.sortColumn; - }); + var column = flow_table_columns[sort.sortColumn]; if (!column) return; var sortKeyFun = column.sortKeyFun; if (sort.sortDesc) { - sortKeyFun = function sortKeyFun() { - var k = column.sortKeyFun.apply(this, arguments); + sortKeyFun = sortKeyFun && function (flow) { + var k = column.sortKeyFun(flow); return _.isString(k) ? (0, _utils.reverseString)("" + k) : -k; }; } @@ -4551,7 +4558,7 @@ function reducer() { case SET_FILTER: return _extends({}, state, { filter: action.filter, - view: (0, _view.updateViewFilterSort)(state.all, makeFilterFn(action.filter), makeSortFn(state.sort)) + view: (0, _view.updateViewFilter)(state.all, makeFilterFn(action.filter), makeSortFn(state.sort)) }); case SET_HIGHLIGHT: return _extends({}, state, { @@ -4560,7 +4567,7 @@ function reducer() { case SET_SORT: return _extends({}, state, { sort: action.sort, - view: (0, _view.updateViewFilterSort)(state.all, makeFilterFn(state.filter), makeSortFn(action.sort)) + view: (0, _view.updateViewSort)(state.view, makeSortFn(action.sort)) }); case SELECT_FLOW: return _extends({}, state, { @@ -4843,7 +4850,8 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol exports.sortedIndexOf = sortedIndexOf; exports.updateViewList = updateViewList; -exports.updateViewFilterSort = updateViewFilterSort; +exports.updateViewFilter = updateViewFilter; +exports.updateViewSort = updateViewSort; var _list = require("./list"); @@ -4937,7 +4945,7 @@ function updateViewList(currentView, currentList, nextList, action) { case _list.REQUEST_LIST: return currentView; case _list.RECEIVE_LIST: - return updateViewFilterSort(nextList, filterFn, sortFn); + return updateViewFilter(nextList, filterFn, sortFn); case _list.ADD: if (filterFn(action.item)) { return sortedInsert(currentView, sortFn, action.item); @@ -4980,7 +4988,7 @@ function updateViewList(currentView, currentList, nextList, action) { } } -function updateViewFilterSort(list) { +function updateViewFilter(list) { var filterFn = arguments.length <= 1 || arguments[1] === undefined ? defaultFilterFn : arguments[1]; var sortFn = arguments.length <= 2 || arguments[2] === undefined ? defaultSortFn : arguments[2]; @@ -4995,6 +5003,20 @@ function updateViewFilterSort(list) { return filtered; } +function updateViewSort(list) { + var sortFn = arguments.length <= 1 || arguments[1] === undefined ? defaultSortFn : arguments[1]; + + var sorted = list.slice(0); + if (sortFn) { + sorted.sort(makeCompareFn(sortFn)); + } + sorted.indexOf = function (x) { + return sortedIndexOf(sorted, x, sortFn); + }; + + return sorted; +} + },{"./list":26}],28:[function(require,module,exports){ 'use strict'; diff --git a/web/src/js/components/flowtable-columns.js b/web/src/js/components/flowtable-columns.js index 1eae64098..799b3f9f6 100644 --- a/web/src/js/components/flowtable-columns.js +++ b/web/src/js/components/flowtable-columns.js @@ -3,7 +3,7 @@ import {RequestUtils, ResponseUtils} from "../flow/utils.js" import {formatSize, formatTimeDelta} from "../utils.js" -function TLSColumn({flow}) { +export function TLSColumn({flow}) { let ssl = (flow.request.scheme === "https") let classes if (ssl) { @@ -17,7 +17,7 @@ TLSColumn.Title = ({className = "", ...props}) =>
-function PathColumn({flow}) { +export function PathColumn({flow}) { return } MethodColumn.Title = ({className = "", ...props}) => @@ -69,7 +69,7 @@ MethodColumn.Title = ({className = "", ...props}) => MethodColumn.sortKeyFun = flow => flow.request.method -function StatusColumn({flow}) { +export function StatusColumn({flow}) { let status if (flow.response) { status = flow.response.status_code @@ -84,7 +84,7 @@ StatusColumn.Title = ({className = "", ...props}) => StatusColumn.sortKeyFun = flow => flow.response ? flow.response.status_code : undefined -function SizeColumn({flow}) { +export function SizeColumn({flow}) { let total = flow.request.contentLength if (flow.response) { total += flow.response.contentLength || 0 @@ -104,7 +104,7 @@ SizeColumn.sortKeyFun = flow => { } -function TimeColumn({flow}) { +export function TimeColumn({flow}) { let time if (flow.response) { time = formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start)) diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js index dae2856e7..5915c9fcd 100644 --- a/web/src/js/components/mainview.js +++ b/web/src/js/components/mainview.js @@ -169,7 +169,6 @@ const MainViewContainer = connect( state => ({ flows: state.flows.view, filter: state.flows.filter, - sort: state.flows.sort, highlight: state.flows.highlight, selectedFlow: state.flows.all.byId[state.flows.selected[0]] }), diff --git a/web/src/js/ducks/flows.js b/web/src/js/ducks/flows.js index 83a7b12c1..6adde71c4 100644 --- a/web/src/js/ducks/flows.js +++ b/web/src/js/ducks/flows.js @@ -1,8 +1,8 @@ import makeList from "./utils/list" import Filt from "../filt/filt" -import {updateViewFilterSort, updateViewList} from "./utils/view" +import {updateViewFilter, updateViewList, updateViewSort} from "./utils/view" import {reverseString} from "../utils.js"; -import flowtable_columns from "../components/flowtable-columns.js"; +import * as flow_table_columns from "../components/flowtable-columns.js"; export const UPDATE_FLOWS = "UPDATE_FLOWS" export const SET_FILTER = "SET_FLOW_FILTER" @@ -32,13 +32,13 @@ function makeFilterFn(filter) { function makeSortFn(sort){ - let column = _.find(flowtable_columns, c => c.name == sort.sortColumn); + let column = flow_table_columns[sort.sortColumn]; if (!column) return; let sortKeyFun = column.sortKeyFun; if (sort.sortDesc) { - sortKeyFun = sortKeyFun && function () { - const k = column.sortKeyFun.apply(this, arguments); + sortKeyFun = sortKeyFun && function (flow) { + const k = column.sortKeyFun(flow); return _.isString(k) ? reverseString("" + k) : -k; }; } @@ -58,7 +58,7 @@ export default function reducer(state = defaultState, action) { return { ...state, filter: action.filter, - view: updateViewFilterSort(state.all, makeFilterFn(action.filter), makeSortFn(state.sort)) + view: updateViewFilter(state.all, makeFilterFn(action.filter), makeSortFn(state.sort)) } case SET_HIGHLIGHT: return { @@ -69,7 +69,7 @@ export default function reducer(state = defaultState, action) { return { ...state, sort: action.sort, - view: updateViewFilterSort(state.all, makeFilterFn(state.filter), makeSortFn(action.sort)) + view: updateViewSort(state.view, makeSortFn(action.sort)) } case SELECT_FLOW: return { diff --git a/web/src/js/ducks/utils/view.js b/web/src/js/ducks/utils/view.js index 712c4d99a..2d23a39ca 100644 --- a/web/src/js/ducks/utils/view.js +++ b/web/src/js/ducks/utils/view.js @@ -75,7 +75,7 @@ export function updateViewList(currentView, currentList, nextList, action, filte case REQUEST_LIST: return currentView case RECEIVE_LIST: - return updateViewFilterSort(nextList, filterFn, sortFn) + return updateViewFilter(nextList, filterFn, sortFn) case ADD: if (filterFn(action.item)) { return sortedInsert(currentView, sortFn, action.item) @@ -113,7 +113,7 @@ export function updateViewList(currentView, currentList, nextList, action, filte } } -export function updateViewFilterSort(list, filterFn = defaultFilterFn, sortFn = defaultSortFn) { +export function updateViewFilter(list, filterFn = defaultFilterFn, sortFn = defaultSortFn) { let filtered = list.list.filter(filterFn) if (sortFn){ filtered.sort(makeCompareFn(sortFn)) @@ -122,3 +122,13 @@ export function updateViewFilterSort(list, filterFn = defaultFilterFn, sortFn = return filtered } + +export function updateViewSort(list, sortFn = defaultSortFn) { + let sorted = list.slice(0) + if (sortFn) { + sorted.sort(makeCompareFn(sortFn)) + } + sorted.indexOf = x => sortedIndexOf(sorted, x, sortFn) + + return sorted +}
flow.request.scheme -function IconColumn({flow}) { +export function IconColumn({flow}) { let icon if (flow.response) { var contentType = ResponseUtils.getContentType(flow.response) @@ -49,7 +49,7 @@ function IconColumn({flow}) { IconColumn.Title = ({className = "", ...props}) => {flow.request.is_replay ? : null} {flow.intercepted ? : null} @@ -61,7 +61,7 @@ PathColumn.Title = ({className = "", ...props}) => PathColumn.sortKeyFun = flow => RequestUtils.pretty_url(flow.request) -function MethodColumn({flow}) { +export function MethodColumn({flow}) { return {flow.request.method}