diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e6049d5dc2..505a5f433bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Breaking changes * **SystemD**: Change systemd description, closes [#5971](https://github.com/grafana/grafana/pull/5971) +* **lodash upgrade**: Upgraded lodash from 2.4.2 to 4.15.0, this contains a number of breaking changes that could effect plugins. closes [#6021](https://github.com/grafana/grafana/pull/6021) ### Bugfixes * **Table Panel**: Fixed problem when switching to Mixed datasource in metrics tab, fixes [#5999](https://github.com/grafana/grafana/pull/5999) diff --git a/bower.json b/bower.json index 3cf8b427f19..47debfb092a 100644 --- a/bower.json +++ b/bower.json @@ -14,7 +14,7 @@ ], "dependencies": { "jquery": "3.1.0", - "lodash": "~4.15.0", + "lodash": "3.10.1", "angular": "1.5.3", "angular-route": "1.5.3", "angular-mocks": "1.5.3", diff --git a/public/app/core/components/query_part/query_part.ts b/public/app/core/components/query_part/query_part.ts index 90724f65d2d..fcd337a0a26 100644 --- a/public/app/core/components/query_part/query_part.ts +++ b/public/app/core/components/query_part/query_part.ts @@ -54,9 +54,9 @@ export class QueryPart { // handle optional parameters // if string contains ',' and next param is optional, split and update both if (this.hasMultipleParamsInString(strValue, index)) { - _.each(strValue.split(','), function(partVal: string, idx) { + _.each(strValue.split(','), (partVal, idx) => { this.updateParam(partVal.trim(), idx); - }, this); + }); return; } diff --git a/public/app/core/lodash_extended.js b/public/app/core/lodash_extended.js index 4edae35f02d..6487b19193e 100644 --- a/public/app/core/lodash_extended.js +++ b/public/app/core/lodash_extended.js @@ -19,7 +19,7 @@ function () { return variable === value ? alt : value; }, toggleInOut: function(array,value) { - if(_.contains(array,value)) { + if(_.includes(array,value)) { array = _.without(array,value); } else { array.push(value); diff --git a/public/app/features/dashboard/timeSrv.js b/public/app/features/dashboard/timeSrv.js index 5a140aeeeb3..ac163e4ad09 100644 --- a/public/app/features/dashboard/timeSrv.js +++ b/public/app/features/dashboard/timeSrv.js @@ -13,6 +13,9 @@ define([ module.service('timeSrv', function($rootScope, $timeout, $routeParams, timer) { var self = this; + // default time + this.time = {from: '6h', to: 'now'}; + $rootScope.$on('zoom-out', function(e, factor) { self.zoomOut(factor); }); this.init = function(dashboard) { diff --git a/public/app/plugins/datasource/cloudwatch/annotation_query.js b/public/app/plugins/datasource/cloudwatch/annotation_query.js index 46fbd3a87a9..20d04314e83 100644 --- a/public/app/plugins/datasource/cloudwatch/annotation_query.js +++ b/public/app/plugins/datasource/cloudwatch/annotation_query.js @@ -47,7 +47,7 @@ function (_) { var start = self.datasource.convertToCloudWatchTime(from, false); var end = self.datasource.convertToCloudWatchTime(to, true); _.chain(alarms) - .pluck('MetricAlarms') + .map('MetricAlarms') .flatten() .each(function(alarm) { if (!alarm) { @@ -70,7 +70,8 @@ function (_) { d.resolve(eventList); }); - }); + }) + .value(); }); return d.promise; @@ -91,7 +92,7 @@ function (_) { if (!_.isEmpty(dimensions) && !isSameDimensions) { return false; } - if (!_.isEmpty(statistics) && !_.contains(statistics, alarm.Statistic)) { + if (!_.isEmpty(statistics) && !_.includes(statistics, alarm.Statistic)) { return false; } if (!_.isNaN(period) && alarm.Period !== period) { diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index f4671fba596..d9fc6464491 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -23,7 +23,7 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) { var queries = []; options = angular.copy(options); - _.each(options.targets, _.bind(function(target) { + _.each(options.targets, function(target) { if (target.hide || !target.namespace || !target.metricName || _.isEmpty(target.statistics)) { return; } @@ -43,7 +43,7 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) { target.period = query.period; queries.push(query); - }, this)); + }.bind(this)); // No valid targets, return the empty result to save a round trip. if (_.isEmpty(queries)) { @@ -54,7 +54,7 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) { var allQueryPromise = _.map(queries, function(query) { return this.performTimeSeriesQuery(query, start, end); - }, this); + }.bind(this)); return $q.all(allQueryPromise).then(function(allResponse) { var result = []; @@ -64,7 +64,7 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) { result = result.concat(metrics); }); - return { data: result }; + return {data: result}; }); }; @@ -125,12 +125,12 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) { return this.awsRequest(request).then(function(result) { return _.chain(result.Metrics) - .pluck('Dimensions') + .map('Dimensions') .flatten() .filter(function(dimension) { return dimension !== null && dimension.Name === dimensionKey; }) - .pluck('Value') + .map('Value') .uniq() .sortBy() .map(function(value) { @@ -295,15 +295,19 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) { namespace: templateSrv.replace(options.namespace, scopedVars), metric: templateSrv.replace(options.metricName, scopedVars), }; + var aliasDimensions = {}; + _.each(_.keys(options.dimensions), function(origKey) { var key = templateSrv.replace(origKey, scopedVars); var value = templateSrv.replace(options.dimensions[origKey], scopedVars); aliasDimensions[key] = value; }); + _.extend(aliasData, aliasDimensions); var periodMs = options.period * 1000; + return _.map(options.statistics, function(stat) { var dps = []; var lastTimestamp = null; @@ -318,7 +322,8 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) { } lastTimestamp = timestamp; dps.push([dp[stat], timestamp]); - }); + }) + .value(); aliasData.stat = stat; var seriesName = aliasPattern.replace(aliasRegex, function(match, g1) { diff --git a/public/app/plugins/datasource/graphite/gfunc.js b/public/app/plugins/datasource/graphite/gfunc.js index d7b0601959a..17fd2d3ce08 100644 --- a/public/app/plugins/datasource/graphite/gfunc.js +++ b/public/app/plugins/datasource/graphite/gfunc.js @@ -688,7 +688,7 @@ function (_, $) { return "'" + value + "'"; - }, this); + }.bind(this)); if (metricExp) { parameters.unshift(metricExp); @@ -711,7 +711,7 @@ function (_, $) { if (this._hasMultipleParamsInString(strValue, index)) { _.each(strValue.split(','), function(partVal, idx) { this.updateParam(partVal.trim(), idx); - }, this); + }.bind(this)); return; } diff --git a/public/app/plugins/datasource/mixed/datasource.ts b/public/app/plugins/datasource/mixed/datasource.ts index b5cea9cc5a8..21fca3d1865 100644 --- a/public/app/plugins/datasource/mixed/datasource.ts +++ b/public/app/plugins/datasource/mixed/datasource.ts @@ -25,7 +25,7 @@ class MixedDatasource { }); return this.$q.all(promises).then(function(results) { - return { data: _.flatten(_.pluck(results, 'data')) }; + return { data: _.flatten(_.map(results, 'data')) }; }); } } diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 8f9fceeba3e..53ce91144a4 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -58,7 +58,6 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS return escapedValues.join('|'); }; - var HTTP_REQUEST_ABORTED = -1; // Called once per panel (graph) this.query = function(options) { var self = this; @@ -69,10 +68,12 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS var activeTargets = []; options = _.clone(options); - _.each(options.targets, _.bind(function(target) { + + _.each(options.targets, target => { if (!target.expr || target.hide) { return; } + activeTargets.push(target); var query: any = {}; @@ -90,7 +91,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS } queries.push(query); - }, this)); + }); // No valid targets, return the empty result to save a round trip. if (_.isEmpty(queries)) { @@ -99,9 +100,9 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS return d.promise; } - var allQueryPromise = _.map(queries, _.bind(function(query) { + var allQueryPromise = _.map(queries, query => { return this.performTimeSeriesQuery(query, start, end); - }, this)); + }); return $q.all(allQueryPromise).then(function(allResponse) { var result = []; @@ -183,7 +184,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS _.each(results.data.data.result, function(series) { var tags = _.chain(series.metric) .filter(function(v, k) { - return _.contains(tagKeys, k); + return _.includes(tagKeys, k); }).value(); _.each(series.values, function(value) { @@ -273,7 +274,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS this.getOriginalMetricName = function(labelData) { var metricName = labelData.__name__ || ''; delete labelData.__name__; - var labelPart = _.map(_.pairs(labelData), function(label) { + var labelPart = _.map(_.toPairs(labelData), function(label) { return label[0] + '="' + label[1] + '"'; }).join(','); return metricName + '{' + labelPart + '}'; diff --git a/public/vendor/lodash/.bower.json b/public/vendor/lodash/.bower.json index e44aa263c4e..4d8d579679a 100644 --- a/public/vendor/lodash/.bower.json +++ b/public/vendor/lodash/.bower.json @@ -1,14 +1,30 @@ { "name": "lodash", + "main": "lodash.js", + "ignore": [ + ".*", + "*.custom.*", + "*.log", + "*.map", + "*.md", + "lodash.src.js", + "component.json", + "package.json", + "doc", + "node_modules", + "perf", + "test", + "vendor" + ], "homepage": "https://github.com/lodash/lodash", - "version": "4.15.0", - "_release": "4.15.0", + "version": "3.10.1", + "_release": "3.10.1", "_resolution": { "type": "version", - "tag": "4.15.0", - "commit": "e538563f2cf208980f24cda75ba21fabf939a604" + "tag": "3.10.1", + "commit": "ef20b4290cc4fe7551c82a552ea7ffa76548eec8" }, "_source": "https://github.com/lodash/lodash.git", - "_target": "~4.15.0", + "_target": "3.10.1", "_originalSource": "lodash" } \ No newline at end of file diff --git a/public/vendor/lodash/.editorconfig b/public/vendor/lodash/.editorconfig deleted file mode 100644 index b889a368c15..00000000000 --- a/public/vendor/lodash/.editorconfig +++ /dev/null @@ -1,12 +0,0 @@ -# This file is for unifying the coding style for different editors and IDEs -# editorconfig.org - -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_size = 2 -indent_style = space -insert_final_newline = true -trim_trailing_whitespace = true diff --git a/public/vendor/lodash/.gitattributes b/public/vendor/lodash/.gitattributes deleted file mode 100644 index 176a458f94e..00000000000 --- a/public/vendor/lodash/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto diff --git a/public/vendor/lodash/.github/CONTRIBUTING.md b/public/vendor/lodash/.github/CONTRIBUTING.md deleted file mode 100644 index eab6b8f744d..00000000000 --- a/public/vendor/lodash/.github/CONTRIBUTING.md +++ /dev/null @@ -1,78 +0,0 @@ -# Contributing to Lodash - -Contributions are always welcome. Before contributing please read the -[code of conduct](https://jquery.org/conduct/) & -[search the issue tracker](https://github.com/lodash/lodash/issues); your issue -may have already been discussed or fixed in `master`. To contribute, -[fork](https://help.github.com/articles/fork-a-repo/) Lodash, commit your changes, -& [send a pull request](https://help.github.com/articles/using-pull-requests/). - -## Feature Requests - -Feature requests should be submitted in the -[issue tracker](https://github.com/lodash/lodash/issues), with a description of -the expected behavior & use case, where they’ll remain closed until sufficient interest, -[e.g. :+1: reactions](https://help.github.com/articles/about-discussions-in-issues-and-pull-requests/), -has been [shown by the community](https://github.com/lodash/lodash/issues?q=label%3A%22votes+needed%22+sort%3Areactions-%2B1-desc). -Before submitting a request, please search for similar ones in the -[closed issues](https://github.com/lodash/lodash/issues?q=is%3Aissue+is%3Aclosed+label%3Aenhancement). - -## Pull Requests - -For additions or bug fixes you should only need to modify `lodash.js`. Include -updated unit tests in the `test` directory as part of your pull request. Don’t -worry about regenerating the `dist/` or `doc/` files. - -Before running the unit tests you’ll need to install, `npm i`, -[development dependencies](https://docs.npmjs.com/files/package.json#devdependencies). -Run unit tests from the command-line via `npm test`, or open `test/index.html` & -`test/fp.html` in a web browser. The [Backbone](http://backbonejs.org/) & -[Underscore](http://underscorejs.org/) test suites are included as well. - -## Contributor License Agreement - -Lodash is a member of the [jQuery Foundation](https://jquery.org/). -As such, we request that all contributors sign the jQuery Foundation -[contributor license agreement (CLA)](https://contribute.jquery.org/CLA/). - -For more information about CLAs, please check out Alex Russell’s excellent post, -[“Why Do I Need to Sign This?”](https://infrequently.org/2008/06/why-do-i-need-to-sign-this/). - -## Coding Guidelines - -In addition to the following guidelines, please follow the conventions already -established in the code. - -- **Spacing**:
- Use two spaces for indentation. No tabs. - -- **Naming**:
- Keep variable & method names concise & descriptive.
- Variable names `index`, `array`, & `iteratee` are preferable to - `i`, `arr`, & `fn`. - -- **Quotes**:
- Single-quoted strings are preferred to double-quoted strings; however, - please use a double-quoted string if the value contains a single-quote - character to avoid unnecessary escaping. - -- **Comments**:
- Please use single-line comments to annotate significant additions, & - [JSDoc-style](http://www.2ality.com/2011/08/jsdoc-intro.html) comments for - functions. - -Guidelines are enforced using [JSCS](https://www.npmjs.com/package/jscs): -```bash -$ npm run style -``` - -## Tips - -You can opt-in to a pre-push git hook by adding an `.opt-in` file to the root of -the project containing: -```txt -pre-push -``` - -With that, when you `git push`, the pre-push git hook will trigger and execute -`npm run validate`. diff --git a/public/vendor/lodash/.gitignore b/public/vendor/lodash/.gitignore deleted file mode 100644 index 89f8a6bf9d7..00000000000 --- a/public/vendor/lodash/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.DS_Store -*.log -doc/*.html -node_modules diff --git a/public/vendor/lodash/.jscsrc b/public/vendor/lodash/.jscsrc deleted file mode 100644 index 5f44ab8453d..00000000000 --- a/public/vendor/lodash/.jscsrc +++ /dev/null @@ -1,97 +0,0 @@ -{ - "maxErrors": "2000", - "maximumLineLength": { - "value": 180, - "allExcept": ["comments", "functionSignature", "regex"] - }, - "requireCurlyBraces": [ - "if", - "else", - "for", - "while", - "do", - "try", - "catch" - ], - "requireOperatorBeforeLineBreak": [ - "=", - "+", - "-", - "/", - "*", - "==", - "===", - "!=", - "!==", - ">", - ">=", - "<", - "<=" - ], - "requireSpaceAfterKeywords": [ - "if", - "else", - "for", - "while", - "do", - "switch", - "return", - "try", - "catch" - ], - "requireSpaceBeforeBinaryOperators": [ - "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", - "&=", "|=", "^=", "+=", - - "+", "-", "*", "/", "%", "<<", ">>", ">>>", "&", - "|", "^", "&&", "||", "===", "==", ">=", - "<=", "<", ">", "!=", "!==" - ], - "requireSpacesInFunctionExpression": { - "beforeOpeningCurlyBrace": true - }, - "requireCamelCaseOrUpperCaseIdentifiers": true, - "requireDotNotation": { "allExcept": ["keywords"] }, - "requireEarlyReturn": true, - "requireLineFeedAtFileEnd": true, - "requireSemicolons": true, - "requireSpaceAfterBinaryOperators": true, - "requireSpacesInConditionalExpression": true, - "requireSpaceBeforeObjectValues": true, - "requireSpaceBeforeBlockStatements": true, - "requireSpacesInForStatement": true, - - "validateIndentation": 2, - "validateParameterSeparator": ", ", - "validateQuoteMarks": { "mark": "'", "escape": true }, - - "disallowSpacesInAnonymousFunctionExpression": { - "beforeOpeningRoundBrace": true - }, - "disallowSpacesInFunctionDeclaration": { - "beforeOpeningRoundBrace": true - }, - "disallowSpacesInFunctionExpression": { - "beforeOpeningRoundBrace": true - }, - "disallowKeywords": ["with"], - "disallowMixedSpacesAndTabs": true, - "disallowMultipleLineBreaks": true, - "disallowNewlineBeforeBlockStatements": true, - "disallowSpaceAfterObjectKeys": true, - "disallowSpaceAfterPrefixUnaryOperators": true, - "disallowSpacesInCallExpression": true, - "disallowSpacesInsideArrayBrackets": true, - "disallowSpacesInsideParentheses": true, - "disallowTrailingWhitespace": true, - "disallowUnusedVariables": true, - - "jsDoc": { - "checkRedundantAccess": true, - "checkTypes": true, - "requireNewlineAfterDescription": true, - "requireParamDescription": true, - "requireParamTypes": true, - "requireReturnTypes": true - } -} diff --git a/public/vendor/lodash/.markdown-doctest-setup.js b/public/vendor/lodash/.markdown-doctest-setup.js deleted file mode 100644 index fc16ea65ec2..00000000000 --- a/public/vendor/lodash/.markdown-doctest-setup.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -delete global['__core-js_shared__']; - -var _ = require('./lodash.js'), - globals = require('lodash-doc-globals'); - -module.exports = { - 'babel': false, - 'globals': _.assign({ '_': _ }, globals) -}; diff --git a/public/vendor/lodash/.travis.yml b/public/vendor/lodash/.travis.yml deleted file mode 100644 index a22462c998a..00000000000 --- a/public/vendor/lodash/.travis.yml +++ /dev/null @@ -1,105 +0,0 @@ -language: node_js -sudo: false -node_js: - - "6" -cache: - directories: - - $HOME/.npm - - travis_phantomjs -env: - global: - - BIN="node" ISTANBUL=false OPTION="" - - SAUCE_LABS=false SAUCE_USERNAME="lodash" - - secure: "tg1JFsIFnxzLaTboFPOnm+aJCuMm5+JdhLlESlqg9x3fwro++7KCnwHKLNovhchaPe4otC43ZMB/nfWhDnDm11dKbm/V6HlTkED+dadTsaLxVDg6J+7yK41QhokBPJOxLV78iDaNaAQVYEirAgZ0yn8kFubxmNKV+bpCGQNc9yU=" - matrix: - - - - BIN="phantomjs" - - ISTANBUL=true - - SAUCE_LABS=true -matrix: - include: - - node_js: "0.10" - env: - - node_js: "0.12" - env: - - node_js: "4" - env: - - node_js: "5" - env: -git: - depth: 10 -branches: - only: - - master -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/4aab6358b0e9aed0b628 - on_success: change - on_failure: always -before_install: - # Upgrade PhantomJS to v2.1.1. - - "export PHANTOMJS_VERSION=2.1.1" - - "export PATH=$PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64/bin:$PATH" - - "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi" - - "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then wget https://github.com/Medium/phantomjs/releases/download/v$PHANTOMJS_VERSION/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2; fi" - - "if [ $(phantomjs --version) != $PHANTOMJS_VERSION ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-$PHANTOMJS_VERSION-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi" - - "phantomjs --version" - - # Use exact Node version. - - "nvm use $TRAVIS_NODE_VERSION" - - # Setup npm. - - "npm set loglevel error" - - "npm set progress false" - - "npm i -g npm@\"^2.0.0\"" - - # Remove code skipped on the coverage run. - - | - PATTERN[0]="|\s*if\s*\(isHostObject\b[\s\S]+?\}(?=\n)|" - PATTERN[1]="|\s*if\s*\(enumerate\b[\s\S]+?\};\s*\}|" - PATTERN[2]="|\s*while\s*\([^)]+\)\s*\{\s*iteratee\(index\);\s*\}|" - PATTERN[3]="|\s*else\s*\{\s*assocSet\(data\b[\s\S]+?\}|" - PATTERN[4]="|\bcase\s+(?:dataView|promise|set|map|weakMap)CtorString:.+|g" - PATTERN[5]="|\bindex,\s*iterable\)\s*===\s*false\)[^}]+?(break;)|" - PATTERN[6]="|\s*if\s*\(\!lodashFunc\)\s*\{\s*return;\s*\}|" - PATTERN[7]="|\s*define\([\s\S]+?\);|" - PATTERN[8]="|\s*root\._\s*=\s*_;|" - - if [ $ISTANBUL == true ]; then - set -e - for PTRN in ${PATTERN[@]}; do - node ./test/remove.js "$PTRN" ./lodash.js - done - fi - - # Use lodash-cli from GitHub. - - "git clone --depth=10 --branch=master git://github.com/lodash/lodash-cli ./node_modules/lodash-cli" - - "mkdir -p ./node_modules/lodash-cli/node_modules/lodash && cd $_ && cp ../../../../lodash.js ./lodash.js && cp ../../../../package.json ./package.json" - - "cd ../../ && npm i --production && cd ../../" - -script: - # Detect code coverage. - - "[ $ISTANBUL == false ] || istanbul cover -x \"**/vendor/**\" --report lcovonly ./test/test.js -- ./lodash.js" - - "[ $ISTANBUL == false ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || (cat ./coverage/lcov.info | coveralls) || true" - - "[ $ISTANBUL == false ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || (cat ./coverage/coverage.json | codecov) || true" - - # Test in Node.js and PhantomJS. - - "[ $ISTANBUL == true ] || node ./node_modules/lodash-cli/bin/lodash -o ./dist/lodash.js" - - "[ $ISTANBUL == true ] || (node ./node_modules/lodash-cli/bin/lodash modularize exports=node -o ./ && node ./node_modules/lodash-cli/bin/lodash -d -o ./lodash.js)" - - "[ $ISTANBUL == true ] || [ $SAUCE_LABS == true ] || cd ./test" - - "[ $ISTANBUL == true ] || [ $SAUCE_LABS == true ] || $BIN $OPTION ./test.js ../lodash.js" - - "[ $ISTANBUL == true ] || [ $SAUCE_LABS == true ] || [ $TRAVIS_SECURE_ENV_VARS == false ] || $BIN $OPTION ./test.js ../dist/lodash.min.js" - - # Test in Sauce Labs. - - "[ $SAUCE_LABS == false ] || node ./node_modules/lodash-cli/bin/lodash core -o ./dist/lodash.core.js" - - "[ $SAUCE_LABS == false ] || npm run build" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../dist/lodash.js&noglobals=true\" tags=\"development\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash tests\" runner=\"test/index.html?build=../dist/lodash.min.js&noglobals=true\" tags=\"production\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"lodash-fp tests\" runner=\"test/fp.html?noglobals=true\" tags=\"development\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../dist/lodash.js\" tags=\"development,underscore\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"underscore tests\" runner=\"test/underscore.html?build=../dist/lodash.min.js\" tags=\"production,underscore\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.js\" tags=\"development,backbone\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.min.js\" tags=\"production,backbone\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.core.js\" tags=\"development,backbone\"" - - "[ $SAUCE_LABS == false ] || $BIN ./test/saucelabs.js name=\"backbone tests\" runner=\"test/backbone.html?build=../dist/lodash.core.min.js\" tags=\"production,backbone\"" diff --git a/public/vendor/lodash/LICENSE b/public/vendor/lodash/LICENSE index e0c69d56032..9cd87e5dcef 100644 --- a/public/vendor/lodash/LICENSE +++ b/public/vendor/lodash/LICENSE @@ -1,17 +1,7 @@ -Copyright jQuery Foundation and other contributors - -Based on Underscore.js, copyright Jeremy Ashkenas, +Copyright 2012-2015 The Dojo Foundation +Based on Underscore.js, copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors -This software consists of voluntary contributions made by many -individuals. For exact contribution history, see the revision history -available at https://github.com/lodash/lodash - -The following license applies to all parts of this software except as -documented below: - -==== - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including @@ -30,18 +20,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -==== - -Copyright and related rights for sample code are waived via CC0. Sample -code is defined as all source code displayed within the prose of the -documentation. - -CC0: http://creativecommons.org/publicdomain/zero/1.0/ - -==== - -Files located in the node_modules and vendor directories are externally -maintained libraries used by this software which have their own -licenses; we recommend you read them, as their terms may differ from the -terms above. diff --git a/public/vendor/lodash/README.md b/public/vendor/lodash/README.md deleted file mode 100644 index d6159df3ef0..00000000000 --- a/public/vendor/lodash/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# lodash v4.15.0 - -[Site](https://lodash.com/) | -[Docs](https://lodash.com/docs) | -[FP Guide](https://github.com/lodash/lodash/wiki/FP-Guide) | -[Contributing](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md) | -[Wiki](https://github.com/lodash/lodash/wiki "Changelog, Roadmap, etc.") | -[Code of Conduct](https://jquery.org/conduct/) | -[Twitter](https://twitter.com/bestiejs) | -[Chat](https://gitter.im/lodash/lodash) - -The [Lodash](https://lodash.com/) library exported as a [UMD](https://github.com/umdjs/umd) module. - -Generated using [lodash-cli](https://www.npmjs.com/package/lodash-cli): -```bash -$ npm run build -$ lodash -o ./dist/lodash.js -$ lodash core -o ./dist/lodash.core.js -``` - -## Download - -Lodash is released under the [MIT license](https://raw.githubusercontent.com/lodash/lodash/4.15.0/LICENSE) & supports [modern environments](#support).
-Review the [build differences](https://github.com/lodash/lodash/wiki/build-differences) & pick one that’s right for you. - - * [Core build](https://raw.githubusercontent.com/lodash/lodash/4.15.0/dist/lodash.core.js) ([~4 kB gzipped](https://raw.githubusercontent.com/lodash/lodash/4.15.0/dist/lodash.core.min.js)) - * [Full build](https://raw.githubusercontent.com/lodash/lodash/4.15.0/dist/lodash.js) ([~23 kB gzipped](https://raw.githubusercontent.com/lodash/lodash/4.15.0/dist/lodash.min.js)) - * [CDN copies](https://www.jsdelivr.com/projects/lodash) - -## Why Lodash? - -Lodash makes JavaScript easier by taking the hassle out of working with arrays,
-numbers, objects, strings, etc. Lodash’s modular methods are great for: - -* Iterating arrays, objects, & strings -* Manipulating & testing values -* Creating composite functions - -## Module Formats - -Lodash is available in a [variety of builds](https://lodash.com/custom-builds) & module formats. - - * [lodash](https://www.npmjs.com/package/lodash) & [per method packages](https://www.npmjs.com/browse/keyword/lodash-modularized) - * [lodash-es](https://www.npmjs.com/package/lodash-es), [babel-plugin-lodash](https://www.npmjs.com/package/babel-plugin-lodash), & [lodash-webpack-plugin](https://www.npmjs.com/package/lodash-webpack-plugin) - * [lodash/fp](https://github.com/lodash/lodash/tree/npm/fp) - * [lodash-amd](https://www.npmjs.com/package/lodash-amd) diff --git a/public/vendor/lodash/bower.json b/public/vendor/lodash/bower.json new file mode 100644 index 00000000000..23c390577d1 --- /dev/null +++ b/public/vendor/lodash/bower.json @@ -0,0 +1,19 @@ +{ + "name": "lodash", + "main": "lodash.js", + "ignore": [ + ".*", + "*.custom.*", + "*.log", + "*.map", + "*.md", + "lodash.src.js", + "component.json", + "package.json", + "doc", + "node_modules", + "perf", + "test", + "vendor" + ] +} diff --git a/public/vendor/lodash/dist/lodash.core.js b/public/vendor/lodash/dist/lodash.core.js deleted file mode 100644 index de27977d22f..00000000000 --- a/public/vendor/lodash/dist/lodash.core.js +++ /dev/null @@ -1,3806 +0,0 @@ -/** - * @license - * lodash (Custom Build) - * Build: `lodash core -o ./dist/lodash.core.js` - * Copyright jQuery Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -;(function() { - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the semantic version number. */ - var VERSION = '4.15.0'; - - /** Used as the `TypeError` message for "Functions" methods. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used to compose bitmasks for function metadata. */ - var BIND_FLAG = 1, - PARTIAL_FLAG = 32; - - /** Used to compose bitmasks for comparison styles. */ - var UNORDERED_COMPARE_FLAG = 1, - PARTIAL_COMPARE_FLAG = 2; - - /** Used as references for various `Number` constants. */ - var INFINITY = 1 / 0, - MAX_SAFE_INTEGER = 9007199254740991; - - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - numberTag = '[object Number]', - objectTag = '[object Object]', - regexpTag = '[object RegExp]', - stringTag = '[object String]'; - - /** Used to match HTML entities and HTML characters. */ - var reUnescapedHtml = /[&<>"'`]/g, - reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`' - }; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - - /** Detect free variable `self`. */ - var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - - /** Used as a reference to the global object. */ - var root = freeGlobal || freeSelf || Function('return this')(); - - /** Detect free variable `exports`. */ - var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - - /*--------------------------------------------------------------------------*/ - - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - array.push.apply(array, values); - return array; - } - - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @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, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); - - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } - - /** - * The base implementation of `_.propertyOf` without support for deep paths. - * - * @private - * @param {Object} object The object to query. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyOf(object) { - return function(key) { - return object == null ? undefined : object[key]; - }; - } - - /** - * The base implementation of `_.reduce` and `_.reduceRight`, without support - * for iteratee shorthands, which iterates over `collection` using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initAccum Specify using the first or last element of - * `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initAccum - ? (initAccum = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - return baseMap(props, function(key) { - return object[key]; - }); - } - - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - var escapeHtmlChar = basePropertyOf(htmlEscapes); - - /** - * Checks if `value` is a host object in IE < 9. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a host object, else `false`. - */ - function isHostObject() { - return false; - } - - /** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ - function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; - } - - /*--------------------------------------------------------------------------*/ - - /** Used for built-in method references. */ - var arrayProto = Array.prototype, - objectProto = Object.prototype; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - - /** Used to generate unique IDs. */ - var idCounter = 0; - - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var objectToString = objectProto.toString; - - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = root._; - - /** Built-in value references. */ - var objectCreate = Object.create, - propertyIsEnumerable = objectProto.propertyIsEnumerable; - - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeIsFinite = root.isFinite, - nativeKeys = overArg(Object.keys, Object), - nativeMax = Math.max; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object which wraps `value` to enable implicit method - * chain sequences. Methods that operate on and return arrays, collections, - * and functions can be chained together. Methods that retrieve a single value - * or may return a primitive value will automatically end the chain sequence - * and return the unwrapped value. Otherwise, the value must be unwrapped - * with `_#value`. - * - * Explicit chain sequences, which must be unwrapped with `_#value`, may be - * enabled using `_.chain`. - * - * The execution of chained methods is lazy, that is, it's deferred until - * `_#value` is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. - * Shortcut fusion is an optimization to merge iteratee calls; this avoids - * the creation of intermediate arrays and can greatly reduce the number of - * iteratee executions. Sections of a chain sequence qualify for shortcut - * fusion if the section is applied to an array of at least `200` elements - * and any iteratees accept only one argument. The heuristic for whether a - * section qualifies for shortcut fusion is subject to change. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, - * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, - * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, - * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, - * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, - * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, - * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, - * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, - * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, - * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, - * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, - * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, - * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, - * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, - * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, - * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, - * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, - * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, - * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, - * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, - * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, - * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, - * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, - * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, - * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, - * `zipObject`, `zipObjectDeep`, and `zipWith` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, - * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, - * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, - * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, - * `findLastIndex`, `findLastKey`, `first`, `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`, `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 - * @category Seq - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2, 3]); - * - * // Returns an unwrapped value. - * wrapped.reduce(_.add); - * // => 6 - * - * // Returns a wrapped value. - * var squares = wrapped.map(square); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - return value instanceof LodashWrapper - ? value - : new LodashWrapper(value); - } - - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable explicit method chain sequences. - */ - function LodashWrapper(value, chainAll) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__chain__ = !!chainAll; - } - - LodashWrapper.prototype = baseCreate(lodash.prototype); - LodashWrapper.prototype.constructor = LodashWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Used by `_.defaults` to customize its `_.assignIn` use. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to assign. - * @param {Object} object The parent object of `objValue`. - * @returns {*} Returns the value to assign. - */ - function assignInDefaults(objValue, srcValue, key, object) { - if (objValue === undefined || - (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { - return srcValue; - } - return objValue; - } - - /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - object[key] = value; - } - } - - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} prototype The object to inherit from. - * @returns {Object} Returns the new object. - */ - function baseCreate(proto) { - return isObject(proto) ? objectCreate(proto) : {}; - } - - /** - * The base implementation of `_.delay` and `_.defer` which accepts `args` - * to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Array} args The arguments to provide to `func`. - * @returns {number|Object} Returns the timer id or timeout object. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return setTimeout(function() { func.apply(undefined, args); }, wait); - } - - /** - * The base implementation of `_.forEach` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); - - /** - * The base implementation of `_.every` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection 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 baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function(value, index, collection) { - result = !!predicate(value, index, collection); - return result; - }); - return result; - } - - /** - * The base implementation of methods like `_.max` and `_.min` which accepts a - * `comparator` to determine the extremum value. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The iteratee invoked per iteration. - * @param {Function} comparator The comparator used to compare values. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(array, iteratee, comparator) { - var index = -1, - length = array.length; - - while (++index < length) { - var value = array[index], - current = iteratee(value); - - if (current != null && (computed === undefined - ? (current === current && !false) - : comparator(current, computed) - )) { - var computed = current, - result = value; - } - } - return result; - } - - /** - * The base implementation of `_.filter` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } - - /** - * The base implementation of `_.flatten` with support for restricting flattening. - * - * @private - * @param {Array} array The array to flatten. - * @param {number} depth The maximum recursion depth. - * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. - * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); - - while (++index < length) { - var value = array[index]; - if (depth > 0 && predicate(value)) { - if (depth > 1) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, predicate, isStrict, result); - } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } - } - return result; - } - - /** - * The base implementation of `baseForOwn` which iterates over `object` - * properties returned by `keysFunc` and invokes `iteratee` for each property. - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); - - /** - * The base implementation of `_.forOwn` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return object && baseFor(object, iteratee, keys); - } - - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from `props`. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the function names. - */ - function baseFunctions(object, props) { - return baseFilter(props, function(key) { - return isFunction(object[key]); - }); - } - - /** - * The base implementation of `_.gt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - */ - function baseGt(value, other) { - return value > other; - } - - /** - * The base implementation of `_.isDate` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - */ - function baseIsDate(value) { - return isObjectLike(value) && objectToString.call(value) == dateTag; - } - - /** - * The base implementation of `_.isEqual` which supports partial comparisons - * and tracks traversed objects. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @param {boolean} [bitmask] The bitmask of comparison flags. - * The bitmask may be composed of the following flags: - * 1 - Unordered comparison - * 2 - Partial comparison - * @param {Object} [stack] Tracks traversed `value` and `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, customizer, bitmask, stack) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack); - } - - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparisons. - * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} [stack] Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = arrayTag, - othTag = arrayTag; - - if (!objIsArr) { - objTag = objectToString.call(object); - objTag = objTag == argsTag ? objectTag : objTag; - } - if (!othIsArr) { - othTag = objectToString.call(other); - othTag = othTag == argsTag ? objectTag : othTag; - } - var objIsObj = objTag == objectTag && !isHostObject(object), - othIsObj = othTag == objectTag && !isHostObject(other), - isSameTag = objTag == othTag; - - stack || (stack = []); - var objStack = find(stack, function(entry) { - return entry[0] == object; - }); - var othStack = find(stack, function(entry) { - return entry[0] == other; - }); - if (objStack && othStack) { - return objStack[1] == other; - } - stack.push([object, other]); - stack.push([other, object]); - if (isSameTag && !objIsObj) { - var result = (objIsArr) - ? equalArrays(object, other, equalFunc, customizer, bitmask, stack) - : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack); - stack.pop(); - return result; - } - if (!(bitmask & PARTIAL_COMPARE_FLAG)) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); - - if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object.value() : object, - othUnwrapped = othIsWrapped ? other.value() : other; - - var result = equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack); - stack.pop(); - return result; - } - } - if (!isSameTag) { - return false; - } - var result = equalObjects(object, other, equalFunc, customizer, bitmask, stack); - stack.pop(); - return result; - } - - /** - * The base implementation of `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ - function baseIsRegExp(value) { - return isObject(value) && objectToString.call(value) == regexpTag; - } - - /** - * The base implementation of `_.iteratee`. - * - * @private - * @param {*} [value=_.identity] The value to convert to an iteratee. - * @returns {Function} Returns the iteratee. - */ - function baseIteratee(func) { - if (typeof func == 'function') { - return func; - } - if (func == null) { - return identity; - } - return (typeof func == 'object' ? baseMatches : baseProperty)(func); - } - - /** - * The base implementation of `_.lt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - */ - function baseLt(value, other) { - return value < other; - } - - /** - * The base implementation of `_.map` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value, key, collection) { - result[++index] = iteratee(value, key, collection); - }); - return result; - } - - /** - * The base implementation of `_.matches` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatches(source) { - var props = nativeKeys(source); - return function(object) { - var length = props.length; - if (object == null) { - return !length; - } - object = Object(object); - while (length--) { - var key = props[length]; - if (!(key in object && - baseIsEqual(source[key], object[key], undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG) - )) { - return false; - } - } - return true; - }; - } - - /** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property identifiers to pick. - * @returns {Object} Returns the new object. - */ - function basePick(object, props) { - object = Object(object); - return reduce(props, function(result, key) { - if (key in object) { - result[key] = object[key]; - } - return result; - }, {}); - } - - /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ - function baseRest(func, start) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); - - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = array; - return func.apply(this, otherArgs); - }; - } - - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, - length = array.length; - - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = end > length ? length : end; - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; - - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; - } - - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function copyArray(source) { - return baseSlice(source, 0, source.length); - } - - /** - * The base implementation of `_.some` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection 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 baseSome(collection, predicate) { - var result; - - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } - - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to perform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - return reduce(actions, function(result, action) { - return action.func.apply(action.thisArg, arrayPush([result], action.args)); - }, result); - } - - /** - * Compares values to sort them in ascending order. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function compareAscending(value, other) { - if (value !== other) { - var valIsDefined = value !== undefined, - valIsNull = value === null, - valIsReflexive = value === value, - valIsSymbol = false; - - var othIsDefined = other !== undefined, - othIsNull = other === null, - othIsReflexive = other === other, - othIsSymbol = false; - - if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || - (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || - (valIsNull && othIsDefined && othIsReflexive) || - (!valIsDefined && othIsReflexive) || - !valIsReflexive) { - return 1; - } - if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || - (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || - (othIsNull && valIsDefined && valIsReflexive) || - (!othIsDefined && valIsReflexive) || - !othIsReflexive) { - return -1; - } - } - return 0; - } - - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ - function copyObject(source, props, object, customizer) { - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; - - assignValue(object, key, newValue === undefined ? source[key] : newValue); - } - return object; - } - - /** - * Creates a function like `_.assign`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return baseRest(function(object, sources) { - var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; - - object = Object(object); - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, index, customizer); - } - } - return object; - }); - } - - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - if (collection == null) { - return collection; - } - if (!isArrayLike(collection)) { - return eachFunc(collection, iteratee); - } - var length = collection.length, - index = fromRight ? length : -1, - iterable = Object(collection); - - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } - - /** - * Creates a base function for methods like `_.forIn` and `_.forOwn`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), - props = keysFunc(object), - length = props.length; - - while (length--) { - var key = props[fromRight ? length : ++index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } - - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtor(Ctor) { - return function() { - // Use a `switch` statement to work with class constructors. See - // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist - // for more details. - var args = arguments; - var thisBinding = baseCreate(Ctor.prototype), - result = Ctor.apply(thisBinding, args); - - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } - - /** - * 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); - if (!isArrayLike(collection)) { - var iteratee = baseIteratee(predicate, 3); - collection = keys(collection); - predicate = function(key) { return iteratee(iterable[key], key, iterable); }; - } - var index = findIndexFunc(collection, predicate, fromIndex); - return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; - }; - } - - /** - * Creates a function that wraps `func` to invoke it with the `this` binding - * of `thisArg` and `partials` prepended to the arguments it receives. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to - * the new function. - * @returns {Function} Returns the new wrapped function. - */ - function createPartial(func, bitmask, thisArg, partials) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var isBind = bitmask & BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var argsIndex = -1, - argsLength = arguments.length, - leftIndex = -1, - leftLength = partials.length, - args = Array(leftLength + argsLength), - fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - return fn.apply(isBind ? thisArg : this, args); - } - return wrapper; - } - - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `array` and `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { - var isPartial = bitmask & PARTIAL_COMPARE_FLAG, - arrLength = array.length, - othLength = other.length; - - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { - return false; - } - var index = -1, - result = true, - seen = (bitmask & UNORDERED_COMPARE_FLAG) ? [] : undefined; - - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index]; - - var compared; - if (compared !== undefined) { - if (compared) { - continue; - } - result = false; - break; - } - // Recursively compare arrays (susceptible to call stack limits). - if (seen) { - if (!baseSome(other, function(othValue, othIndex) { - if (!indexOf(seen, othIndex) && - (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) { - return seen.push(othIndex); - } - })) { - result = false; - break; - } - } else if (!( - arrValue === othValue || - equalFunc(arrValue, othValue, customizer, bitmask, stack) - )) { - result = false; - break; - } - } - return result; - } - - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) { - switch (tag) { - - case boolTag: - case dateTag: - case numberTag: - // Coerce booleans to `1` or `0` and dates to milliseconds. - // Invalid dates are coerced to `NaN`. - return eq(+object, +other); - - case errorTag: - return object.name == other.name && object.message == other.message; - - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings, primitives and objects, - // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring - // for more details. - return object == (other + ''); - - } - return false; - } - - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, equalFunc, customizer, bitmask, stack) { - var isPartial = bitmask & PARTIAL_COMPARE_FLAG, - objProps = keys(object), - objLength = objProps.length, - othProps = keys(other), - othLength = othProps.length; - - if (objLength != othLength && !isPartial) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - var result = true; - - var skipCtor = isPartial; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key]; - - var compared; - // Recursively compare objects (susceptible to call stack limits). - if (!(compared === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack)) - : compared - )) { - result = false; - break; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (result && !skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - result = false; - } - } - return result; - } - - /** - * Checks if `value` is a flattenable `arguments` object or array. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ - function isFlattenable(value) { - return isArray(value) || isArguments(value); - } - - /** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); - } - } - return result; - } - - /** - * Converts `value` to a string key if it's not a string or symbol. - * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. - */ - var toKey = String; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - return baseFilter(array, Boolean); - } - - /** - * Creates a new array concatenating `array` with any additional arrays - * and/or values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to concatenate. - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var other = _.concat(array, 2, [3], [[4]]); - * - * console.log(other); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - function concat() { - var length = arguments.length, - args = Array(length ? length - 1 : 0), - array = arguments[0], - index = length; - - while (index--) { - args[index - 1] = arguments[index]; - } - return length - ? arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)) - : []; - } - - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [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 - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(o) { return o.user == 'barney'; }); - * // => 0 - * - * // The `_.matches` iteratee shorthand. - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findIndex(users, ['active', false]); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.findIndex(users, 'active'); - * // => 2 - */ - 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, baseIteratee(predicate, 3), index); - } - - /** - * Flattens `array` a single level deep. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] - */ - function flatten(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, 1) : []; - } - - /** - * Recursively flattens `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, [3, [4]], 5]]); - * // => [1, 2, 3, 4, 5] - */ - function flattenDeep(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, INFINITY) : []; - } - - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias first - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.head([1, 2, 3]); - * // => 1 - * - * _.head([]); - * // => undefined - */ - function head(array) { - return (array && array.length) ? array[0] : undefined; - } - - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the - * offset from the end of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // Search from the `fromIndex`. - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - */ - function indexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (typeof fromIndex == 'number') { - fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; - } else { - fromIndex = 0; - } - var index = (fromIndex || 0) - 1, - isReflexive = value === value; - - while (++index < length) { - var other = array[index]; - if ((isReflexive ? other === value : other !== other)) { - return index; - } - } - return -1; - } - - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array ? array.length : 0; - return length ? array[length - 1] : undefined; - } - - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of - * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are - * returned. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array ? array.length : 0; - start = start == null ? 0 : +start; - end = end === undefined ? length : +end; - return length ? baseSlice(array, start, end) : []; - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` wrapper instance that wraps `value` with explicit method - * chain sequences enabled. The result of such sequences must be unwrapped - * with `_#value`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Seq - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _ - * .chain(users) - * .sortBy('age') - * .map(function(o) { - * return o.user + ' is ' + o.age; - * }) - * .head() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } - - /** - * This method invokes `interceptor` and returns `value`. The interceptor - * is invoked with one argument; (value). The purpose of this method is to - * "tap into" a method chain sequence in order to modify intermediate results. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * // Mutate input array. - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor) { - interceptor(value); - return value; - } - - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * The purpose of this method is to "pass thru" values replacing intermediate - * results in a method chain sequence. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor) { - return interceptor(value); - } - - /** - * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. - * - * @name chain - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // A sequence without explicit chaining. - * _(users).head(); - * // => { 'user': 'barney', 'age': 36 } - * - * // A sequence with explicit chaining. - * _(users) - * .chain() - * .head() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } - - /** - * Executes the chain sequence to resolve the unwrapped value. - * - * @name value - * @memberOf _ - * @since 0.1.0 - * @alias toJSON, valueOf - * @category Seq - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } - - /*------------------------------------------------------------------------*/ - - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * Iteration is stopped once `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * **Note:** This method returns `true` for - * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because - * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of - * elements of empty collections. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.every(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, guard) { - predicate = guard ? undefined : predicate; - return baseEvery(collection, baseIteratee(predicate)); - } - - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * **Note:** Unlike `_.remove`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.reject - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.filter(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.filter(users, { 'age': 36, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.filter(users, 'active'); - * // => objects for ['barney'] - */ - function filter(collection, predicate) { - return baseFilter(collection, baseIteratee(predicate)); - } - - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.find(users, function(o) { return o.age < 40; }); - * // => object for 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.find(users, { 'age': 1, 'active': true }); - * // => object for 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.find(users, ['active', false]); - * // => object for 'fred' - * - * // The `_.property` iteratee shorthand. - * _.find(users, 'active'); - * // => object for 'barney' - */ - var find = createFind(findIndex); - - /** - * Iterates over elements of `collection` and invokes `iteratee` for each element. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" - * property are iterated like arrays. To avoid this behavior use `_.forIn` - * or `_.forOwn` for object iteration. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias each - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEachRight - * @example - * - * _([1, 2]).forEach(function(value) { - * console.log(value); - * }); - * // => Logs `1` then `2`. - * - * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forEach(collection, iteratee) { - return baseEach(collection, baseIteratee(iteratee)); - } - - /** - * Creates an array of values by running each element in `collection` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, - * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, - * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, - * `template`, `trim`, `trimEnd`, `trimStart`, and `words` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - * @example - * - * function square(n) { - * return n * n; - * } - * - * _.map([4, 8], square); - * // => [16, 64] - * - * _.map({ 'a': 4, 'b': 8 }, square); - * // => [16, 64] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // The `_.property` iteratee shorthand. - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee) { - return baseMap(collection, baseIteratee(iteratee)); - } - - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` thru `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not given, the first element of `collection` is used as the initial - * value. The iteratee is invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, - * and `sortBy` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduceRight - * @example - * - * _.reduce([1, 2], function(sum, n) { - * return sum + n; - * }, 0); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * return result; - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) - */ - function reduce(collection, iteratee, accumulator) { - return baseReduce(collection, baseIteratee(iteratee), accumulator, arguments.length < 3, baseEach); - } - - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable string keyed properties for objects. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the collection size. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - if (collection == null) { - return 0; - } - collection = isArrayLike(collection) ? collection : nativeKeys(collection); - return collection.length; - } - - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * Iteration is stopped once `predicate` returns truthy. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.some(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, guard) { - predicate = guard ? undefined : predicate; - return baseSome(collection, baseIteratee(predicate)); - } - - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection thru each iteratee. This method - * performs a stable sort, that is, it preserves the original sort order of - * equal elements. The iteratees are invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {...(Function|Function[])} [iteratees=[_.identity]] - * The iteratees to sort by. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.sortBy(users, function(o) { return o.user; }); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - * - * _.sortBy(users, ['user', 'age']); - * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] - * - * _.sortBy(users, 'user', function(o) { - * return Math.floor(o.age / 10); - * }); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - */ - function sortBy(collection, iteratee) { - var index = 0; - iteratee = baseIteratee(iteratee); - - return baseMap(baseMap(collection, function(value, key, collection) { - return { 'value': value, 'index': index++, 'criteria': iteratee(value, key, collection) }; - }).sort(function(object, other) { - return compareAscending(object.criteria, other.criteria) || (object.index - other.index); - }), baseProperty('value')); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it's called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery(element).on('click', _.before(5, addContactToList)); - * // => Allows adding up to 4 contacts to the list. - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = undefined; - } - return result; - }; - } - - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and `partials` prepended to the arguments it receives. - * - * 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" - * property of bound functions. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * function greet(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // Bound with placeholders. - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = baseRest(function(func, thisArg, partials) { - return createPartial(func, BIND_FLAG | PARTIAL_FLAG, thisArg, partials); - }); - - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // => Logs 'deferred' after one or more milliseconds. - */ - var defer = baseRest(function(func, args) { - return baseDelay(func, 1, args); - }); - - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => Logs 'later' after one second. - */ - var delay = baseRest(function(func, wait, args) { - return baseDelay(func, toNumber(wait) || 0, args); - }); - - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new negated function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - var args = arguments; - return !predicate.apply(this, args); - }; - } - - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first invocation. The `func` is - * invoked with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // => `createApplication` is invoked once - */ - function once(func) { - return before(2, func); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a shallow clone of `value`. - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) - * and supports cloning arrays, array buffers, booleans, date objects, maps, - * numbers, `Object` objects, regexes, sets, strings, symbols, and typed - * arrays. The own enumerable properties of `arguments` objects are cloned - * as plain objects. An empty object is returned for uncloneable values such - * as error objects, functions, DOM nodes, and WeakMaps. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to clone. - * @returns {*} Returns the cloned value. - * @see _.cloneDeep - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var shallow = _.clone(objects); - * console.log(shallow[0] === objects[0]); - * // => true - */ - function clone(value) { - if (!isObject(value)) { - return value; - } - return isArray(value) ? copyArray(value) : copyObject(value, nativeKeys(value)); - } - - /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ - function eq(value, other) { - return value === other || (value !== value && other !== other); - } - - /** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - function isArguments(value) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && - (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); - } - - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ - var isArray = Array.isArray; - - /** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } - - /** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ - function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); - } - - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || - (isObjectLike(value) && objectToString.call(value) == boolTag); - } - - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - var isDate = baseIsDate; - - /** - * Checks if `value` is an empty object, collection, map, or set. - * - * Objects are considered empty if they have no own enumerable string keyed - * properties. - * - * Array-like values such as `arguments` objects, arrays, buffers, strings, or - * jQuery-like collections are considered empty if they have a `length` of `0`. - * Similarly, maps and sets are considered empty if they have a `size` of `0`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (isArrayLike(value) && - (isArray(value) || isString(value) || - isFunction(value.splice) || isArguments(value))) { - return !value.length; - } - return !nativeKeys(value).length; - } - - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. - * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are **not** supported. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.isEqual(object, other); - * // => true - * - * object === other; - * // => false - */ - function isEqual(value, other) { - return baseIsEqual(value, other); - } - - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on - * [`Number.isFinite`](https://mdn.io/Number/isFinite). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(3); - * // => true - * - * _.isFinite(Number.MIN_VALUE); - * // => true - * - * _.isFinite(Infinity); - * // => false - * - * _.isFinite('3'); - * // => false - */ - function isFinite(value) { - return typeof value == 'number' && nativeIsFinite(value); - } - - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 8-9 which returns 'object' for typed array and other constructors. - var tag = isObject(value) ? objectToString.call(value) : ''; - return tag == funcTag || tag == genTag; - } - - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ - function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ - function isObject(value) { - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); - } - - /** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ - function isObjectLike(value) { - return !!value && typeof value == 'object'; - } - - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is based on - * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as - * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for - * `undefined` and other non-number values. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some - // ActiveX objects in IE. - return isNumber(value) && value != +value; - } - - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } - - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are - * classified as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a number, else `false`. - * @example - * - * _.isNumber(3); - * // => true - * - * _.isNumber(Number.MIN_VALUE); - * // => true - * - * _.isNumber(Infinity); - * // => true - * - * _.isNumber('3'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || - (isObjectLike(value) && objectToString.call(value) == numberTag); - } - - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - var isRegExp = baseIsRegExp; - - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a string, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag); - } - - /** - * Checks if `value` is `undefined`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; - } - - /** - * Converts `value` to an array. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * _.toArray({ 'a': 1, 'b': 2 }); - * // => [1, 2] - * - * _.toArray('abc'); - * // => ['a', 'b', 'c'] - * - * _.toArray(1); - * // => [] - * - * _.toArray(null); - * // => [] - */ - function toArray(value) { - if (!isArrayLike(value)) { - return values(value); - } - return value.length ? copyArray(value) : []; - } - - /** - * Converts `value` to an integer. - * - * **Note:** This method is loosely based on - * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toInteger(3.2); - * // => 3 - * - * _.toInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toInteger(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toInteger('3.2'); - * // => 3 - */ - var toInteger = Number; - - /** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ - var toNumber = Number; - - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {string} Returns the string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ - function toString(value) { - if (typeof value == 'string') { - return value; - } - return value == null ? '' : (value + ''); - } - - /*------------------------------------------------------------------------*/ - - /** - * Assigns own enumerable string keyed properties of source objects to the - * destination object. Source objects are applied from left to right. - * Subsequent sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object` and is loosely based on - * [`Object.assign`](https://mdn.io/Object/assign). - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assignIn - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assign({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'c': 3 } - */ - var assign = createAssigner(function(object, source) { - copyObject(source, nativeKeys(source), object); - }); - - /** - * This method is like `_.assign` except that it iterates over own and - * inherited source properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assign - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assignIn({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } - */ - var assignIn = createAssigner(function(object, source) { - copyObject(source, nativeKeysIn(source), object); - }); - - /** - * This method is like `_.assignIn` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extendWith - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignInWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keysIn(source), object, customizer); - }); - - /** - * Creates an object that inherits from the `prototype` object. If a - * `properties` object is given, its own enumerable string keyed properties - * are assigned to the created object. - * - * @static - * @memberOf _ - * @since 2.3.0 - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties) { - var result = baseCreate(prototype); - return properties ? assign(result, properties) : result; - } - - /** - * Assigns own and inherited enumerable string keyed properties of source - * objects to the destination object for all destination properties that - * resolve to `undefined`. Source objects are applied from left to right. - * Once a property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaultsDeep - * @example - * - * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var defaults = baseRest(function(args) { - args.push(undefined, assignInDefaults); - return assignInWith.apply(undefined, args); - }); - - /** - * Checks if `path` is a direct property of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = { 'a': { 'b': 2 } }; - * var other = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b'); - * // => true - * - * _.has(object, ['a', 'b']); - * // => true - * - * _.has(other, 'a'); - * // => false - */ - function has(object, path) { - return object != null && hasOwnProperty.call(object, path); - } - - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - var keys = nativeKeys; - - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - var keysIn = nativeKeysIn; - - /** - * Creates an object composed of the picked `object` properties. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [props] The property identifiers to pick. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pick(object, ['a', 'c']); - * // => { 'a': 1, 'c': 3 } - */ - var pick = baseRest(function(object, props) { - return object == null ? {} : basePick(object, baseMap(baseFlatten(props, 1), toKey)); - }); - - /** - * This method is like `_.get` except that if the resolved value is a - * function it's invoked with the `this` binding of its parent object and - * its result is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a[0].b.c3', 'default'); - * // => 'default' - * - * _.result(object, 'a[0].b.c3', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - var value = object == null ? undefined : object[path]; - if (value === undefined) { - value = defaultValue; - } - return isFunction(value) ? value.call(object) : value; - } - - /** - * Creates an array of the own enumerable string keyed property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return object ? baseValues(object, keys(object)) : []; - } - - /*------------------------------------------------------------------------*/ - - /** - * Converts the characters "&", "<", ">", '"', "'", and "\`" in `string` to - * their corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional - * characters use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. See - * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * Backticks are escaped because in IE < 9, they can break out of - * attribute values or HTML comments. See [#59](https://html5sec.org/#59), - * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and - * [#133](https://html5sec.org/#133) of the - * [HTML5 Security Cheatsheet](https://html5sec.org/) for more details. - * - * When working with HTML you should always - * [quote attribute values](http://wonko.com/post/html-escaping) to reduce - * XSS vectors. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - string = toString(string); - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, escapeHtmlChar) - : string; - } - - /*------------------------------------------------------------------------*/ - - /** - * This method returns the first argument it receives. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var object = { 'a': 1 }; - * - * console.log(_.identity(object) === object); - * // => true - */ - function identity(value) { - return value; - } - - /** - * Creates a function that invokes `func` with the arguments of the created - * function. If `func` is a property name, the created function returns the - * property value for a given element. If `func` is an array or object, the - * created function returns `true` for elements that contain the equivalent - * source properties, otherwise it returns `false`. - * - * @static - * @since 4.0.0 - * @memberOf _ - * @category Util - * @param {*} [func=_.identity] The value to convert to a callback. - * @returns {Function} Returns the callback. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true })); - * // => [{ 'user': 'barney', 'age': 36, 'active': true }] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, _.iteratee(['user', 'fred'])); - * // => [{ 'user': 'fred', 'age': 40 }] - * - * // The `_.property` iteratee shorthand. - * _.map(users, _.iteratee('user')); - * // => ['barney', 'fred'] - * - * // Create custom iteratee shorthands. - * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) { - * return !_.isRegExp(func) ? iteratee(func) : function(string) { - * return func.test(string); - * }; - * }); - * - * _.filter(['abc', 'def'], /ef/); - * // => ['def'] - */ - var iteratee = baseIteratee; - - /** - * Creates a function that performs a partial deep comparison between a given - * object and `source`, returning `true` if the given object has equivalent - * property values, else `false`. - * - * **Note:** The created function is equivalent to `_.isMatch` with `source` - * partially applied. - * - * Partial comparisons will match empty array and empty object `source` - * values against any array or object value, respectively. See `_.isEqual` - * for a list of supported value comparisons. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Util - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. - * @example - * - * var objects = [ - * { 'a': 1, 'b': 2, 'c': 3 }, - * { 'a': 4, 'b': 5, 'c': 6 } - * ]; - * - * _.filter(objects, _.matches({ 'a': 4, 'c': 6 })); - * // => [{ 'a': 4, 'b': 5, 'c': 6 }] - */ - function matches(source) { - return baseMatches(assign({}, source)); - } - - /** - * Adds all own enumerable string keyed function properties of a source - * object to the destination object. If `object` is a function, then methods - * are added to its prototype as well. - * - * **Note:** Use `_.runInContext` to create a pristine `lodash` function to - * avoid conflicts caused by modifying the original. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {Function|Object} [object=lodash] The destination object. - * @param {Object} source The object of functions to add. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.chain=true] Specify whether mixins are chainable. - * @returns {Function|Object} Returns `object`. - * @example - * - * function vowels(string) { - * return _.filter(string, function(v) { - * return /[aeiou]/i.test(v); - * }); - * } - * - * _.mixin({ 'vowels': vowels }); - * _.vowels('fred'); - * // => ['e'] - * - * _('fred').vowels().value(); - * // => ['e'] - * - * _.mixin({ 'vowels': vowels }, { 'chain': false }); - * _('fred').vowels(); - * // => ['e'] - */ - function mixin(object, source, options) { - var props = keys(source), - methodNames = baseFunctions(source, props); - - if (options == null && - !(isObject(source) && (methodNames.length || !props.length))) { - options = source; - source = object; - object = this; - methodNames = baseFunctions(source, keys(source)); - } - var chain = !(isObject(options) && 'chain' in options) || !!options.chain, - isFunc = isFunction(object); - - baseEach(methodNames, function(methodName) { - var func = source[methodName]; - object[methodName] = func; - if (isFunc) { - object.prototype[methodName] = function() { - var chainAll = this.__chain__; - if (chain || chainAll) { - var result = object(this.__wrapped__), - actions = result.__actions__ = copyArray(this.__actions__); - - actions.push({ 'func': func, 'args': arguments, 'thisArg': object }); - result.__chain__ = chainAll; - return result; - } - return func.apply(object, arrayPush([this.value()], arguments)); - }; - } - }); - - return object; - } - - /** - * Reverts the `_` variable to its previous value and returns a reference to - * the `lodash` function. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @returns {Function} Returns the `lodash` function. - * @example - * - * var lodash = _.noConflict(); - */ - function noConflict() { - if (root._ === this) { - root._ = oldDash; - } - return this; - } - - /** - * This method returns `undefined`. - * - * @static - * @memberOf _ - * @since 2.3.0 - * @category Util - * @example - * - * _.times(2, _.noop); - * // => [undefined, undefined] - */ - function noop() { - // No operation performed. - } - - /** - * Generates a unique ID. If `prefix` is given, the ID is appended to it. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {string} [prefix=''] The value to prefix the ID with. - * @returns {string} Returns the unique ID. - * @example - * - * _.uniqueId('contact_'); - * // => 'contact_104' - * - * _.uniqueId(); - * // => '105' - */ - function uniqueId(prefix) { - var id = ++idCounter; - return toString(prefix) + id; - } - - /*------------------------------------------------------------------------*/ - - /** - * Computes the maximum value of `array`. If `array` is empty or falsey, - * `undefined` is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Math - * @param {Array} array The array to iterate over. - * @returns {*} Returns the maximum value. - * @example - * - * _.max([4, 2, 8, 6]); - * // => 8 - * - * _.max([]); - * // => undefined - */ - function max(array) { - return (array && array.length) - ? baseExtremum(array, identity, baseGt) - : undefined; - } - - /** - * Computes the minimum value of `array`. If `array` is empty or falsey, - * `undefined` is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Math - * @param {Array} array The array to iterate over. - * @returns {*} Returns the minimum value. - * @example - * - * _.min([4, 2, 8, 6]); - * // => 2 - * - * _.min([]); - * // => undefined - */ - function min(array) { - return (array && array.length) - ? baseExtremum(array, identity, baseLt) - : undefined; - } - - /*------------------------------------------------------------------------*/ - - // Add methods that return wrapped values in chain sequences. - lodash.assignIn = assignIn; - lodash.before = before; - lodash.bind = bind; - lodash.chain = chain; - lodash.compact = compact; - lodash.concat = concat; - lodash.create = create; - lodash.defaults = defaults; - lodash.defer = defer; - lodash.delay = delay; - lodash.filter = filter; - lodash.flatten = flatten; - lodash.flattenDeep = flattenDeep; - lodash.iteratee = iteratee; - lodash.keys = keys; - lodash.map = map; - lodash.matches = matches; - lodash.mixin = mixin; - lodash.negate = negate; - lodash.once = once; - lodash.pick = pick; - lodash.slice = slice; - lodash.sortBy = sortBy; - lodash.tap = tap; - lodash.thru = thru; - lodash.toArray = toArray; - lodash.values = values; - - // Add aliases. - lodash.extend = assignIn; - - // Add methods to `lodash.prototype`. - mixin(lodash, lodash); - - /*------------------------------------------------------------------------*/ - - // Add methods that return unwrapped values in chain sequences. - lodash.clone = clone; - lodash.escape = escape; - lodash.every = every; - lodash.find = find; - lodash.forEach = forEach; - lodash.has = has; - lodash.head = head; - lodash.identity = identity; - lodash.indexOf = indexOf; - lodash.isArguments = isArguments; - lodash.isArray = isArray; - lodash.isBoolean = isBoolean; - lodash.isDate = isDate; - lodash.isEmpty = isEmpty; - lodash.isEqual = isEqual; - lodash.isFinite = isFinite; - lodash.isFunction = isFunction; - lodash.isNaN = isNaN; - lodash.isNull = isNull; - lodash.isNumber = isNumber; - lodash.isObject = isObject; - lodash.isRegExp = isRegExp; - lodash.isString = isString; - lodash.isUndefined = isUndefined; - lodash.last = last; - lodash.max = max; - lodash.min = min; - lodash.noConflict = noConflict; - lodash.noop = noop; - lodash.reduce = reduce; - lodash.result = result; - lodash.size = size; - lodash.some = some; - lodash.uniqueId = uniqueId; - - // Add aliases. - lodash.each = forEach; - lodash.first = head; - - mixin(lodash, (function() { - var source = {}; - baseForOwn(lodash, function(func, methodName) { - if (!hasOwnProperty.call(lodash.prototype, methodName)) { - source[methodName] = func; - } - }); - return source; - }()), { 'chain': false }); - - /*------------------------------------------------------------------------*/ - - /** - * The semantic version number. - * - * @static - * @memberOf _ - * @type {string} - */ - lodash.VERSION = VERSION; - - // Add `Array` methods to `lodash.prototype`. - baseEach(['pop', 'join', 'replace', 'reverse', 'split', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) { - var func = (/^(?:replace|split)$/.test(methodName) ? String.prototype : arrayProto)[methodName], - chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru', - retUnwrapped = /^(?:pop|join|replace|shift)$/.test(methodName); - - lodash.prototype[methodName] = function() { - var args = arguments; - if (retUnwrapped && !this.__chain__) { - var value = this.value(); - return func.apply(isArray(value) ? value : [], args); - } - return this[chainName](function(value) { - return func.apply(isArray(value) ? value : [], args); - }); - }; - }); - - // Add chain sequence methods to the `lodash` wrapper. - lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue; - - /*--------------------------------------------------------------------------*/ - - // Some AMD build optimizers, like r.js, check for condition patterns like: - if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { - // Expose Lodash on the global object to prevent errors when 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. - root._ = lodash; - - // Define as an anonymous module so, through path mapping, it can be - // referenced as the "underscore" module. - define(function() { - return lodash; - }); - } - // Check for `exports` after `define` in case a build optimizer adds it. - else if (freeModule) { - // Export for Node.js. - (freeModule.exports = lodash)._ = lodash; - // Export for CommonJS support. - freeExports._ = lodash; - } - else { - // Export to the global object. - root._ = lodash; - } -}.call(this)); diff --git a/public/vendor/lodash/dist/lodash.core.min.js b/public/vendor/lodash/dist/lodash.core.min.js deleted file mode 100644 index f5c9efaeeed..00000000000 --- a/public/vendor/lodash/dist/lodash.core.min.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * lodash (Custom Build) /license | Underscore.js 1.8.3 underscorejs.org/LICENSE - * Build: `lodash core -o ./dist/lodash.core.js` - */ -;(function(){function n(n,t){return n.push.apply(n,t),n}function t(n){return function(t){return null==t?Z:t[n]}}function r(n,t,r,e,u){return u(n,function(n,u,o){r=e?(e=false,n):t(r,n,u,o)}),r}function e(n,t){return d(t,function(t){return n[t]})}function u(n){return n instanceof o?n:new o(n)}function o(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t}function i(n,t,r,e){return n===Z||J(n,an[r])&&!ln.call(e,r)?t:n}function c(n){return V(n)?vn(n):{}}function f(n,t,r){if(typeof n!="function")throw new TypeError("Expected a function"); -return setTimeout(function(){n.apply(Z,r)},t)}function a(n,t){var r=true;return jn(n,function(n,e,u){return r=!!t(n,e,u)}),r}function l(n,t,r){for(var e=-1,u=n.length;++et}function y(n,t,r,e,u){return n===t||(null==n||null==t||!V(n)&&!H(t)?n!==n&&t!==t:g(n,t,y,r,e,u))}function g(n,t,r,e,u,o){var i=wn(n),c=wn(t),f="[object Array]",a="[object Array]";i||(f=sn.call(n),f="[object Arguments]"==f?"[object Object]":f),c||(a=sn.call(t),a="[object Arguments]"==a?"[object Object]":a);var l="[object Object]"==f&&true,c="[object Object]"==a&&true,a=f==a;o||(o=[]);var p=On(o,function(t){return t[0]==n; -}),s=On(o,function(n){return n[0]==t});if(p&&s)return p[1]==t;if(o.push([n,t]),o.push([t,n]),a&&!l){if(i)r=B(n,t,r,e,u,o);else n:{switch(f){case"[object Boolean]":case"[object Date]":case"[object Number]":r=J(+n,+t);break n;case"[object Error]":r=n.name==t.name&&n.message==t.message;break n;case"[object RegExp]":case"[object String]":r=n==t+"";break n}r=false}return o.pop(),r}return 2&u||(i=l&&ln.call(n,"__wrapped__"),f=c&&ln.call(t,"__wrapped__"),!i&&!f)?!!a&&(r=R(n,t,r,e,u,o),o.pop(),r):(i=i?n.value():n, -f=f?t.value():t,r=r(i,f,e,u,o),o.pop(),r)}function _(n){return typeof n=="function"?n:null==n?X:(typeof n=="object"?m:t)(n)}function j(n,t){return nt&&(t=-t>u?0:u+t),r=r>u?u:r,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Array(u);++ei))return false;for(var c=-1,f=true,a=1&u?[]:Z;++cr?_n(e+r,0):r:0,r=(r||0)-1;for(var u=t===t;++rarguments.length,jn)}function G(n,t){var r;if(typeof t!="function")throw new TypeError("Expected a function");return n=kn(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=Z),r}}function J(n,t){return n===t||n!==n&&t!==t}function M(n){ -return H(n)&&P(n)&&ln.call(n,"callee")&&(!bn.call(n,"callee")||"[object Arguments]"==sn.call(n))}function P(n){var t;return(t=null!=n)&&(t=n.length,t=typeof t=="number"&&-1=t),t&&!U(n)}function U(n){return n=V(n)?sn.call(n):"","[object Function]"==n||"[object GeneratorFunction]"==n}function V(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function H(n){return!!n&&typeof n=="object"}function K(n){return typeof n=="number"||H(n)&&"[object Number]"==sn.call(n)} -function L(n){return typeof n=="string"||!wn(n)&&H(n)&&"[object String]"==sn.call(n)}function Q(n){return typeof n=="string"?n:null==n?"":n+""}function W(n){return n?e(n,Rn(n)):[]}function X(n){return n}function Y(t,r,e){var u=Rn(r),o=v(r,u);null!=e||V(r)&&(o.length||!u.length)||(e=r,r=t,t=this,o=v(r,Rn(r)));var i=!(V(e)&&"chain"in e&&!e.chain),c=U(t);return jn(o,function(e){var u=r[e];t[e]=u,c&&(t.prototype[e]=function(){var r=this.__chain__;if(i||r){var e=t(this.__wrapped__);return(e.__actions__=E(this.__actions__)).push({ -func:u,args:arguments,thisArg:t}),e.__chain__=r,e}return u.apply(t,n([this.value()],arguments))})}),t}var Z,nn=1/0,tn=/[&<>"'`]/g,rn=RegExp(tn.source),en=typeof self=="object"&&self&&self.Object===Object&&self,un=typeof global=="object"&&global&&global.Object===Object&&global||en||Function("return this")(),on=(en=typeof exports=="object"&&exports&&!exports.nodeType&&exports)&&typeof module=="object"&&module&&!module.nodeType&&module,cn=function(n){return function(t){return null==n?Z:n[t]}}({"&":"&", -"<":"<",">":">",'"':""","'":"'","`":"`"}),fn=Array.prototype,an=Object.prototype,ln=an.hasOwnProperty,pn=0,sn=an.toString,hn=un._,vn=Object.create,bn=an.propertyIsEnumerable,yn=un.isFinite,gn=function(n,t){return function(r){return n(t(r))}}(Object.keys,Object),_n=Math.max;o.prototype=c(u.prototype),o.prototype.constructor=o;var jn=function(n,t){return function(r,e){if(null==r)return r;if(!P(r))return n(r,e);for(var u=r.length,o=t?u:-1,i=Object(r);(t?o--:++or&&(r=_n(e+r,0));n:{for(t=_(t),e=n.length,r+=-1;++re||o&&c&&a||!u&&a||!i){r=1;break n}if(!o&&r 2 ? (arity - 2) : 1; - return (length && length <= arity) ? result : baseAry(result, arity); - } - return result; - }; - }, - 'mixin': function(mixin) { - return function(source) { - var func = this; - if (!isFunction(func)) { - return mixin(func, Object(source)); - } - var pairs = []; - each(keys(source), function(key) { - if (isFunction(source[key])) { - pairs.push([key, func.prototype[key]]); - } - }); - - mixin(func, Object(source)); - - each(pairs, function(pair) { - var value = pair[1]; - if (isFunction(value)) { - func.prototype[pair[0]] = value; - } else { - delete func.prototype[pair[0]]; - } - }); - return func; - }; - }, - 'nthArg': function(nthArg) { - return function(n) { - var arity = n < 0 ? 1 : (toInteger(n) + 1); - return curry(nthArg(n), arity); - }; - }, - 'rearg': function(rearg) { - return function(func, indexes) { - var arity = indexes ? indexes.length : 0; - return curry(rearg(func, indexes), arity); - }; - }, - 'runInContext': function(runInContext) { - return function(context) { - return baseConvert(util, runInContext(context), options); - }; - } - }; - - /*--------------------------------------------------------------------------*/ - - /** - * Casts `func` to a function with an arity capped iteratee if needed. - * - * @private - * @param {string} name The name of the function to inspect. - * @param {Function} func The function to inspect. - * @returns {Function} Returns the cast function. - */ - function castCap(name, func) { - if (config.cap) { - var indexes = mapping.iterateeRearg[name]; - if (indexes) { - return iterateeRearg(func, indexes); - } - var n = !isLib && mapping.iterateeAry[name]; - if (n) { - return iterateeAry(func, n); - } - } - return func; - } - - /** - * Casts `func` to a curried function if needed. - * - * @private - * @param {string} name The name of the function to inspect. - * @param {Function} func The function to inspect. - * @param {number} n The arity of `func`. - * @returns {Function} Returns the cast function. - */ - function castCurry(name, func, n) { - return (forceCurry || (config.curry && n > 1)) - ? curry(func, n) - : func; - } - - /** - * Casts `func` to a fixed arity function if needed. - * - * @private - * @param {string} name The name of the function to inspect. - * @param {Function} func The function to inspect. - * @param {number} n The arity cap. - * @returns {Function} Returns the cast function. - */ - function castFixed(name, func, n) { - if (config.fixed && (forceFixed || !mapping.skipFixed[name])) { - var data = mapping.methodSpread[name], - start = data && data.start; - - return start === undefined ? ary(func, n) : spread(func, start); - } - return func; - } - - /** - * Casts `func` to an rearged function if needed. - * - * @private - * @param {string} name The name of the function to inspect. - * @param {Function} func The function to inspect. - * @param {number} n The arity of `func`. - * @returns {Function} Returns the cast function. - */ - function castRearg(name, func, n) { - return (config.rearg && n > 1 && (forceRearg || !mapping.skipRearg[name])) - ? rearg(func, mapping.methodRearg[name] || mapping.aryRearg[n]) - : func; - } - - /** - * Creates a clone of `object` by `path`. - * - * @private - * @param {Object} object The object to clone. - * @param {Array|string} path The path to clone by. - * @returns {Object} Returns the cloned object. - */ - function cloneByPath(object, path) { - path = toPath(path); - - var index = -1, - length = path.length, - lastIndex = length - 1, - result = clone(Object(object)), - nested = result; - - while (nested != null && ++index < length) { - var key = path[index], - value = nested[key]; - - if (value != null) { - nested[path[index]] = clone(index == lastIndex ? value : Object(value)); - } - nested = nested[key]; - } - return result; - } - - /** - * Converts `lodash` to an immutable auto-curried iteratee-first data-last - * version with conversion `options` applied. - * - * @param {Object} [options] The options object. See `baseConvert` for more details. - * @returns {Function} Returns the converted `lodash`. - */ - function convertLib(options) { - return _.runInContext.convert(options)(undefined); - } - - /** - * Create a converter function for `func` of `name`. - * - * @param {string} name The name of the function to convert. - * @param {Function} func The function to convert. - * @returns {Function} Returns the new converter function. - */ - function createConverter(name, func) { - var oldOptions = options; - return function(options) { - var newUtil = isLib ? pristine : helpers, - newFunc = isLib ? pristine[name] : func, - newOptions = assign(assign({}, oldOptions), options); - - return baseConvert(newUtil, name, newFunc, newOptions); - }; - } - - /** - * Creates a function that wraps `func` to invoke its iteratee, with up to `n` - * arguments, ignoring any additional arguments. - * - * @private - * @param {Function} func The function to cap iteratee arguments for. - * @param {number} n The arity cap. - * @returns {Function} Returns the new function. - */ - function iterateeAry(func, n) { - return overArg(func, function(func) { - return typeof func == 'function' ? baseAry(func, n) : func; - }); - } - - /** - * Creates a function that wraps `func` to invoke its iteratee with arguments - * arranged according to the specified `indexes` where the argument value at - * the first index is provided as the first argument, the argument value at - * the second index is provided as the second argument, and so on. - * - * @private - * @param {Function} func The function to rearrange iteratee arguments for. - * @param {number[]} indexes The arranged argument indexes. - * @returns {Function} Returns the new function. - */ - function iterateeRearg(func, indexes) { - return overArg(func, function(func) { - var n = indexes.length; - return baseArity(rearg(baseAry(func, n), indexes), n); - }); - } - - /** - * Creates a function that invokes `func` with its first argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ - function overArg(func, transform) { - return function() { - var length = arguments.length; - if (!length) { - return func(); - } - var args = Array(length); - while (length--) { - args[length] = arguments[length]; - } - var index = config.rearg ? 0 : (length - 1); - args[index] = transform(args[index]); - return func.apply(undefined, args); - }; - } - - /** - * Creates a function that wraps `func` and applys the conversions - * rules by `name`. - * - * @private - * @param {string} name The name of the function to wrap. - * @param {Function} func The function to wrap. - * @returns {Function} Returns the converted function. - */ - function wrap(name, func) { - name = mapping.aliasToReal[name] || name; - - var result, - wrapped = func, - wrapper = wrappers[name]; - - if (wrapper) { - wrapped = wrapper(func); - } - else if (config.immutable) { - if (mutateMap.array[name]) { - wrapped = wrapImmutable(func, cloneArray); - } - else if (mutateMap.object[name]) { - wrapped = wrapImmutable(func, createCloner(func)); - } - else if (mutateMap.set[name]) { - wrapped = wrapImmutable(func, cloneByPath); - } - } - each(aryMethodKeys, function(aryKey) { - each(mapping.aryMethod[aryKey], function(otherName) { - if (name == otherName) { - var spreadData = mapping.methodSpread[name], - afterRearg = spreadData && spreadData.afterRearg; - - result = afterRearg - ? castFixed(name, castRearg(name, wrapped, aryKey), aryKey) - : castRearg(name, castFixed(name, wrapped, aryKey), aryKey); - - result = castCap(name, result); - result = castCurry(name, result, aryKey); - return false; - } - }); - return !result; - }); - - result || (result = wrapped); - if (result == func) { - result = forceCurry ? curry(result, 1) : function() { - return func.apply(this, arguments); - }; - } - result.convert = createConverter(name, func); - if (mapping.placeholder[name]) { - setPlaceholder = true; - result.placeholder = func.placeholder = placeholder; - } - return result; - } - - /*--------------------------------------------------------------------------*/ - - if (!isObj) { - return wrap(name, func); - } - var _ = func; - - // Convert methods by ary cap. - var pairs = []; - each(aryMethodKeys, function(aryKey) { - each(mapping.aryMethod[aryKey], function(key) { - var func = _[mapping.remap[key] || key]; - if (func) { - pairs.push([key, wrap(key, func)]); - } - }); - }); - - // Convert remaining methods. - each(keys(_), function(key) { - var func = _[key]; - if (typeof func == 'function') { - var length = pairs.length; - while (length--) { - if (pairs[length][0] == key) { - return; - } - } - func.convert = createConverter(key, func); - pairs.push([key, func]); - } - }); - - // Assign to `_` leaving `_.prototype` unchanged to allow chaining. - each(pairs, function(pair) { - _[pair[0]] = pair[1]; - }); - - _.convert = convertLib; - if (setPlaceholder) { - _.placeholder = placeholder; - } - // Assign aliases. - each(keys(_), function(key) { - each(mapping.realToAlias[key] || [], function(alias) { - _[alias] = _[key]; - }); - }); - - return _; - } - - module.exports = baseConvert; - - -/***/ }, -/* 2 */ -/***/ function(module, exports) { - - /** Used to map aliases to their real names. */ - exports.aliasToReal = { - - // Lodash aliases. - 'each': 'forEach', - 'eachRight': 'forEachRight', - 'entries': 'toPairs', - 'entriesIn': 'toPairsIn', - 'extend': 'assignIn', - 'extendAll': 'assignInAll', - 'extendAllWith': 'assignInAllWith', - 'extendWith': 'assignInWith', - 'first': 'head', - - // Methods that are curried variants of others. - 'conforms': 'conformsTo', - 'matches': 'isMatch', - 'property': 'get', - - // Ramda aliases. - '__': 'placeholder', - 'F': 'stubFalse', - 'T': 'stubTrue', - 'all': 'every', - 'allPass': 'overEvery', - 'always': 'constant', - 'any': 'some', - 'anyPass': 'overSome', - 'apply': 'spread', - 'assoc': 'set', - 'assocPath': 'set', - 'complement': 'negate', - 'compose': 'flowRight', - 'contains': 'includes', - 'dissoc': 'unset', - 'dissocPath': 'unset', - 'dropLast': 'dropRight', - 'dropLastWhile': 'dropRightWhile', - 'equals': 'isEqual', - 'identical': 'eq', - 'indexBy': 'keyBy', - 'init': 'initial', - 'invertObj': 'invert', - 'juxt': 'over', - 'omitAll': 'omit', - 'nAry': 'ary', - 'path': 'get', - 'pathEq': 'matchesProperty', - 'pathOr': 'getOr', - 'paths': 'at', - 'pickAll': 'pick', - 'pipe': 'flow', - 'pluck': 'map', - 'prop': 'get', - 'propEq': 'matchesProperty', - 'propOr': 'getOr', - 'props': 'at', - 'symmetricDifference': 'xor', - 'symmetricDifferenceBy': 'xorBy', - 'symmetricDifferenceWith': 'xorWith', - 'takeLast': 'takeRight', - 'takeLastWhile': 'takeRightWhile', - 'unapply': 'rest', - 'unnest': 'flatten', - 'useWith': 'overArgs', - 'where': 'conformsTo', - 'whereEq': 'isMatch', - 'zipObj': 'zipObject' - }; - - /** Used to map ary to method names. */ - exports.aryMethod = { - '1': [ - 'assignAll', 'assignInAll', 'attempt', 'castArray', 'ceil', 'create', - 'curry', 'curryRight', 'defaultsAll', 'defaultsDeepAll', 'floor', 'flow', - 'flowRight', 'fromPairs', 'invert', 'iteratee', 'memoize', 'method', 'mergeAll', - 'methodOf', 'mixin', 'nthArg', 'over', 'overEvery', 'overSome','rest', 'reverse', - 'round', 'runInContext', 'spread', 'template', 'trim', 'trimEnd', 'trimStart', - 'uniqueId', 'words', 'zipAll' - ], - '2': [ - 'add', 'after', 'ary', 'assign', 'assignAllWith', 'assignIn', 'assignInAllWith', - 'at', 'before', 'bind', 'bindAll', 'bindKey', 'chunk', 'cloneDeepWith', - 'cloneWith', 'concat', 'conformsTo', 'countBy', 'curryN', 'curryRightN', - 'debounce', 'defaults', 'defaultsDeep', 'defaultTo', 'delay', 'difference', - 'divide', 'drop', 'dropRight', 'dropRightWhile', 'dropWhile', 'endsWith', 'eq', - 'every', 'filter', 'find', 'findIndex', 'findKey', 'findLast', 'findLastIndex', - 'findLastKey', 'flatMap', 'flatMapDeep', 'flattenDepth', 'forEach', - 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight', 'get', - 'groupBy', 'gt', 'gte', 'has', 'hasIn', 'includes', 'indexOf', 'intersection', - 'invertBy', 'invoke', 'invokeMap', 'isEqual', 'isMatch', 'join', 'keyBy', - 'lastIndexOf', 'lt', 'lte', 'map', 'mapKeys', 'mapValues', 'matchesProperty', - 'maxBy', 'meanBy', 'merge', 'mergeAllWith', 'minBy', 'multiply', 'nth', 'omit', - 'omitBy', 'overArgs', 'pad', 'padEnd', 'padStart', 'parseInt', 'partial', - 'partialRight', 'partition', 'pick', 'pickBy', 'propertyOf', 'pull', 'pullAll', - 'pullAt', 'random', 'range', 'rangeRight', 'rearg', 'reject', 'remove', - 'repeat', 'restFrom', 'result', 'sampleSize', 'some', 'sortBy', 'sortedIndex', - 'sortedIndexOf', 'sortedLastIndex', 'sortedLastIndexOf', 'sortedUniqBy', - 'split', 'spreadFrom', 'startsWith', 'subtract', 'sumBy', 'take', 'takeRight', - 'takeRightWhile', 'takeWhile', 'tap', 'throttle', 'thru', 'times', 'trimChars', - 'trimCharsEnd', 'trimCharsStart', 'truncate', 'union', 'uniqBy', 'uniqWith', - 'unset', 'unzipWith', 'without', 'wrap', 'xor', 'zip', 'zipObject', - 'zipObjectDeep' - ], - '3': [ - 'assignInWith', 'assignWith', 'clamp', 'differenceBy', 'differenceWith', - 'findFrom', 'findIndexFrom', 'findLastFrom', 'findLastIndexFrom', 'getOr', - 'includesFrom', 'indexOfFrom', 'inRange', 'intersectionBy', 'intersectionWith', - 'invokeArgs', 'invokeArgsMap', 'isEqualWith', 'isMatchWith', 'flatMapDepth', - 'lastIndexOfFrom', 'mergeWith', 'orderBy', 'padChars', 'padCharsEnd', - 'padCharsStart', 'pullAllBy', 'pullAllWith', 'reduce', 'reduceRight', 'replace', - 'set', 'slice', 'sortedIndexBy', 'sortedLastIndexBy', 'transform', 'unionBy', - 'unionWith', 'update', 'xorBy', 'xorWith', 'zipWith' - ], - '4': [ - 'fill', 'setWith', 'updateWith' - ] - }; - - /** Used to map ary to rearg configs. */ - exports.aryRearg = { - '2': [1, 0], - '3': [2, 0, 1], - '4': [3, 2, 0, 1] - }; - - /** Used to map method names to their iteratee ary. */ - exports.iterateeAry = { - 'dropRightWhile': 1, - 'dropWhile': 1, - 'every': 1, - 'filter': 1, - 'find': 1, - 'findFrom': 1, - 'findIndex': 1, - 'findIndexFrom': 1, - 'findKey': 1, - 'findLast': 1, - 'findLastFrom': 1, - 'findLastIndex': 1, - 'findLastIndexFrom': 1, - 'findLastKey': 1, - 'flatMap': 1, - 'flatMapDeep': 1, - 'flatMapDepth': 1, - 'forEach': 1, - 'forEachRight': 1, - 'forIn': 1, - 'forInRight': 1, - 'forOwn': 1, - 'forOwnRight': 1, - 'map': 1, - 'mapKeys': 1, - 'mapValues': 1, - 'partition': 1, - 'reduce': 2, - 'reduceRight': 2, - 'reject': 1, - 'remove': 1, - 'some': 1, - 'takeRightWhile': 1, - 'takeWhile': 1, - 'times': 1, - 'transform': 2 - }; - - /** Used to map method names to iteratee rearg configs. */ - exports.iterateeRearg = { - 'mapKeys': [1] - }; - - /** Used to map method names to rearg configs. */ - exports.methodRearg = { - 'assignInAllWith': [1, 2, 0], - 'assignInWith': [1, 2, 0], - 'assignAllWith': [1, 2, 0], - 'assignWith': [1, 2, 0], - 'differenceBy': [1, 2, 0], - 'differenceWith': [1, 2, 0], - 'getOr': [2, 1, 0], - 'intersectionBy': [1, 2, 0], - 'intersectionWith': [1, 2, 0], - 'isEqualWith': [1, 2, 0], - 'isMatchWith': [2, 1, 0], - 'mergeAllWith': [1, 2, 0], - 'mergeWith': [1, 2, 0], - 'padChars': [2, 1, 0], - 'padCharsEnd': [2, 1, 0], - 'padCharsStart': [2, 1, 0], - 'pullAllBy': [2, 1, 0], - 'pullAllWith': [2, 1, 0], - 'setWith': [3, 1, 2, 0], - 'sortedIndexBy': [2, 1, 0], - 'sortedLastIndexBy': [2, 1, 0], - 'unionBy': [1, 2, 0], - 'unionWith': [1, 2, 0], - 'updateWith': [3, 1, 2, 0], - 'xorBy': [1, 2, 0], - 'xorWith': [1, 2, 0], - 'zipWith': [1, 2, 0] - }; - - /** Used to map method names to spread configs. */ - exports.methodSpread = { - 'assignAll': { 'start': 0 }, - 'assignAllWith': { 'afterRearg': true, 'start': 1 }, - 'assignInAll': { 'start': 0 }, - 'assignInAllWith': { 'afterRearg': true, 'start': 1 }, - 'defaultsAll': { 'start': 0 }, - 'defaultsDeepAll': { 'start': 0 }, - 'invokeArgs': { 'start': 2 }, - 'invokeArgsMap': { 'start': 2 }, - 'mergeAll': { 'start': 0 }, - 'mergeAllWith': { 'afterRearg': true, 'start': 1 }, - 'partial': { 'start': 1 }, - 'partialRight': { 'start': 1 }, - 'without': { 'start': 1 }, - 'zipAll': { 'start': 0 } - }; - - /** Used to identify methods which mutate arrays or objects. */ - exports.mutate = { - 'array': { - 'fill': true, - 'pull': true, - 'pullAll': true, - 'pullAllBy': true, - 'pullAllWith': true, - 'pullAt': true, - 'remove': true, - 'reverse': true - }, - 'object': { - 'assign': true, - 'assignAll': true, - 'assignAllWith': true, - 'assignIn': true, - 'assignInAll': true, - 'assignInAllWith': true, - 'assignInWith': true, - 'assignWith': true, - 'defaults': true, - 'defaultsAll': true, - 'defaultsDeep': true, - 'defaultsDeepAll': true, - 'merge': true, - 'mergeAll': true, - 'mergeAllWith': true, - 'mergeWith': true, - }, - 'set': { - 'set': true, - 'setWith': true, - 'unset': true, - 'update': true, - 'updateWith': true - } - }; - - /** Used to track methods with placeholder support */ - exports.placeholder = { - 'bind': true, - 'bindKey': true, - 'curry': true, - 'curryRight': true, - 'partial': true, - 'partialRight': true - }; - - /** Used to map real names to their aliases. */ - exports.realToAlias = (function() { - var hasOwnProperty = Object.prototype.hasOwnProperty, - object = exports.aliasToReal, - result = {}; - - for (var key in object) { - var value = object[key]; - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - } - return result; - }()); - - /** Used to map method names to other names. */ - exports.remap = { - 'assignAll': 'assign', - 'assignAllWith': 'assignWith', - 'assignInAll': 'assignIn', - 'assignInAllWith': 'assignInWith', - 'curryN': 'curry', - 'curryRightN': 'curryRight', - 'defaultsAll': 'defaults', - 'defaultsDeepAll': 'defaultsDeep', - 'findFrom': 'find', - 'findIndexFrom': 'findIndex', - 'findLastFrom': 'findLast', - 'findLastIndexFrom': 'findLastIndex', - 'getOr': 'get', - 'includesFrom': 'includes', - 'indexOfFrom': 'indexOf', - 'invokeArgs': 'invoke', - 'invokeArgsMap': 'invokeMap', - 'lastIndexOfFrom': 'lastIndexOf', - 'mergeAll': 'merge', - 'mergeAllWith': 'mergeWith', - 'padChars': 'pad', - 'padCharsEnd': 'padEnd', - 'padCharsStart': 'padStart', - 'propertyOf': 'get', - 'restFrom': 'rest', - 'spreadFrom': 'spread', - 'trimChars': 'trim', - 'trimCharsEnd': 'trimEnd', - 'trimCharsStart': 'trimStart', - 'zipAll': 'zip' - }; - - /** Used to track methods that skip fixing their arity. */ - exports.skipFixed = { - 'castArray': true, - 'flow': true, - 'flowRight': true, - 'iteratee': true, - 'mixin': true, - 'rearg': true, - 'runInContext': true - }; - - /** Used to track methods that skip rearranging arguments. */ - exports.skipRearg = { - 'add': true, - 'assign': true, - 'assignIn': true, - 'bind': true, - 'bindKey': true, - 'concat': true, - 'difference': true, - 'divide': true, - 'eq': true, - 'gt': true, - 'gte': true, - 'isEqual': true, - 'lt': true, - 'lte': true, - 'matchesProperty': true, - 'merge': true, - 'multiply': true, - 'overArgs': true, - 'partial': true, - 'partialRight': true, - 'propertyOf': true, - 'random': true, - 'range': true, - 'rangeRight': true, - 'subtract': true, - 'zip': true, - 'zipObject': true, - 'zipObjectDeep': true - }; - - -/***/ }, -/* 3 */ -/***/ function(module, exports) { - - /** - * The default argument placeholder value for methods. - * - * @type {Object} - */ - module.exports = {}; - - -/***/ } -/******/ ]) -}); -; \ No newline at end of file diff --git a/public/vendor/lodash/dist/lodash.fp.min.js b/public/vendor/lodash/dist/lodash.fp.min.js deleted file mode 100644 index f1a25b010e6..00000000000 --- a/public/vendor/lodash/dist/lodash.fp.min.js +++ /dev/null @@ -1,20 +0,0 @@ -(function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.fp=e():t.fp=e()})(this,function(){return function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return t[n].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){function n(t,e){return i(t,t,e)}var i=r(1);"function"==typeof _&&(_=n(_.runInContext())), -t.exports=n},function(t,e,r){function n(t,e){return 2==e?function(e,r){return t.apply(void 0,arguments)}:function(e){return t.apply(void 0,arguments)}}function i(t,e){return 2==e?function(e,r){return t(e,r)}:function(e){return t(e)}}function a(t){for(var e=t?t.length:0,r=Array(e);e--;)r[e]=t[e];return r}function o(t){return function(e){return t({},e)}}function s(t,e){return function(){var r=arguments.length;if(r){for(var n=Array(r);r--;)n[r]=arguments[r];var i=n[0]=e.apply(void 0,n);return t.apply(void 0,n), -i}}}function l(t,e,r,d){function c(t,e){if(B.cap){var r=u.iterateeRearg[t];if(r)return x(e,r);var n=!b&&u.iterateeAry[t];if(n)return W(e,n)}return e}function h(t,e,r){return E||B.curry&&r>1?q(e,r):e}function g(t,e,r){if(B.fixed&&(F||!u.skipFixed[t])){var n=u.methodSpread[t],i=n&&n.start;return void 0===i?M(e,r):N(e,i)}return e}function y(t,e,r){return B.rearg&&r>1&&(j||!u.skipRearg[t])?_(e,u.methodRearg[t]||u.aryRearg[r]):e}function m(t,e){e=U(e);for(var r=-1,n=e.length,i=n-1,a=z(Object(t)),o=a;null!=o&&++r2?r-2:1,a&&a<=r?n:i(n,r)):n}}, -mixin:function(t){return function(e){var r=this;if(!T(r))return t(r,Object(e));var n=[];return P(K(e),function(t){T(e[t])&&n.push([t,r.prototype[t]])}),t(r,Object(e)),P(n,function(t){var e=t[1];T(e)?r.prototype[t[0]]=e:delete r.prototype[t[0]]}),r}},nthArg:function(t){return function(e){var r=e<0?1:V(e)+1;return q(t(e),r)}},rearg:function(t){return function(e,r){var n=r?r.length:0;return q(t(e,r),n)}},runInContext:function(e){return function(r){return l(t,e(r),d)}}};if(!k)return R(e,r);var J=r,Q=[]; -return P(G,function(t){P(u.aryMethod[t],function(t){var e=J[u.remap[t]||t];e&&Q.push([t,R(t,e)])})}),P(K(J),function(t){var e=J[t];if("function"==typeof e){for(var r=Q.length;r--;)if(Q[r][0]==t)return;e.convert=A(t,e),Q.push([t,e])}}),P(Q,function(t){J[t[0]]=t[1]}),J.convert=v,O&&(J.placeholder=L),P(K(J),function(t){P(u.realToAlias[t]||[],function(e){J[e]=J[t]})}),J}var u=r(2),p=u.mutate,f=r(3);t.exports=l},function(t,e){e.aliasToReal={each:"forEach",eachRight:"forEachRight",entries:"toPairs",entriesIn:"toPairsIn", -extend:"assignIn",extendAll:"assignInAll",extendAllWith:"assignInAllWith",extendWith:"assignInWith",first:"head",conforms:"conformsTo",matches:"isMatch",property:"get",__:"placeholder",F:"stubFalse",T:"stubTrue",all:"every",allPass:"overEvery",always:"constant",any:"some",anyPass:"overSome",apply:"spread",assoc:"set",assocPath:"set",complement:"negate",compose:"flowRight",contains:"includes",dissoc:"unset",dissocPath:"unset",dropLast:"dropRight",dropLastWhile:"dropRightWhile",equals:"isEqual",identical:"eq", -indexBy:"keyBy",init:"initial",invertObj:"invert",juxt:"over",omitAll:"omit",nAry:"ary",path:"get",pathEq:"matchesProperty",pathOr:"getOr",paths:"at",pickAll:"pick",pipe:"flow",pluck:"map",prop:"get",propEq:"matchesProperty",propOr:"getOr",props:"at",symmetricDifference:"xor",symmetricDifferenceBy:"xorBy",symmetricDifferenceWith:"xorWith",takeLast:"takeRight",takeLastWhile:"takeRightWhile",unapply:"rest",unnest:"flatten",useWith:"overArgs",where:"conformsTo",whereEq:"isMatch",zipObj:"zipObject"}, -e.aryMethod={1:["assignAll","assignInAll","attempt","castArray","ceil","create","curry","curryRight","defaultsAll","defaultsDeepAll","floor","flow","flowRight","fromPairs","invert","iteratee","memoize","method","mergeAll","methodOf","mixin","nthArg","over","overEvery","overSome","rest","reverse","round","runInContext","spread","template","trim","trimEnd","trimStart","uniqueId","words","zipAll"],2:["add","after","ary","assign","assignAllWith","assignIn","assignInAllWith","at","before","bind","bindAll","bindKey","chunk","cloneDeepWith","cloneWith","concat","conformsTo","countBy","curryN","curryRightN","debounce","defaults","defaultsDeep","defaultTo","delay","difference","divide","drop","dropRight","dropRightWhile","dropWhile","endsWith","eq","every","filter","find","findIndex","findKey","findLast","findLastIndex","findLastKey","flatMap","flatMapDeep","flattenDepth","forEach","forEachRight","forIn","forInRight","forOwn","forOwnRight","get","groupBy","gt","gte","has","hasIn","includes","indexOf","intersection","invertBy","invoke","invokeMap","isEqual","isMatch","join","keyBy","lastIndexOf","lt","lte","map","mapKeys","mapValues","matchesProperty","maxBy","meanBy","merge","mergeAllWith","minBy","multiply","nth","omit","omitBy","overArgs","pad","padEnd","padStart","parseInt","partial","partialRight","partition","pick","pickBy","propertyOf","pull","pullAll","pullAt","random","range","rangeRight","rearg","reject","remove","repeat","restFrom","result","sampleSize","some","sortBy","sortedIndex","sortedIndexOf","sortedLastIndex","sortedLastIndexOf","sortedUniqBy","split","spreadFrom","startsWith","subtract","sumBy","take","takeRight","takeRightWhile","takeWhile","tap","throttle","thru","times","trimChars","trimCharsEnd","trimCharsStart","truncate","union","uniqBy","uniqWith","unset","unzipWith","without","wrap","xor","zip","zipObject","zipObjectDeep"], -3:["assignInWith","assignWith","clamp","differenceBy","differenceWith","findFrom","findIndexFrom","findLastFrom","findLastIndexFrom","getOr","includesFrom","indexOfFrom","inRange","intersectionBy","intersectionWith","invokeArgs","invokeArgsMap","isEqualWith","isMatchWith","flatMapDepth","lastIndexOfFrom","mergeWith","orderBy","padChars","padCharsEnd","padCharsStart","pullAllBy","pullAllWith","reduce","reduceRight","replace","set","slice","sortedIndexBy","sortedLastIndexBy","transform","unionBy","unionWith","update","xorBy","xorWith","zipWith"], -4:["fill","setWith","updateWith"]},e.aryRearg={2:[1,0],3:[2,0,1],4:[3,2,0,1]},e.iterateeAry={dropRightWhile:1,dropWhile:1,every:1,filter:1,find:1,findFrom:1,findIndex:1,findIndexFrom:1,findKey:1,findLast:1,findLastFrom:1,findLastIndex:1,findLastIndexFrom:1,findLastKey:1,flatMap:1,flatMapDeep:1,flatMapDepth:1,forEach:1,forEachRight:1,forIn:1,forInRight:1,forOwn:1,forOwnRight:1,map:1,mapKeys:1,mapValues:1,partition:1,reduce:2,reduceRight:2,reject:1,remove:1,some:1,takeRightWhile:1,takeWhile:1,times:1, -transform:2},e.iterateeRearg={mapKeys:[1]},e.methodRearg={assignInAllWith:[1,2,0],assignInWith:[1,2,0],assignAllWith:[1,2,0],assignWith:[1,2,0],differenceBy:[1,2,0],differenceWith:[1,2,0],getOr:[2,1,0],intersectionBy:[1,2,0],intersectionWith:[1,2,0],isEqualWith:[1,2,0],isMatchWith:[2,1,0],mergeAllWith:[1,2,0],mergeWith:[1,2,0],padChars:[2,1,0],padCharsEnd:[2,1,0],padCharsStart:[2,1,0],pullAllBy:[2,1,0],pullAllWith:[2,1,0],setWith:[3,1,2,0],sortedIndexBy:[2,1,0],sortedLastIndexBy:[2,1,0],unionBy:[1,2,0], -unionWith:[1,2,0],updateWith:[3,1,2,0],xorBy:[1,2,0],xorWith:[1,2,0],zipWith:[1,2,0]},e.methodSpread={assignAll:{start:0},assignAllWith:{afterRearg:!0,start:1},assignInAll:{start:0},assignInAllWith:{afterRearg:!0,start:1},defaultsAll:{start:0},defaultsDeepAll:{start:0},invokeArgs:{start:2},invokeArgsMap:{start:2},mergeAll:{start:0},mergeAllWith:{afterRearg:!0,start:1},partial:{start:1},partialRight:{start:1},without:{start:1},zipAll:{start:0}},e.mutate={array:{fill:!0,pull:!0,pullAll:!0,pullAllBy:!0, -pullAllWith:!0,pullAt:!0,remove:!0,reverse:!0},object:{assign:!0,assignAll:!0,assignAllWith:!0,assignIn:!0,assignInAll:!0,assignInAllWith:!0,assignInWith:!0,assignWith:!0,defaults:!0,defaultsAll:!0,defaultsDeep:!0,defaultsDeepAll:!0,merge:!0,mergeAll:!0,mergeAllWith:!0,mergeWith:!0},set:{set:!0,setWith:!0,unset:!0,update:!0,updateWith:!0}},e.placeholder={bind:!0,bindKey:!0,curry:!0,curryRight:!0,partial:!0,partialRight:!0},e.realToAlias=function(){var t=Object.prototype.hasOwnProperty,r=e.aliasToReal,n={}; -for(var i in r){var a=r[i];t.call(n,a)?n[a].push(i):n[a]=[i]}return n}(),e.remap={assignAll:"assign",assignAllWith:"assignWith",assignInAll:"assignIn",assignInAllWith:"assignInWith",curryN:"curry",curryRightN:"curryRight",defaultsAll:"defaults",defaultsDeepAll:"defaultsDeep",findFrom:"find",findIndexFrom:"findIndex",findLastFrom:"findLast",findLastIndexFrom:"findLastIndex",getOr:"get",includesFrom:"includes",indexOfFrom:"indexOf",invokeArgs:"invoke",invokeArgsMap:"invokeMap",lastIndexOfFrom:"lastIndexOf", -mergeAll:"merge",mergeAllWith:"mergeWith",padChars:"pad",padCharsEnd:"padEnd",padCharsStart:"padStart",propertyOf:"get",restFrom:"rest",spreadFrom:"spread",trimChars:"trim",trimCharsEnd:"trimEnd",trimCharsStart:"trimStart",zipAll:"zip"},e.skipFixed={castArray:!0,flow:!0,flowRight:!0,iteratee:!0,mixin:!0,rearg:!0,runInContext:!0},e.skipRearg={add:!0,assign:!0,assignIn:!0,bind:!0,bindKey:!0,concat:!0,difference:!0,divide:!0,eq:!0,gt:!0,gte:!0,isEqual:!0,lt:!0,lte:!0,matchesProperty:!0,merge:!0,multiply:!0, -overArgs:!0,partial:!0,partialRight:!0,propertyOf:!0,random:!0,range:!0,rangeRight:!0,subtract:!0,zip:!0,zipObject:!0,zipObjectDeep:!0}},function(t,e){t.exports={}}])}); \ No newline at end of file diff --git a/public/vendor/lodash/dist/lodash.js b/public/vendor/lodash/dist/lodash.js deleted file mode 100644 index 6b252563043..00000000000 --- a/public/vendor/lodash/dist/lodash.js +++ /dev/null @@ -1,16733 +0,0 @@ -/** - * @license - * lodash - * Copyright jQuery Foundation and other contributors - * Released under MIT license - * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - */ -;(function() { - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the semantic version number. */ - var VERSION = '4.15.0'; - - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Used as the `TypeError` message for "Functions" methods. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED = '__lodash_hash_undefined__'; - - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - - /** Used to compose bitmasks for function metadata. */ - var BIND_FLAG = 1, - BIND_KEY_FLAG = 2, - CURRY_BOUND_FLAG = 4, - CURRY_FLAG = 8, - CURRY_RIGHT_FLAG = 16, - PARTIAL_FLAG = 32, - PARTIAL_RIGHT_FLAG = 64, - ARY_FLAG = 128, - REARG_FLAG = 256, - FLIP_FLAG = 512; - - /** Used to compose bitmasks for comparison styles. */ - var UNORDERED_COMPARE_FLAG = 1, - PARTIAL_COMPARE_FLAG = 2; - - /** Used as default options for `_.truncate`. */ - var DEFAULT_TRUNC_LENGTH = 30, - DEFAULT_TRUNC_OMISSION = '...'; - - /** Used to detect hot functions by number of calls within a span of milliseconds. */ - var HOT_COUNT = 150, - HOT_SPAN = 16; - - /** Used to indicate the type of lazy iteratees. */ - var LAZY_FILTER_FLAG = 1, - LAZY_MAP_FLAG = 2, - LAZY_WHILE_FLAG = 3; - - /** Used as references for various `Number` constants. */ - var INFINITY = 1 / 0, - MAX_SAFE_INTEGER = 9007199254740991, - MAX_INTEGER = 1.7976931348623157e+308, - NAN = 0 / 0; - - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, - HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - - /** Used to associate wrap methods with their bit flags. */ - var wrapFlags = [ - ['ary', ARY_FLAG], - ['bind', BIND_FLAG], - ['bindKey', BIND_KEY_FLAG], - ['curry', CURRY_FLAG], - ['curryRight', CURRY_RIGHT_FLAG], - ['flip', FLIP_FLAG], - ['partial', PARTIAL_FLAG], - ['partialRight', PARTIAL_RIGHT_FLAG], - ['rearg', REARG_FLAG] - ]; - - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - mapTag = '[object Map]', - numberTag = '[object Number]', - objectTag = '[object Object]', - promiseTag = '[object Promise]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - symbolTag = '[object Symbol]', - weakMapTag = '[object WeakMap]', - weakSetTag = '[object WeakSet]'; - - var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - - /** Used to match empty string literals in compiled template source. */ - var reEmptyStringLeading = /\b__p \+= '';/g, - reEmptyStringMiddle = /\b(__p \+=) '' \+/g, - reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; - - /** Used to match HTML entities and HTML characters. */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g, - reUnescapedHtml = /[&<>"'`]/g, - reHasEscapedHtml = RegExp(reEscapedHtml.source), - reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - - /** Used to match template delimiters. */ - var reEscape = /<%-([\s\S]+?)%>/g, - reEvaluate = /<%([\s\S]+?)%>/g, - reInterpolate = /<%=([\s\S]+?)%>/g; - - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/, - reLeadingDot = /^\./, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - - /** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, - reHasRegExpChar = RegExp(reRegExpChar.source); - - /** Used to match leading and trailing whitespace. */ - var reTrim = /^\s+|\s+$/g, - reTrimStart = /^\s+/, - reTrimEnd = /\s+$/; - - /** Used to match wrap detail comments. */ - var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, - reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, - reSplitDetails = /,? & /; - - /** Used to match words composed of alphanumeric characters. */ - var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; - - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; - - /** - * Used to match - * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). - */ - var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; - - /** Used to match `RegExp` flags from their coerced string values. */ - var reFlags = /\w*$/; - - /** Used to detect hexadecimal string values. */ - var reHasHexPrefix = /^0x/i; - - /** Used to detect bad signed hexadecimal string values. */ - var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - - /** Used to detect binary string values. */ - var reIsBinary = /^0b[01]+$/i; - - /** Used to detect host constructors (Safari). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - /** Used to detect octal string values. */ - var reIsOctal = /^0o[0-7]+$/i; - - /** Used to detect unsigned integer values. */ - var reIsUint = /^(?:0|[1-9]\d*)$/; - - /** Used to match Latin Unicode letters (excluding mathematical operators). */ - var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; - - /** Used to ensure capturing order of template delimiters. */ - var reNoMatch = /($^)/; - - /** Used to match unescaped characters in compiled string literals. */ - var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - - /** Used to compose unicode character classes. */ - var rsAstralRange = '\\ud800-\\udfff', - rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23', - rsComboSymbolsRange = '\\u20d0-\\u20f0', - rsDingbatRange = '\\u2700-\\u27bf', - rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', - rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', - rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', - rsPunctuationRange = '\\u2000-\\u206f', - rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', - rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', - rsVarRange = '\\ufe0e\\ufe0f', - rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; - - /** Used to compose unicode capture groups. */ - var rsApos = "['\u2019]", - rsAstral = '[' + rsAstralRange + ']', - rsBreak = '[' + rsBreakRange + ']', - rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']', - rsDigits = '\\d+', - rsDingbat = '[' + rsDingbatRange + ']', - rsLower = '[' + rsLowerRange + ']', - rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', - rsFitz = '\\ud83c[\\udffb-\\udfff]', - rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', - rsNonAstral = '[^' + rsAstralRange + ']', - rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', - rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', - rsUpper = '[' + rsUpperRange + ']', - rsZWJ = '\\u200d'; - - /** Used to compose unicode regexes. */ - var rsLowerMisc = '(?:' + rsLower + '|' + rsMisc + ')', - rsUpperMisc = '(?:' + rsUpper + '|' + rsMisc + ')', - rsOptLowerContr = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', - rsOptUpperContr = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', - reOptMod = rsModifier + '?', - rsOptVar = '[' + rsVarRange + ']?', - rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', - rsSeq = rsOptVar + reOptMod + rsOptJoin, - rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, - rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; - - /** Used to match apostrophes. */ - var reApos = RegExp(rsApos, 'g'); - - /** - * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and - * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). - */ - var reComboMark = RegExp(rsCombo, 'g'); - - /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ - var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); - - /** Used to match complex or compound words. */ - var reUnicodeWord = RegExp([ - rsUpper + '?' + rsLower + '+' + rsOptLowerContr + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', - rsUpperMisc + '+' + rsOptUpperContr + '(?=' + [rsBreak, rsUpper + rsLowerMisc, '$'].join('|') + ')', - rsUpper + '?' + rsLowerMisc + '+' + rsOptLowerContr, - rsUpper + '+' + rsOptUpperContr, - rsDigits, - rsEmoji - ].join('|'), 'g'); - - /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ - var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboMarksRange + rsComboSymbolsRange + rsVarRange + ']'); - - /** Used to detect strings that need a more robust regexp to match words. */ - var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; - - /** Used to assign default `context` object properties. */ - var contextProps = [ - 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', - 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', - 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', - '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' - ]; - - /** Used to make template sourceURLs easier to identify. */ - var templateCounter = -1; - - /** Used to identify `toStringTag` values of typed arrays. */ - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = - typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = - typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = - typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = - typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = - typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = - typedArrayTags[errorTag] = typedArrayTags[funcTag] = - typedArrayTags[mapTag] = typedArrayTags[numberTag] = - typedArrayTags[objectTag] = typedArrayTags[regexpTag] = - typedArrayTags[setTag] = typedArrayTags[stringTag] = - typedArrayTags[weakMapTag] = false; - - /** Used to identify `toStringTag` values supported by `_.clone`. */ - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = - cloneableTags[boolTag] = cloneableTags[dateTag] = - cloneableTags[float32Tag] = cloneableTags[float64Tag] = - cloneableTags[int8Tag] = cloneableTags[int16Tag] = - cloneableTags[int32Tag] = cloneableTags[mapTag] = - cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[setTag] = - cloneableTags[stringTag] = cloneableTags[symbolTag] = - cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = - cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = - cloneableTags[weakMapTag] = false; - - /** Used to map Latin Unicode letters to basic Latin letters. */ - var deburredLetters = { - // Latin-1 Supplement block. - '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', - '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', - '\xc7': 'C', '\xe7': 'c', - '\xd0': 'D', '\xf0': 'd', - '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', - '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', - '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', - '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', - '\xd1': 'N', '\xf1': 'n', - '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', - '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', - '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', - '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', - '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', - '\xc6': 'Ae', '\xe6': 'ae', - '\xde': 'Th', '\xfe': 'th', - '\xdf': 'ss', - // Latin Extended-A block. - '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', - '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', - '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', - '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', - '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', - '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', - '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', - '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', - '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', - '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', - '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', - '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', - '\u0134': 'J', '\u0135': 'j', - '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', - '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', - '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', - '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', - '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', - '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', - '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', - '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', - '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', - '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', - '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', - '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', - '\u0163': 't', '\u0165': 't', '\u0167': 't', - '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', - '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', - '\u0174': 'W', '\u0175': 'w', - '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', - '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', - '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', - '\u0132': 'IJ', '\u0133': 'ij', - '\u0152': 'Oe', '\u0153': 'oe', - '\u0149': "'n", '\u017f': 'ss' - }; - - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`' - }; - - /** Used to map HTML entities to characters. */ - var htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'", - '`': '`' - }; - - /** Used to escape characters for inclusion in compiled string literals. */ - var stringEscapes = { - '\\': '\\', - "'": "'", - '\n': 'n', - '\r': 'r', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - /** Built-in method references without a dependency on `root`. */ - var freeParseFloat = parseFloat, - freeParseInt = parseInt; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - - /** Detect free variable `self`. */ - var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - - /** Used as a reference to the global object. */ - var root = freeGlobal || freeSelf || Function('return this')(); - - /** Detect free variable `exports`. */ - var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports; - - /** Detect free variable `process` from Node.js. */ - var freeProcess = moduleExports && freeGlobal.process; - - /** Used to access faster Node.js helpers. */ - var nodeUtil = (function() { - try { - return freeProcess && freeProcess.binding('util'); - } catch (e) {} - }()); - - /* Node.js helper references. */ - var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, - nodeIsDate = nodeUtil && nodeUtil.isDate, - nodeIsMap = nodeUtil && nodeUtil.isMap, - nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, - nodeIsSet = nodeUtil && nodeUtil.isSet, - nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; - - /*--------------------------------------------------------------------------*/ - - /** - * Adds the key-value `pair` to `map`. - * - * @private - * @param {Object} map The map to modify. - * @param {Array} pair The key-value pair to add. - * @returns {Object} Returns `map`. - */ - function addMapEntry(map, pair) { - // Don't return `map.set` because it's not chainable in IE 11. - map.set(pair[0], pair[1]); - return map; - } - - /** - * Adds `value` to `set`. - * - * @private - * @param {Object} set The set to modify. - * @param {*} value The value to add. - * @returns {Object} Returns `set`. - */ - function addSetEntry(set, value) { - // Don't return `set.add` because it's not chainable in IE 11. - set.add(value); - return set; - } - - /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} args The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ - function apply(func, thisArg, args) { - switch (args.length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); - } - - /** - * A specialized version of `baseAggregator` for arrays. - * - * @private - * @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. - * @returns {Function} Returns `accumulator`. - */ - function arrayAggregator(array, setter, iteratee, accumulator) { - var index = -1, - length = array ? array.length : 0; - - while (++index < length) { - var value = array[index]; - setter(accumulator, value, iteratee(value), array); - } - return accumulator; - } - - /** - * A specialized version of `_.forEach` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 ? array.length : 0; - - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.forEachRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 ? array.length : 0; - - while (length--) { - if (iteratee(array[length], length, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.every` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 ? array.length : 0; - - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } - } - return true; - } - - /** - * A specialized version of `_.filter` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 ? array.length : 0, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * A specialized version of `_.includes` for arrays without support for - * specifying an index to search from. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludes(array, value) { - 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 inspect. - * @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 ? array.length : 0; - - while (++index < length) { - if (comparator(value, array[index])) { - return true; - } - } - return false; - } - - /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @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 ? array.length : 0, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } - - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; - - while (++index < length) { - array[offset + index] = values[index]; - } - return array; - } - - /** - * A specialized version of `_.reduce` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initAccum) { - var index = -1, - length = array ? array.length : 0; - - if (initAccum && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } - - /** - * A specialized version of `_.reduceRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduceRight(array, iteratee, accumulator, initAccum) { - var length = array ? array.length : 0; - if (initAccum && length) { - accumulator = array[--length]; - } - while (length--) { - accumulator = iteratee(accumulator, array[length], length, array); - } - return accumulator; - } - - /** - * A specialized version of `_.some` for arrays without support for iteratee - * shorthands. - * - * @private - * @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 ? array.length : 0; - - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; - } - - /** - * Gets the size of an ASCII `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - var asciiSize = baseProperty('length'); - - /** - * Converts an ASCII `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function asciiToArray(string) { - return string.split(''); - } - - /** - * Splits an ASCII `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function asciiWords(string) { - return string.match(reAsciiWord) || []; - } - - /** - * 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 inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFindKey(collection, predicate, eachFunc) { - var result; - eachFunc(collection, function(value, key, collection) { - if (predicate(value, key, collection)) { - result = key; - return false; - } - }); - return result; - } - - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @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, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); - - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - if (value !== value) { - return baseFindIndex(array, baseIsNaN, fromIndex); - } - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * This function is like `baseIndexOf` except that it accepts a comparator. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @param {Function} comparator The comparator invoked per element. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOfWith(array, value, fromIndex, comparator) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (comparator(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.isNaN` without support for number objects. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - */ - function baseIsNaN(value) { - return value !== value; - } - - /** - * The base implementation of `_.mean` and `_.meanBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the mean. - */ - function baseMean(array, iteratee) { - var length = array ? array.length : 0; - return length ? (baseSum(array, iteratee) / length) : NAN; - } - - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; - } - - /** - * The base implementation of `_.propertyOf` without support for deep paths. - * - * @private - * @param {Object} object The object to query. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyOf(object) { - return function(key) { - return object == null ? undefined : object[key]; - }; - } - - /** - * The base implementation of `_.reduce` and `_.reduceRight`, without support - * for iteratee shorthands, which iterates over `collection` using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initAccum Specify using the first or last element of - * `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initAccum - ? (initAccum = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.sortBy` which uses `comparer` to define the - * sort order of `array` and replaces criteria objects with their corresponding - * values. - * - * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. - */ - function baseSortBy(array, comparer) { - var length = array.length; - - array.sort(comparer); - while (length--) { - array[length] = array[length].value; - } - return array; - } - - /** - * The base implementation of `_.sum` and `_.sumBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(array, iteratee) { - var result, - index = -1, - length = array.length; - - while (++index < length) { - var current = iteratee(array[index]); - if (current !== undefined) { - result = result === undefined ? current : (result + current); - } - } - return result; - } - - /** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ - function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); - - while (++index < n) { - result[index] = iteratee(index); - } - return result; - } - - /** - * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array - * of key-value pairs for `object` corresponding to the property names of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the key-value pairs. - */ - function baseToPairs(object, props) { - return arrayMap(props, function(key) { - return [key, object[key]]; - }); - } - - /** - * The base implementation of `_.unary` without support for storing metadata. - * - * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - */ - function baseUnary(func) { - return function(value) { - return func(value); - }; - } - - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - return arrayMap(props, function(key) { - return object[key]; - }); - } - - /** - * 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. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the first unmatched string symbol. - */ - function charsStartIndex(strSymbols, chrSymbols) { - var index = -1, - length = strSymbols.length; - - while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the last unmatched string symbol. - */ - function charsEndIndex(strSymbols, chrSymbols) { - var index = strSymbols.length; - - while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Gets the number of `placeholder` occurrences in `array`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} placeholder The placeholder to search for. - * @returns {number} Returns the placeholder count. - */ - function countHolders(array, placeholder) { - var length = array.length, - result = 0; - - while (length--) { - if (array[length] === placeholder) { - result++; - } - } - return result; - } - - /** - * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A - * letters to basic Latin letters. - * - * @private - * @param {string} letter The matched letter to deburr. - * @returns {string} Returns the deburred letter. - */ - var deburrLetter = basePropertyOf(deburredLetters); - - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - var escapeHtmlChar = basePropertyOf(htmlEscapes); - - /** - * Used by `_.template` to escape characters for inclusion in compiled string literals. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - function escapeStringChar(chr) { - 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]; - } - - /** - * Checks if `string` contains Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a symbol is found, else `false`. - */ - function hasUnicode(string) { - return reHasUnicode.test(string); - } - - /** - * Checks if `string` contains a word composed of Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a word is found, else `false`. - */ - function hasUnicodeWord(string) { - return reHasUnicodeWord.test(string); - } - - /** - * Checks if `value` is a host object in IE < 9. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a host object, else `false`. - */ - function isHostObject(value) { - // Many host objects are `Object` objects that can coerce to strings - // despite having improperly defined `toString` methods. - var result = false; - if (value != null && typeof value.toString != 'function') { - try { - result = !!(value + ''); - } catch (e) {} - } - return result; - } - - /** - * Converts `iterator` to an array. - * - * @private - * @param {Object} iterator The iterator to convert. - * @returns {Array} Returns the converted array. - */ - function iteratorToArray(iterator) { - var data, - result = []; - - while (!(data = iterator.next()).done) { - result.push(data.value); - } - return result; - } - - /** - * Converts `map` to its key-value pairs. - * - * @private - * @param {Object} map The map to convert. - * @returns {Array} Returns the key-value pairs. - */ - function mapToArray(map) { - var index = -1, - result = Array(map.size); - - map.forEach(function(value, key) { - result[++index] = [key, value]; - }); - return result; - } - - /** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ - function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; - } - - /** - * Replaces all `placeholder` elements in `array` with an internal placeholder - * and returns an array of their indexes. - * - * @private - * @param {Array} array The array to modify. - * @param {*} placeholder The placeholder to replace. - * @returns {Array} Returns the new array of placeholder indexes. - */ - function replaceHolders(array, placeholder) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value === placeholder || value === PLACEHOLDER) { - array[index] = PLACEHOLDER; - result[resIndex++] = index; - } - } - return result; - } - - /** - * Converts `set` to an array of its values. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the values. - */ - function setToArray(set) { - var index = -1, - result = Array(set.size); - - set.forEach(function(value) { - result[++index] = value; - }); - 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`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the string size. - */ - function stringSize(string) { - return hasUnicode(string) - ? unicodeSize(string) - : asciiSize(string); - } - - /** - * Converts `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function stringToArray(string) { - return hasUnicode(string) - ? unicodeToArray(string) - : asciiToArray(string); - } - - /** - * Used by `_.unescape` to convert HTML entities to characters. - * - * @private - * @param {string} chr The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - var unescapeHtmlChar = basePropertyOf(htmlUnescapes); - - /** - * Gets the size of a Unicode `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - function unicodeSize(string) { - var result = reUnicode.lastIndex = 0; - while (reUnicode.test(string)) { - result++; - } - return result; - } - - /** - * Converts a Unicode `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function unicodeToArray(string) { - return string.match(reUnicode) || []; - } - - /** - * Splits a Unicode `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function unicodeWords(string) { - return string.match(reUnicodeWord) || []; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Create a new pristine `lodash` function using the `context` object. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Util - * @param {Object} [context=root] The context object. - * @returns {Function} Returns a new `lodash` function. - * @example - * - * _.mixin({ 'foo': _.constant('foo') }); - * - * var lodash = _.runInContext(); - * lodash.mixin({ 'bar': lodash.constant('bar') }); - * - * _.isFunction(_.foo); - * // => true - * _.isFunction(_.bar); - * // => false - * - * lodash.isFunction(lodash.foo); - * // => false - * lodash.isFunction(lodash.bar); - * // => true - * - * // Use `context` to stub `Date#getTime` use in `_.now`. - * var stubbed = _.runInContext({ - * 'Date': function() { - * return { 'getTime': stubGetTime }; - * } - * }); - * - * // Create a suped-up `defer` in Node.js. - * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; - */ - function runInContext(context) { - context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; - - /** Built-in constructor references. */ - var Array = context.Array, - Date = context.Date, - Error = context.Error, - Function = context.Function, - Math = context.Math, - Object = context.Object, - RegExp = context.RegExp, - String = context.String, - TypeError = context.TypeError; - - /** Used for built-in method references. */ - var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.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 = funcProto.toString; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - - /** Used to generate unique IDs. */ - var idCounter = 0; - - /** Used to infer the `Object` constructor. */ - var objectCtorString = funcToString.call(Object); - - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var objectToString = objectProto.toString; - - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = root._; - - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); - - /** Built-in value references. */ - var Buffer = moduleExports ? context.Buffer : undefined, - Symbol = context.Symbol, - Uint8Array = context.Uint8Array, - getPrototype = overArg(Object.getPrototypeOf, Object), - iteratorSymbol = Symbol ? Symbol.iterator : undefined, - objectCreate = Object.create, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - splice = arrayProto.splice, - spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined; - - /** Mocked built-ins. */ - var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, - ctxNow = Date && Date.now !== root.Date.now && Date.now, - ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; - - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeCeil = Math.ceil, - nativeFloor = Math.floor, - nativeGetSymbols = Object.getOwnPropertySymbols, - nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, - nativeIsFinite = context.isFinite, - nativeJoin = arrayProto.join, - nativeKeys = overArg(Object.keys, Object), - nativeMax = Math.max, - nativeMin = Math.min, - nativeParseInt = context.parseInt, - nativeRandom = Math.random, - nativeReverse = arrayProto.reverse; - - /* Built-in method references that are verified to be native. */ - var DataView = getNative(context, 'DataView'), - Map = getNative(context, 'Map'), - Promise = getNative(context, 'Promise'), - Set = getNative(context, 'Set'), - WeakMap = getNative(context, 'WeakMap'), - nativeCreate = getNative(Object, 'create'); - - /* Used to set `toString` methods. */ - var defineProperty = (function() { - var func = getNative(Object, 'defineProperty'), - name = getNative.name; - - return (name && name.length > 2) ? func : undefined; - }()); - - /** Used to store function metadata. */ - var metaMap = WeakMap && new WeakMap; - - /** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */ - var nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf'); - - /** Used to lookup unminified function names. */ - var realNames = {}; - - /** Used to detect maps, sets, and weakmaps. */ - var dataViewCtorString = toSource(DataView), - mapCtorString = toSource(Map), - promiseCtorString = toSource(Promise), - setCtorString = toSource(Set), - weakMapCtorString = toSource(WeakMap); - - /** Used to convert symbols to primitives and strings. */ - var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object which wraps `value` to enable implicit method - * chain sequences. Methods that operate on and return arrays, collections, - * and functions can be chained together. Methods that retrieve a single value - * or may return a primitive value will automatically end the chain sequence - * and return the unwrapped value. Otherwise, the value must be unwrapped - * with `_#value`. - * - * Explicit chain sequences, which must be unwrapped with `_#value`, may be - * enabled using `_.chain`. - * - * The execution of chained methods is lazy, that is, it's deferred until - * `_#value` is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. - * Shortcut fusion is an optimization to merge iteratee calls; this avoids - * the creation of intermediate arrays and can greatly reduce the number of - * iteratee executions. Sections of a chain sequence qualify for shortcut - * fusion if the section is applied to an array of at least `200` elements - * and any iteratees accept only one argument. The heuristic for whether a - * section qualifies for shortcut fusion is subject to change. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, - * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, - * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, - * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, - * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, - * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, - * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, - * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, - * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, - * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, - * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, - * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, - * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, - * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, - * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, - * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, - * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, - * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, - * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, - * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, - * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, - * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, - * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, - * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, - * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, - * `zipObject`, `zipObjectDeep`, and `zipWith` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, - * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, - * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, - * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, - * `findLastIndex`, `findLastKey`, `first`, `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`, `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 - * @category Seq - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2, 3]); - * - * // Returns an unwrapped value. - * wrapped.reduce(_.add); - * // => 6 - * - * // Returns a wrapped value. - * var squares = wrapped.map(square); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { - if (value instanceof LodashWrapper) { - return value; - } - if (hasOwnProperty.call(value, '__wrapped__')) { - return wrapperClone(value); - } - } - return new LodashWrapper(value); - } - - /** - * The function whose prototype chain sequence wrappers inherit from. - * - * @private - */ - function baseLodash() { - // No operation performed. - } - - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable explicit method chain sequences. - */ - function LodashWrapper(value, chainAll) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__chain__ = !!chainAll; - this.__index__ = 0; - this.__values__ = undefined; - } - - /** - * By default, the template delimiters used by lodash are like those in - * embedded Ruby (ERB). Change the following template settings to use - * alternative delimiters. - * - * @static - * @memberOf _ - * @type {Object} - */ - lodash.templateSettings = { - - /** - * Used to detect `data` property values to be HTML-escaped. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'escape': reEscape, - - /** - * Used to detect code to be evaluated. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'evaluate': reEvaluate, - - /** - * Used to detect `data` property values to inject. - * - * @memberOf _.templateSettings - * @type {RegExp} - */ - 'interpolate': reInterpolate, - - /** - * Used to reference the data object in the template text. - * - * @memberOf _.templateSettings - * @type {string} - */ - 'variable': '', - - /** - * Used to import variables into the compiled template. - * - * @memberOf _.templateSettings - * @type {Object} - */ - 'imports': { - - /** - * A reference to the `lodash` function. - * - * @memberOf _.templateSettings.imports - * @type {Function} - */ - '_': lodash - } - }; - - // Ensure wrappers are instances of `baseLodash`. - lodash.prototype = baseLodash.prototype; - lodash.prototype.constructor = lodash; - - LodashWrapper.prototype = baseCreate(baseLodash.prototype); - LodashWrapper.prototype.constructor = LodashWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. - * - * @private - * @constructor - * @param {*} value The value to wrap. - */ - function LazyWrapper(value) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__dir__ = 1; - this.__filtered__ = false; - this.__iteratees__ = []; - this.__takeCount__ = MAX_ARRAY_LENGTH; - this.__views__ = []; - } - - /** - * Creates a clone of the lazy wrapper object. - * - * @private - * @name clone - * @memberOf LazyWrapper - * @returns {Object} Returns the cloned `LazyWrapper` object. - */ - function lazyClone() { - var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = copyArray(this.__actions__); - result.__dir__ = this.__dir__; - result.__filtered__ = this.__filtered__; - result.__iteratees__ = copyArray(this.__iteratees__); - result.__takeCount__ = this.__takeCount__; - result.__views__ = copyArray(this.__views__); - return result; - } - - /** - * Reverses the direction of lazy iteration. - * - * @private - * @name reverse - * @memberOf LazyWrapper - * @returns {Object} Returns the new reversed `LazyWrapper` object. - */ - function lazyReverse() { - if (this.__filtered__) { - var result = new LazyWrapper(this); - result.__dir__ = -1; - result.__filtered__ = true; - } else { - result = this.clone(); - result.__dir__ *= -1; - } - return result; - } - - /** - * Extracts the unwrapped value from its lazy wrapper. - * - * @private - * @name value - * @memberOf LazyWrapper - * @returns {*} Returns the unwrapped value. - */ - function lazyValue() { - var array = this.__wrapped__.value(), - dir = this.__dir__, - isArr = isArray(array), - isRight = dir < 0, - arrLength = isArr ? array.length : 0, - view = getView(0, arrLength, this.__views__), - start = view.start, - end = view.end, - length = end - start, - index = isRight ? end : (start - 1), - iteratees = this.__iteratees__, - iterLength = iteratees.length, - resIndex = 0, - takeCount = nativeMin(length, this.__takeCount__); - - if (!isArr || arrLength < LARGE_ARRAY_SIZE || - (arrLength == length && takeCount == length)) { - return baseWrapperValue(array, this.__actions__); - } - var result = []; - - outer: - while (length-- && resIndex < takeCount) { - index += dir; - - var iterIndex = -1, - value = array[index]; - - while (++iterIndex < iterLength) { - var data = iteratees[iterIndex], - iteratee = data.iteratee, - type = data.type, - computed = iteratee(value); - - if (type == LAZY_MAP_FLAG) { - value = computed; - } else if (!computed) { - if (type == LAZY_FILTER_FLAG) { - continue outer; - } else { - break outer; - } - } - } - result[resIndex++] = value; - } - return result; - } - - // Ensure `LazyWrapper` is an instance of `baseLodash`. - LazyWrapper.prototype = baseCreate(baseLodash.prototype); - LazyWrapper.prototype.constructor = LazyWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a hash object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - 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(key) { - return this.has(key) && delete this.__data__[key]; - } - - /** - * Gets the hash value for `key`. - * - * @private - * @name get - * @memberOf Hash - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; - } - - /** - * Checks if a hash value for `key` exists. - * - * @private - * @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(key) { - var data = this.__data__; - return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); - } - - /** - * Sets the hash `key` to `value`. - * - * @private - * @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(key, value) { - var data = this.__data__; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; - return this; - } - - // 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; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function MapCache(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 map. - * - * @private - * @name clear - * @memberOf MapCache - */ - function mapCacheClear() { - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash - }; - } - - /** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function mapCacheDelete(key) { - return getMapData(this, key)['delete'](key); - } - - /** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function mapCacheGet(key) { - return getMapData(this, key).get(key); - } - - /** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapCacheHas(key) { - return getMapData(this, key).has(key); - } - - /** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ - function mapCacheSet(key, value) { - getMapData(this, key).set(key, value); - return this; - } - - // Add methods to `MapCache`. - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype['delete'] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; - - /*------------------------------------------------------------------------*/ - - /** - * - * Creates an array cache object to store unique values. - * - * @private - * @constructor - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var index = -1, - length = values ? values.length : 0; - - this.__data__ = new MapCache; - while (++index < length) { - this.add(values[index]); - } - } - - /** - * Adds `value` to the array cache. - * - * @private - * @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 setCacheHas(value) { - return this.__data__.has(value); - } - - // Add methods to `SetCache`. - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a stack cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Stack(entries) { - this.__data__ = new ListCache(entries); - } - - /** - * Removes all key-value entries from the stack. - * - * @private - * @name clear - * @memberOf Stack - */ - function stackClear() { - this.__data__ = new ListCache; - } - - /** - * Removes `key` and its value from the stack. - * - * @private - * @name delete - * @memberOf Stack - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function stackDelete(key) { - return this.__data__['delete'](key); - } - - /** - * Gets the stack value for `key`. - * - * @private - * @name get - * @memberOf Stack - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function stackGet(key) { - return this.__data__.get(key); - } - - /** - * Checks if a stack value for `key` exists. - * - * @private - * @name has - * @memberOf Stack - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function stackHas(key) { - return this.__data__.has(key); - } - - /** - * Sets the stack `key` to `value`. - * - * @private - * @name set - * @memberOf Stack - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the stack cache instance. - */ - function stackSet(key, value) { - var cache = this.__data__; - if (cache instanceof ListCache) { - var pairs = cache.__data__; - if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { - pairs.push([key, value]); - return this; - } - cache = this.__data__ = new MapCache(pairs); - } - cache.set(key, value); - return this; - } - - // Add methods to `Stack`. - Stack.prototype.clear = stackClear; - Stack.prototype['delete'] = stackDelete; - Stack.prototype.get = stackGet; - Stack.prototype.has = stackHas; - Stack.prototype.set = stackSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ - function arrayLikeKeys(value, inherited) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - // Safari 9 makes `arguments.length` enumerable in strict mode. - var result = (isArray(value) || isArguments(value)) - ? baseTimes(value.length, String) - : []; - - var length = result.length, - skipIndexes = !!length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && (key == 'length' || isIndex(key, length)))) { - result.push(key); - } - } - return result; - } - - /** - * Used by `_.defaults` to customize its `_.assignIn` use. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to assign. - * @param {Object} object The parent object of `objValue`. - * @returns {*} Returns the value to assign. - */ - function assignInDefaults(objValue, srcValue, key, object) { - if (objValue === undefined || - (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { - return srcValue; - } - return objValue; - } - - /** - * This function is like `assignValue` except that it doesn't assign - * `undefined` values. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignMergeValue(object, key, value) { - if ((value !== undefined && !eq(object[key], value)) || - (typeof key == 'number' && value === undefined && !(key in object))) { - object[key] = value; - } - } - - /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - object[key] = value; - } - } - - /** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @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`. - * - * @private - * @param {Array|Object} collection The collection 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. - * @returns {Function} Returns `accumulator`. - */ - function baseAggregator(collection, setter, iteratee, accumulator) { - baseEach(collection, function(value, key, collection) { - setter(accumulator, value, iteratee(value), collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.assign` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssign(object, source) { - return object && copyObject(source, keys(source), object); - } - - /** - * The base implementation of `_.at` without support for individual paths. - * - * @private - * @param {Object} object The object to iterate over. - * @param {string[]} paths The property paths of elements to pick. - * @returns {Array} Returns the picked elements. - */ - function baseAt(object, paths) { - var index = -1, - isNil = object == null, - length = paths.length, - result = Array(length); - - while (++index < length) { - result[index] = isNil ? undefined : get(object, paths[index]); - } - return result; - } - - /** - * The base implementation of `_.clamp` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - */ - function baseClamp(number, lower, upper) { - if (number === number) { - if (upper !== undefined) { - number = number <= upper ? number : upper; - } - if (lower !== undefined) { - number = number >= lower ? number : lower; - } - } - return number; - } - - /** - * The base implementation of `_.clone` and `_.cloneDeep` which tracks - * traversed objects. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @param {boolean} [isFull] Specify a clone including symbols. - * @param {Function} [customizer] The function to customize cloning. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The parent object of `value`. - * @param {Object} [stack] Tracks traversed objects and their clone counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, isDeep, isFull, customizer, key, object, stack) { - var result; - if (customizer) { - result = object ? customizer(value, key, object, stack) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return copyArray(value, result); - } - } else { - var tag = getTag(value), - isFunc = tag == funcTag || tag == genTag; - - if (isBuffer(value)) { - return cloneBuffer(value, isDeep); - } - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - if (isHostObject(value)) { - return object ? value : {}; - } - result = initCloneObject(isFunc ? {} : value); - if (!isDeep) { - return copySymbols(value, baseAssign(result, value)); - } - } else { - if (!cloneableTags[tag]) { - return object ? value : {}; - } - result = initCloneByTag(value, tag, baseClone, isDeep); - } - } - // Check for circular references and return its corresponding clone. - stack || (stack = new Stack); - var stacked = stack.get(value); - if (stacked) { - return stacked; - } - stack.set(value, result); - - if (!isArr) { - var props = isFull ? getAllKeys(value) : keys(value); - } - arrayEach(props || value, function(subValue, key) { - if (props) { - key = subValue; - subValue = value[key]; - } - // Recursively populate clone (susceptible to call stack limits). - assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack)); - }); - return result; - } - - /** - * The base implementation of `_.conforms` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property predicates to conform to. - * @returns {Function} Returns the new spec function. - */ - function baseConforms(source) { - var props = keys(source); - return function(object) { - return baseConformsTo(object, source, props); - }; - } - - /** - * The base implementation of `_.conformsTo` which accepts `props` to check. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - */ - function baseConformsTo(object, source, props) { - var length = props.length; - if (object == null) { - return !length; - } - object = Object(object); - while (length--) { - var key = props[length], - predicate = source[key], - value = object[key]; - - if ((value === undefined && !(key in object)) || !predicate(value)) { - return false; - } - } - return true; - } - - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} prototype The object to inherit from. - * @returns {Object} Returns the new object. - */ - function baseCreate(proto) { - return isObject(proto) ? objectCreate(proto) : {}; - } - - /** - * The base implementation of `_.delay` and `_.defer` which accepts `args` - * to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Array} args The arguments to provide to `func`. - * @returns {number|Object} Returns the timer id or timeout object. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return setTimeout(function() { func.apply(undefined, args); }, wait); - } - - /** - * The base implementation of methods like `_.difference` without support - * for excluding multiple arrays or iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Array} values The values to exclude. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - */ - function baseDifference(array, values, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - isCommon = true, - length = array.length, - result = [], - valuesLength = values.length; - - if (!length) { - return result; - } - if (iteratee) { - values = arrayMap(values, baseUnary(iteratee)); - } - if (comparator) { - includes = arrayIncludesWith; - isCommon = false; - } - else if (values.length >= LARGE_ARRAY_SIZE) { - includes = cacheHas; - isCommon = false; - values = new SetCache(values); - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === computed) { - continue outer; - } - } - result.push(value); - } - else if (!includes(values, computed, comparator)) { - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.forEach` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); - - /** - * The base implementation of `_.forEachRight` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEachRight = createBaseEach(baseForOwnRight, true); - - /** - * The base implementation of `_.every` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection 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 baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function(value, index, collection) { - result = !!predicate(value, index, collection); - return result; - }); - return result; - } - - /** - * The base implementation of methods like `_.max` and `_.min` which accepts a - * `comparator` to determine the extremum value. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The iteratee invoked per iteration. - * @param {Function} comparator The comparator used to compare values. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(array, iteratee, comparator) { - var index = -1, - length = array.length; - - while (++index < length) { - var value = array[index], - current = iteratee(value); - - if (current != null && (computed === undefined - ? (current === current && !isSymbol(current)) - : comparator(current, computed) - )) { - var computed = current, - result = value; - } - } - return result; - } - - /** - * The base implementation of `_.fill` without an iteratee call guard. - * - * @private - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - */ - function baseFill(array, value, start, end) { - var length = array.length; - - start = toInteger(start); - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = (end === undefined || end > length) ? length : toInteger(end); - if (end < 0) { - end += length; - } - end = start > end ? 0 : toLength(end); - while (start < end) { - array[start++] = value; - } - return array; - } - - /** - * The base implementation of `_.filter` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } - }); - return result; - } - - /** - * The base implementation of `_.flatten` with support for restricting flattening. - * - * @private - * @param {Array} array The array to flatten. - * @param {number} depth The maximum recursion depth. - * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. - * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); - - while (++index < length) { - var value = array[index]; - if (depth > 0 && predicate(value)) { - if (depth > 1) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, predicate, isStrict, result); - } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } - } - return result; - } - - /** - * The base implementation of `baseForOwn` which iterates over `object` - * properties returned by `keysFunc` and invokes `iteratee` for each property. - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); - - /** - * This function is like `baseFor` except that it iterates over properties - * in the opposite order. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseForRight = createBaseFor(true); - - /** - * The base implementation of `_.forOwn` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return object && baseFor(object, iteratee, keys); - } - - /** - * The base implementation of `_.forOwnRight` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwnRight(object, iteratee) { - return object && baseForRight(object, iteratee, keys); - } - - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from `props`. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the function names. - */ - function baseFunctions(object, props) { - return arrayFilter(props, function(key) { - return isFunction(object[key]); - }); - } - - /** - * The base implementation of `_.get` without support for default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path) { - path = isKey(path, object) ? [path] : castPath(path); - - var index = 0, - length = path.length; - - while (object != null && index < length) { - object = object[toKey(path[index++])]; - } - return (index && index == length) ? object : undefined; - } - - /** - * The base implementation of `getAllKeys` and `getAllKeysIn` which uses - * `keysFunc` and `symbolsFunc` to get the enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Function} keysFunc The function to get the keys of `object`. - * @param {Function} symbolsFunc The function to get the symbols of `object`. - * @returns {Array} Returns the array of property names and symbols. - */ - function baseGetAllKeys(object, keysFunc, symbolsFunc) { - var result = keysFunc(object); - return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); - } - - /** - * The base implementation of `getTag`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - function baseGetTag(value) { - return objectToString.call(value); - } - - /** - * The base implementation of `_.gt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - */ - function baseGt(value, other) { - return value > other; - } - - /** - * The base implementation of `_.has` without support for deep paths. - * - * @private - * @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 baseHas(object, key) { - return object != null && hasOwnProperty.call(object, key); - } - - /** - * The base implementation of `_.hasIn` without support for deep paths. - * - * @private - * @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 object != null && key in Object(object); - } - - /** - * The base implementation of `_.inRange` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to check. - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - */ - function baseInRange(number, start, end) { - return number >= nativeMin(start, end) && number < nativeMax(start, end); - } - - /** - * The base implementation of methods like `_.intersection`, without support - * for iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of shared values. - */ - function baseIntersection(arrays, iteratee, comparator) { - var includes = comparator ? arrayIncludesWith : arrayIncludes, - length = arrays[0].length, - othLength = arrays.length, - othIndex = othLength, - caches = Array(othLength), - maxLength = Infinity, - result = []; - - while (othIndex--) { - var array = arrays[othIndex]; - if (othIndex && iteratee) { - array = arrayMap(array, baseUnary(iteratee)); - } - maxLength = nativeMin(array.length, maxLength); - caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) - ? new SetCache(othIndex && array) - : undefined; - } - array = arrays[0]; - - var index = -1, - seen = caches[0]; - - outer: - while (++index < length && result.length < maxLength) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (!(seen - ? cacheHas(seen, computed) - : includes(result, computed, comparator) - )) { - othIndex = othLength; - while (--othIndex) { - var cache = caches[othIndex]; - if (!(cache - ? cacheHas(cache, computed) - : includes(arrays[othIndex], computed, comparator)) - ) { - continue outer; - } - } - if (seen) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.invert` and `_.invertBy` which inverts - * `object` with values transformed by `iteratee` and set by `setter`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform values. - * @param {Object} accumulator The initial inverted object. - * @returns {Function} Returns `accumulator`. - */ - function baseInverter(object, setter, iteratee, accumulator) { - baseForOwn(object, function(value, key, object) { - setter(accumulator, iteratee(value), key, object); - }); - return accumulator; - } - - /** - * The base implementation of `_.invoke` without support for individual - * method arguments. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - */ - function baseInvoke(object, path, args) { - if (!isKey(path, object)) { - path = castPath(path); - object = parent(object, path); - path = last(path); - } - var func = object == null ? object : object[toKey(path)]; - return func == null ? undefined : apply(func, object, args); - } - - /** - * The base implementation of `_.isArrayBuffer` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - */ - function baseIsArrayBuffer(value) { - return isObjectLike(value) && objectToString.call(value) == arrayBufferTag; - } - - /** - * The base implementation of `_.isDate` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - */ - function baseIsDate(value) { - return isObjectLike(value) && objectToString.call(value) == dateTag; - } - - /** - * The base implementation of `_.isEqual` which supports partial comparisons - * and tracks traversed objects. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @param {boolean} [bitmask] The bitmask of comparison flags. - * The bitmask may be composed of the following flags: - * 1 - Unordered comparison - * 2 - Partial comparison - * @param {Object} [stack] Tracks traversed `value` and `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, customizer, bitmask, stack) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack); - } - - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparisons. - * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} [stack] Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = arrayTag, - othTag = arrayTag; - - if (!objIsArr) { - objTag = getTag(object); - objTag = objTag == argsTag ? objectTag : objTag; - } - if (!othIsArr) { - othTag = getTag(other); - othTag = othTag == argsTag ? objectTag : othTag; - } - var objIsObj = objTag == objectTag && !isHostObject(object), - othIsObj = othTag == objectTag && !isHostObject(other), - isSameTag = objTag == othTag; - - if (isSameTag && !objIsObj) { - stack || (stack = new Stack); - return (objIsArr || isTypedArray(object)) - ? equalArrays(object, other, equalFunc, customizer, bitmask, stack) - : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack); - } - if (!(bitmask & PARTIAL_COMPARE_FLAG)) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); - - if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object.value() : object, - othUnwrapped = othIsWrapped ? other.value() : other; - - stack || (stack = new Stack); - return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack); - } - } - if (!isSameTag) { - return false; - } - stack || (stack = new Stack); - return equalObjects(object, other, equalFunc, customizer, bitmask, stack); - } - - /** - * The base implementation of `_.isMap` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - */ - function baseIsMap(value) { - return isObjectLike(value) && getTag(value) == mapTag; - } - - /** - * The base implementation of `_.isMatch` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Array} matchData The property names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - */ - function baseIsMatch(object, source, matchData, customizer) { - var index = matchData.length, - length = index, - noCustomizer = !customizer; - - if (object == null) { - return !length; - } - object = Object(object); - while (index--) { - var data = matchData[index]; - if ((noCustomizer && data[2]) - ? data[1] !== object[data[0]] - : !(data[0] in object) - ) { - return false; - } - } - while (++index < length) { - data = matchData[index]; - var key = data[0], - objValue = object[key], - srcValue = data[1]; - - if (noCustomizer && data[2]) { - if (objValue === undefined && !(key in object)) { - return false; - } - } else { - var stack = new Stack; - if (customizer) { - var result = customizer(objValue, srcValue, key, object, source, stack); - } - if (!(result === undefined - ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack) - : result - )) { - return false; - } - } - } - 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 `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ - function baseIsRegExp(value) { - return isObject(value) && objectToString.call(value) == regexpTag; - } - - /** - * The base implementation of `_.isSet` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - */ - function baseIsSet(value) { - return isObjectLike(value) && getTag(value) == setTag; - } - - /** - * The base implementation of `_.isTypedArray` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - */ - function baseIsTypedArray(value) { - return isObjectLike(value) && - isLength(value.length) && !!typedArrayTags[objectToString.call(value)]; - } - - /** - * The base implementation of `_.iteratee`. - * - * @private - * @param {*} [value=_.identity] The value to convert to an iteratee. - * @returns {Function} Returns the iteratee. - */ - function baseIteratee(value) { - // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. - // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. - if (typeof value == 'function') { - return value; - } - if (value == null) { - return identity; - } - if (typeof value == 'object') { - return isArray(value) - ? baseMatchesProperty(value[0], value[1]) - : baseMatches(value); - } - return property(value); - } - - /** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeysIn(object) { - if (!isObject(object)) { - return nativeKeysIn(object); - } - var isProto = isPrototype(object), - result = []; - - for (var key in object) { - if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.lt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - */ - function baseLt(value, other) { - return value < other; - } - - /** - * The base implementation of `_.map` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value, key, collection) { - result[++index] = iteratee(value, key, collection); - }); - return result; - } - - /** - * The base implementation of `_.matches` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatches(source) { - var matchData = getMatchData(source); - if (matchData.length == 1 && matchData[0][2]) { - return matchesStrictComparable(matchData[0][0], matchData[0][1]); - } - return function(object) { - return object === source || baseIsMatch(object, source, matchData); - }; - } - - /** - * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. - * - * @private - * @param {string} path The path of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatchesProperty(path, srcValue) { - if (isKey(path) && isStrictComparable(srcValue)) { - return matchesStrictComparable(toKey(path), srcValue); - } - return function(object) { - var objValue = get(object, path); - return (objValue === undefined && objValue === srcValue) - ? hasIn(object, path) - : baseIsEqual(srcValue, objValue, undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG); - }; - } - - /** - * The base implementation of `_.merge` without support for multiple sources. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {number} srcIndex The index of `source`. - * @param {Function} [customizer] The function to customize merged values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMerge(object, source, srcIndex, customizer, stack) { - if (object === source) { - return; - } - if (!(isArray(source) || isTypedArray(source))) { - var props = baseKeysIn(source); - } - arrayEach(props || source, function(srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } - if (isObject(srcValue)) { - stack || (stack = new Stack); - baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); - } - else { - var newValue = customizer - ? customizer(object[key], srcValue, (key + ''), object, source, stack) - : undefined; - - if (newValue === undefined) { - newValue = srcValue; - } - assignMergeValue(object, key, newValue); - } - }); - } - - /** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {number} srcIndex The index of `source`. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize assigned values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { - var objValue = object[key], - srcValue = source[key], - stacked = stack.get(srcValue); - - if (stacked) { - assignMergeValue(object, key, stacked); - return; - } - var newValue = customizer - ? customizer(objValue, srcValue, (key + ''), object, source, stack) - : undefined; - - var isCommon = newValue === undefined; - - if (isCommon) { - newValue = srcValue; - if (isArray(srcValue) || isTypedArray(srcValue)) { - if (isArray(objValue)) { - newValue = objValue; - } - else if (isArrayLikeObject(objValue)) { - newValue = copyArray(objValue); - } - else { - isCommon = false; - newValue = baseClone(srcValue, true); - } - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - if (isArguments(objValue)) { - newValue = toPlainObject(objValue); - } - else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { - isCommon = false; - newValue = baseClone(srcValue, true); - } - else { - newValue = objValue; - } - } - else { - isCommon = false; - } - } - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, newValue); - mergeFunc(newValue, srcValue, srcIndex, customizer, stack); - stack['delete'](srcValue); - } - assignMergeValue(object, key, newValue); - } - - /** - * The base implementation of `_.nth` which doesn't coerce arguments. - * - * @private - * @param {Array} array The array to query. - * @param {number} n The index of the element to return. - * @returns {*} Returns the nth element of `array`. - */ - function baseNth(array, n) { - var length = array.length; - if (!length) { - return; - } - n += n < 0 ? length : 0; - return isIndex(n, length) ? array[n] : undefined; - } - - /** - * The base implementation of `_.orderBy` without param guards. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {string[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseOrderBy(collection, iteratees, orders) { - var index = -1; - iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); - - var result = baseMap(collection, function(value, key, collection) { - var criteria = arrayMap(iteratees, function(iteratee) { - return iteratee(value); - }); - return { 'criteria': criteria, 'index': ++index, 'value': value }; - }); - - return baseSortBy(result, function(object, other) { - return compareMultiple(object, other, orders); - }); - } - - /** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property identifiers to pick. - * @returns {Object} Returns the new object. - */ - function basePick(object, props) { - object = Object(object); - return basePickBy(object, props, function(value, key) { - return key in object; - }); - } - - /** - * The base implementation of `_.pickBy` without support for iteratee shorthands. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property identifiers to pick from. - * @param {Function} predicate The function invoked per property. - * @returns {Object} Returns the new object. - */ - function basePickBy(object, props, predicate) { - var index = -1, - length = props.length, - result = {}; - - while (++index < length) { - var key = props[index], - value = object[key]; - - if (predicate(value, key)) { - result[key] = value; - } - } - return result; - } - - /** - * A specialized version of `baseProperty` which supports deep paths. - * - * @private - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyDeep(path) { - return function(object) { - return baseGet(object, path); - }; - } - - /** - * The base implementation of `_.pullAllBy` without support for iteratee - * shorthands. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - */ - function basePullAll(array, values, iteratee, comparator) { - var indexOf = comparator ? baseIndexOfWith : baseIndexOf, - index = -1, - length = values.length, - seen = array; - - if (array === values) { - values = copyArray(values); - } - if (iteratee) { - seen = arrayMap(array, baseUnary(iteratee)); - } - while (++index < length) { - var fromIndex = 0, - value = values[index], - computed = iteratee ? iteratee(value) : value; - - while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { - if (seen !== array) { - splice.call(seen, fromIndex, 1); - } - splice.call(array, fromIndex, 1); - } - } - return array; - } - - /** - * The base implementation of `_.pullAt` without support for individual - * indexes or capturing the removed elements. - * - * @private - * @param {Array} array The array to modify. - * @param {number[]} indexes The indexes of elements to remove. - * @returns {Array} Returns `array`. - */ - function basePullAt(array, indexes) { - var length = array ? indexes.length : 0, - lastIndex = length - 1; - - while (length--) { - var index = indexes[length]; - if (length == lastIndex || index !== previous) { - var previous = index; - if (isIndex(index)) { - splice.call(array, index, 1); - } - else if (!isKey(index, array)) { - var path = castPath(index), - object = parent(array, path); - - if (object != null) { - delete object[toKey(last(path))]; - } - } - else { - delete array[toKey(index)]; - } - } - } - return array; - } - - /** - * The base implementation of `_.random` without support for returning - * floating-point numbers. - * - * @private - * @param {number} lower The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the random number. - */ - function baseRandom(lower, upper) { - return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); - } - - /** - * The base implementation of `_.range` and `_.rangeRight` which doesn't - * coerce arguments. - * - * @private - * @param {number} start The start of the range. - * @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 range of numbers. - */ - function baseRange(start, end, step, fromRight) { - var index = -1, - length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), - result = Array(length); - - while (length--) { - result[fromRight ? length : ++index] = start; - start += step; - } - return result; - } - - /** - * The base implementation of `_.repeat` which doesn't coerce arguments. - * - * @private - * @param {string} string The string to repeat. - * @param {number} n The number of times to repeat the string. - * @returns {string} Returns the repeated string. - */ - function baseRepeat(string, n) { - var result = ''; - if (!string || n < 1 || n > MAX_SAFE_INTEGER) { - return result; - } - // Leverage the exponentiation by squaring algorithm for a faster repeat. - // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. - do { - if (n % 2) { - result += string; - } - n = nativeFloor(n / 2); - if (n) { - string += string; - } - } while (n); - - return result; - } - - /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ - function baseRest(func, start) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); - - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = array; - return apply(func, this, otherArgs); - }; - } - - /** - * The base implementation of `_.set`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseSet(object, path, value, customizer) { - if (!isObject(object)) { - return object; - } - path = isKey(path, object) ? [path] : castPath(path); - - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; - - while (nested != null && ++index < length) { - var key = toKey(path[index]), - newValue = value; - - if (index != lastIndex) { - var objValue = nested[key]; - newValue = customizer ? customizer(objValue, key, nested) : undefined; - if (newValue === undefined) { - newValue = isObject(objValue) - ? objValue - : (isIndex(path[index + 1]) ? [] : {}); - } - } - assignValue(nested, key, newValue); - nested = nested[key]; - } - return object; - } - - /** - * The base implementation of `setData` without support for hot loop detection. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var baseSetData = !metaMap ? identity : function(func, data) { - metaMap.set(func, data); - return func; - }; - - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, - length = array.length; - - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = end > length ? length : end; - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; - - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; - } - - /** - * The base implementation of `_.some` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection 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 baseSome(collection, predicate) { - var result; - - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } - - /** - * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which - * performs a binary search of `array` to determine the index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function baseSortedIndex(array, value, retHighest) { - var low = 0, - high = array ? array.length : low; - - if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { - while (low < high) { - var mid = (low + high) >>> 1, - computed = array[mid]; - - if (computed !== null && !isSymbol(computed) && - (retHighest ? (computed <= value) : (computed < value))) { - low = mid + 1; - } else { - high = mid; - } - } - return high; - } - return baseSortedIndexBy(array, value, identity, retHighest); - } - - /** - * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` - * which invokes `iteratee` for `value` and each element of `array` to compute - * their sort ranking. The iteratee is invoked with one argument; (value). - * - * @private - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} iteratee The iteratee invoked per element. - * @param {boolean} [retHighest] Specify returning the highest qualified index. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - */ - function baseSortedIndexBy(array, value, iteratee, retHighest) { - value = iteratee(value); - - var low = 0, - high = array ? array.length : 0, - valIsNaN = value !== value, - valIsNull = value === null, - valIsSymbol = isSymbol(value), - valIsUndefined = value === undefined; - - while (low < high) { - var mid = nativeFloor((low + high) / 2), - computed = iteratee(array[mid]), - othIsDefined = computed !== undefined, - othIsNull = computed === null, - othIsReflexive = computed === computed, - othIsSymbol = isSymbol(computed); - - if (valIsNaN) { - var setLow = retHighest || othIsReflexive; - } else if (valIsUndefined) { - setLow = othIsReflexive && (retHighest || othIsDefined); - } else if (valIsNull) { - setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); - } else if (valIsSymbol) { - setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); - } else if (othIsNull || othIsSymbol) { - setLow = false; - } else { - setLow = retHighest ? (computed <= value) : (computed < value); - } - if (setLow) { - low = mid + 1; - } else { - high = mid; - } - } - return nativeMin(high, MAX_ARRAY_INDEX); - } - - /** - * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseSortedUniq(array, iteratee) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - if (!index || !eq(computed, seen)) { - var seen = computed; - result[resIndex++] = value === 0 ? 0 : value; - } - } - return result; - } - - /** - * The base implementation of `_.toNumber` which doesn't ensure correct - * conversions of binary, hexadecimal, or octal string values. - * - * @private - * @param {*} value The value to process. - * @returns {number} Returns the number. - */ - function baseToNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - return +value; - } - - /** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * The base implementation of `_.uniqBy` without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseUniq(array, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - length = array.length, - isCommon = true, - result = [], - seen = result; - - if (comparator) { - isCommon = false; - includes = arrayIncludesWith; - } - else if (length >= LARGE_ARRAY_SIZE) { - var set = iteratee ? null : createSet(array); - if (set) { - return setToArray(set); - } - isCommon = false; - includes = cacheHas; - seen = new SetCache; - } - else { - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } - } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } - else if (!includes(seen, computed, comparator)) { - if (seen !== result) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.unset`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - */ - function baseUnset(object, path) { - path = isKey(path, object) ? [path] : castPath(path); - object = parent(object, path); - - var key = toKey(last(path)); - return !(object != null && hasOwnProperty.call(object, key)) || delete object[key]; - } - - /** - * The base implementation of `_.update`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to update. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseUpdate(object, path, updater, customizer) { - return baseSet(object, path, updater(baseGet(object, path)), customizer); - } - - /** - * The base implementation of methods like `_.dropWhile` and `_.takeWhile` - * without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to query. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [isDrop] Specify dropping elements instead of taking them. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the slice of `array`. - */ - function baseWhile(array, predicate, isDrop, fromRight) { - var length = array.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length) && - predicate(array[index], index, array)) {} - - return isDrop - ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) - : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); - } - - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to perform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - return arrayReduce(actions, function(result, action) { - return action.func.apply(action.thisArg, arrayPush([result], action.args)); - }, result); - } - - /** - * The base implementation of methods like `_.xor`, without support for - * iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of values. - */ - function baseXor(arrays, iteratee, comparator) { - var index = -1, - length = arrays.length; - - while (++index < length) { - var result = result - ? arrayPush( - baseDifference(result, arrays[index], iteratee, comparator), - baseDifference(arrays[index], result, iteratee, comparator) - ) - : arrays[index]; - } - return (result && result.length) ? baseUniq(result, iteratee, comparator) : []; - } - - /** - * This base implementation of `_.zipObject` which assigns values using `assignFunc`. - * - * @private - * @param {Array} props The property identifiers. - * @param {Array} values The property values. - * @param {Function} assignFunc The function to assign values. - * @returns {Object} Returns the new object. - */ - function baseZipObject(props, values, assignFunc) { - var index = -1, - length = props.length, - valsLength = values.length, - result = {}; - - while (++index < length) { - var value = index < valsLength ? values[index] : undefined; - assignFunc(result, props[index], value); - } - return result; - } - - /** - * Casts `value` to an empty array if it's not an array like object. - * - * @private - * @param {*} value The value to inspect. - * @returns {Array|Object} Returns the cast array-like object. - */ - function castArrayLikeObject(value) { - return isArrayLikeObject(value) ? value : []; - } - - /** - * Casts `value` to `identity` if it's not a function. - * - * @private - * @param {*} value The value to inspect. - * @returns {Function} Returns cast function. - */ - function castFunction(value) { - return typeof value == 'function' ? value : identity; - } - - /** - * Casts `value` to a path array if it's not one. - * - * @private - * @param {*} value The value to inspect. - * @returns {Array} Returns the cast property path array. - */ - function castPath(value) { - return isArray(value) ? value : stringToPath(value); - } - - /** - * Casts `array` to a slice if it's needed. - * - * @private - * @param {Array} array The array to inspect. - * @param {number} start The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the cast slice. - */ - function castSlice(array, start, end) { - var length = array.length; - end = end === undefined ? length : end; - return (!start && end >= length) ? array : baseSlice(array, start, end); - } - - /** - * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). - * - * @private - * @param {number|Object} id The timer id or timeout object of the timer to clear. - */ - var clearTimeout = ctxClearTimeout || function(id) { - return root.clearTimeout(id); - }; - - /** - * Creates a clone of `buffer`. - * - * @private - * @param {Buffer} buffer The buffer to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Buffer} Returns the cloned buffer. - */ - function cloneBuffer(buffer, isDeep) { - if (isDeep) { - return buffer.slice(); - } - var result = new buffer.constructor(buffer.length); - buffer.copy(result); - return result; - } - - /** - * Creates a clone of `arrayBuffer`. - * - * @private - * @param {ArrayBuffer} arrayBuffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ - function cloneArrayBuffer(arrayBuffer) { - var result = new arrayBuffer.constructor(arrayBuffer.byteLength); - new Uint8Array(result).set(new Uint8Array(arrayBuffer)); - return result; - } - - /** - * Creates a clone of `dataView`. - * - * @private - * @param {Object} dataView The data view to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned data view. - */ - function cloneDataView(dataView, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; - return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); - } - - /** - * Creates a clone of `map`. - * - * @private - * @param {Object} map The map to clone. - * @param {Function} cloneFunc The function to clone values. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned map. - */ - function cloneMap(map, isDeep, cloneFunc) { - var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map); - return arrayReduce(array, addMapEntry, new map.constructor); - } - - /** - * Creates a clone of `regexp`. - * - * @private - * @param {Object} regexp The regexp to clone. - * @returns {Object} Returns the cloned regexp. - */ - function cloneRegExp(regexp) { - var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); - result.lastIndex = regexp.lastIndex; - return result; - } - - /** - * Creates a clone of `set`. - * - * @private - * @param {Object} set The set to clone. - * @param {Function} cloneFunc The function to clone values. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned set. - */ - function cloneSet(set, isDeep, cloneFunc) { - var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set); - return arrayReduce(array, addSetEntry, new set.constructor); - } - - /** - * Creates a clone of the `symbol` object. - * - * @private - * @param {Object} symbol The symbol object to clone. - * @returns {Object} Returns the cloned symbol object. - */ - function cloneSymbol(symbol) { - return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; - } - - /** - * Creates a clone of `typedArray`. - * - * @private - * @param {Object} typedArray The typed array to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned typed array. - */ - function cloneTypedArray(typedArray, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; - return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); - } - - /** - * Compares values to sort them in ascending order. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function compareAscending(value, other) { - if (value !== other) { - var valIsDefined = value !== undefined, - valIsNull = value === null, - valIsReflexive = value === value, - valIsSymbol = isSymbol(value); - - var othIsDefined = other !== undefined, - othIsNull = other === null, - othIsReflexive = other === other, - othIsSymbol = isSymbol(other); - - if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || - (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || - (valIsNull && othIsDefined && othIsReflexive) || - (!valIsDefined && othIsReflexive) || - !valIsReflexive) { - return 1; - } - if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || - (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || - (othIsNull && valIsDefined && valIsReflexive) || - (!othIsDefined && valIsReflexive) || - !othIsReflexive) { - return -1; - } - } - return 0; - } - - /** - * Used by `_.orderBy` to compare multiple properties of a value to another - * and stable sort them. - * - * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, - * specify an order of "desc" for descending or "asc" for ascending sort order - * of corresponding values. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {boolean[]|string[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, - objCriteria = object.criteria, - othCriteria = other.criteria, - length = objCriteria.length, - ordersLength = orders.length; - - while (++index < length) { - var result = compareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; - } - var order = orders[index]; - return result * (order == 'desc' ? -1 : 1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } - - /** - * Creates an array that is the composition of partially applied arguments, - * placeholders, and provided arguments into a single array of arguments. - * - * @private - * @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. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgs(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersLength = holders.length, - leftIndex = -1, - leftLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(leftLength + rangeLength), - isUncurried = !isCurried; - - while (++leftIndex < leftLength) { - result[leftIndex] = partials[leftIndex]; - } - while (++argsIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[holders[argsIndex]] = args[argsIndex]; - } - } - while (rangeLength--) { - result[leftIndex++] = args[argsIndex++]; - } - return result; - } - - /** - * This function is like `composeArgs` except that the arguments composition - * is tailored for `_.partialRight`. - * - * @private - * @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. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgsRight(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersIndex = -1, - holdersLength = holders.length, - rightIndex = -1, - rightLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(rangeLength + rightLength), - isUncurried = !isCurried; - - while (++argsIndex < rangeLength) { - result[argsIndex] = args[argsIndex]; - } - var offset = argsIndex; - while (++rightIndex < rightLength) { - result[offset + rightIndex] = partials[rightIndex]; - } - while (++holdersIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } - } - return result; - } - - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function copyArray(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } - - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ - function copyObject(source, props, object, customizer) { - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; - - assignValue(object, key, newValue === undefined ? source[key] : newValue); - } - return object; - } - - /** - * Copies own symbol properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbols(source, object) { - return copyObject(source, getSymbols(source), object); - } - - /** - * Creates a function like `_.groupBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} [initializer] The accumulator object initializer. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter, initializer) { - return function(collection, iteratee) { - var func = isArray(collection) ? arrayAggregator : baseAggregator, - accumulator = initializer ? initializer() : {}; - - return func(collection, setter, getIteratee(iteratee, 2), accumulator); - }; - } - - /** - * Creates a function like `_.assign`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return baseRest(function(object, sources) { - var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined, - guard = length > 2 ? sources[2] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - object = Object(object); - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, index, customizer); - } - } - return object; - }); - } - - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - if (collection == null) { - return collection; - } - if (!isArrayLike(collection)) { - return eachFunc(collection, iteratee); - } - var length = collection.length, - index = fromRight ? length : -1, - iterable = Object(collection); - - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } - - /** - * Creates a base function for methods like `_.forIn` and `_.forOwn`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), - props = keysFunc(object), - length = props.length; - - while (length--) { - var key = props[fromRight ? length : ++index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } - - /** - * Creates a function that wraps `func` to invoke it with the optional `this` - * binding of `thisArg`. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createBind(func, bitmask, thisArg) { - var isBind = bitmask & BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(isBind ? thisArg : this, arguments); - } - return wrapper; - } - - /** - * Creates a function like `_.lowerFirst`. - * - * @private - * @param {string} methodName The name of the `String` case method to use. - * @returns {Function} Returns the new case function. - */ - function createCaseFirst(methodName) { - return function(string) { - string = toString(string); - - var strSymbols = hasUnicode(string) - ? stringToArray(string) - : undefined; - - var chr = strSymbols - ? strSymbols[0] - : string.charAt(0); - - var trailing = strSymbols - ? castSlice(strSymbols, 1).join('') - : string.slice(1); - - return chr[methodName]() + trailing; - }; - } - - /** - * Creates a function like `_.camelCase`. - * - * @private - * @param {Function} callback The function to combine each word. - * @returns {Function} Returns the new compounder function. - */ - function createCompounder(callback) { - return function(string) { - return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); - }; - } - - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtor(Ctor) { - return function() { - // Use a `switch` statement to work with class constructors. See - // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist - // for more details. - var args = arguments; - switch (args.length) { - case 0: return new Ctor; - case 1: return new Ctor(args[0]); - case 2: return new Ctor(args[0], args[1]); - case 3: return new Ctor(args[0], args[1], args[2]); - case 4: return new Ctor(args[0], args[1], args[2], args[3]); - case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); - case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); - case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - } - var thisBinding = baseCreate(Ctor.prototype), - result = Ctor.apply(thisBinding, args); - - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } - - /** - * Creates a function that wraps `func` to enable currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {number} arity The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createCurry(func, bitmask, arity) { - var Ctor = createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length, - placeholder = getHolder(wrapper); - - while (index--) { - args[index] = arguments[index]; - } - var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) - ? [] - : replaceHolders(args, placeholder); - - length -= holders.length; - if (length < arity) { - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, undefined, - args, holders, undefined, undefined, arity - length); - } - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return apply(fn, this, args); - } - 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); - if (!isArrayLike(collection)) { - var iteratee = getIteratee(predicate, 3); - collection = keys(collection); - predicate = function(key) { return iteratee(iterable[key], key, iterable); }; - } - var index = findIndexFunc(collection, predicate, fromIndex); - return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; - }; - } - - /** - * Creates a `_.flow` or `_.flowRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new flow function. - */ - function createFlow(fromRight) { - return baseRest(function(funcs) { - funcs = baseFlatten(funcs, 1); - - var length = funcs.length, - index = length, - prereq = LodashWrapper.prototype.thru; - - if (fromRight) { - funcs.reverse(); - } - while (index--) { - var func = funcs[index]; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (prereq && !wrapper && getFuncName(func) == 'wrapper') { - var wrapper = new LodashWrapper([], true); - } - } - index = wrapper ? index : length; - while (++index < length) { - func = funcs[index]; - - var funcName = getFuncName(func), - data = funcName == 'wrapper' ? getData(func) : undefined; - - if (data && isLaziable(data[0]) && - data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && - !data[4].length && data[9] == 1 - ) { - wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); - } else { - wrapper = (func.length == 1 && isLaziable(func)) - ? wrapper[funcName]() - : wrapper.thru(func); - } - } - return function() { - var args = arguments, - value = args[0]; - - if (wrapper && args.length == 1 && - isArray(value) && value.length >= LARGE_ARRAY_SIZE) { - return wrapper.plant(value).value(); - } - var index = 0, - result = length ? funcs[index].apply(this, args) : value; - - while (++index < length) { - result = funcs[index].call(this, result); - } - return result; - }; - }); - } - - /** - * Creates a function that wraps `func` to invoke it with optional `this` - * binding of `thisArg`, partial application, and currying. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided - * to the new function. - * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { - var isAry = bitmask & ARY_FLAG, - isBind = bitmask & BIND_FLAG, - isBindKey = bitmask & BIND_KEY_FLAG, - isCurried = bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG), - isFlip = bitmask & FLIP_FLAG, - Ctor = isBindKey ? undefined : createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length; - - while (index--) { - args[index] = arguments[index]; - } - if (isCurried) { - var placeholder = getHolder(wrapper), - holdersCount = countHolders(args, placeholder); - } - if (partials) { - args = composeArgs(args, partials, holders, isCurried); - } - if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight, isCurried); - } - length -= holdersCount; - if (isCurried && length < arity) { - var newHolders = replaceHolders(args, placeholder); - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, thisArg, - args, newHolders, argPos, ary, arity - length - ); - } - var thisBinding = isBind ? thisArg : this, - fn = isBindKey ? thisBinding[func] : func; - - length = args.length; - if (argPos) { - args = reorder(args, argPos); - } else if (isFlip && length > 1) { - args.reverse(); - } - if (isAry && ary < length) { - args.length = ary; - } - if (this && this !== root && this instanceof wrapper) { - fn = Ctor || createCtor(fn); - } - return fn.apply(thisBinding, args); - } - return wrapper; - } - - /** - * Creates a function like `_.invertBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} toIteratee The function to resolve iteratees. - * @returns {Function} Returns the new inverter function. - */ - function createInverter(setter, toIteratee) { - return function(object, iteratee) { - return baseInverter(object, setter, toIteratee(iteratee), {}); - }; - } - - /** - * Creates a function that performs a mathematical operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @param {number} [defaultValue] The value used for `undefined` arguments. - * @returns {Function} Returns the new mathematical operation function. - */ - function createMathOperation(operator, defaultValue) { - return function(value, other) { - var result; - if (value === undefined && other === undefined) { - return defaultValue; - } - if (value !== undefined) { - result = value; - } - if (other !== undefined) { - if (result === undefined) { - return other; - } - if (typeof value == 'string' || typeof other == 'string') { - value = baseToString(value); - other = baseToString(other); - } else { - value = baseToNumber(value); - other = baseToNumber(other); - } - result = operator(value, other); - } - return result; - }; - } - - /** - * Creates a function like `_.over`. - * - * @private - * @param {Function} arrayFunc The function to iterate over iteratees. - * @returns {Function} Returns the new over function. - */ - function createOver(arrayFunc) { - return baseRest(function(iteratees) { - iteratees = (iteratees.length == 1 && isArray(iteratees[0])) - ? arrayMap(iteratees[0], baseUnary(getIteratee())) - : arrayMap(baseFlatten(iteratees, 1), baseUnary(getIteratee())); - - return baseRest(function(args) { - var thisArg = this; - return arrayFunc(iteratees, function(iteratee) { - return apply(iteratee, thisArg, args); - }); - }); - }); - } - - /** - * Creates the padding for `string` based on `length`. The `chars` string - * is truncated if the number of characters exceeds `length`. - * - * @private - * @param {number} length The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padding for `string`. - */ - function createPadding(length, chars) { - chars = chars === undefined ? ' ' : baseToString(chars); - - var charsLength = chars.length; - if (charsLength < 2) { - return charsLength ? baseRepeat(chars, length) : chars; - } - var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); - return hasUnicode(chars) - ? castSlice(stringToArray(result), 0, length).join('') - : result.slice(0, length); - } - - /** - * Creates a function that wraps `func` to invoke it with the `this` binding - * of `thisArg` and `partials` prepended to the arguments it receives. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to - * the new function. - * @returns {Function} Returns the new wrapped function. - */ - function createPartial(func, bitmask, thisArg, partials) { - var isBind = bitmask & BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var argsIndex = -1, - argsLength = arguments.length, - leftIndex = -1, - leftLength = partials.length, - args = Array(leftLength + argsLength), - fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - return apply(fn, isBind ? thisArg : this, args); - } - return wrapper; - } - - /** - * Creates a `_.range` or `_.rangeRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new range function. - */ - function createRange(fromRight) { - return function(start, end, step) { - if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { - end = step = undefined; - } - // Ensure the sign of `-0` is preserved. - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); - return baseRange(start, end, step, fromRight); - }; - } - - /** - * Creates a function that performs a relational operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @returns {Function} Returns the new relational operation function. - */ - function createRelationalOperation(operator) { - return function(value, other) { - if (!(typeof value == 'string' && typeof other == 'string')) { - value = toNumber(value); - other = toNumber(other); - } - return operator(value, other); - }; - } - - /** - * Creates a function that wraps `func` to continue currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {Function} wrapFunc The function to create the `func` wrapper. - * @param {*} placeholder The placeholder value. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { - var isCurry = bitmask & CURRY_FLAG, - newHolders = isCurry ? holders : undefined, - newHoldersRight = isCurry ? undefined : holders, - newPartials = isCurry ? partials : undefined, - newPartialsRight = isCurry ? undefined : partials; - - bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); - bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); - - if (!(bitmask & CURRY_BOUND_FLAG)) { - bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); - } - var newData = [ - func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, - newHoldersRight, argPos, ary, arity - ]; - - var result = wrapFunc.apply(undefined, newData); - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return setWrapToString(result, func, bitmask); - } - - /** - * Creates a function like `_.round`. - * - * @private - * @param {string} methodName The name of the `Math` method to use when rounding. - * @returns {Function} Returns the new round function. - */ - function createRound(methodName) { - var func = Math[methodName]; - return function(number, precision) { - number = toNumber(number); - 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. - var pair = (toString(number) + 'e').split('e'), - value = func(pair[0] + 'e' + (+pair[1] + precision)); - - pair = (toString(value) + 'e').split('e'); - return +(pair[0] + 'e' + (+pair[1] - precision)); - } - return func(number); - }; - } - - /** - * Creates a set object of `values`. - * - * @private - * @param {Array} values The values to add to the set. - * @returns {Object} Returns the new set. - */ - var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { - 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. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. - * The bitmask may be composed of the following flags: - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` or `_.curryRight` of a bound function - * 8 - `_.curry` - * 16 - `_.curryRight` - * 32 - `_.partial` - * 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. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { - var isBindKey = bitmask & BIND_KEY_FLAG; - if (!isBindKey && typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = partials ? partials.length : 0; - if (!length) { - bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); - partials = holders = undefined; - } - ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); - arity = arity === undefined ? arity : toInteger(arity); - length -= holders ? holders.length : 0; - - if (bitmask & PARTIAL_RIGHT_FLAG) { - var partialsRight = partials, - holdersRight = holders; - - partials = holders = undefined; - } - var data = isBindKey ? undefined : getData(func); - - var newData = [ - func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, - argPos, ary, arity - ]; - - if (data) { - mergeData(newData, data); - } - func = newData[0]; - bitmask = newData[1]; - thisArg = newData[2]; - partials = newData[3]; - holders = newData[4]; - arity = newData[9] = newData[9] == null - ? (isBindKey ? 0 : func.length) - : nativeMax(newData[9] - length, 0); - - if (!arity && bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG)) { - bitmask &= ~(CURRY_FLAG | CURRY_RIGHT_FLAG); - } - if (!bitmask || bitmask == BIND_FLAG) { - var result = createBind(func, bitmask, thisArg); - } else if (bitmask == CURRY_FLAG || bitmask == CURRY_RIGHT_FLAG) { - result = createCurry(func, bitmask, arity); - } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !holders.length) { - result = createPartial(func, bitmask, thisArg, partials); - } else { - result = createHybrid.apply(undefined, newData); - } - var setter = data ? baseSetData : setData; - return setWrapToString(setter(result, newData), func, bitmask); - } - - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `array` and `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { - var isPartial = bitmask & PARTIAL_COMPARE_FLAG, - arrLength = array.length, - othLength = other.length; - - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(array); - if (stacked && stack.get(other)) { - return stacked == other; - } - var index = -1, - result = true, - seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined; - - stack.set(array, other); - stack.set(other, array); - - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, arrValue, index, other, array, stack) - : customizer(arrValue, othValue, index, array, other, stack); - } - if (compared !== undefined) { - if (compared) { - continue; - } - result = false; - break; - } - // Recursively compare arrays (susceptible to call stack limits). - 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; - } - } else if (!( - arrValue === othValue || - equalFunc(arrValue, othValue, customizer, bitmask, stack) - )) { - result = false; - break; - } - } - stack['delete'](array); - stack['delete'](other); - return result; - } - - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) { - switch (tag) { - case dataViewTag: - if ((object.byteLength != other.byteLength) || - (object.byteOffset != other.byteOffset)) { - return false; - } - object = object.buffer; - other = other.buffer; - - case arrayBufferTag: - if ((object.byteLength != other.byteLength) || - !equalFunc(new Uint8Array(object), new Uint8Array(other))) { - return false; - } - return true; - - case boolTag: - case dateTag: - case numberTag: - // Coerce booleans to `1` or `0` and dates to milliseconds. - // Invalid dates are coerced to `NaN`. - return eq(+object, +other); - - case errorTag: - return object.name == other.name && object.message == other.message; - - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings, primitives and objects, - // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring - // for more details. - return object == (other + ''); - - case mapTag: - var convert = mapToArray; - - case setTag: - var isPartial = bitmask & PARTIAL_COMPARE_FLAG; - convert || (convert = setToArray); - - if (object.size != other.size && !isPartial) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked) { - return stacked == other; - } - bitmask |= UNORDERED_COMPARE_FLAG; - - // Recursively compare objects (susceptible to call stack limits). - stack.set(object, other); - var result = equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack); - stack['delete'](object); - return result; - - case symbolTag: - if (symbolValueOf) { - return symbolValueOf.call(object) == symbolValueOf.call(other); - } - } - return false; - } - - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, equalFunc, customizer, bitmask, stack) { - var isPartial = bitmask & PARTIAL_COMPARE_FLAG, - objProps = keys(object), - objLength = objProps.length, - othProps = keys(other), - othLength = othProps.length; - - if (objLength != othLength && !isPartial) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked && stack.get(other)) { - return stacked == other; - } - var result = true; - stack.set(object, other); - stack.set(other, object); - - var skipCtor = isPartial; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, objValue, key, other, object, stack) - : customizer(objValue, othValue, key, object, other, stack); - } - // Recursively compare objects (susceptible to call stack limits). - if (!(compared === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack)) - : compared - )) { - result = false; - break; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (result && !skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - result = false; - } - } - stack['delete'](object); - stack['delete'](other); - return result; - } - - /** - * Creates an array of own enumerable property names and symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeys(object) { - return baseGetAllKeys(object, keys, getSymbols); - } - - /** - * Creates an array of own and inherited enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeysIn(object) { - return baseGetAllKeys(object, keysIn, getSymbolsIn); - } - - /** - * Gets metadata for `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {*} Returns the metadata for `func`. - */ - var getData = !metaMap ? noop : function(func) { - return metaMap.get(func); - }; - - /** - * Gets the name of `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {string} Returns the function name. - */ - function getFuncName(func) { - var result = (func.name + ''), - array = realNames[result], - length = hasOwnProperty.call(realNames, result) ? array.length : 0; - - while (length--) { - var data = array[length], - otherFunc = data.func; - if (otherFunc == null || otherFunc == func) { - return data.name; - } - } - 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`. - * If arguments are provided, the chosen function is invoked with them and - * its result is returned. - * - * @private - * @param {*} [value] The value to convert to an iteratee. - * @param {number} [arity] The arity of the created iteratee. - * @returns {Function} Returns the chosen function or its result. - */ - function getIteratee() { - var result = lodash.iteratee || iteratee; - result = result === iteratee ? baseIteratee : result; - return arguments.length ? result(arguments[0], arguments[1]) : result; - } - - /** - * 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`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the match data of `object`. - */ - function getMatchData(object) { - var result = keys(object), - length = result.length; - - while (length--) { - var key = result[length], - value = object[key]; - - result[length] = [key, value, isStrictComparable(value)]; - } - return result; - } - - /** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ - function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; - } - - /** - * Creates an array of the own enumerable symbol properties of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray; - - /** - * Creates an array of the own and inherited enumerable symbol properties - * of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { - var result = []; - while (object) { - arrayPush(result, getSymbols(object)); - object = getPrototype(object); - } - return result; - }; - - /** - * Gets the `toStringTag` of `value`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - var getTag = baseGetTag; - - // Fallback for data views, maps, sets, and weak maps in IE 11, - // for data views in Edge < 14, and promises in Node.js. - if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || - (Map && getTag(new Map) != mapTag) || - (Promise && getTag(Promise.resolve()) != promiseTag) || - (Set && getTag(new Set) != setTag) || - (WeakMap && getTag(new WeakMap) != weakMapTag)) { - getTag = function(value) { - var result = objectToString.call(value), - Ctor = result == objectTag ? value.constructor : undefined, - ctorString = Ctor ? toSource(Ctor) : undefined; - - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: return dataViewTag; - case mapCtorString: return mapTag; - case promiseCtorString: return promiseTag; - case setCtorString: return setTag; - case weakMapCtorString: return weakMapTag; - } - } - return result; - }; - } - - /** - * Gets the view, applying any `transforms` to the `start` and `end` positions. - * - * @private - * @param {number} start The start of the view. - * @param {number} end The end of the view. - * @param {Array} transforms The transformations to apply to the view. - * @returns {Object} Returns an object containing the `start` and `end` - * positions of the view. - */ - function getView(start, end, transforms) { - var index = -1, - length = transforms.length; - - while (++index < length) { - var data = transforms[index], - size = data.size; - - switch (data.type) { - case 'drop': start += size; break; - case 'dropRight': end -= size; break; - case 'take': end = nativeMin(end, start + size); break; - case 'takeRight': start = nativeMax(start, end - size); break; - } - } - return { 'start': start, 'end': end }; - } - - /** - * Extracts wrapper details from the `source` body comment. - * - * @private - * @param {string} source The source to inspect. - * @returns {Array} Returns the wrapper details. - */ - function getWrapDetails(source) { - var match = source.match(reWrapDetails); - return match ? match[1].split(reSplitDetails) : []; - } - - /** - * Checks if `path` exists on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @param {Function} hasFunc The function to check properties. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - */ - function hasPath(object, path, hasFunc) { - path = isKey(path, object) ? [path] : castPath(path); - - var result, - index = -1, - length = path.length; - - while (++index < length) { - var key = toKey(path[index]); - if (!(result = object != null && hasFunc(object, key))) { - break; - } - object = object[key]; - } - if (result) { - return result; - } - var length = object ? object.length : 0; - return !!length && isLength(length) && isIndex(key, length) && - (isArray(object) || isArguments(object)); - } - - /** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ - function initCloneArray(array) { - var length = array.length, - result = array.constructor(length); - - // Add properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } - - /** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneObject(object) { - return (typeof object.constructor == 'function' && !isPrototype(object)) - ? baseCreate(getPrototype(object)) - : {}; - } - - /** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {Function} cloneFunc The function to clone values. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneByTag(object, tag, cloneFunc, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return cloneArrayBuffer(object); - - case boolTag: - case dateTag: - return new Ctor(+object); - - case dataViewTag: - return cloneDataView(object, isDeep); - - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - return cloneTypedArray(object, isDeep); - - case mapTag: - return cloneMap(object, isDeep, cloneFunc); - - case numberTag: - case stringTag: - return new Ctor(object); - - case regexpTag: - return cloneRegExp(object); - - case setTag: - return cloneSet(object, isDeep, cloneFunc); - - case symbolTag: - return cloneSymbol(object); - } - } - - /** - * Inserts wrapper `details` in a comment at the top of the `source` body. - * - * @private - * @param {string} source The source to modify. - * @returns {Array} details The details to insert. - * @returns {string} Returns the modified source. - */ - function insertWrapDetails(source, details) { - var length = details.length, - lastIndex = length - 1; - - details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; - details = details.join(length > 2 ? ', ' : ' '); - return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); - } - - /** - * Checks if `value` is a flattenable `arguments` object or array. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ - function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); - } - - /** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ - function isIndex(value, length) { - length = length == null ? MAX_SAFE_INTEGER : length; - return !!length && - (typeof value == 'number' || reIsUint.test(value)) && - (value > -1 && value % 1 == 0 && value < length); - } - - /** - * Checks if the given arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, - * else `false`. - */ - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object) - ) { - return eq(object[index], value); - } - return false; - } - - /** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ - function isKey(value, object) { - if (isArray(value)) { - return false; - } - var type = typeof value; - if (type == 'number' || type == 'symbol' || type == 'boolean' || - value == null || isSymbol(value)) { - return true; - } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); - } - - /** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ - function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); - } - - /** - * Checks if `func` has a lazy counterpart. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, - * else `false`. - */ - function isLaziable(func) { - var funcName = getFuncName(func), - other = lodash[funcName]; - - if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { - return false; - } - if (func === other) { - return true; - } - var data = getData(other); - 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. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ - function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - - return value === proto; - } - - /** - * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` if suitable for strict - * equality comparisons, else `false`. - */ - function isStrictComparable(value) { - return value === value && !isObject(value); - } - - /** - * A specialized version of `matchesProperty` for source values suitable - * for strict equality comparisons, i.e. `===`. - * - * @private - * @param {string} key The key of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function matchesStrictComparable(key, srcValue) { - return function(object) { - if (object == null) { - return false; - } - return object[key] === srcValue && - (srcValue !== undefined || (key in Object(object))); - }; - } - - /** - * Merges the function metadata of `source` into `data`. - * - * Merging metadata reduces the number of wrappers used to invoke a function. - * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and - * `_.rearg` modify function arguments, making the order in which they are - * executed important, preventing the merging of metadata. However, we make - * an exception for a safe combined case where curried functions have `_.ary` - * and or `_.rearg` applied. - * - * @private - * @param {Array} data The destination metadata. - * @param {Array} source The source metadata. - * @returns {Array} Returns `data`. - */ - function mergeData(data, source) { - var bitmask = data[1], - srcBitmask = source[1], - newBitmask = bitmask | srcBitmask, - isCommon = newBitmask < (BIND_FLAG | BIND_KEY_FLAG | ARY_FLAG); - - var isCombo = - ((srcBitmask == ARY_FLAG) && (bitmask == CURRY_FLAG)) || - ((srcBitmask == ARY_FLAG) && (bitmask == REARG_FLAG) && (data[7].length <= source[8])) || - ((srcBitmask == (ARY_FLAG | REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == CURRY_FLAG)); - - // Exit early if metadata can't be merged. - if (!(isCommon || isCombo)) { - return data; - } - // Use source `thisArg` if available. - if (srcBitmask & BIND_FLAG) { - data[2] = source[2]; - // Set when currying a bound function. - newBitmask |= bitmask & BIND_FLAG ? 0 : CURRY_BOUND_FLAG; - } - // Compose partial arguments. - var value = source[3]; - if (value) { - var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : value; - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; - } - // Compose partial right arguments. - value = source[5]; - if (value) { - partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; - } - // Use source `argPos` if available. - value = source[7]; - if (value) { - data[7] = value; - } - // Use source `ary` if it's smaller. - if (srcBitmask & ARY_FLAG) { - data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); - } - // Use source `arity` if one is not provided. - if (data[9] == null) { - data[9] = source[9]; - } - // Use source `func` and merge bitmasks. - data[0] = source[0]; - data[1] = newBitmask; - - return data; - } - - /** - * Used by `_.defaultsDeep` to customize its `_.merge` use. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to merge. - * @param {Object} object The parent object of `objValue`. - * @param {Object} source The parent object of `srcValue`. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - * @returns {*} Returns the value to assign. - */ - function mergeDefaults(objValue, srcValue, key, object, source, stack) { - if (isObject(objValue) && isObject(srcValue)) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, objValue); - baseMerge(objValue, srcValue, undefined, mergeDefaults, stack); - stack['delete'](srcValue); - } - return objValue; - } - - /** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); - } - } - return result; - } - - /** - * Gets the parent value at `path` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path to get the parent value of. - * @returns {*} Returns the parent value. - */ - function parent(object, path) { - return path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); - } - - /** - * Reorder `array` according to the specified indexes where the element at - * the first index is assigned as the first element, the element at - * the second index is assigned as the second element, and so on. - * - * @private - * @param {Array} array The array to reorder. - * @param {Array} indexes The arranged array indexes. - * @returns {Array} Returns `array`. - */ - function reorder(array, indexes) { - var arrLength = array.length, - length = nativeMin(indexes.length, arrLength), - oldArray = copyArray(array); - - while (length--) { - var index = indexes[length]; - array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; - } - return array; - } - - /** - * Sets metadata for `func`. - * - * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity - * function to avoid garbage collection pauses in V8. See - * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) - * for more details. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var setData = (function() { - var count = 0, - lastCalled = 0; - - return function(key, value) { - var stamp = now(), - remaining = HOT_SPAN - (stamp - lastCalled); - - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return key; - } - } else { - count = 0; - } - return baseSetData(key, value); - }; - }()); - - /** - * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @returns {number|Object} Returns the timer id or timeout object. - */ - var setTimeout = ctxSetTimeout || function(func, wait) { - return root.setTimeout(func, wait); - }; - - /** - * Sets the `toString` method of `wrapper` to mimic the source of `reference` - * with wrapper details in a comment at the top of the source body. - * - * @private - * @param {Function} wrapper The function to modify. - * @param {Function} reference The reference function. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Function} Returns `wrapper`. - */ - var setWrapToString = !defineProperty ? identity : function(wrapper, reference, bitmask) { - var source = (reference + ''); - return defineProperty(wrapper, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))) - }); - }; - - /** - * Converts `string` to a property path array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the property path array. - */ - var stringToPath = memoize(function(string) { - string = toString(string); - - var result = []; - if (reLeadingDot.test(string)) { - result.push(''); - } - string.replace(rePropName, function(match, number, quote, string) { - result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; - }); - - /** - * Converts `value` to a string key if it's not a string or symbol. - * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. - */ - function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to process. - * @returns {string} Returns the source code. - */ - function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; - } - - /** - * Updates wrapper `details` based on `bitmask` flags. - * - * @private - * @returns {Array} details The details to modify. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Array} Returns `details`. - */ - function updateWrapDetails(details, bitmask) { - arrayEach(wrapFlags, function(pair) { - var value = '_.' + pair[0]; - if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { - details.push(value); - } - }); - return details.sort(); - } - - /** - * Creates a clone of `wrapper`. - * - * @private - * @param {Object} wrapper The wrapper to clone. - * @returns {Object} Returns the cloned wrapper. - */ - function wrapperClone(wrapper) { - if (wrapper instanceof LazyWrapper) { - return wrapper.clone(); - } - var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); - result.__actions__ = copyArray(wrapper.__actions__); - result.__index__ = wrapper.__index__; - result.__values__ = wrapper.__values__; - return result; - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of elements split into groups the length of `size`. - * If `array` can't be split evenly, the final chunk will be the remaining - * elements. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @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 of chunks. - * @example - * - * _.chunk(['a', 'b', 'c', 'd'], 2); - * // => [['a', 'b'], ['c', 'd']] - * - * _.chunk(['a', 'b', 'c', 'd'], 3); - * // => [['a', 'b', 'c'], ['d']] - */ - function chunk(array, size, guard) { - if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { - size = 1; - } else { - size = nativeMax(toInteger(size), 0); - } - var length = array ? array.length : 0; - if (!length || size < 1) { - return []; - } - var index = 0, - resIndex = 0, - result = Array(nativeCeil(length / size)); - - while (index < length) { - result[resIndex++] = baseSlice(array, index, (index += size)); - } - return result; - } - - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, - length = array ? array.length : 0, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * Creates a new array concatenating `array` with any additional arrays - * and/or values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to concatenate. - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var other = _.concat(array, 2, [3], [[4]]); - * - * console.log(other); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - function concat() { - var length = arguments.length, - args = Array(length ? length - 1 : 0), - array = arguments[0], - index = length; - - while (index--) { - args[index - 1] = arguments[index]; - } - return length - ? arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)) - : []; - } - - /** - * Creates an array of `array` values not included in the other given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order of result values is determined by the - * order they occur in the first array. - * - * **Note:** Unlike `_.pullAll`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.without, _.xor - * @example - * - * _.difference([2, 1], [2, 3]); - * // => [1] - */ - var difference = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : []; - }); - - /** - * This method is like `_.difference` except that it accepts `iteratee` which - * is invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. Result values are chosen from the first array. - * The iteratee is invoked with one argument: (value). - * - * **Note:** Unlike `_.pullAllBy`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.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'); - * // => [{ 'x': 2 }] - */ - var differenceBy = baseRest(function(array, values) { - var iteratee = last(values); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) - : []; - }); - - /** - * This method is like `_.difference` except that it accepts `comparator` - * which is invoked to compare elements of `array` to `values`. Result values - * are chosen from the first array. The comparator is invoked with two arguments: - * (arrVal, othVal). - * - * **Note:** Unlike `_.pullAllWith`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * - * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); - * // => [{ 'x': 2, 'y': 1 }] - */ - var differenceWith = baseRest(function(array, values) { - var comparator = last(values); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) - : []; - }); - - /** - * Creates a slice of `array` with `n` elements dropped from the beginning. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.drop([1, 2, 3]); - * // => [2, 3] - * - * _.drop([1, 2, 3], 2); - * // => [3] - * - * _.drop([1, 2, 3], 5); - * // => [] - * - * _.drop([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function drop(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, n < 0 ? 0 : n, length); - } - - /** - * Creates a slice of `array` with `n` elements dropped from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.dropRight([1, 2, 3]); - * // => [1, 2] - * - * _.dropRight([1, 2, 3], 2); - * // => [1] - * - * _.dropRight([1, 2, 3], 5); - * // => [] - * - * _.dropRight([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function dropRight(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` excluding elements dropped from the end. - * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.dropRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney'] - * - * // The `_.matches` iteratee shorthand. - * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['barney', 'fred'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropRightWhile(users, ['active', false]); - * // => objects for ['barney'] - * - * // The `_.property` iteratee shorthand. - * _.dropRightWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] - */ - function dropRightWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true, true) - : []; - } - - /** - * Creates a slice of `array` excluding elements dropped from the beginning. - * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.dropWhile(users, function(o) { return !o.active; }); - * // => objects for ['pebbles'] - * - * // The `_.matches` iteratee shorthand. - * _.dropWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropWhile(users, ['active', false]); - * // => objects for ['pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.dropWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] - */ - function dropWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true) - : []; - } - - /** - * Fills elements of `array` with `value` from `start` up to, but not - * including, `end`. - * - * **Note:** This method mutates `array`. - * - * @static - * @memberOf _ - * @since 3.2.0 - * @category Array - * @param {Array} array The array to fill. - * @param {*} value The value to fill `array` with. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.fill(array, 'a'); - * console.log(array); - * // => ['a', 'a', 'a'] - * - * _.fill(Array(3), 2); - * // => [2, 2, 2] - * - * _.fill([4, 6, 8, 10], '*', 1, 3); - * // => [4, '*', '*', 10] - */ - function fill(array, value, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { - start = 0; - end = length; - } - return baseFill(array, value, start, end); - } - - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [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 - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(o) { return o.user == 'barney'; }); - * // => 0 - * - * // The `_.matches` iteratee shorthand. - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findIndex(users, ['active', false]); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.findIndex(users, 'active'); - * // => 2 - */ - 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); - } - - /** - * This method is like `_.findIndex` except that it iterates over elements - * of `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [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 - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); - * // => 2 - * - * // The `_.matches` iteratee shorthand. - * _.findLastIndex(users, { 'user': 'barney', 'active': true }); - * // => 0 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastIndex(users, ['active', false]); - * // => 2 - * - * // The `_.property` iteratee shorthand. - * _.findLastIndex(users, 'active'); - * // => 0 - */ - 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); - } - - /** - * Flattens `array` a single level deep. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] - */ - function flatten(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, 1) : []; - } - - /** - * Recursively flattens `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, [3, [4]], 5]]); - * // => [1, 2, 3, 4, 5] - */ - function flattenDeep(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, INFINITY) : []; - } - - /** - * Recursively flatten `array` up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Array - * @param {Array} array The array to flatten. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * var array = [1, [2, [3, [4]], 5]]; - * - * _.flattenDepth(array, 1); - * // => [1, 2, [3, [4]], 5] - * - * _.flattenDepth(array, 2); - * // => [1, 2, 3, [4], 5] - */ - function flattenDepth(array, depth) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(array, depth); - } - - /** - * The inverse of `_.toPairs`; this method returns an object composed - * from key-value `pairs`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} pairs The key-value pairs. - * @returns {Object} Returns the new object. - * @example - * - * _.fromPairs([['a', 1], ['b', 2]]); - * // => { 'a': 1, 'b': 2 } - */ - function fromPairs(pairs) { - var index = -1, - length = pairs ? pairs.length : 0, - result = {}; - - while (++index < length) { - var pair = pairs[index]; - result[pair[0]] = pair[1]; - } - return result; - } - - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias first - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.head([1, 2, 3]); - * // => 1 - * - * _.head([]); - * // => undefined - */ - function head(array) { - return (array && array.length) ? array[0] : undefined; - } - - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the - * offset from the end of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // Search from the `fromIndex`. - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - */ - function indexOf(array, value, 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 baseIndexOf(array, value, index); - } - - /** - * Gets all but the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - */ - function initial(array) { - var length = array ? array.length : 0; - return length ? baseSlice(array, 0, -1) : []; - } - - /** - * Creates an array of unique values that are included in all given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order of result values is determined by the - * order they occur in the first array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersection([2, 1], [2, 3]); - * // => [2] - */ - var intersection = baseRest(function(arrays) { - var mapped = arrayMap(arrays, castArrayLikeObject); - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped) - : []; - }); - - /** - * This method is like `_.intersection` except that it accepts `iteratee` - * which is invoked for each element of each `arrays` to generate the criterion - * by which they're compared. Result values are chosen from the first array. - * The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [2.1] - * - * // The `_.property` iteratee shorthand. - * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }] - */ - var intersectionBy = baseRest(function(arrays) { - var iteratee = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); - - if (iteratee === last(mapped)) { - iteratee = undefined; - } else { - mapped.pop(); - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, getIteratee(iteratee, 2)) - : []; - }); - - /** - * This method is like `_.intersection` except that it accepts `comparator` - * which is invoked to compare elements of `arrays`. Result values are chosen - * from the first array. The comparator is invoked with two arguments: - * (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.intersectionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }] - */ - var intersectionWith = baseRest(function(arrays) { - var comparator = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); - - if (comparator === last(mapped)) { - comparator = undefined; - } else { - mapped.pop(); - } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, undefined, comparator) - : []; - }); - - /** - * Converts all elements in `array` into a string separated by `separator`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to convert. - * @param {string} [separator=','] The element separator. - * @returns {string} Returns the joined string. - * @example - * - * _.join(['a', 'b', 'c'], '~'); - * // => 'a~b~c' - */ - function join(array, separator) { - return array ? nativeJoin.call(array, separator) : ''; - } - - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array ? array.length : 0; - return length ? array[length - 1] : undefined; - } - - /** - * This method is like `_.indexOf` except that it iterates over elements of - * `array` from right to left. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.lastIndexOf([1, 2, 1, 2], 2); - * // => 3 - * - * // Search from the `fromIndex`. - * _.lastIndexOf([1, 2, 1, 2], 2, 2); - * // => 1 - */ - function lastIndexOf(array, value, fromIndex) { - var length = array ? array.length : 0; - if (!length) { - return -1; - } - var index = length; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = ( - index < 0 - ? nativeMax(length + index, 0) - : nativeMin(index, length - 1) - ) + 1; - } - if (value !== value) { - return baseFindIndex(array, baseIsNaN, index - 1, true); - } - while (index--) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * Gets the element at index `n` of `array`. If `n` is negative, the nth - * element from the end is returned. - * - * @static - * @memberOf _ - * @since 4.11.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=0] The index of the element to return. - * @returns {*} Returns the nth element of `array`. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * - * _.nth(array, 1); - * // => 'b' - * - * _.nth(array, -2); - * // => 'c'; - */ - function nth(array, n) { - return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; - } - - /** - * Removes all given values from `array` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` - * to remove elements from an array by predicate. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {...*} [values] The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pull(array, 'a', 'c'); - * console.log(array); - * // => ['b', 'b'] - */ - var pull = baseRest(pullAll); - - /** - * This method is like `_.pull` except that it accepts an array of values to remove. - * - * **Note:** Unlike `_.difference`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pullAll(array, ['a', 'c']); - * console.log(array); - * // => ['b', 'b'] - */ - function pullAll(array, values) { - return (array && array.length && values && values.length) - ? basePullAll(array, values) - : array; - } - - /** - * This method is like `_.pullAll` except that it accepts `iteratee` which is - * invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. The iteratee is invoked with one argument: (value). - * - * **Note:** Unlike `_.differenceBy`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; - * - * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); - * console.log(array); - * // => [{ 'x': 2 }] - */ - function pullAllBy(array, values, iteratee) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, getIteratee(iteratee, 2)) - : array; - } - - /** - * This method is like `_.pullAll` except that it accepts `comparator` which - * is invoked to compare elements of `array` to `values`. The comparator is - * invoked with two arguments: (arrVal, othVal). - * - * **Note:** Unlike `_.differenceWith`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; - * - * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); - * console.log(array); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] - */ - function pullAllWith(array, values, comparator) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, undefined, comparator) - : array; - } - - /** - * Removes elements from `array` corresponding to `indexes` and returns an - * array of removed elements. - * - * **Note:** Unlike `_.at`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {...(number|number[])} [indexes] The indexes of elements to remove. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * var pulled = _.pullAt(array, [1, 3]); - * - * console.log(array); - * // => ['a', 'c'] - * - * console.log(pulled); - * // => ['b', 'd'] - */ - var pullAt = baseRest(function(array, indexes) { - indexes = baseFlatten(indexes, 1); - - var length = array ? array.length : 0, - result = baseAt(array, indexes); - - basePullAt(array, arrayMap(indexes, function(index) { - return isIndex(index, length) ? +index : index; - }).sort(compareAscending)); - - return result; - }); - - /** - * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is invoked - * with three arguments: (value, index, array). - * - * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` - * to pull elements from an array by value. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the new array of removed elements. - * @example - * - * var array = [1, 2, 3, 4]; - * var evens = _.remove(array, function(n) { - * return n % 2 == 0; - * }); - * - * console.log(array); - * // => [1, 3] - * - * console.log(evens); - * // => [2, 4] - */ - function remove(array, predicate) { - var result = []; - if (!(array && array.length)) { - return result; - } - var index = -1, - indexes = [], - length = array.length; - - predicate = getIteratee(predicate, 3); - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result.push(value); - indexes.push(index); - } - } - basePullAt(array, indexes); - return result; - } - - /** - * Reverses `array` so that the first element becomes the last, the second - * element becomes the second to last, and so on. - * - * **Note:** This method mutates `array` and is based on - * [`Array#reverse`](https://mdn.io/Array/reverse). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.reverse(array); - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function reverse(array) { - return array ? nativeReverse.call(array) : array; - } - - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of - * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are - * returned. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - else { - start = start == null ? 0 : toInteger(start); - end = end === undefined ? length : toInteger(end); - } - return baseSlice(array, start, end); - } - - /** - * Uses a binary search to determine the lowest index at which `value` - * should be inserted into `array` in order to maintain its sort order. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedIndex([30, 50], 40); - * // => 1 - */ - function sortedIndex(array, value) { - return baseSortedIndex(array, value); - } - - /** - * This method is like `_.sortedIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); - * // => 0 - */ - function sortedIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); - } - - /** - * This method is like `_.indexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedIndexOf([4, 5, 5, 5, 6], 5); - * // => 1 - */ - function sortedIndexOf(array, value) { - var length = array ? array.length : 0; - if (length) { - var index = baseSortedIndex(array, value); - if (index < length && eq(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * This method is like `_.sortedIndex` except that it returns the highest - * index at which `value` should be inserted into `array` in order to - * maintain its sort order. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * _.sortedLastIndex([4, 5, 5, 5, 6], 5); - * // => 4 - */ - function sortedLastIndex(array, value) { - return baseSortedIndex(array, value, true); - } - - /** - * This method is like `_.sortedLastIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 1 - * - * // The `_.property` iteratee shorthand. - * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); - * // => 1 - */ - function sortedLastIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); - } - - /** - * This method is like `_.lastIndexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); - * // => 3 - */ - function sortedLastIndexOf(array, value) { - var length = array ? array.length : 0; - if (length) { - var index = baseSortedIndex(array, value, true) - 1; - if (eq(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * This method is like `_.uniq` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniq([1, 1, 2]); - * // => [1, 2] - */ - function sortedUniq(array) { - return (array && array.length) - ? baseSortedUniq(array) - : []; - } - - /** - * This method is like `_.uniqBy` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); - * // => [1.1, 2.3] - */ - function sortedUniqBy(array, iteratee) { - return (array && array.length) - ? baseSortedUniq(array, getIteratee(iteratee, 2)) - : []; - } - - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.tail([1, 2, 3]); - * // => [2, 3] - */ - function tail(array) { - var length = array ? array.length : 0; - return length ? baseSlice(array, 1, length) : []; - } - - /** - * Creates a slice of `array` with `n` elements taken from the beginning. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.take([1, 2, 3]); - * // => [1] - * - * _.take([1, 2, 3], 2); - * // => [1, 2] - * - * _.take([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.take([1, 2, 3], 0); - * // => [] - */ - function take(array, n, guard) { - if (!(array && array.length)) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` with `n` elements taken from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRight([1, 2, 3]); - * // => [3] - * - * _.takeRight([1, 2, 3], 2); - * // => [2, 3] - * - * _.takeRight([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.takeRight([1, 2, 3], 0); - * // => [] - */ - function takeRight(array, n, guard) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, n < 0 ? 0 : n, length); - } - - /** - * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.takeRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.matches` iteratee shorthand. - * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['pebbles'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeRightWhile(users, ['active', false]); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.takeRightWhile(users, 'active'); - * // => [] - */ - function takeRightWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), false, true) - : []; - } - - /** - * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the slice of `array`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false}, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.takeWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney', 'fred'] - * - * // The `_.matches` iteratee shorthand. - * _.takeWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeWhile(users, ['active', false]); - * // => objects for ['barney', 'fred'] - * - * // The `_.property` iteratee shorthand. - * _.takeWhile(users, 'active'); - * // => [] - */ - function takeWhile(array, predicate) { - return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3)) - : []; - } - - /** - * Creates an array of unique values, in order, from all given arrays using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.union([2], [1, 2]); - * // => [2, 1] - */ - var union = baseRest(function(arrays) { - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); - }); - - /** - * This method is like `_.union` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which uniqueness is computed. Result values are chosen from the first - * array in which the value occurs. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.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'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - var unionBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); - }); - - /** - * This method is like `_.union` except that it accepts `comparator` which - * is invoked to compare elements of `arrays`. Result values are chosen from - * the first array in which the value occurs. The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.unionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var unionWith = baseRest(function(arrays) { - var comparator = last(arrays); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); - }); - - /** - * Creates a duplicate-free version of an array, using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons, in which only the first occurrence of each - * element is kept. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniq([2, 1, 2]); - * // => [2, 1] - */ - function uniq(array) { - return (array && array.length) - ? baseUniq(array) - : []; - } - - /** - * This method is like `_.uniq` except that it accepts `iteratee` which is - * invoked for each element in `array` to generate the criterion by which - * uniqueness is computed. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniqBy([2.1, 1.2, 2.3], Math.floor); - * // => [2.1, 1.2] - * - * // The `_.property` iteratee shorthand. - * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniqBy(array, iteratee) { - return (array && array.length) - ? baseUniq(array, getIteratee(iteratee, 2)) - : []; - } - - /** - * This method is like `_.uniq` except that it accepts `comparator` which - * is invoked to compare elements of `array`. The comparator is invoked with - * two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * 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 }] - */ - function uniqWith(array, comparator) { - return (array && array.length) - ? baseUniq(array, undefined, comparator) - : []; - } - - /** - * This method is like `_.zip` except that it accepts an array of grouped - * elements and creates an array regrouping the elements to their pre-zip - * configuration. - * - * @static - * @memberOf _ - * @since 1.2.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - * - * _.unzip(zipped); - * // => [['a', 'b'], [1, 2], [true, false]] - */ - function unzip(array) { - if (!(array && array.length)) { - return []; - } - var length = 0; - array = arrayFilter(array, function(group) { - if (isArrayLikeObject(group)) { - length = nativeMax(group.length, length); - return true; - } - }); - return baseTimes(length, function(index) { - return arrayMap(array, baseProperty(index)); - }); - } - - /** - * This method is like `_.unzip` except that it accepts `iteratee` to specify - * how regrouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee=_.identity] The function to combine - * regrouped values. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip([1, 2], [10, 20], [100, 200]); - * // => [[1, 10, 100], [2, 20, 200]] - * - * _.unzipWith(zipped, _.add); - * // => [3, 30, 300] - */ - function unzipWith(array, iteratee) { - if (!(array && array.length)) { - return []; - } - var result = unzip(array); - if (iteratee == null) { - return result; - } - return arrayMap(result, function(group) { - return apply(iteratee, undefined, group); - }); - } - - /** - * Creates an array excluding all given values using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.pull`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @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([2, 1, 2, 3], 1, 2); - * // => [3] - */ - var without = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, values) - : []; - }); - - /** - * Creates an array of unique values that is the - * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) - * of the given arrays. The order of result values is determined by the order - * they occur in the arrays. - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.without - * @example - * - * _.xor([2, 1], [2, 3]); - * // => [1, 3] - */ - var xor = baseRest(function(arrays) { - return baseXor(arrayFilter(arrays, isArrayLikeObject)); - }); - - /** - * This method is like `_.xor` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which by which they're compared. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.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'); - * // => [{ 'x': 2 }] - */ - var xorBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); - }); - - /** - * This method is like `_.xor` except that it accepts `comparator` which is - * invoked to compare elements of `arrays`. The comparator is invoked with - * two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.xorWith(objects, others, _.isEqual); - * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var xorWith = baseRest(function(arrays) { - var comparator = last(arrays); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); - }); - - /** - * Creates an array of grouped elements, the first of which contains the - * first elements of the given arrays, the second of which contains the - * second elements of the given arrays, and so on. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - */ - var zip = baseRest(unzip); - - /** - * This method is like `_.fromPairs` except that it accepts two arrays, - * one of property identifiers and one of corresponding values. - * - * @static - * @memberOf _ - * @since 0.4.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject(['a', 'b'], [1, 2]); - * // => { 'a': 1, 'b': 2 } - */ - function zipObject(props, values) { - return baseZipObject(props || [], values || [], assignValue); - } - - /** - * This method is like `_.zipObject` except that it supports property paths. - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); - * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } - */ - function zipObjectDeep(props, values) { - return baseZipObject(props || [], values || [], baseSet); - } - - /** - * This method is like `_.zip` except that it accepts `iteratee` to specify - * how grouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee=_.identity] The function to combine grouped values. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { - * return a + b + c; - * }); - * // => [111, 222] - */ - var zipWith = baseRest(function(arrays) { - var length = arrays.length, - iteratee = length > 1 ? arrays[length - 1] : undefined; - - iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; - return unzipWith(arrays, iteratee); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` wrapper instance that wraps `value` with explicit method - * chain sequences enabled. The result of such sequences must be unwrapped - * with `_#value`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Seq - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _ - * .chain(users) - * .sortBy('age') - * .map(function(o) { - * return o.user + ' is ' + o.age; - * }) - * .head() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } - - /** - * This method invokes `interceptor` and returns `value`. The interceptor - * is invoked with one argument; (value). The purpose of this method is to - * "tap into" a method chain sequence in order to modify intermediate results. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * // Mutate input array. - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor) { - interceptor(value); - return value; - } - - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * The purpose of this method is to "pass thru" values replacing intermediate - * results in a method chain sequence. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor) { - return interceptor(value); - } - - /** - * This method is the wrapper version of `_.at`. - * - * @name at - * @memberOf _ - * @since 1.0.0 - * @category Seq - * @param {...(string|string[])} [paths] The property paths of elements to pick. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _(object).at(['a[0].b.c', 'a[1]']).value(); - * // => [3, 4] - */ - var wrapperAt = baseRest(function(paths) { - paths = baseFlatten(paths, 1); - var length = paths.length, - start = length ? paths[0] : 0, - value = this.__wrapped__, - interceptor = function(object) { return baseAt(object, paths); }; - - if (length > 1 || this.__actions__.length || - !(value instanceof LazyWrapper) || !isIndex(start)) { - return this.thru(interceptor); - } - value = value.slice(start, +start + (length ? 1 : 0)); - value.__actions__.push({ - 'func': thru, - 'args': [interceptor], - 'thisArg': undefined - }); - return new LodashWrapper(value, this.__chain__).thru(function(array) { - if (length && !array.length) { - array.push(undefined); - } - return array; - }); - }); - - /** - * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. - * - * @name chain - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // A sequence without explicit chaining. - * _(users).head(); - * // => { 'user': 'barney', 'age': 36 } - * - * // A sequence with explicit chaining. - * _(users) - * .chain() - * .head() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } - - /** - * Executes the chain sequence and returns the wrapped result. - * - * @name commit - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).push(3); - * - * console.log(array); - * // => [1, 2] - * - * wrapped = wrapped.commit(); - * console.log(array); - * // => [1, 2, 3] - * - * wrapped.last(); - * // => 3 - * - * console.log(array); - * // => [1, 2, 3] - */ - function wrapperCommit() { - return new LodashWrapper(this.value(), this.__chain__); - } - - /** - * Gets the next value on a wrapped object following the - * [iterator protocol](https://mdn.io/iteration_protocols#iterator). - * - * @name next - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the next iterator value. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped.next(); - * // => { 'done': false, 'value': 1 } - * - * wrapped.next(); - * // => { 'done': false, 'value': 2 } - * - * wrapped.next(); - * // => { 'done': true, 'value': undefined } - */ - function wrapperNext() { - if (this.__values__ === undefined) { - this.__values__ = toArray(this.value()); - } - var done = this.__index__ >= this.__values__.length, - value = done ? undefined : this.__values__[this.__index__++]; - - return { 'done': done, 'value': value }; - } - - /** - * Enables the wrapper to be iterable. - * - * @name Symbol.iterator - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the wrapper object. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped[Symbol.iterator]() === wrapped; - * // => true - * - * Array.from(wrapped); - * // => [1, 2] - */ - function wrapperToIterator() { - return this; - } - - /** - * Creates a clone of the chain sequence planting `value` as the wrapped value. - * - * @name plant - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @param {*} value The value to plant. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2]).map(square); - * var other = wrapped.plant([3, 4]); - * - * other.value(); - * // => [9, 16] - * - * wrapped.value(); - * // => [1, 4] - */ - function wrapperPlant(value) { - var result, - parent = this; - - while (parent instanceof baseLodash) { - var clone = wrapperClone(parent); - clone.__index__ = 0; - clone.__values__ = undefined; - if (result) { - previous.__wrapped__ = clone; - } else { - result = clone; - } - var previous = clone; - parent = parent.__wrapped__; - } - previous.__wrapped__ = value; - return result; - } - - /** - * This method is the wrapper version of `_.reverse`. - * - * **Note:** This method mutates the wrapped array. - * - * @name reverse - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2, 3]; - * - * _(array).reverse().value() - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function wrapperReverse() { - var value = this.__wrapped__; - if (value instanceof LazyWrapper) { - var wrapped = value; - if (this.__actions__.length) { - wrapped = new LazyWrapper(this); - } - wrapped = wrapped.reverse(); - wrapped.__actions__.push({ - 'func': thru, - 'args': [reverse], - 'thisArg': undefined - }); - return new LodashWrapper(wrapped, this.__chain__); - } - return this.thru(reverse); - } - - /** - * Executes the chain sequence to resolve the unwrapped value. - * - * @name value - * @memberOf _ - * @since 0.1.0 - * @alias toJSON, valueOf - * @category Seq - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the number of times the key was returned by `iteratee`. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.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 } - */ - var countBy = createAggregator(function(result, value, key) { - hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1); - }); - - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * Iteration is stopped once `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * **Note:** This method returns `true` for - * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because - * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of - * elements of empty collections. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.every(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, guard) { - var func = isArray(collection) ? arrayEvery : baseEvery; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * **Note:** Unlike `_.remove`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.reject - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.filter(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.filter(users, { 'age': 36, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.filter(users, 'active'); - * // => objects for ['barney'] - */ - function filter(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.find(users, function(o) { return o.age < 40; }); - * // => object for 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.find(users, { 'age': 1, 'active': true }); - * // => object for 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.find(users, ['active', false]); - * // => object for 'fred' - * - * // The `_.property` iteratee shorthand. - * _.find(users, 'active'); - * // => object for 'barney' - */ - var find = createFind(findIndex); - - /** - * This method is like `_.find` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [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 - * - * _.findLast([1, 2, 3, 4], function(n) { - * return n % 2 == 1; - * }); - * // => 3 - */ - var findLast = createFind(findLastIndex); - - /** - * Creates a flattened array of values by running each element in `collection` - * thru `iteratee` and flattening the mapped results. The iteratee is invoked - * with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [n, n]; - * } - * - * _.flatMap([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMap(collection, iteratee) { - return baseFlatten(map(collection, iteratee), 1); - } - - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDeep([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMapDeep(collection, iteratee) { - return baseFlatten(map(collection, iteratee), INFINITY); - } - - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The function invoked per iteration. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDepth([1, 2], duplicate, 2); - * // => [[1, 1], [2, 2]] - */ - function flatMapDepth(collection, iteratee, depth) { - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(map(collection, iteratee), depth); - } - - /** - * Iterates over elements of `collection` and invokes `iteratee` for each element. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" - * property are iterated like arrays. To avoid this behavior use `_.forIn` - * or `_.forOwn` for object iteration. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias each - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEachRight - * @example - * - * _([1, 2]).forEach(function(value) { - * console.log(value); - * }); - * // => Logs `1` then `2`. - * - * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forEach(collection, iteratee) { - var func = isArray(collection) ? arrayEach : baseEach; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.forEach` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @alias eachRight - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEach - * @example - * - * _.forEachRight([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `2` then `1`. - */ - function forEachRight(collection, iteratee) { - var func = isArray(collection) ? arrayEachRight : baseEachRight; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The order of grouped values - * is determined by the order they occur in `collection`. The corresponding - * value of each key is an array of elements responsible for generating the - * key. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': [4.2], '6': [6.1, 6.3] } - * - * // The `_.property` iteratee shorthand. - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - result[key].push(value); - } else { - result[key] = [value]; - } - }); - - /** - * Checks if `value` is in `collection`. If `collection` is a string, it's - * checked for a substring of `value`, otherwise - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * is used for equality comparisons. If `fromIndex` is negative, it's used as - * the offset from the end of `collection`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {boolean} Returns `true` if `value` is found, else `false`. - * @example - * - * _.includes([1, 2, 3], 1); - * // => true - * - * _.includes([1, 2, 3], 1, 2); - * // => false - * - * _.includes({ 'a': 1, 'b': 2 }, 1); - * // => true - * - * _.includes('abcd', 'bc'); - * // => true - */ - function includes(collection, value, fromIndex, guard) { - collection = isArrayLike(collection) ? collection : values(collection); - fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; - - var length = collection.length; - if (fromIndex < 0) { - fromIndex = nativeMax(length + fromIndex, 0); - } - return isString(collection) - ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) - : (!!length && baseIndexOf(collection, value, fromIndex) > -1); - } - - /** - * Invokes the method at `path` of each element in `collection`, returning - * an array of the results of each invoked method. Any additional arguments - * are provided to each invoked method. If `path` is a function, it's invoked - * for, and `this` bound to, each element in `collection`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array|Function|string} path The path of the method to invoke or - * the function invoked per iteration. - * @param {...*} [args] The arguments to invoke each method with. - * @returns {Array} Returns the array of results. - * @example - * - * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); - * // => [[1, 5, 7], [1, 2, 3]] - * - * _.invokeMap([123, 456], String.prototype.split, ''); - * // => [['1', '2', '3'], ['4', '5', '6']] - */ - var invokeMap = baseRest(function(collection, path, args) { - var index = -1, - isFunc = typeof path == 'function', - isProp = isKey(path), - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value) { - var func = isFunc ? path : ((isProp && value != null) ? value[path] : undefined); - result[++index] = func ? apply(func, value, args) : baseInvoke(value, path, args); - }); - return result; - }); - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the last element responsible for generating the key. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * var array = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; - * - * _.keyBy(array, function(o) { - * return String.fromCharCode(o.code); - * }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.keyBy(array, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - */ - var keyBy = createAggregator(function(result, value, key) { - result[key] = value; - }); - - /** - * Creates an array of values by running each element in `collection` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, - * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, - * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, - * `template`, `trim`, `trimEnd`, `trimStart`, and `words` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - * @example - * - * function square(n) { - * return n * n; - * } - * - * _.map([4, 8], square); - * // => [16, 64] - * - * _.map({ 'a': 4, 'b': 8 }, square); - * // => [16, 64] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // The `_.property` iteratee shorthand. - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee) { - var func = isArray(collection) ? arrayMap : baseMap; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.sortBy` except that it allows specifying the sort - * orders of the iteratees to sort by. If `orders` is unspecified, all values - * are sorted in ascending order. Otherwise, specify an order of "desc" for - * descending or "asc" for ascending sort order of corresponding values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] - * The iteratees to sort by. - * @param {string[]} [orders] The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 34 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 36 } - * ]; - * - * // Sort by `user` in ascending order and by `age` in descending order. - * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - */ - function orderBy(collection, iteratees, orders, guard) { - if (collection == null) { - return []; - } - if (!isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees]; - } - orders = guard ? undefined : orders; - if (!isArray(orders)) { - orders = orders == null ? [] : [orders]; - } - return baseOrderBy(collection, iteratees, orders); - } - - /** - * Creates an array of elements split into two groups, the first of which - * contains elements `predicate` returns truthy for, the second of which - * contains elements `predicate` returns falsey for. The predicate is - * invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the array of grouped elements. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true }, - * { 'user': 'pebbles', 'age': 1, 'active': false } - * ]; - * - * _.partition(users, function(o) { return o.active; }); - * // => objects for [['fred'], ['barney', 'pebbles']] - * - * // The `_.matches` iteratee shorthand. - * _.partition(users, { 'age': 1, 'active': false }); - * // => objects for [['pebbles'], ['barney', 'fred']] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.partition(users, ['active', false]); - * // => objects for [['barney', 'pebbles'], ['fred']] - * - * // The `_.property` iteratee shorthand. - * _.partition(users, 'active'); - * // => objects for [['fred'], ['barney', 'pebbles']] - */ - var partition = createAggregator(function(result, value, key) { - result[key ? 0 : 1].push(value); - }, function() { return [[], []]; }); - - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` thru `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not given, the first element of `collection` is used as the initial - * value. The iteratee is invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, - * and `sortBy` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduceRight - * @example - * - * _.reduce([1, 2], function(sum, n) { - * return sum + n; - * }, 0); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * return result; - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) - */ - function reduce(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduce : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); - } - - /** - * This method is like `_.reduce` except that it iterates over elements of - * `collection` from right to left. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduce - * @example - * - * var array = [[0, 1], [2, 3], [4, 5]]; - * - * _.reduceRight(array, function(flattened, other) { - * return flattened.concat(other); - * }, []); - * // => [4, 5, 2, 3, 0, 1] - */ - function reduceRight(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduceRight : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); - } - - /** - * The opposite of `_.filter`; this method returns the elements of `collection` - * that `predicate` does **not** return truthy for. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.filter - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true } - * ]; - * - * _.reject(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.reject(users, { 'age': 40, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.reject(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.reject(users, 'active'); - * // => objects for ['barney'] - */ - function reject(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, negate(getIteratee(predicate, 3))); - } - - /** - * Gets a random element from `collection`. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @returns {*} Returns the random element. - * @example - * - * _.sample([1, 2, 3, 4]); - * // => 2 - */ - function sample(collection) { - var array = isArrayLike(collection) ? collection : values(collection), - length = array.length; - - return length > 0 ? array[baseRandom(0, length - 1)] : undefined; - } - - /** - * Gets `n` random elements at unique keys from `collection` up to the - * size of `collection`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @param {number} [n=1] The number of elements to sample. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the random elements. - * @example - * - * _.sampleSize([1, 2, 3], 2); - * // => [3, 1] - * - * _.sampleSize([1, 2, 3], 4); - * // => [2, 3, 1] - */ - function sampleSize(collection, n, guard) { - var index = -1, - result = toArray(collection), - length = result.length, - lastIndex = length - 1; - - if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { - n = 1; - } else { - n = baseClamp(toInteger(n), 0, length); - } - while (++index < n) { - var rand = baseRandom(index, lastIndex), - value = result[rand]; - - result[rand] = result[index]; - result[index] = value; - } - result.length = n; - return result; - } - - /** - * Creates an array of shuffled values, using a version of the - * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to shuffle. - * @returns {Array} Returns the new shuffled array. - * @example - * - * _.shuffle([1, 2, 3, 4]); - * // => [4, 1, 3, 2] - */ - function shuffle(collection) { - return sampleSize(collection, MAX_ARRAY_LENGTH); - } - - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable string keyed properties for objects. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the collection size. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - if (collection == null) { - return 0; - } - if (isArrayLike(collection)) { - return isString(collection) ? stringSize(collection) : collection.length; - } - var tag = getTag(collection); - if (tag == mapTag || tag == setTag) { - return collection.size; - } - return baseKeys(collection).length; - } - - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * Iteration is stopped once `predicate` returns truthy. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.some(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, guard) { - var func = isArray(collection) ? arraySome : baseSome; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, getIteratee(predicate, 3)); - } - - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection thru each iteratee. This method - * performs a stable sort, that is, it preserves the original sort order of - * equal elements. The iteratees are invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {...(Function|Function[])} [iteratees=[_.identity]] - * The iteratees to sort by. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.sortBy(users, function(o) { return o.user; }); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - * - * _.sortBy(users, ['user', 'age']); - * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] - * - * _.sortBy(users, 'user', function(o) { - * return Math.floor(o.age / 10); - * }); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - */ - var sortBy = baseRest(function(collection, iteratees) { - if (collection == null) { - return []; - } - var length = iteratees.length; - if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { - iteratees = []; - } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { - iteratees = [iteratees[0]]; - } - return baseOrderBy(collection, baseFlatten(iteratees, 1), []); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Date - * @returns {number} Returns the timestamp. - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. - */ - var now = ctxNow || function() { - return root.Date.now(); - }; - - /*------------------------------------------------------------------------*/ - - /** - * The opposite of `_.before`; this method creates a function that invokes - * `func` once it's called `n` or more times. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {number} n The number of calls before `func` is invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => Logs 'done saving!' after the two async saves have completed. - */ - function after(n, func) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } - - /** - * Creates a function that invokes `func`, with up to `n` arguments, - * ignoring any additional arguments. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @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 capped function. - * @example - * - * _.map(['6', '8', '10'], _.ary(parseInt, 1)); - * // => [6, 8, 10] - */ - function ary(func, n, guard) { - n = guard ? undefined : n; - n = (func && n == null) ? func.length : n; - return createWrap(func, ARY_FLAG, undefined, undefined, undefined, undefined, n); - } - - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it's called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery(element).on('click', _.before(5, addContactToList)); - * // => Allows adding up to 4 contacts to the list. - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = undefined; - } - return result; - }; - } - - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and `partials` prepended to the arguments it receives. - * - * 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" - * property of bound functions. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * function greet(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // Bound with placeholders. - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = baseRest(function(func, thisArg, partials) { - var bitmask = BIND_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bind)); - bitmask |= PARTIAL_FLAG; - } - return createWrap(func, bitmask, thisArg, partials, holders); - }); - - /** - * Creates a function that invokes the method at `object[key]` with `partials` - * prepended to the arguments it receives. - * - * This method differs from `_.bind` by allowing bound functions to reference - * methods that may be redefined or don't yet exist. See - * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) - * for more details. - * - * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Function - * @param {Object} object The object to invoke the method on. - * @param {string} key The key of the method. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * var object = { - * 'user': 'fred', - * 'greet': function(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * }; - * - * var bound = _.bindKey(object, 'greet', 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * object.greet = function(greeting, punctuation) { - * return greeting + 'ya ' + this.user + punctuation; - * }; - * - * bound('!'); - * // => 'hiya fred!' - * - * // Bound with placeholders. - * var bound = _.bindKey(object, 'greet', _, '!'); - * bound('hi'); - * // => 'hiya fred!' - */ - var bindKey = baseRest(function(object, key, partials) { - var bitmask = BIND_FLAG | BIND_KEY_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bindKey)); - bitmask |= PARTIAL_FLAG; - } - return createWrap(key, bitmask, object, partials, holders); - }); - - /** - * Creates a function that accepts arguments of `func` and either invokes - * `func` returning its result, if at least `arity` number of arguments have - * been provided, or returns a function that accepts the remaining `func` - * arguments, and so on. The arity of `func` may be specified if `func.length` - * is not sufficient. - * - * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for provided arguments. - * - * **Note:** This method doesn't set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curry(abc); - * - * curried(1)(2)(3); - * // => [1, 2, 3] - * - * curried(1, 2)(3); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // Curried with placeholders. - * curried(1)(_, 3)(2); - * // => [1, 2, 3] - */ - function curry(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curry.placeholder; - return result; - } - - /** - * This method is like `_.curry` except that arguments are applied to `func` - * in the manner of `_.partialRight` instead of `_.partial`. - * - * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for provided arguments. - * - * **Note:** This method doesn't set the "length" property of curried functions. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to curry. - * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the new curried function. - * @example - * - * var abc = function(a, b, c) { - * return [a, b, c]; - * }; - * - * var curried = _.curryRight(abc); - * - * curried(3)(2)(1); - * // => [1, 2, 3] - * - * curried(2, 3)(1); - * // => [1, 2, 3] - * - * curried(1, 2, 3); - * // => [1, 2, 3] - * - * // Curried with placeholders. - * curried(3)(1, _)(2); - * // => [1, 2, 3] - */ - function curryRight(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curryRight.placeholder; - return result; - } - - /** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // Avoid costly calculations while the window size is in flux. - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); - * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); - */ - function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; - - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } - - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - result = wait - timeSinceLastCall; - - return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; - } - - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; - - // 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 === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } - - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } - - function trailingEdge(time) { - timerId = undefined; - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } - - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; - } - - function flush() { - return timerId === undefined ? result : trailingEdge(now()); - } - - function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); - - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; - } - - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // => Logs 'deferred' after one or more milliseconds. - */ - var defer = baseRest(function(func, args) { - return baseDelay(func, 1, args); - }); - - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => Logs 'later' after one second. - */ - var delay = baseRest(function(func, wait, args) { - return baseDelay(func, toNumber(wait) || 0, args); - }); - - /** - * Creates a function that invokes `func` with arguments reversed. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to flip arguments for. - * @returns {Function} Returns the new flipped function. - * @example - * - * var flipped = _.flip(function() { - * return _.toArray(arguments); - * }); - * - * flipped('a', 'b', 'c', 'd'); - * // => ['d', 'c', 'b', 'a'] - */ - function flip(func) { - return createWrap(func, FLIP_FLAG); - } - - /** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided, it determines the cache key for storing the result based on the - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is used as the map cache key. The `func` - * is invoked with the `this` binding of the memoized function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the - * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `delete`, `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @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 memoized function. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; - * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] - * - * values(other); - * // => [3, 4] - * - * object.a = 2; - * values(object); - * // => [1, 2] - * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] - * - * // Replace `_.memoize.Cache`. - * _.memoize.Cache = WeakMap; - */ - function memoize(func, resolver) { - if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function() { - var args = arguments, - key = resolver ? resolver.apply(this, args) : args[0], - cache = memoized.cache; - - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - memoized.cache = cache.set(key, result); - return result; - }; - memoized.cache = new (memoize.Cache || MapCache); - return memoized; - } - - // Assign cache to `_.memoize`. - memoize.Cache = MapCache; - - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new negated function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - var args = arguments; - switch (args.length) { - case 0: return !predicate.call(this); - case 1: return !predicate.call(this, args[0]); - case 2: return !predicate.call(this, args[0], args[1]); - case 3: return !predicate.call(this, args[0], args[1], args[2]); - } - return !predicate.apply(this, args); - }; - } - - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first invocation. The `func` is - * invoked with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // => `createApplication` is invoked once - */ - function once(func) { - return before(2, func); - } - - /** - * Creates a function that invokes `func` with its arguments transformed. - * - * @static - * @since 4.0.0 - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms=[_.identity]] - * The argument transforms. - * @returns {Function} Returns the new function. - * @example - * - * function doubled(n) { - * return n * 2; - * } - * - * function square(n) { - * return n * n; - * } - * - * var func = _.overArgs(function(x, y) { - * return [x, y]; - * }, [square, doubled]); - * - * func(9, 3); - * // => [81, 6] - * - * func(10, 5); - * // => [100, 10] - */ - var overArgs = baseRest(function(func, transforms) { - transforms = (transforms.length == 1 && isArray(transforms[0])) - ? arrayMap(transforms[0], baseUnary(getIteratee())) - : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); - - var funcsLength = transforms.length; - return baseRest(function(args) { - var index = -1, - length = nativeMin(args.length, funcsLength); - - while (++index < length) { - args[index] = transforms[index].call(this, args[index]); - } - return apply(func, this, args); - }); - }); - - /** - * Creates a function that invokes `func` with `partials` prepended to the - * arguments it receives. This method is like `_.bind` except it does **not** - * alter the `this` binding. - * - * The `_.partial.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method doesn't set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @since 0.2.0 - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * function greet(greeting, name) { - * return greeting + ' ' + name; - * } - * - * var sayHelloTo = _.partial(greet, 'hello'); - * sayHelloTo('fred'); - * // => 'hello fred' - * - * // Partially applied with placeholders. - * var greetFred = _.partial(greet, _, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - */ - var partial = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partial)); - return createWrap(func, PARTIAL_FLAG, undefined, partials, holders); - }); - - /** - * This method is like `_.partial` except that partially applied arguments - * are appended to the arguments it receives. - * - * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic - * builds, may be used as a placeholder for partially applied arguments. - * - * **Note:** This method doesn't set the "length" property of partially - * applied functions. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Function - * @param {Function} func The function to partially apply arguments to. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new partially applied function. - * @example - * - * function greet(greeting, name) { - * return greeting + ' ' + name; - * } - * - * var greetFred = _.partialRight(greet, 'fred'); - * greetFred('hi'); - * // => 'hi fred' - * - * // Partially applied with placeholders. - * var sayHelloTo = _.partialRight(greet, 'hello', _); - * sayHelloTo('fred'); - * // => 'hello fred' - */ - var partialRight = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partialRight)); - return createWrap(func, PARTIAL_RIGHT_FLAG, undefined, partials, holders); - }); - - /** - * Creates a function that invokes `func` with arguments arranged according - * to the specified `indexes` where the argument value at the first index is - * provided as the first argument, the argument value at the second index is - * provided as the second argument, and so on. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} func The function to rearrange arguments for. - * @param {...(number|number[])} indexes The arranged argument indexes. - * @returns {Function} Returns the new function. - * @example - * - * var rearged = _.rearg(function(a, b, c) { - * return [a, b, c]; - * }, [2, 0, 1]); - * - * rearged('b', 'c', 'a') - * // => ['a', 'b', 'c'] - */ - var rearg = baseRest(function(func, indexes) { - return createWrap(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes, 1)); - }); - - /** - * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as - * an array. - * - * **Note:** This method is based on the - * [rest parameter](https://mdn.io/rest_parameters). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.rest(function(what, names) { - * return what + ' ' + _.initial(names).join(', ') + - * (_.size(names) > 1 ? ', & ' : '') + _.last(names); - * }); - * - * say('hello', 'fred', 'barney', 'pebbles'); - * // => 'hello fred, barney, & pebbles' - */ - function rest(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = start === undefined ? start : toInteger(start); - return baseRest(func, start); - } - - /** - * Creates a function that invokes `func` with the `this` binding of the - * create function and an array of arguments much like - * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). - * - * **Note:** This method is based on the - * [spread operator](https://mdn.io/spread_operator). - * - * @static - * @memberOf _ - * @since 3.2.0 - * @category Function - * @param {Function} func The function to spread arguments over. - * @param {number} [start=0] The start position of the spread. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.spread(function(who, what) { - * return who + ' says ' + what; - * }); - * - * say(['fred', 'hello']); - * // => 'fred says hello' - * - * var numbers = Promise.all([ - * Promise.resolve(40), - * Promise.resolve(36) - * ]); - * - * numbers.then(_.spread(function(x, y) { - * return x + y; - * })); - * // => a Promise of 76 - */ - function spread(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = start === undefined ? 0 : nativeMax(toInteger(start), 0); - return baseRest(function(args) { - var array = args[start], - otherArgs = castSlice(args, 0, start); - - if (array) { - arrayPush(otherArgs, array); - } - return apply(func, this, otherArgs); - }); - } - - /** - * Creates a throttled function that only invokes `func` at most once per - * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed `func` invocations and a `flush` method to - * immediately invoke them. Provide `options` to indicate whether `func` - * should be invoked on the leading and/or trailing edge of the `wait` - * timeout. The `func` is invoked with the last arguments provided to the - * throttled function. Subsequent calls to the throttled function return the - * result of the last `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the throttled function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=true] - * Specify invoking on the leading edge of the timeout. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // Avoid excessively updating the position while scrolling. - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. - * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); - * jQuery(element).on('click', throttled); - * - * // Cancel the trailing throttled invocation. - * jQuery(window).on('popstate', throttled.cancel); - */ - function throttle(func, wait, options) { - var leading = true, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - return debounce(func, wait, { - 'leading': leading, - 'maxWait': wait, - 'trailing': trailing - }); - } - - /** - * Creates a function that accepts up to one argument, ignoring any - * additional arguments. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - * @example - * - * _.map(['6', '8', '10'], _.unary(parseInt)); - * // => [6, 8, 10] - */ - function unary(func) { - return ary(func, 1); - } - - /** - * Creates a function that provides `value` to `wrapper` as its first - * argument. Any additional arguments provided to the function are appended - * to those provided to the `wrapper`. The wrapper is invoked with the `this` - * binding of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {*} value The value to wrap. - * @param {Function} [wrapper=identity] The wrapper function. - * @returns {Function} Returns the new function. - * @example - * - * var p = _.wrap(_.escape, function(func, text) { - * return '

' + func(text) + '

'; - * }); - * - * p('fred, barney, & pebbles'); - * // => '

fred, barney, & pebbles

' - */ - function wrap(value, wrapper) { - wrapper = wrapper == null ? identity : wrapper; - return partial(wrapper, value); - } - - /*------------------------------------------------------------------------*/ - - /** - * Casts `value` as an array if it's not one. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Lang - * @param {*} value The value to inspect. - * @returns {Array} Returns the cast array. - * @example - * - * _.castArray(1); - * // => [1] - * - * _.castArray({ 'a': 1 }); - * // => [{ 'a': 1 }] - * - * _.castArray('abc'); - * // => ['abc'] - * - * _.castArray(null); - * // => [null] - * - * _.castArray(undefined); - * // => [undefined] - * - * _.castArray(); - * // => [] - * - * var array = [1, 2, 3]; - * console.log(_.castArray(array) === array); - * // => true - */ - function castArray() { - if (!arguments.length) { - return []; - } - var value = arguments[0]; - return isArray(value) ? value : [value]; - } - - /** - * Creates a shallow clone of `value`. - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) - * and supports cloning arrays, array buffers, booleans, date objects, maps, - * numbers, `Object` objects, regexes, sets, strings, symbols, and typed - * arrays. The own enumerable properties of `arguments` objects are cloned - * as plain objects. An empty object is returned for uncloneable values such - * as error objects, functions, DOM nodes, and WeakMaps. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to clone. - * @returns {*} Returns the cloned value. - * @see _.cloneDeep - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var shallow = _.clone(objects); - * console.log(shallow[0] === objects[0]); - * // => true - */ - function clone(value) { - return baseClone(value, false, true); - } - - /** - * This method is like `_.clone` except that it accepts `customizer` which - * is invoked to produce the cloned value. If `customizer` returns `undefined`, - * cloning is handled by the method instead. The `customizer` is invoked with - * up to four arguments; (value [, index|key, object, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the cloned value. - * @see _.cloneDeepWith - * @example - * - * function customizer(value) { - * if (_.isElement(value)) { - * return value.cloneNode(false); - * } - * } - * - * var el = _.cloneWith(document.body, customizer); - * - * console.log(el === document.body); - * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); - * // => 0 - */ - function cloneWith(value, customizer) { - return baseClone(value, false, true, customizer); - } - - /** - * This method is like `_.clone` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @returns {*} Returns the deep cloned value. - * @see _.clone - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var deep = _.cloneDeep(objects); - * console.log(deep[0] === objects[0]); - * // => false - */ - function cloneDeep(value) { - return baseClone(value, true, true); - } - - /** - * This method is like `_.cloneWith` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the deep cloned value. - * @see _.cloneWith - * @example - * - * function customizer(value) { - * if (_.isElement(value)) { - * return value.cloneNode(true); - * } - * } - * - * var el = _.cloneDeepWith(document.body, customizer); - * - * console.log(el === document.body); - * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); - * // => 20 - */ - function cloneDeepWith(value, customizer) { - return baseClone(value, true, true, customizer); - } - - /** - * Checks if `object` conforms to `source` by invoking the predicate - * properties of `source` with the corresponding property values of `object`. - * - * **Note:** This method is equivalent to `_.conforms` when `source` is - * partially applied. - * - * @static - * @memberOf _ - * @since 4.14.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); - * // => true - * - * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); - * // => false - */ - function conformsTo(object, source) { - return source == null || baseConformsTo(object, source, keys(source)); - } - - /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ - function eq(value, other) { - return value === other || (value !== value && other !== other); - } - - /** - * Checks if `value` is greater than `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - * @see _.lt - * @example - * - * _.gt(3, 1); - * // => true - * - * _.gt(3, 3); - * // => false - * - * _.gt(1, 3); - * // => false - */ - var gt = createRelationalOperation(baseGt); - - /** - * Checks if `value` is greater than or equal to `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than or equal to - * `other`, else `false`. - * @see _.lte - * @example - * - * _.gte(3, 1); - * // => true - * - * _.gte(3, 3); - * // => true - * - * _.gte(1, 3); - * // => false - */ - var gte = createRelationalOperation(function(value, other) { - return value >= other; - }); - - /** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - function isArguments(value) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && - (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); - } - - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ - var isArray = Array.isArray; - - /** - * Checks if `value` is classified as an `ArrayBuffer` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - * @example - * - * _.isArrayBuffer(new ArrayBuffer(2)); - * // => true - * - * _.isArrayBuffer(new Array(2)); - * // => false - */ - var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; - - /** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } - - /** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ - function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); - } - - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || - (isObjectLike(value) && objectToString.call(value) == boolTag); - } - - /** - * Checks if `value` is a buffer. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. - * @example - * - * _.isBuffer(new Buffer(2)); - * // => true - * - * _.isBuffer(new Uint8Array(2)); - * // => false - */ - var isBuffer = nativeIsBuffer || stubFalse; - - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; - - /** - * Checks if `value` is likely a DOM element. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. - * @example - * - * _.isElement(document.body); - * // => true - * - * _.isElement(''); - * // => false - */ - function isElement(value) { - return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value); - } - - /** - * Checks if `value` is an empty object, collection, map, or set. - * - * Objects are considered empty if they have no own enumerable string keyed - * properties. - * - * Array-like values such as `arguments` objects, arrays, buffers, strings, or - * jQuery-like collections are considered empty if they have a `length` of `0`. - * Similarly, maps and sets are considered empty if they have a `size` of `0`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (isArrayLike(value) && - (isArray(value) || typeof value == 'string' || - typeof value.splice == 'function' || isBuffer(value) || isArguments(value))) { - return !value.length; - } - var tag = getTag(value); - if (tag == mapTag || tag == setTag) { - return !value.size; - } - if (nonEnumShadows || isPrototype(value)) { - return !nativeKeys(value).length; - } - for (var key in value) { - if (hasOwnProperty.call(value, key)) { - return false; - } - } - return true; - } - - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. - * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are **not** supported. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.isEqual(object, other); - * // => true - * - * object === other; - * // => false - */ - function isEqual(value, other) { - return baseIsEqual(value, other); - } - - /** - * This method is like `_.isEqual` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with up to - * six arguments: (objValue, othValue [, index|key, object, other, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, othValue) { - * if (isGreeting(objValue) && isGreeting(othValue)) { - * return true; - * } - * } - * - * var array = ['hello', 'goodbye']; - * var other = ['hi', 'goodbye']; - * - * _.isEqualWith(array, other, customizer); - * // => true - */ - function isEqualWith(value, other, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, customizer) : !!result; - } - - /** - * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, - * `SyntaxError`, `TypeError`, or `URIError` object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an error object, else `false`. - * @example - * - * _.isError(new Error); - * // => true - * - * _.isError(Error); - * // => false - */ - function isError(value) { - if (!isObjectLike(value)) { - return false; - } - return (objectToString.call(value) == errorTag) || - (typeof value.message == 'string' && typeof value.name == 'string'); - } - - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on - * [`Number.isFinite`](https://mdn.io/Number/isFinite). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(3); - * // => true - * - * _.isFinite(Number.MIN_VALUE); - * // => true - * - * _.isFinite(Infinity); - * // => false - * - * _.isFinite('3'); - * // => false - */ - function isFinite(value) { - return typeof value == 'number' && nativeIsFinite(value); - } - - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - function isFunction(value) { - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 8-9 which returns 'object' for typed array and other constructors. - var tag = isObject(value) ? objectToString.call(value) : ''; - return tag == funcTag || tag == genTag; - } - - /** - * Checks if `value` is an integer. - * - * **Note:** This method is based on - * [`Number.isInteger`](https://mdn.io/Number/isInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an integer, else `false`. - * @example - * - * _.isInteger(3); - * // => true - * - * _.isInteger(Number.MIN_VALUE); - * // => false - * - * _.isInteger(Infinity); - * // => false - * - * _.isInteger('3'); - * // => false - */ - function isInteger(value) { - return typeof value == 'number' && value == toInteger(value); - } - - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ - function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ - function isObject(value) { - var type = typeof value; - return !!value && (type == 'object' || type == 'function'); - } - - /** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ - function isObjectLike(value) { - return !!value && typeof value == 'object'; - } - - /** - * Checks if `value` is classified as a `Map` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - * @example - * - * _.isMap(new Map); - * // => true - * - * _.isMap(new WeakMap); - * // => false - */ - var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; - - /** - * Performs a partial deep comparison between `object` and `source` to - * determine if `object` contains equivalent property values. - * - * **Note:** This method is equivalent to `_.matches` when `source` is - * partially applied. - * - * Partial comparisons will match empty array and empty object `source` - * values against any array or object value, respectively. See `_.isEqual` - * for a list of supported value comparisons. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.isMatch(object, { 'b': 2 }); - * // => true - * - * _.isMatch(object, { 'b': 1 }); - * // => false - */ - function isMatch(object, source) { - return object === source || baseIsMatch(object, source, getMatchData(source)); - } - - /** - * This method is like `_.isMatch` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with five - * arguments: (objValue, srcValue, index|key, object, source). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, srcValue) { - * if (isGreeting(objValue) && isGreeting(srcValue)) { - * return true; - * } - * } - * - * var object = { 'greeting': 'hello' }; - * var source = { 'greeting': 'hi' }; - * - * _.isMatchWith(object, source, customizer); - * // => true - */ - function isMatchWith(object, source, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseIsMatch(object, source, getMatchData(source), customizer); - } - - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is based on - * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as - * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for - * `undefined` and other non-number values. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some - // ActiveX objects in IE. - return isNumber(value) && value != +value; - } - - /** - * 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 _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - * @example - * - * _.isNative(Array.prototype.push); - * // => true - * - * _.isNative(_); - * // => false - */ - function isNative(value) { - if (isMaskable(value)) { - throw new Error('This method is not supported with core-js. Try https://github.com/es-shims.'); - } - return baseIsNative(value); - } - - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } - - /** - * Checks if `value` is `null` or `undefined`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is nullish, else `false`. - * @example - * - * _.isNil(null); - * // => true - * - * _.isNil(void 0); - * // => true - * - * _.isNil(NaN); - * // => false - */ - function isNil(value) { - return value == null; - } - - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are - * classified as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a number, else `false`. - * @example - * - * _.isNumber(3); - * // => true - * - * _.isNumber(Number.MIN_VALUE); - * // => true - * - * _.isNumber(Infinity); - * // => true - * - * _.isNumber('3'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || - (isObjectLike(value) && objectToString.call(value) == numberTag); - } - - /** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * @static - * @memberOf _ - * @since 0.8.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ - function isPlainObject(value) { - if (!isObjectLike(value) || - objectToString.call(value) != objectTag || isHostObject(value)) { - return false; - } - var proto = getPrototype(value); - if (proto === null) { - return true; - } - var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return (typeof Ctor == 'function' && - Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString); - } - - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; - - /** - * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 - * double precision number which isn't the result of a rounded unsafe integer. - * - * **Note:** This method is based on - * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. - * @example - * - * _.isSafeInteger(3); - * // => true - * - * _.isSafeInteger(Number.MIN_VALUE); - * // => false - * - * _.isSafeInteger(Infinity); - * // => false - * - * _.isSafeInteger('3'); - * // => false - */ - function isSafeInteger(value) { - return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is classified as a `Set` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - * @example - * - * _.isSet(new Set); - * // => true - * - * _.isSet(new WeakSet); - * // => false - */ - var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; - - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a string, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag); - } - - /** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ - function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && objectToString.call(value) == symbolTag); - } - - /** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ - var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; - - /** - * Checks if `value` is `undefined`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; - } - - /** - * Checks if `value` is classified as a `WeakMap` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. - * @example - * - * _.isWeakMap(new WeakMap); - * // => true - * - * _.isWeakMap(new Map); - * // => false - */ - function isWeakMap(value) { - return isObjectLike(value) && getTag(value) == weakMapTag; - } - - /** - * Checks if `value` is classified as a `WeakSet` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. - * @example - * - * _.isWeakSet(new WeakSet); - * // => true - * - * _.isWeakSet(new Set); - * // => false - */ - function isWeakSet(value) { - return isObjectLike(value) && objectToString.call(value) == weakSetTag; - } - - /** - * Checks if `value` is less than `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - * @see _.gt - * @example - * - * _.lt(1, 3); - * // => true - * - * _.lt(3, 3); - * // => false - * - * _.lt(3, 1); - * // => false - */ - var lt = createRelationalOperation(baseLt); - - /** - * Checks if `value` is less than or equal to `other`. - * - * @static - * @memberOf _ - * @since 3.9.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than or equal to - * `other`, else `false`. - * @see _.gte - * @example - * - * _.lte(1, 3); - * // => true - * - * _.lte(3, 3); - * // => true - * - * _.lte(3, 1); - * // => false - */ - var lte = createRelationalOperation(function(value, other) { - return value <= other; - }); - - /** - * Converts `value` to an array. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * _.toArray({ 'a': 1, 'b': 2 }); - * // => [1, 2] - * - * _.toArray('abc'); - * // => ['a', 'b', 'c'] - * - * _.toArray(1); - * // => [] - * - * _.toArray(null); - * // => [] - */ - function toArray(value) { - if (!value) { - return []; - } - if (isArrayLike(value)) { - return isString(value) ? stringToArray(value) : copyArray(value); - } - if (iteratorSymbol && value[iteratorSymbol]) { - return iteratorToArray(value[iteratorSymbol]()); - } - var tag = getTag(value), - func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); - - 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 method is loosely based on - * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toInteger(3.2); - * // => 3 - * - * _.toInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toInteger(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toInteger('3.2'); - * // => 3 - */ - function toInteger(value) { - var result = toFinite(value), - remainder = result % 1; - - return result === result ? (remainder ? result - remainder : result) : 0; - } - - /** - * Converts `value` to an integer suitable for use as the length of an - * array-like object. - * - * **Note:** This method is based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toLength(3.2); - * // => 3 - * - * _.toLength(Number.MIN_VALUE); - * // => 0 - * - * _.toLength(Infinity); - * // => 4294967295 - * - * _.toLength('3.2'); - * // => 3 - */ - function toLength(value) { - return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; - } - - /** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ - function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); - } - - /** - * Converts `value` to a plain object flattening inherited enumerable string - * keyed properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ - function toPlainObject(value) { - return copyObject(value, keysIn(value)); - } - - /** - * Converts `value` to a safe integer. A safe integer can be compared and - * represented correctly. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toSafeInteger(3.2); - * // => 3 - * - * _.toSafeInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toSafeInteger(Infinity); - * // => 9007199254740991 - * - * _.toSafeInteger('3.2'); - * // => 3 - */ - function toSafeInteger(value) { - return baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER); - } - - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {string} Returns the string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ - function toString(value) { - return value == null ? '' : baseToString(value); - } - - /*------------------------------------------------------------------------*/ - - /** - * Assigns own enumerable string keyed properties of source objects to the - * destination object. Source objects are applied from left to right. - * Subsequent sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object` and is loosely based on - * [`Object.assign`](https://mdn.io/Object/assign). - * - * @static - * @memberOf _ - * @since 0.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assignIn - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assign({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'c': 3 } - */ - var assign = createAssigner(function(object, source) { - if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) { - copyObject(source, keys(source), object); - return; - } - for (var key in source) { - if (hasOwnProperty.call(source, key)) { - assignValue(object, key, source[key]); - } - } - }); - - /** - * This method is like `_.assign` except that it iterates over own and - * inherited source properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assign - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assignIn({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } - */ - var assignIn = createAssigner(function(object, source) { - copyObject(source, keysIn(source), object); - }); - - /** - * This method is like `_.assignIn` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extendWith - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignInWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keysIn(source), object, customizer); - }); - - /** - * This method is like `_.assign` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignInWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keys(source), object, customizer); - }); - - /** - * Creates an array of values corresponding to `paths` of `object`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @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 picked values. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _.at(object, ['a[0].b.c', 'a[1]']); - * // => [3, 4] - */ - var at = baseRest(function(object, paths) { - return baseAt(object, baseFlatten(paths, 1)); - }); - - /** - * Creates an object that inherits from the `prototype` object. If a - * `properties` object is given, its own enumerable string keyed properties - * are assigned to the created object. - * - * @static - * @memberOf _ - * @since 2.3.0 - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties) { - var result = baseCreate(prototype); - return properties ? baseAssign(result, properties) : result; - } - - /** - * Assigns own and inherited enumerable string keyed properties of source - * objects to the destination object for all destination properties that - * resolve to `undefined`. Source objects are applied from left to right. - * Once a property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaultsDeep - * @example - * - * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var defaults = baseRest(function(args) { - args.push(undefined, assignInDefaults); - return apply(assignInWith, undefined, args); - }); - - /** - * This method is like `_.defaults` except that it recursively assigns - * default properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaults - * @example - * - * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); - * // => { 'a': { 'b': 2, 'c': 3 } } - */ - var defaultsDeep = baseRest(function(args) { - args.push(undefined, mergeDefaults); - return apply(mergeWith, undefined, args); - }); - - /** - * This method is like `_.find` except that it returns the key of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findKey(users, function(o) { return o.age < 40; }); - * // => 'barney' (iteration order is not guaranteed) - * - * // The `_.matches` iteratee shorthand. - * _.findKey(users, { 'age': 1, 'active': true }); - * // => 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findKey(users, 'active'); - * // => 'barney' - */ - function findKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); - } - - /** - * This method is like `_.findKey` except that it iterates over elements of - * a collection in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findLastKey(users, function(o) { return o.age < 40; }); - * // => returns 'pebbles' assuming `_.findKey` returns 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.findLastKey(users, { 'age': 36, 'active': true }); - * // => 'barney' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findLastKey(users, 'active'); - * // => 'pebbles' - */ - function findLastKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); - } - - /** - * Iterates over own and inherited enumerable string keyed properties of an - * object and invokes `iteratee` for each property. The iteratee is invoked - * with three arguments: (value, key, object). Iteratee functions may exit - * iteration early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 0.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forInRight - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forIn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). - */ - function forIn(object, iteratee) { - return object == null - ? object - : baseFor(object, getIteratee(iteratee, 3), keysIn); - } - - /** - * This method is like `_.forIn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forIn - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forInRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. - */ - function forInRight(object, iteratee) { - return object == null - ? object - : baseForRight(object, getIteratee(iteratee, 3), keysIn); - } - - /** - * Iterates over own enumerable string keyed properties of an object and - * invokes `iteratee` for each property. The iteratee is invoked with three - * arguments: (value, key, object). Iteratee functions may exit iteration - * early by explicitly returning `false`. - * - * @static - * @memberOf _ - * @since 0.3.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forOwnRight - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwn(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forOwn(object, iteratee) { - return object && baseForOwn(object, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.forOwn` except that it iterates over properties of - * `object` in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns `object`. - * @see _.forOwn - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.forOwnRight(new Foo, function(value, key) { - * console.log(key); - * }); - * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. - */ - function forOwnRight(object, iteratee) { - return object && baseForOwnRight(object, getIteratee(iteratee, 3)); - } - - /** - * Creates an array of function property names from own enumerable properties - * of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functionsIn - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functions(new Foo); - * // => ['a', 'b'] - */ - function functions(object) { - return object == null ? [] : baseFunctions(object, keys(object)); - } - - /** - * Creates an array of function property names from own and inherited - * enumerable properties of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functions - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functionsIn(new Foo); - * // => ['a', 'b', 'c'] - */ - function functionsIn(object) { - return object == null ? [] : baseFunctions(object, keysIn(object)); - } - - /** - * Gets the value at `path` of `object`. If the resolved value is - * `undefined`, the `defaultValue` is returned in its place. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ - function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, path); - return result === undefined ? defaultValue : result; - } - - /** - * Checks if `path` is a direct property of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = { 'a': { 'b': 2 } }; - * var other = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b'); - * // => true - * - * _.has(object, ['a', 'b']); - * // => true - * - * _.has(other, 'a'); - * // => false - */ - function has(object, path) { - return object != null && hasPath(object, path, baseHas); - } - - /** - * Checks if `path` is a direct or inherited property of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.hasIn(object, 'a'); - * // => true - * - * _.hasIn(object, 'a.b'); - * // => true - * - * _.hasIn(object, ['a', 'b']); - * // => true - * - * _.hasIn(object, 'b'); - * // => false - */ - function hasIn(object, path) { - return object != null && hasPath(object, path, baseHasIn); - } - - /** - * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite - * property assignments of previous values. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Object - * @param {Object} object The object to invert. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invert(object); - * // => { '1': 'c', '2': 'b' } - */ - var invert = createInverter(function(result, value, key) { - result[value] = key; - }, constant(identity)); - - /** - * This method is like `_.invert` except that the inverted object is generated - * from the results of running each element of `object` thru `iteratee`. The - * corresponding inverted value of each inverted key is an array of keys - * responsible for generating the inverted value. The iteratee is invoked - * with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Object - * @param {Object} object The object to invert. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invertBy(object); - * // => { '1': ['a', 'c'], '2': ['b'] } - * - * _.invertBy(object, function(value) { - * return 'group' + value; - * }); - * // => { 'group1': ['a', 'c'], 'group2': ['b'] } - */ - var invertBy = createInverter(function(result, value, key) { - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - }, getIteratee); - - /** - * Invokes the method at `path` of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {...*} [args] The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - * @example - * - * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; - * - * _.invoke(object, 'a[0].b.c.slice', 1, 3); - * // => [2, 3] - */ - var invoke = baseRest(baseInvoke); - - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); - } - - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - function keysIn(object) { - return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); - } - - /** - * The opposite of `_.mapValues`; this method creates an object with the - * same values as `object` and keys generated by running each own enumerable - * string keyed property of `object` thru `iteratee`. The iteratee is invoked - * with three arguments: (value, key, object). - * - * @static - * @memberOf _ - * @since 3.8.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns the new mapped object. - * @see _.mapValues - * @example - * - * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { - * return key + value; - * }); - * // => { 'a1': 1, 'b2': 2 } - */ - function mapKeys(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); - - baseForOwn(object, function(value, key, object) { - result[iteratee(value, key, object)] = value; - }); - return result; - } - - /** - * Creates an object with the same keys as `object` and values generated - * by running each own enumerable string keyed property of `object` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, key, object). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Object - * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Object} Returns the new mapped object. - * @see _.mapKeys - * @example - * - * var users = { - * 'fred': { 'user': 'fred', 'age': 40 }, - * 'pebbles': { 'user': 'pebbles', 'age': 1 } - * }; - * - * _.mapValues(users, function(o) { return o.age; }); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - * - * // The `_.property` iteratee shorthand. - * _.mapValues(users, 'age'); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - */ - function mapValues(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); - - baseForOwn(object, function(value, key, object) { - result[key] = iteratee(value, key, object); - }); - return result; - } - - /** - * This method is like `_.assign` except that it recursively merges own and - * 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 - * assignment. Source objects are applied from left to right. Subsequent - * sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * var object = { - * 'a': [{ 'b': 2 }, { 'd': 4 }] - * }; - * - * var other = { - * 'a': [{ 'c': 3 }, { 'e': 5 }] - * }; - * - * _.merge(object, other); - * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } - */ - var merge = createAssigner(function(object, source, srcIndex) { - baseMerge(object, source, srcIndex); - }); - - /** - * This method is like `_.merge` except that it accepts `customizer` which - * is invoked to produce the merged values of the destination and source - * properties. If `customizer` returns `undefined`, merging is handled by the - * method instead. The `customizer` is invoked with seven arguments: - * (objValue, srcValue, key, object, source, stack). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * function customizer(objValue, srcValue) { - * if (_.isArray(objValue)) { - * return objValue.concat(srcValue); - * } - * } - * - * var object = { 'a': [1], 'b': [2] }; - * var other = { 'a': [3], 'b': [4] }; - * - * _.mergeWith(object, other, customizer); - * // => { 'a': [1, 3], 'b': [2, 4] } - */ - var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { - baseMerge(object, source, srcIndex, customizer); - }); - - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable string keyed properties of `object` that are - * not omitted. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [props] The property identifiers to omit. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omit(object, ['a', 'c']); - * // => { 'b': '2' } - */ - var omit = baseRest(function(object, props) { - if (object == null) { - return {}; - } - props = arrayMap(baseFlatten(props, 1), toKey); - return basePick(object, baseDifference(getAllKeysIn(object), props)); - }); - - /** - * The opposite of `_.pickBy`; this method creates an object composed of - * the own and inherited enumerable string keyed properties of `object` that - * `predicate` doesn't return truthy for. The predicate is invoked with two - * arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omitBy(object, _.isNumber); - * // => { 'b': '2' } - */ - function omitBy(object, predicate) { - return pickBy(object, negate(getIteratee(predicate))); - } - - /** - * Creates an object composed of the picked `object` properties. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [props] The property identifiers to pick. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pick(object, ['a', 'c']); - * // => { 'a': 1, 'c': 3 } - */ - var pick = baseRest(function(object, props) { - return object == null ? {} : basePick(object, arrayMap(baseFlatten(props, 1), toKey)); - }); - - /** - * Creates an object composed of the `object` properties `predicate` returns - * truthy for. The predicate is invoked with two arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pickBy(object, _.isNumber); - * // => { 'a': 1, 'c': 3 } - */ - function pickBy(object, predicate) { - return object == null ? {} : basePickBy(object, getAllKeysIn(object), getIteratee(predicate)); - } - - /** - * This method is like `_.get` except that if the resolved value is a - * function it's invoked with the `this` binding of its parent object and - * its result is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a[0].b.c3', 'default'); - * // => 'default' - * - * _.result(object, 'a[0].b.c3', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - path = isKey(path, object) ? [path] : castPath(path); - - var index = -1, - length = path.length; - - // Ensure the loop is entered when path is empty. - if (!length) { - object = undefined; - length = 1; - } - while (++index < length) { - var value = object == null ? undefined : object[toKey(path[index])]; - if (value === undefined) { - index = length; - value = defaultValue; - } - object = isFunction(value) ? value.call(object) : value; - } - return object; - } - - /** - * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, - * it's created. Arrays are created for missing index properties while objects - * are created for all other missing properties. Use `_.setWith` to customize - * `path` creation. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.set(object, 'a[0].b.c', 4); - * console.log(object.a[0].b.c); - * // => 4 - * - * _.set(object, ['x', '0', 'y', 'z'], 5); - * console.log(object.x[0].y.z); - * // => 5 - */ - function set(object, path, value) { - return object == null ? object : baseSet(object, path, value); - } - - /** - * This method is like `_.set` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.setWith(object, '[0][1]', 'a', Object); - * // => { '0': { '1': 'a' } } - */ - function setWith(object, path, value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseSet(object, path, value, customizer); - } - - /** - * Creates an array of own enumerable string keyed-value pairs for `object` - * which can be consumed by `_.fromPairs`. If `object` is a map or set, its - * entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entries - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairs(new Foo); - * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) - */ - var toPairs = createToPairs(keys); - - /** - * Creates an array of own and inherited enumerable string keyed-value pairs - * for `object` which can be consumed by `_.fromPairs`. If `object` is a map - * or set, its entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entriesIn - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairsIn(new Foo); - * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) - */ - 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. 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 {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. - * @example - * - * _.transform([2, 3, 4], function(result, n) { - * result.push(n *= n); - * return n % 2 == 0; - * }, []); - * // => [4, 9] - * - * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } - */ - function transform(object, iteratee, accumulator) { - var isArr = isArray(object) || isTypedArray(object); - iteratee = getIteratee(iteratee, 4); - - if (accumulator == null) { - if (isArr || isObject(object)) { - var Ctor = object.constructor; - if (isArr) { - accumulator = isArray(object) ? new Ctor : []; - } else { - accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; - } - } else { - accumulator = {}; - } - } - (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) { - return iteratee(accumulator, value, index, object); - }); - return accumulator; - } - - /** - * Removes the property at `path` of `object`. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 7 } }] }; - * _.unset(object, 'a[0].b.c'); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - * - * _.unset(object, ['a', '0', 'b', 'c']); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - */ - function unset(object, path) { - return object == null ? true : baseUnset(object, path); - } - - /** - * This method is like `_.set` except that accepts `updater` to produce the - * value to set. Use `_.updateWith` to customize `path` creation. The `updater` - * is invoked with one argument: (value). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.update(object, 'a[0].b.c', function(n) { return n * n; }); - * console.log(object.a[0].b.c); - * // => 9 - * - * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); - * console.log(object.x[0].y.z); - * // => 0 - */ - function update(object, path, updater) { - return object == null ? object : baseUpdate(object, path, castFunction(updater)); - } - - /** - * This method is like `_.update` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.updateWith(object, '[0][1]', _.constant('a'), Object); - * // => { '0': { '1': 'a' } } - */ - function updateWith(object, path, updater, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); - } - - /** - * Creates an array of the own enumerable string keyed property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return object ? baseValues(object, keys(object)) : []; - } - - /** - * Creates an array of the own and inherited enumerable string keyed property - * values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.valuesIn(new Foo); - * // => [1, 2, 3] (iteration order is not guaranteed) - */ - function valuesIn(object) { - return object == null ? [] : baseValues(object, keysIn(object)); - } - - /*------------------------------------------------------------------------*/ - - /** - * Clamps `number` within the inclusive `lower` and `upper` bounds. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Number - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - * @example - * - * _.clamp(-10, -5, 5); - * // => -5 - * - * _.clamp(10, -5, 5); - * // => 5 - */ - function clamp(number, lower, upper) { - if (upper === undefined) { - upper = lower; - lower = undefined; - } - if (upper !== undefined) { - upper = toNumber(upper); - upper = upper === upper ? upper : 0; - } - if (lower !== undefined) { - lower = toNumber(lower); - lower = lower === lower ? lower : 0; - } - return baseClamp(toNumber(number), lower, upper); - } - - /** - * Checks if `n` is between `start` and up to, but not including, `end`. If - * `end` is not specified, it's set to `start` with `start` then set to `0`. - * If `start` is greater than `end` the params are swapped to support - * negative ranges. - * - * @static - * @memberOf _ - * @since 3.3.0 - * @category Number - * @param {number} number The number to check. - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - * @see _.range, _.rangeRight - * @example - * - * _.inRange(3, 2, 4); - * // => true - * - * _.inRange(4, 8); - * // => true - * - * _.inRange(4, 2); - * // => false - * - * _.inRange(2, 2); - * // => false - * - * _.inRange(1.2, 2); - * // => true - * - * _.inRange(5.2, 4); - * // => false - * - * _.inRange(-3, -2, -6); - * // => true - */ - function inRange(number, start, end) { - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - number = toNumber(number); - return baseInRange(number, start, end); - } - - /** - * Produces a random number between the inclusive `lower` and `upper` bounds. - * If only one argument is provided a number between `0` and the given number - * is returned. If `floating` is `true`, or either `lower` or `upper` are - * floats, a floating-point number is returned instead of an integer. - * - * **Note:** JavaScript follows the IEEE-754 standard for resolving - * floating-point values which can produce unexpected results. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Number - * @param {number} [lower=0] The lower bound. - * @param {number} [upper=1] The upper bound. - * @param {boolean} [floating] Specify returning a floating-point number. - * @returns {number} Returns the random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(lower, upper, floating) { - if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { - upper = floating = undefined; - } - if (floating === undefined) { - if (typeof upper == 'boolean') { - floating = upper; - upper = undefined; - } - else if (typeof lower == 'boolean') { - floating = lower; - lower = undefined; - } - } - if (lower === undefined && upper === undefined) { - lower = 0; - upper = 1; - } - else { - lower = toFinite(lower); - if (upper === undefined) { - upper = lower; - lower = 0; - } else { - upper = toFinite(upper); - } - } - if (lower > upper) { - var temp = lower; - lower = upper; - upper = temp; - } - if (floating || lower % 1 || upper % 1) { - var rand = nativeRandom(); - return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); - } - return baseRandom(lower, upper); - } - - /*------------------------------------------------------------------------*/ - - /** - * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the camel cased string. - * @example - * - * _.camelCase('Foo Bar'); - * // => 'fooBar' - * - * _.camelCase('--foo-bar--'); - * // => 'fooBar' - * - * _.camelCase('__FOO_BAR__'); - * // => 'fooBar' - */ - var camelCase = createCompounder(function(result, word, index) { - word = word.toLowerCase(); - return result + (index ? capitalize(word) : word); - }); - - /** - * Converts the first character of `string` to upper case and the remaining - * to lower case. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to capitalize. - * @returns {string} Returns the capitalized string. - * @example - * - * _.capitalize('FRED'); - * // => 'Fred' - */ - function capitalize(string) { - return upperFirst(toString(string).toLowerCase()); - } - - /** - * Deburrs `string` by converting - * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) - * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) - * letters to basic Latin letters and removing - * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to deburr. - * @returns {string} Returns the deburred string. - * @example - * - * _.deburr('déjà vu'); - * // => 'deja vu' - */ - function deburr(string) { - string = toString(string); - return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); - } - - /** - * Checks if `string` ends with the given target string. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to inspect. - * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search up to. - * @returns {boolean} Returns `true` if `string` ends with `target`, - * else `false`. - * @example - * - * _.endsWith('abc', 'c'); - * // => true - * - * _.endsWith('abc', 'b'); - * // => false - * - * _.endsWith('abc', 'b', 2); - * // => true - */ - function endsWith(string, target, position) { - string = toString(string); - target = baseToString(target); - - var length = string.length; - position = position === undefined - ? length - : baseClamp(toInteger(position), 0, length); - - var end = position; - position -= target.length; - return position >= 0 && string.slice(position, end) == target; - } - - /** - * Converts the characters "&", "<", ">", '"', "'", and "\`" in `string` to - * their corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional - * characters use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. See - * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * Backticks are escaped because in IE < 9, they can break out of - * attribute values or HTML comments. See [#59](https://html5sec.org/#59), - * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and - * [#133](https://html5sec.org/#133) of the - * [HTML5 Security Cheatsheet](https://html5sec.org/) for more details. - * - * When working with HTML you should always - * [quote attribute values](http://wonko.com/post/html-escaping) to reduce - * XSS vectors. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - string = toString(string); - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, escapeHtmlChar) - : string; - } - - /** - * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", - * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escapeRegExp('[lodash](https://lodash.com/)'); - * // => '\[lodash\]\(https://lodash\.com/\)' - */ - function escapeRegExp(string) { - string = toString(string); - return (string && reHasRegExpChar.test(string)) - ? string.replace(reRegExpChar, '\\$&') - : string; - } - - /** - * Converts `string` to - * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the kebab cased string. - * @example - * - * _.kebabCase('Foo Bar'); - * // => 'foo-bar' - * - * _.kebabCase('fooBar'); - * // => 'foo-bar' - * - * _.kebabCase('__FOO_BAR__'); - * // => 'foo-bar' - */ - var kebabCase = createCompounder(function(result, word, index) { - return result + (index ? '-' : '') + word.toLowerCase(); - }); - - /** - * Converts `string`, as space separated words, to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the lower cased string. - * @example - * - * _.lowerCase('--Foo-Bar--'); - * // => 'foo bar' - * - * _.lowerCase('fooBar'); - * // => 'foo bar' - * - * _.lowerCase('__FOO_BAR__'); - * // => 'foo bar' - */ - var lowerCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + word.toLowerCase(); - }); - - /** - * Converts the first character of `string` to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.lowerFirst('Fred'); - * // => 'fred' - * - * _.lowerFirst('FRED'); - * // => 'fRED' - */ - var lowerFirst = createCaseFirst('toLowerCase'); - - /** - * Pads `string` on the left and right sides if it's shorter than `length`. - * Padding characters are truncated if they can't be evenly divided by `length`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.pad('abc', 8); - * // => ' abc ' - * - * _.pad('abc', 8, '_-'); - * // => '_-abc_-_' - * - * _.pad('abc', 3); - * // => 'abc' - */ - function pad(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - if (!length || strLength >= length) { - return string; - } - var mid = (length - strLength) / 2; - return ( - createPadding(nativeFloor(mid), chars) + - string + - createPadding(nativeCeil(mid), chars) - ); - } - - /** - * Pads `string` on the right side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padEnd('abc', 6); - * // => 'abc ' - * - * _.padEnd('abc', 6, '_-'); - * // => 'abc_-_' - * - * _.padEnd('abc', 3); - * // => 'abc' - */ - function padEnd(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (string + createPadding(length - strLength, chars)) - : string; - } - - /** - * Pads `string` on the left side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padStart('abc', 6); - * // => ' abc' - * - * _.padStart('abc', 6, '_-'); - * // => '_-_abc' - * - * _.padStart('abc', 3); - * // => 'abc' - */ - function padStart(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (createPadding(length - strLength, chars) + string) - : string; - } - - /** - * Converts `string` to an integer of the specified radix. If `radix` is - * `undefined` or `0`, a `radix` of `10` is used unless `value` is a - * hexadecimal, in which case a `radix` of `16` is used. - * - * **Note:** This method aligns with the - * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category String - * @param {string} string The string to convert. - * @param {number} [radix=10] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {number} Returns the converted integer. - * @example - * - * _.parseInt('08'); - * // => 8 - * - * _.map(['6', '08', '10'], _.parseInt); - * // => [6, 8, 10] - */ - function parseInt(string, radix, guard) { - // Chrome fails to trim leading whitespace characters. - // See https://bugs.chromium.org/p/v8/issues/detail?id=3109 for more details. - if (guard || radix == null) { - radix = 0; - } else if (radix) { - radix = +radix; - } - string = toString(string).replace(reTrim, ''); - return nativeParseInt(string, radix || (reHasHexPrefix.test(string) ? 16 : 10)); - } - - /** - * Repeats the given string `n` times. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to repeat. - * @param {number} [n=1] The number of times to repeat the string. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {string} Returns the repeated string. - * @example - * - * _.repeat('*', 3); - * // => '***' - * - * _.repeat('abc', 2); - * // => 'abcabc' - * - * _.repeat('abc', 0); - * // => '' - */ - function repeat(string, n, guard) { - if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { - n = 1; - } else { - n = toInteger(n); - } - return baseRepeat(toString(string), n); - } - - /** - * Replaces matches for `pattern` in `string` with `replacement`. - * - * **Note:** This method is based on - * [`String#replace`](https://mdn.io/String/replace). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to modify. - * @param {RegExp|string} pattern The pattern to replace. - * @param {Function|string} replacement The match replacement. - * @returns {string} Returns the modified string. - * @example - * - * _.replace('Hi Fred', 'Fred', 'Barney'); - * // => 'Hi Barney' - */ - function replace() { - var args = arguments, - string = toString(args[0]); - - return args.length < 3 ? string : string.replace(args[1], args[2]); - } - - /** - * Converts `string` to - * [snake case](https://en.wikipedia.org/wiki/Snake_case). - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the snake cased string. - * @example - * - * _.snakeCase('Foo Bar'); - * // => 'foo_bar' - * - * _.snakeCase('fooBar'); - * // => 'foo_bar' - * - * _.snakeCase('--FOO-BAR--'); - * // => 'foo_bar' - */ - var snakeCase = createCompounder(function(result, word, index) { - return result + (index ? '_' : '') + word.toLowerCase(); - }); - - /** - * Splits `string` by `separator`. - * - * **Note:** This method is based on - * [`String#split`](https://mdn.io/String/split). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @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 string segments. - * @example - * - * _.split('a-b-c', '-', 2); - * // => ['a', 'b'] - */ - function split(string, separator, limit) { - if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { - separator = limit = undefined; - } - limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; - if (!limit) { - return []; - } - string = toString(string); - if (string && ( - typeof separator == 'string' || - (separator != null && !isRegExp(separator)) - )) { - separator = baseToString(separator); - if (!separator && hasUnicode(string)) { - return castSlice(stringToArray(string), 0, limit); - } - } - return string.split(separator, limit); - } - - /** - * Converts `string` to - * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). - * - * @static - * @memberOf _ - * @since 3.1.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the start cased string. - * @example - * - * _.startCase('--foo-bar--'); - * // => 'Foo Bar' - * - * _.startCase('fooBar'); - * // => 'Foo Bar' - * - * _.startCase('__FOO_BAR__'); - * // => 'FOO BAR' - */ - var startCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + upperFirst(word); - }); - - /** - * Checks if `string` starts with the given target string. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to inspect. - * @param {string} [target] The string to search for. - * @param {number} [position=0] The position to search from. - * @returns {boolean} Returns `true` if `string` starts with `target`, - * else `false`. - * @example - * - * _.startsWith('abc', 'a'); - * // => true - * - * _.startsWith('abc', 'b'); - * // => false - * - * _.startsWith('abc', 'b', 1); - * // => true - */ - function startsWith(string, target, position) { - string = toString(string); - position = baseClamp(toInteger(position), 0, string.length); - target = baseToString(target); - return string.slice(position, position + target.length) == target; - } - - /** - * Creates a compiled template function that can interpolate data properties - * in "interpolate" delimiters, HTML-escape interpolated data properties in - * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data - * properties may be accessed as free variables in the template. If a setting - * object is given, it takes precedence over `_.templateSettings` values. - * - * **Note:** In the development build `_.template` utilizes - * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) - * for easier debugging. - * - * For more information on precompiling templates see - * [lodash's custom builds documentation](https://lodash.com/custom-builds). - * - * For more information on Chrome extension sandboxes see - * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The template string. - * @param {Object} [options={}] The options object. - * @param {RegExp} [options.escape=_.templateSettings.escape] - * The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] - * The "evaluate" delimiter. - * @param {Object} [options.imports=_.templateSettings.imports] - * An object to import into the template as free variables. - * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] - * The "interpolate" delimiter. - * @param {string} [options.sourceURL='lodash.templateSources[n]'] - * The sourceURL of the compiled template. - * @param {string} [options.variable='obj'] - * The data object variable name. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Function} Returns the compiled template function. - * @example - * - * // Use the "interpolate" delimiter to create a compiled template. - * var compiled = _.template('hello <%= user %>!'); - * compiled({ 'user': 'fred' }); - * // => 'hello fred!' - * - * // Use the HTML "escape" delimiter to escape data property values. - * var compiled = _.template('<%- value %>'); - * compiled({ 'value': ' - - -``` - -In Node.js: -```js -// Load the fp build. -var fp = require('lodash/fp'); - -// Load a method category. -var object = require('lodash/fp/object'); - -// Load a single method for smaller builds with browserify/rollup/webpack. -var extend = require('lodash/fp/extend'); -``` - -## Mapping - -Immutable auto-curried iteratee-first data-last methods sound great, but what -does that really mean for each method? Below is a breakdown of the mapping used -to convert each method. - -#### Capped Iteratee Arguments - -Iteratee arguments are capped to avoid gotchas with variadic iteratees. -```js -// The `lodash/map` iteratee receives three arguments: -// (value, index|key, collection) -_.map(['6', '8', '10'], parseInt); -// ➜ [6, NaN, 2] - -// The `lodash/fp/map` iteratee is capped at one argument: -// (value) -fp.map(parseInt)(['6', '8', '10']); -// ➜ [6, 8, 10] -``` - -Methods that cap iteratees to one argument:
-<%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 1)))) %> - -Methods that cap iteratees to two arguments:
-<%= toFuncList(_.keys(_.pickBy(mapping.iterateeAry, _.partial(_.eq, _, 2)))) %> - -The iteratee of `mapKeys` is invoked with one argument: (key) - -#### Fixed Arity - -Methods have fixed arities to support auto-currying. -```js -// `lodash/padStart` accepts an optional `chars` param. -_.padStart('a', 3, '-') -// ➜ '--a' - -// `lodash/fp/padStart` does not. -fp.padStart(3)('a'); -// ➜ ' a' -fp.padCharsStart('-')(3)('a'); -// ➜ '--a' -``` - -Methods with a fixed arity of one:
-<%= toFuncList(_.difference(mapping.aryMethod[1], _.keys(mapping.skipFixed))) %> - -Methods with a fixed arity of two:
-<%= toFuncList(_.difference(mapping.aryMethod[2], _.keys(mapping.skipFixed))) %> - -Methods with a fixed arity of three:
-<%= toFuncList(_.difference(mapping.aryMethod[3], _.keys(mapping.skipFixed))) %> - -Methods with a fixed arity of four:
-<%= toFuncList(_.difference(mapping.aryMethod[4], _.keys(mapping.skipFixed))) %> - -#### Rearranged Arguments - -Method arguments are rearranged to make composition easier. -```js -// `lodash/filter` is data-first iteratee-last: -// (collection, iteratee) -var compact = _.partial(_.filter, _, Boolean); -compact(['a', null, 'c']); -// ➜ ['a', 'c'] - -// `lodash/fp/filter` is iteratee-first data-last: -// (iteratee, collection) -var compact = fp.filter(Boolean); -compact(['a', null, 'c']); -// ➜ ['a', 'c'] -``` - -##### Most methods follow these rules - -A fixed arity of two has an argument order of:
-<%= toArgOrder(mapping.aryRearg[2]) %> - -A fixed arity of three has an argument order of:
-<%= toArgOrder(mapping.aryRearg[3]) %> - -A fixed arity of four has an argument order of:
-<%= toArgOrder(mapping.aryRearg[4]) %> - -##### Exceptions to the rules - -Methods that accept an array of arguments:
-<%= toFuncList(_.keys(mapping.methodSpread)) %> - -Methods with unchanged argument orders:
-<%= toFuncList(_.keys(mapping.skipRearg)) %> - -Methods with custom argument orders:
-<%= _.map(_.keys(mapping.methodRearg), function(methodName) { - var orders = mapping.methodRearg[methodName]; - return ' * `_.' + methodName + '` has an order of ' + toArgOrder(orders); -}).join('\n') %> - -#### New Methods - -Not all variadic methods have corresponding new method variants. Feel free to -[request](https://github.com/lodash/lodash/blob/master/.github/CONTRIBUTING.md#feature-requests) -any additions. - -Methods created to accommodate Lodash’s variadic methods:
-<%= toFuncList(_.keys(mapping.remap)) %> - -#### Aliases - -There are <%= _.size(mapping.aliasToReal) %> method aliases:
-<%= _.map(_.keys(mapping.aliasToReal).sort(), function(alias) { - var realName = mapping.aliasToReal[alias]; - return ' * `_.' + alias + '` is an alias of `_.' + realName + '`'; -}).join('\n') %> - -## Placeholders - -The placeholder argument, which defaults to `_`, may be used to fill in method -arguments in a different order. Placeholders are filled by the first available -arguments of the curried returned function. -```js -// The equivalent of `2 > 5`. -_.gt(2)(5); -// ➜ false - -// The equivalent of `_.gt(5, 2)` or `5 > 2`. -_.gt(_, 2)(5); -// ➜ true -``` - -## Chaining - -The `lodash/fp` module **does not** convert chain sequence methods. See -[Izaak Schroeder’s article](https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba) -on using functional composition as an alternative to method chaining. - -## Convert - -Although `lodash/fp` & its method modules come pre-converted, there are times -when you may want to customize the conversion. That’s when the `convert` method -comes in handy. -```js -// Every option is `true` by default. -var _fp = fp.convert({ - // Specify capping iteratee arguments. - 'cap': true, - // Specify currying. - 'curry': true, - // Specify fixed arity. - 'fixed': true, - // Specify immutable operations. - 'immutable': true, - // Specify rearranging arguments. - 'rearg': true -}); - -// The `convert` method is available on each method too. -var mapValuesWithKey = fp.mapValues.convert({ 'cap': false }); - -// Here’s an example of disabling iteratee argument caps to access the `key` param. -mapValuesWithKey(function(value, key) { - return key == 'a' ? -1 : value; -})({ 'a': 1, 'b': 1 }); -// => { 'a': -1, 'b': 1 } -``` - -Manual conversions are also possible with the `convert` module. -```js -var convert = require('lodash/fp/convert'); - -// Convert by name. -var assign = convert('assign', require('lodash.assign')); - -// Convert by object. -var fp = convert({ - 'assign': require('lodash.assign'), - 'chunk': require('lodash.chunk') -}); - -// Convert by `lodash` instance. -var fp = convert(lodash.runInContext()); -``` - -## Tooling - -Use [eslint-plugin-lodash-fp](https://www.npmjs.com/package/eslint-plugin-lodash-fp) -to help use `lodash/fp` more efficiently. diff --git a/public/vendor/lodash/lib/fp/template/modules/_falseOptions.jst b/public/vendor/lodash/lib/fp/template/modules/_falseOptions.jst deleted file mode 100644 index 773235e3437..00000000000 --- a/public/vendor/lodash/lib/fp/template/modules/_falseOptions.jst +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - 'cap': false, - 'curry': false, - 'fixed': false, - 'immutable': false, - 'rearg': false -}; diff --git a/public/vendor/lodash/lib/fp/template/modules/_util.jst b/public/vendor/lodash/lib/fp/template/modules/_util.jst deleted file mode 100644 index f8148129eb8..00000000000 --- a/public/vendor/lodash/lib/fp/template/modules/_util.jst +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - 'ary': require('../ary'), - 'assign': require('../_baseAssign'), - 'clone': require('../clone'), - 'curry': require('../curry'), - 'forEach': require('../_arrayEach'), - 'isArray': require('../isArray'), - 'isFunction': require('../isFunction'), - 'iteratee': require('../iteratee'), - 'keys': require('../_baseKeys'), - 'rearg': require('../rearg'), - 'spread': require('../spread'), - 'toInteger': require('../toInteger'), - 'toPath': require('../toPath') -}; diff --git a/public/vendor/lodash/lib/fp/template/modules/alias.jst b/public/vendor/lodash/lib/fp/template/modules/alias.jst deleted file mode 100644 index 6d72710a349..00000000000 --- a/public/vendor/lodash/lib/fp/template/modules/alias.jst +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./<%= name %>'); diff --git a/public/vendor/lodash/lib/fp/template/modules/category.jst b/public/vendor/lodash/lib/fp/template/modules/category.jst deleted file mode 100644 index 62c2db8a16c..00000000000 --- a/public/vendor/lodash/lib/fp/template/modules/category.jst +++ /dev/null @@ -1,2 +0,0 @@ -var convert = require('./convert'); -module.exports = convert(require('../<%= name %>')); diff --git a/public/vendor/lodash/lib/fp/template/modules/convert.jst b/public/vendor/lodash/lib/fp/template/modules/convert.jst deleted file mode 100644 index 4795dc42460..00000000000 --- a/public/vendor/lodash/lib/fp/template/modules/convert.jst +++ /dev/null @@ -1,18 +0,0 @@ -var baseConvert = require('./_baseConvert'), - util = require('./_util'); - -/** - * Converts `func` of `name` to an immutable auto-curried iteratee-first data-last - * version with conversion `options` applied. If `name` is an object its methods - * will be converted. - * - * @param {string} name The name of the function to wrap. - * @param {Function} [func] The function to wrap. - * @param {Object} [options] The options object. See `baseConvert` for more details. - * @returns {Function|Object} Returns the converted function or object. - */ -function convert(name, func, options) { - return baseConvert(util, name, func, options); -} - -module.exports = convert; diff --git a/public/vendor/lodash/lib/fp/template/modules/fp.jst b/public/vendor/lodash/lib/fp/template/modules/fp.jst deleted file mode 100644 index e372dbbdf6d..00000000000 --- a/public/vendor/lodash/lib/fp/template/modules/fp.jst +++ /dev/null @@ -1,2 +0,0 @@ -var _ = require('./lodash.min').runInContext(); -module.exports = require('./fp/_baseConvert')(_, _); diff --git a/public/vendor/lodash/lib/fp/template/modules/module.jst b/public/vendor/lodash/lib/fp/template/modules/module.jst deleted file mode 100644 index 1fb809cb22a..00000000000 --- a/public/vendor/lodash/lib/fp/template/modules/module.jst +++ /dev/null @@ -1,5 +0,0 @@ -var convert = require('./convert'), - func = convert('<%= name %>', require('../<%= _.get(mapping.remap, name, name) %>')); - -func.placeholder = require('./placeholder'); -module.exports = func; diff --git a/public/vendor/lodash/lib/fp/template/modules/thru.jst b/public/vendor/lodash/lib/fp/template/modules/thru.jst deleted file mode 100644 index 838e8b03a81..00000000000 --- a/public/vendor/lodash/lib/fp/template/modules/thru.jst +++ /dev/null @@ -1,5 +0,0 @@ -var convert = require('./convert'), - func = convert('<%= name %>', require('../<%= _.get(mapping.remap, name, name) %>'), require('./_falseOptions')); - -func.placeholder = require('./placeholder'); -module.exports = func; diff --git a/public/vendor/lodash/lib/main/build-dist.js b/public/vendor/lodash/lib/main/build-dist.js deleted file mode 100644 index 137b6915edc..00000000000 --- a/public/vendor/lodash/lib/main/build-dist.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -var async = require('async'), - path = require('path'); - -var file = require('../common/file'), - util = require('../common/util'); - -var basePath = path.join(__dirname, '..', '..'), - distPath = path.join(basePath, 'dist'), - filename = 'lodash.js'; - -var baseLodash = path.join(basePath, filename), - distLodash = path.join(distPath, filename); - -/*----------------------------------------------------------------------------*/ - -/** - * Creates browser builds of Lodash at the `target` path. - * - * @private - * @param {string} target The output directory path. - */ -function build() { - async.series([ - file.copy(baseLodash, distLodash), - file.min(distLodash) - ], util.pitch); -} - -build(); diff --git a/public/vendor/lodash/lib/main/build-doc.js b/public/vendor/lodash/lib/main/build-doc.js deleted file mode 100644 index 94003448bfc..00000000000 --- a/public/vendor/lodash/lib/main/build-doc.js +++ /dev/null @@ -1,83 +0,0 @@ -'use strict'; - -var _ = require('lodash'), - docdown = require('docdown'), - fs = require('fs-extra'), - path = require('path'); - -var util = require('../common/util'); - -var basePath = path.join(__dirname, '..', '..'), - docPath = path.join(basePath, 'doc'), - readmePath = path.join(docPath, 'README.md'); - -var pkg = require('../../package.json'), - version = pkg.version; - -var config = { - 'base': { - 'path': path.join(basePath, 'lodash.js'), - 'title': 'lodash v' + version + '', - 'toc': 'categories', - 'url': 'https://github.com/lodash/lodash/blob/' + version + '/lodash.js' - }, - 'github': { - 'style': 'github', - 'sublinks': [npmLink('Ⓝ', 'See the npm package')] - }, - 'site': { - 'entryLink': '', - 'sourceLink': '[source](${sourceHref})', - 'tocHref': '', - 'tocLink': '', - 'sublinks': [npmLink('npm package')] - } -}; - -/** - * Composes a npm link from `text` and optional `title`. - * - * @private - * @param {string} text The link text. - * @param {string} [title] The link title. - * @returns {string} Returns the composed npm link. - */ -function npmLink(text, title) { - return ( - '<% if (name == "templateSettings" || !/^(?:methods|properties|seq)$/i.test(category)) {' + - 'print(' + - '"[' + text + '](https://www.npmjs.com/package/lodash." + name.toLowerCase() + ' + - '"' + (title == null ? '' : ' \\"' + title + '\\"') + ')"' + - ');' + - '} %>' - ); -} - -/** - * Post-process `markdown` to make adjustments. - * - * @private - * @param {string} markdown The markdown to process. - * @returns {string} Returns the processed markdown. - */ -function postprocess(markdown) { - // Wrap symbol property identifiers in brackets. - return markdown.replace(/\.(Symbol\.(?:[a-z]+[A-Z]?)+)/g, '[$1]'); -} - -/*----------------------------------------------------------------------------*/ - -/** - * Creates the documentation markdown formatted for 'github' or 'site'. - * - * @private - * @param {string} type The format type. - */ -function build(type) { - var options = _.defaults({}, config.base, config[type]), - markdown = docdown(options); - - fs.writeFile(readmePath, postprocess(markdown), util.pitch); -} - -build(_.last(process.argv)); diff --git a/public/vendor/lodash/lib/main/build-modules.js b/public/vendor/lodash/lib/main/build-modules.js deleted file mode 100644 index e9e3f365b03..00000000000 --- a/public/vendor/lodash/lib/main/build-modules.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -var _ = require('lodash'), - async = require('async'), - path = require('path'); - -var file = require('../common/file'), - util = require('../common/util'); - -var basePath = path.join(__dirname, '..', '..'), - distPath = path.join(basePath, 'dist'); - -var filePairs = [ - [path.join(distPath, 'lodash.core.js'), 'core.js'], - [path.join(distPath, 'lodash.core.min.js'), 'core.min.js'], - [path.join(distPath, 'lodash.min.js'), 'lodash.min.js'] -]; - -/*----------------------------------------------------------------------------*/ - -/** - * Creates supplementary Lodash modules at the `target` path. - * - * @private - * @param {string} target The output directory path. - */ -function build(target) { - var actions = _.map(filePairs, function(pair) { - return file.copy(pair[0], path.join(target, pair[1])); - }); - - async.series(actions, util.pitch); -} - -build(_.last(process.argv)); diff --git a/public/vendor/lodash/lib/main/build-site.js b/public/vendor/lodash/lib/main/build-site.js deleted file mode 100644 index 37c1ab04595..00000000000 --- a/public/vendor/lodash/lib/main/build-site.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -var _ = require('lodash'), - fs = require('fs'), - marky = require('marky-markdown'), - path = require('path'), - util = require('../common/util'); - -var basePath = path.join(__dirname, '..', '..'), - docPath = path.join(basePath, 'doc'), - readmePath = path.join(docPath, 'README.md'); - -function build(type) { - var markdown = fs - // Load markdown. - .readFileSync(readmePath, 'utf8') - // Uncomment docdown HTML hints. - .replace(/(<)!--\s*|\s*--(>)/g, '$1$2'); - - var $ = marky(markdown, { 'sanitize': false }), - $header = $('h1').first().remove(), - version = _.trim($header.find('span').first().text()).slice(1); - - // Remove docdown horizontal rules. - $('hr').remove(); - - // Remove marky-markdown additions. - $('[id^="user-content-"]') - .attr('class', null) - .attr('id', null); - - $(':header:not(h3) > a').each(function() { - var $a = $(this); - $a.replaceWith($a.html()); - }); - - // Fix marky-markdown wrapping around headers. - $('p:empty + h3').prev().remove(); - - $('h3 ~ p:empty').each(function() { - var $p = $(this), - node = this.previousSibling; - - while ((node = node.previousSibling) && node.name != 'h3' && node.name != 'p') { - $p.prepend(node.nextSibling); - } - }); - - $('h3 code em').parent().each(function() { - var $code = $(this); - $code.html($code.html().replace(/<\/?em>/g, '_')); - }); - - var html = [ - // Append YAML front matter. - '---', - 'id: docs', - 'layout: docs', - 'title: Lodash Documentation', - 'version: ' + (version || null), - '---', - '', - // Wrap in raw tags to avoid Liquid template tag processing. - '{% raw %}', - _.trim($.html()), - '{% endraw %}', - '' - ].join('\n'); - - fs.writeFile(path.join(docPath, version + '.html'), html, util.pitch); -} - -build(); diff --git a/public/vendor/lodash/lodash.js b/public/vendor/lodash/lodash.js index 6b252563043..d1f45b6ecd6 100644 --- a/public/vendor/lodash/lodash.js +++ b/public/vendor/lodash/lodash.js @@ -1,10 +1,11 @@ /** * @license - * lodash - * Copyright jQuery Foundation and other contributors - * Released under MIT license + * lodash 3.10.1 (Custom Build) + * Build: `lodash modern -o ./lodash.js` + * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 - * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license */ ;(function() { @@ -12,21 +13,9 @@ var undefined; /** Used as the semantic version number. */ - var VERSION = '4.15.0'; + var VERSION = '3.10.1'; - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Used as the `TypeError` message for "Functions" methods. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED = '__lodash_hash_undefined__'; - - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - - /** Used to compose bitmasks for function metadata. */ + /** Used to compose bitmasks for wrapper metadata. */ var BIND_FLAG = 1, BIND_KEY_FLAG = 2, CURRY_BOUND_FLAG = 4, @@ -35,49 +24,28 @@ PARTIAL_FLAG = 32, PARTIAL_RIGHT_FLAG = 64, ARY_FLAG = 128, - REARG_FLAG = 256, - FLIP_FLAG = 512; + REARG_FLAG = 256; - /** Used to compose bitmasks for comparison styles. */ - var UNORDERED_COMPARE_FLAG = 1, - PARTIAL_COMPARE_FLAG = 2; - - /** Used as default options for `_.truncate`. */ + /** Used as default options for `_.trunc`. */ var DEFAULT_TRUNC_LENGTH = 30, DEFAULT_TRUNC_OMISSION = '...'; - /** Used to detect hot functions by number of calls within a span of milliseconds. */ + /** Used to detect when a function becomes hot. */ var HOT_COUNT = 150, HOT_SPAN = 16; + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + /** Used to indicate the type of lazy iteratees. */ var LAZY_FILTER_FLAG = 1, - LAZY_MAP_FLAG = 2, - LAZY_WHILE_FLAG = 3; + LAZY_MAP_FLAG = 2; - /** Used as references for various `Number` constants. */ - var INFINITY = 1 / 0, - MAX_SAFE_INTEGER = 9007199254740991, - MAX_INTEGER = 1.7976931348623157e+308, - NAN = 0 / 0; + /** Used as the `TypeError` message for "Functions" methods. */ + var FUNC_ERROR_TEXT = 'Expected a function'; - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, - HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - - /** Used to associate wrap methods with their bit flags. */ - var wrapFlags = [ - ['ary', ARY_FLAG], - ['bind', BIND_FLAG], - ['bindKey', BIND_KEY_FLAG], - ['curry', CURRY_FLAG], - ['curryRight', CURRY_RIGHT_FLAG], - ['flip', FLIP_FLAG], - ['partial', PARTIAL_FLAG], - ['partialRight', PARTIAL_RIGHT_FLAG], - ['rearg', REARG_FLAG] - ]; + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; /** `Object#toString` result references. */ var argsTag = '[object Arguments]', @@ -86,20 +54,15 @@ dateTag = '[object Date]', errorTag = '[object Error]', funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', mapTag = '[object Map]', numberTag = '[object Number]', objectTag = '[object Object]', - promiseTag = '[object Promise]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', - symbolTag = '[object Symbol]', - weakMapTag = '[object WeakMap]', - weakSetTag = '[object WeakSet]'; + weakMapTag = '[object WeakMap]'; var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', @@ -127,63 +90,40 @@ reInterpolate = /<%=([\s\S]+?)%>/g; /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/, - reLeadingDot = /^\./, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g; /** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + * Used to match `RegExp` [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns) + * and those outlined by [`EscapeRegExpPattern`](http://ecma-international.org/ecma-262/6.0/#sec-escaperegexppattern). */ - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, - reHasRegExpChar = RegExp(reRegExpChar.source); + var reRegExpChars = /^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g, + reHasRegExpChars = RegExp(reRegExpChars.source); - /** Used to match leading and trailing whitespace. */ - var reTrim = /^\s+|\s+$/g, - reTrimStart = /^\s+/, - reTrimEnd = /\s+$/; - - /** Used to match wrap detail comments. */ - var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, - reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, - reSplitDetails = /,? & /; - - /** Used to match words composed of alphanumeric characters. */ - var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + /** Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). */ + var reComboMark = /[\u0300-\u036f\ufe20-\ufe23]/g; /** Used to match backslashes in property paths. */ var reEscapeChar = /\\(\\)?/g; - /** - * Used to match - * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). - */ + /** Used to match [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components). */ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; /** Used to match `RegExp` flags from their coerced string values. */ var reFlags = /\w*$/; /** Used to detect hexadecimal string values. */ - var reHasHexPrefix = /^0x/i; + var reHasHexPrefix = /^0[xX]/; - /** Used to detect bad signed hexadecimal string values. */ - var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - - /** Used to detect binary string values. */ - var reIsBinary = /^0b[01]+$/i; - - /** Used to detect host constructors (Safari). */ + /** Used to detect host constructors (Safari > 5). */ var reIsHostCtor = /^\[object .+?Constructor\]$/; - /** Used to detect octal string values. */ - var reIsOctal = /^0o[0-7]+$/i; - /** Used to detect unsigned integer values. */ - var reIsUint = /^(?:0|[1-9]\d*)$/; + var reIsUint = /^\d+$/; - /** Used to match Latin Unicode letters (excluding mathematical operators). */ - var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; + /** Used to match latin-1 supplementary letters (excluding mathematical operators). */ + var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g; /** Used to ensure capturing order of template delimiters. */ var reNoMatch = /($^)/; @@ -191,84 +131,21 @@ /** Used to match unescaped characters in compiled string literals. */ var reUnescapedString = /['\n\r\u2028\u2029\\]/g; - /** Used to compose unicode character classes. */ - var rsAstralRange = '\\ud800-\\udfff', - rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23', - rsComboSymbolsRange = '\\u20d0-\\u20f0', - rsDingbatRange = '\\u2700-\\u27bf', - rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', - rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', - rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', - rsPunctuationRange = '\\u2000-\\u206f', - rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', - rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', - rsVarRange = '\\ufe0e\\ufe0f', - rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; + /** Used to match words to create compound words. */ + var reWords = (function() { + var upper = '[A-Z\\xc0-\\xd6\\xd8-\\xde]', + lower = '[a-z\\xdf-\\xf6\\xf8-\\xff]+'; - /** Used to compose unicode capture groups. */ - var rsApos = "['\u2019]", - rsAstral = '[' + rsAstralRange + ']', - rsBreak = '[' + rsBreakRange + ']', - rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']', - rsDigits = '\\d+', - rsDingbat = '[' + rsDingbatRange + ']', - rsLower = '[' + rsLowerRange + ']', - rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', - rsFitz = '\\ud83c[\\udffb-\\udfff]', - rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', - rsNonAstral = '[^' + rsAstralRange + ']', - rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', - rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', - rsUpper = '[' + rsUpperRange + ']', - rsZWJ = '\\u200d'; - - /** Used to compose unicode regexes. */ - var rsLowerMisc = '(?:' + rsLower + '|' + rsMisc + ')', - rsUpperMisc = '(?:' + rsUpper + '|' + rsMisc + ')', - rsOptLowerContr = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', - rsOptUpperContr = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', - reOptMod = rsModifier + '?', - rsOptVar = '[' + rsVarRange + ']?', - rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', - rsSeq = rsOptVar + reOptMod + rsOptJoin, - rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, - rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; - - /** Used to match apostrophes. */ - var reApos = RegExp(rsApos, 'g'); - - /** - * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and - * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). - */ - var reComboMark = RegExp(rsCombo, 'g'); - - /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ - var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); - - /** Used to match complex or compound words. */ - var reUnicodeWord = RegExp([ - rsUpper + '?' + rsLower + '+' + rsOptLowerContr + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', - rsUpperMisc + '+' + rsOptUpperContr + '(?=' + [rsBreak, rsUpper + rsLowerMisc, '$'].join('|') + ')', - rsUpper + '?' + rsLowerMisc + '+' + rsOptLowerContr, - rsUpper + '+' + rsOptUpperContr, - rsDigits, - rsEmoji - ].join('|'), 'g'); - - /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ - var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboMarksRange + rsComboSymbolsRange + rsVarRange + ']'); - - /** Used to detect strings that need a more robust regexp to match words. */ - var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; + return RegExp(upper + '+(?=' + upper + lower + ')|' + upper + '?' + lower + '|' + upper + '+|[0-9]+', 'g'); + }()); /** Used to assign default `context` object properties. */ var contextProps = [ - 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', - 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', - 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', - 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', - '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' + 'Array', 'ArrayBuffer', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Math', 'Number', + 'Object', 'RegExp', 'Set', 'String', '_', 'clearTimeout', 'isFinite', + 'parseFloat', 'parseInt', 'setTimeout', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap' ]; /** Used to make template sourceURLs easier to identify. */ @@ -283,40 +160,37 @@ typedArrayTags[uint32Tag] = true; typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = - typedArrayTags[errorTag] = typedArrayTags[funcTag] = - typedArrayTags[mapTag] = typedArrayTags[numberTag] = - typedArrayTags[objectTag] = typedArrayTags[regexpTag] = - typedArrayTags[setTag] = typedArrayTags[stringTag] = - typedArrayTags[weakMapTag] = false; + typedArrayTags[dateTag] = typedArrayTags[errorTag] = + typedArrayTags[funcTag] = typedArrayTags[mapTag] = + typedArrayTags[numberTag] = typedArrayTags[objectTag] = + typedArrayTags[regexpTag] = typedArrayTags[setTag] = + typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; /** Used to identify `toStringTag` values supported by `_.clone`. */ var cloneableTags = {}; cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = - cloneableTags[boolTag] = cloneableTags[dateTag] = - cloneableTags[float32Tag] = cloneableTags[float64Tag] = - cloneableTags[int8Tag] = cloneableTags[int16Tag] = - cloneableTags[int32Tag] = cloneableTags[mapTag] = + cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = + cloneableTags[dateTag] = cloneableTags[float32Tag] = + cloneableTags[float64Tag] = cloneableTags[int8Tag] = + cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[setTag] = - cloneableTags[stringTag] = cloneableTags[symbolTag] = + cloneableTags[regexpTag] = cloneableTags[stringTag] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[mapTag] = cloneableTags[setTag] = cloneableTags[weakMapTag] = false; - /** Used to map Latin Unicode letters to basic Latin letters. */ + /** Used to map latin-1 supplementary letters to basic latin letters. */ var deburredLetters = { - // Latin-1 Supplement block. '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', '\xc7': 'C', '\xe7': 'c', '\xd0': 'D', '\xf0': 'd', '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', - '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', - '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', + '\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', + '\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', '\xd1': 'N', '\xf1': 'n', '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', @@ -325,43 +199,7 @@ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', '\xc6': 'Ae', '\xe6': 'ae', '\xde': 'Th', '\xfe': 'th', - '\xdf': 'ss', - // Latin Extended-A block. - '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', - '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', - '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', - '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', - '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', - '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', - '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', - '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', - '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', - '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', - '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', - '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', - '\u0134': 'J', '\u0135': 'j', - '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', - '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', - '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', - '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', - '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', - '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', - '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', - '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', - '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', - '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', - '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', - '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', - '\u0163': 't', '\u0165': 't', '\u0167': 't', - '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', - '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', - '\u0174': 'W', '\u0175': 'w', - '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', - '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', - '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', - '\u0132': 'IJ', '\u0133': 'ij', - '\u0152': 'Oe', '\u0153': 'oe', - '\u0149': "'n", '\u017f': 'ss' + '\xdf': 'ss' }; /** Used to map characters to HTML entities. */ @@ -384,6 +222,21 @@ '`': '`' }; + /** 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 regexes. */ + var regexpEscapes = { + '0': 'x30', '1': 'x31', '2': 'x32', '3': 'x33', '4': 'x34', + '5': 'x35', '6': 'x36', '7': 'x37', '8': 'x38', '9': 'x39', + 'A': 'x41', 'B': 'x42', 'C': 'x43', 'D': 'x44', 'E': 'x45', 'F': 'x46', + 'a': 'x61', 'b': 'x62', 'c': 'x63', 'd': 'x64', 'e': 'x65', 'f': 'x66', + 'n': 'x6e', 'r': 'x72', 't': 'x74', 'u': 'x75', 'v': 'x76', 'x': 'x78' + }; + /** Used to escape characters for inclusion in compiled string literals. */ var stringEscapes = { '\\': '\\', @@ -394,415 +247,80 @@ '\u2029': 'u2029' }; - /** Built-in method references without a dependency on `root`. */ - var freeParseFloat = parseFloat, - freeParseInt = parseInt; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - - /** Detect free variable `self`. */ - var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - - /** Used as a reference to the global object. */ - var root = freeGlobal || freeSelf || Function('return this')(); - /** Detect free variable `exports`. */ - var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; /** Detect free variable `module`. */ - var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global; + + /** Detect free variable `self`. */ + var freeSelf = objectTypes[typeof self] && self && self.Object && self; + + /** Detect free variable `window`. */ + var freeWindow = objectTypes[typeof window] && window && window.Object && window; /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports; + var moduleExports = freeModule && freeModule.exports === freeExports && freeExports; - /** Detect free variable `process` from Node.js. */ - var freeProcess = moduleExports && freeGlobal.process; - - /** Used to access faster Node.js helpers. */ - var nodeUtil = (function() { - try { - return freeProcess && freeProcess.binding('util'); - } catch (e) {} - }()); - - /* Node.js helper references. */ - var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, - nodeIsDate = nodeUtil && nodeUtil.isDate, - nodeIsMap = nodeUtil && nodeUtil.isMap, - nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, - nodeIsSet = nodeUtil && nodeUtil.isSet, - nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + /** + * 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 !== (this && this.window)) && freeWindow) || freeSelf || this; /*--------------------------------------------------------------------------*/ /** - * Adds the key-value `pair` to `map`. + * The base implementation of `compareAscending` which compares values and + * sorts them in ascending order without guaranteeing a stable sort. * * @private - * @param {Object} map The map to modify. - * @param {Array} pair The key-value pair to add. - * @returns {Object} Returns `map`. + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. */ - function addMapEntry(map, pair) { - // Don't return `map.set` because it's not chainable in IE 11. - map.set(pair[0], pair[1]); - return map; - } + function baseCompareAscending(value, other) { + if (value !== other) { + var valIsNull = value === null, + valIsUndef = value === undefined, + valIsReflexive = value === value; - /** - * Adds `value` to `set`. - * - * @private - * @param {Object} set The set to modify. - * @param {*} value The value to add. - * @returns {Object} Returns `set`. - */ - function addSetEntry(set, value) { - // Don't return `set.add` because it's not chainable in IE 11. - set.add(value); - return set; - } + var othIsNull = other === null, + othIsUndef = other === undefined, + othIsReflexive = other === other; - /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} args The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ - function apply(func, thisArg, args) { - switch (args.length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); - } - - /** - * A specialized version of `baseAggregator` for arrays. - * - * @private - * @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. - * @returns {Function} Returns `accumulator`. - */ - function arrayAggregator(array, setter, iteratee, accumulator) { - var index = -1, - length = array ? array.length : 0; - - while (++index < length) { - var value = array[index]; - setter(accumulator, value, iteratee(value), array); - } - return accumulator; - } - - /** - * A specialized version of `_.forEach` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 ? array.length : 0; - - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; + if ((value > other && !othIsNull) || !valIsReflexive || + (valIsNull && !othIsUndef && othIsReflexive) || + (valIsUndef && othIsReflexive)) { + return 1; + } + if ((value < other && !valIsNull) || !othIsReflexive || + (othIsNull && !valIsUndef && valIsReflexive) || + (othIsUndef && valIsReflexive)) { + return -1; } } - return array; - } - - /** - * A specialized version of `_.forEachRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 ? array.length : 0; - - while (length--) { - if (iteratee(array[length], length, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.every` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 ? array.length : 0; - - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } - } - return true; - } - - /** - * A specialized version of `_.filter` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 ? array.length : 0, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * A specialized version of `_.includes` for arrays without support for - * specifying an index to search from. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludes(array, value) { - 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 inspect. - * @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 ? array.length : 0; - - while (++index < length) { - if (comparator(value, array[index])) { - return true; - } - } - return false; - } - - /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @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 ? array.length : 0, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } - - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; - - while (++index < length) { - array[offset + index] = values[index]; - } - return array; - } - - /** - * A specialized version of `_.reduce` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initAccum) { - var index = -1, - length = array ? array.length : 0; - - if (initAccum && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } - - /** - * A specialized version of `_.reduceRight` for arrays without support for - * iteratee shorthands. - * - * @private - * @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 - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduceRight(array, iteratee, accumulator, initAccum) { - var length = array ? array.length : 0; - if (initAccum && length) { - accumulator = array[--length]; - } - while (length--) { - accumulator = iteratee(accumulator, array[length], length, array); - } - return accumulator; - } - - /** - * A specialized version of `_.some` for arrays without support for iteratee - * shorthands. - * - * @private - * @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 ? array.length : 0; - - while (++index < length) { - if (predicate(array[index], index, array)) { - return true; - } - } - return false; - } - - /** - * Gets the size of an ASCII `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - var asciiSize = baseProperty('length'); - - /** - * Converts an ASCII `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function asciiToArray(string) { - return string.split(''); - } - - /** - * Splits an ASCII `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function asciiWords(string) { - return string.match(reAsciiWord) || []; - } - - /** - * 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 inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFindKey(collection, predicate, eachFunc) { - var result; - eachFunc(collection, function(value, key, collection) { - if (predicate(value, key, collection)) { - result = key; - return false; - } - }); - return result; + return 0; } /** * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. + * support for callback shorthands and `this` binding. * * @private - * @param {Array} array The array to inspect. + * @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, fromIndex, fromRight) { + function baseFindIndex(array, predicate, fromRight) { var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); + index = fromRight ? length : -1; while ((fromRight ? index-- : ++index < length)) { if (predicate(array[index], index, array)) { @@ -813,17 +331,17 @@ } /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * The base implementation of `_.indexOf` without support for binary searches. * * @private - * @param {Array} array The array to inspect. + * @param {Array} array The array to search. * @param {*} value The value to search for. * @param {number} fromIndex The index to search from. * @returns {number} Returns the index of the matched value, else `-1`. */ function baseIndexOf(array, value, fromIndex) { if (value !== value) { - return baseFindIndex(array, baseIsNaN, fromIndex); + return indexOfNaN(array, fromIndex); } var index = fromIndex - 1, length = array.length; @@ -837,280 +355,128 @@ } /** - * This function is like `baseIndexOf` except that it accepts a comparator. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @param {Function} comparator The comparator invoked per element. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOfWith(array, value, fromIndex, comparator) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (comparator(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * The base implementation of `_.isNaN` without support for number objects. + * The base implementation of `_.isFunction` without support for environments + * with incorrect `typeof` results. * * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. */ - function baseIsNaN(value) { - return value !== value; + function baseIsFunction(value) { + // Avoid a Chakra JIT bug in compatibility modes of IE 11. + // See https://github.com/jashkenas/underscore/issues/1621 for more details. + return typeof value == 'function' || false; } /** - * The base implementation of `_.mean` and `_.meanBy` without support for - * iteratee shorthands. + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` or `undefined` values. * * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the mean. + * @param {*} value The value to process. + * @returns {string} Returns the string. */ - function baseMean(array, iteratee) { - var length = array ? array.length : 0; - return length ? (baseSum(array, iteratee) / length) : NAN; + function baseToString(value) { + return value == null ? '' : (value + ''); } /** - * The base implementation of `_.property` without support for deep paths. + * Used by `_.trim` and `_.trimLeft` to get the index of the first character + * of `string` that is not found in `chars`. * * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new accessor function. + * @param {string} string The string to inspect. + * @param {string} chars The characters to find. + * @returns {number} Returns the index of the first character not found in `chars`. */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; - }; + function charsLeftIndex(string, chars) { + var index = -1, + length = string.length; + + while (++index < length && chars.indexOf(string.charAt(index)) > -1) {} + return index; } /** - * The base implementation of `_.propertyOf` without support for deep paths. + * Used by `_.trim` and `_.trimRight` to get the index of the last character + * of `string` that is not found in `chars`. * * @private - * @param {Object} object The object to query. - * @returns {Function} Returns the new accessor function. + * @param {string} string The string to inspect. + * @param {string} chars The characters to find. + * @returns {number} Returns the index of the last character not found in `chars`. */ - function basePropertyOf(object) { - return function(key) { - return object == null ? undefined : object[key]; - }; + function charsRightIndex(string, chars) { + var index = string.length; + + while (index-- && chars.indexOf(string.charAt(index)) > -1) {} + return index; } /** - * The base implementation of `_.reduce` and `_.reduceRight`, without support - * for iteratee shorthands, which iterates over `collection` using `eachFunc`. + * Used by `_.sortBy` to compare transformed elements of a collection and stable + * sort them in ascending order. * * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initAccum Specify using the first or last element of - * `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @returns {number} Returns the sort order indicator for `object`. */ - function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initAccum - ? (initAccum = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; + function compareAscending(object, other) { + return baseCompareAscending(object.criteria, other.criteria) || (object.index - other.index); } /** - * The base implementation of `_.sortBy` which uses `comparer` to define the - * sort order of `array` and replaces criteria objects with their corresponding - * values. + * Used by `_.sortByOrder` to compare multiple properties of a value to another + * and stable sort them. + * + * If `orders` is unspecified, all valuess are sorted in ascending order. Otherwise, + * a value is sorted in ascending order if its corresponding order is "asc", and + * descending if "desc". * * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {boolean[]} orders The order to sort by for each property. + * @returns {number} Returns the sort order indicator for `object`. */ - function baseSortBy(array, comparer) { - var length = array.length; - - array.sort(comparer); - while (length--) { - array[length] = array[length].value; - } - return array; - } - - /** - * The base implementation of `_.sum` and `_.sumBy` without support for - * iteratee shorthands. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {number} Returns the sum. - */ - function baseSum(array, iteratee) { - var result, - index = -1, - length = array.length; + function compareMultiple(object, other, orders) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length, + ordersLength = orders.length; while (++index < length) { - var current = iteratee(array[index]); - if (current !== undefined) { - result = result === undefined ? current : (result + current); + var result = baseCompareAscending(objCriteria[index], othCriteria[index]); + if (result) { + if (index >= ordersLength) { + return result; + } + var order = orders[index]; + return result * ((order === 'asc' || order === true) ? 1 : -1); } } - return result; + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://code.google.com/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; } /** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ - function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); - - while (++index < n) { - result[index] = iteratee(index); - } - return result; - } - - /** - * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array - * of key-value pairs for `object` corresponding to the property names of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the key-value pairs. - */ - function baseToPairs(object, props) { - return arrayMap(props, function(key) { - return [key, object[key]]; - }); - } - - /** - * The base implementation of `_.unary` without support for storing metadata. - * - * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - */ - function baseUnary(func) { - return function(value) { - return func(value); - }; - } - - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - return arrayMap(props, function(key) { - return object[key]; - }); - } - - /** - * 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. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the first unmatched string symbol. - */ - function charsStartIndex(strSymbols, chrSymbols) { - var index = -1, - length = strSymbols.length; - - while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the last unmatched string symbol. - */ - function charsEndIndex(strSymbols, chrSymbols) { - var index = strSymbols.length; - - while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Gets the number of `placeholder` occurrences in `array`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} placeholder The placeholder to search for. - * @returns {number} Returns the placeholder count. - */ - function countHolders(array, placeholder) { - var length = array.length, - result = 0; - - while (length--) { - if (array[length] === placeholder) { - result++; - } - } - return result; - } - - /** - * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A - * letters to basic Latin letters. + * Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters. * * @private * @param {string} letter The matched letter to deburr. * @returns {string} Returns the deburred letter. */ - var deburrLetter = basePropertyOf(deburredLetters); + function deburrLetter(letter) { + return deburredLetters[letter]; + } /** * Used by `_.escape` to convert characters to HTML entities. @@ -1119,7 +485,27 @@ * @param {string} chr The matched character to escape. * @returns {string} Returns the escaped character. */ - var escapeHtmlChar = basePropertyOf(htmlEscapes); + function escapeHtmlChar(chr) { + return htmlEscapes[chr]; + } + + /** + * Used by `_.escapeRegExp` to escape characters for inclusion in compiled regexes. + * + * @private + * @param {string} chr The matched character to escape. + * @param {string} leadingChar The capture group for a leading character. + * @param {string} whitespaceChar The capture group for a whitespace character. + * @returns {string} Returns the escaped character. + */ + function escapeRegExpChar(chr, leadingChar, whitespaceChar) { + if (leadingChar) { + chr = regexpEscapes[chr]; + } else if (whitespaceChar) { + chr = stringEscapes[chr]; + } + return '\\' + chr; + } /** * Used by `_.template` to escape characters for inclusion in compiled string literals. @@ -1133,104 +519,49 @@ } /** - * Gets the value at `key` of `object`. + * Gets the index at which the first occurrence of `NaN` is found in `array`. * * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. + * @param {Array} array The array to search. + * @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 `NaN`, else `-1`. */ - function getValue(object, key) { - return object == null ? undefined : object[key]; + function indexOfNaN(array, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 0 : -1); + + while ((fromRight ? index-- : ++index < length)) { + var other = array[index]; + if (other !== other) { + return index; + } + } + return -1; } /** - * Checks if `string` contains Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a symbol is found, else `false`. - */ - function hasUnicode(string) { - return reHasUnicode.test(string); - } - - /** - * Checks if `string` contains a word composed of Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a word is found, else `false`. - */ - function hasUnicodeWord(string) { - return reHasUnicodeWord.test(string); - } - - /** - * Checks if `value` is a host object in IE < 9. + * Checks if `value` is object-like. * * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a host object, else `false`. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. */ - function isHostObject(value) { - // Many host objects are `Object` objects that can coerce to strings - // despite having improperly defined `toString` methods. - var result = false; - if (value != null && typeof value.toString != 'function') { - try { - result = !!(value + ''); - } catch (e) {} - } - return result; + function isObjectLike(value) { + return !!value && typeof value == 'object'; } /** - * Converts `iterator` to an array. + * Used by `trimmedLeftIndex` and `trimmedRightIndex` to determine if a + * character code is whitespace. * * @private - * @param {Object} iterator The iterator to convert. - * @returns {Array} Returns the converted array. + * @param {number} charCode The character code to inspect. + * @returns {boolean} Returns `true` if `charCode` is whitespace, else `false`. */ - function iteratorToArray(iterator) { - var data, - result = []; - - while (!(data = iterator.next()).done) { - result.push(data.value); - } - return result; - } - - /** - * Converts `map` to its key-value pairs. - * - * @private - * @param {Object} map The map to convert. - * @returns {Array} Returns the key-value pairs. - */ - function mapToArray(map) { - var index = -1, - result = Array(map.size); - - map.forEach(function(value, key) { - result[++index] = [key, value]; - }); - return result; - } - - /** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ - function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); - }; + function isSpace(charCode) { + return ((charCode <= 160 && (charCode >= 9 && charCode <= 13) || charCode == 32 || charCode == 160) || charCode == 5760 || charCode == 6158 || + (charCode >= 8192 && (charCode <= 8202 || charCode == 8232 || charCode == 8233 || charCode == 8239 || charCode == 8287 || charCode == 12288 || charCode == 65279))); } /** @@ -1245,77 +576,75 @@ function replaceHolders(array, placeholder) { var index = -1, length = array.length, - resIndex = 0, + resIndex = -1, result = []; while (++index < length) { - var value = array[index]; - if (value === placeholder || value === PLACEHOLDER) { + if (array[index] === placeholder) { array[index] = PLACEHOLDER; - result[resIndex++] = index; + result[++resIndex] = index; } } return result; } /** - * Converts `set` to an array of its values. + * An implementation of `_.uniq` optimized for sorted arrays without support + * for callback shorthands and `this` binding. * * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the values. + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The function invoked per iteration. + * @returns {Array} Returns the new duplicate free array. */ - function setToArray(set) { - var index = -1, - result = Array(set.size); + function sortedUniq(array, iteratee) { + var seen, + index = -1, + length = array.length, + resIndex = -1, + result = []; - set.forEach(function(value) { - result[++index] = value; - }); + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value, index, array) : value; + + if (!index || seen !== computed) { + seen = computed; + result[++resIndex] = value; + } + } 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`. + * Used by `_.trim` and `_.trimLeft` to get the index of the first non-whitespace + * character of `string`. * * @private * @param {string} string The string to inspect. - * @returns {number} Returns the string size. + * @returns {number} Returns the index of the first non-whitespace character. */ - function stringSize(string) { - return hasUnicode(string) - ? unicodeSize(string) - : asciiSize(string); + function trimmedLeftIndex(string) { + var index = -1, + length = string.length; + + while (++index < length && isSpace(string.charCodeAt(index))) {} + return index; } /** - * Converts `string` to an array. + * Used by `_.trim` and `_.trimRight` to get the index of the last non-whitespace + * character of `string`. * * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the last non-whitespace character. */ - function stringToArray(string) { - return hasUnicode(string) - ? unicodeToArray(string) - : asciiToArray(string); + function trimmedRightIndex(string) { + var index = string.length; + + while (index-- && isSpace(string.charCodeAt(index))) {} + return index; } /** @@ -1325,54 +654,18 @@ * @param {string} chr The matched character to unescape. * @returns {string} Returns the unescaped character. */ - var unescapeHtmlChar = basePropertyOf(htmlUnescapes); - - /** - * Gets the size of a Unicode `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - function unicodeSize(string) { - var result = reUnicode.lastIndex = 0; - while (reUnicode.test(string)) { - result++; - } - return result; - } - - /** - * Converts a Unicode `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function unicodeToArray(string) { - return string.match(reUnicode) || []; - } - - /** - * Splits a Unicode `string` into an array of its words. - * - * @private - * @param {string} The string to inspect. - * @returns {Array} Returns the words of `string`. - */ - function unicodeWords(string) { - return string.match(reUnicodeWord) || []; + function unescapeHtmlChar(chr) { + return htmlUnescapes[chr]; } /*--------------------------------------------------------------------------*/ /** - * Create a new pristine `lodash` function using the `context` object. + * Create a new pristine `lodash` function using the given `context` object. * * @static * @memberOf _ - * @since 1.1.0 - * @category Util + * @category Utility * @param {Object} [context=root] The context object. * @returns {Function} Returns a new `lodash` function. * @example @@ -1392,46 +685,42 @@ * lodash.isFunction(lodash.bar); * // => true * - * // Use `context` to stub `Date#getTime` use in `_.now`. - * var stubbed = _.runInContext({ + * // using `context` to mock `Date#getTime` use in `_.now` + * var mock = _.runInContext({ * 'Date': function() { - * return { 'getTime': stubGetTime }; + * return { 'getTime': getTimeMock }; * } * }); * - * // Create a suped-up `defer` in Node.js. + * // or creating a suped-up `defer` in Node.js * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; */ function runInContext(context) { + // Avoid issues with some ES3 environments that attempt to use values, named + // after built-in constructors like `Object`, for the creation of literals. + // ES5 clears this up by stating that literals must use built-in constructors. + // See https://es5.github.io/#x11.1.5 for more details. context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root; - /** Built-in constructor references. */ + /** Native constructor references. */ var Array = context.Array, Date = context.Date, Error = context.Error, Function = context.Function, Math = context.Math, + Number = context.Number, Object = context.Object, RegExp = context.RegExp, String = context.String, TypeError = context.TypeError; - /** Used for built-in method references. */ + /** Used for native method references. */ var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.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) : ''; - }()); + objectProto = Object.prototype, + stringProto = String.prototype; /** Used to resolve the decompiled source of functions. */ - var funcToString = funcProto.toString; + var fnToString = Function.prototype.toString; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; @@ -1439,115 +728,82 @@ /** Used to generate unique IDs. */ var idCounter = 0; - /** Used to infer the `Object` constructor. */ - var objectCtorString = funcToString.call(Object); - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ - var objectToString = objectProto.toString; + var objToString = objectProto.toString; /** Used to restore the original `_` reference in `_.noConflict`. */ var oldDash = root._; /** Used to detect if a method is native. */ var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&') .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); - /** Built-in value references. */ - var Buffer = moduleExports ? context.Buffer : undefined, - Symbol = context.Symbol, - Uint8Array = context.Uint8Array, - getPrototype = overArg(Object.getPrototypeOf, Object), - iteratorSymbol = Symbol ? Symbol.iterator : undefined, - objectCreate = Object.create, + /** Native method references. */ + var ArrayBuffer = context.ArrayBuffer, + clearTimeout = context.clearTimeout, + parseFloat = context.parseFloat, + pow = Math.pow, propertyIsEnumerable = objectProto.propertyIsEnumerable, + Set = getNative(context, 'Set'), + setTimeout = context.setTimeout, splice = arrayProto.splice, - spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined; + Uint8Array = context.Uint8Array, + WeakMap = getNative(context, 'WeakMap'); - /** Mocked built-ins. */ - var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, - ctxNow = Date && Date.now !== root.Date.now && Date.now, - ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; - - /* Built-in method references for those with the same name as other `lodash` methods. */ + /* Native method references for those with the same name as other `lodash` methods. */ var nativeCeil = Math.ceil, + nativeCreate = getNative(Object, 'create'), nativeFloor = Math.floor, - nativeGetSymbols = Object.getOwnPropertySymbols, - nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeIsArray = getNative(Array, 'isArray'), nativeIsFinite = context.isFinite, - nativeJoin = arrayProto.join, - nativeKeys = overArg(Object.keys, Object), + nativeKeys = getNative(Object, 'keys'), nativeMax = Math.max, nativeMin = Math.min, + nativeNow = getNative(Date, 'now'), nativeParseInt = context.parseInt, - nativeRandom = Math.random, - nativeReverse = arrayProto.reverse; + nativeRandom = Math.random; - /* Built-in method references that are verified to be native. */ - var DataView = getNative(context, 'DataView'), - Map = getNative(context, 'Map'), - Promise = getNative(context, 'Promise'), - Set = getNative(context, 'Set'), - WeakMap = getNative(context, 'WeakMap'), - nativeCreate = getNative(Object, 'create'); + /** Used as references for `-Infinity` and `Infinity`. */ + var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY, + POSITIVE_INFINITY = Number.POSITIVE_INFINITY; - /* Used to set `toString` methods. */ - var defineProperty = (function() { - var func = getNative(Object, 'defineProperty'), - name = getNative.name; + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; - return (name && name.length > 2) ? func : undefined; - }()); + /** + * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer) + * of an array-like value. + */ + var MAX_SAFE_INTEGER = 9007199254740991; /** Used to store function metadata. */ var metaMap = WeakMap && new WeakMap; - /** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */ - var nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf'); - /** Used to lookup unminified function names. */ var realNames = {}; - /** Used to detect maps, sets, and weakmaps. */ - var dataViewCtorString = toSource(DataView), - mapCtorString = toSource(Map), - promiseCtorString = toSource(Promise), - setCtorString = toSource(Set), - weakMapCtorString = toSource(WeakMap); - - /** Used to convert symbols to primitives and strings. */ - var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; - /*------------------------------------------------------------------------*/ /** - * Creates a `lodash` object which wraps `value` to enable implicit method - * chain sequences. Methods that operate on and return arrays, collections, - * and functions can be chained together. Methods that retrieve a single value - * or may return a primitive value will automatically end the chain sequence - * and return the unwrapped value. Otherwise, the value must be unwrapped - * with `_#value`. + * Creates a `lodash` object which wraps `value` to enable implicit chaining. + * Methods that operate on and return arrays, collections, and functions can + * be chained together. Methods that retrieve a single value or may return a + * primitive value will automatically end the chain returning the unwrapped + * value. Explicit chaining may be enabled using `_.chain`. The execution of + * chained methods is lazy, that is, execution is deferred until `_#value` + * is implicitly or explicitly called. * - * Explicit chain sequences, which must be unwrapped with `_#value`, may be - * enabled using `_.chain`. - * - * The execution of chained methods is lazy, that is, it's deferred until - * `_#value` is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. - * Shortcut fusion is an optimization to merge iteratee calls; this avoids - * the creation of intermediate arrays and can greatly reduce the number of - * iteratee executions. Sections of a chain sequence qualify for shortcut - * fusion if the section is applied to an array of at least `200` elements - * and any iteratees accept only one argument. The heuristic for whether a - * section qualifies for shortcut fusion is subject to change. + * Lazy evaluation allows several methods to support shortcut fusion. Shortcut + * fusion is an optimization strategy which merge iteratee calls; this can help + * to avoid the creation of intermediate data structures and greatly reduce the + * number of iteratee executions. * * Chaining is supported in custom builds as long as the `_#value` method is * directly or indirectly included in the build. @@ -1555,88 +811,75 @@ * In addition to lodash methods, wrappers have `Array` and `String` methods. * * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` + * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, + * `splice`, and `unshift` * * The wrapper `String` methods are: * `replace` and `split` * * The wrapper methods that support shortcut fusion are: - * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, - * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, - * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` + * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`, + * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`, + * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`, + * and `where` * * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, - * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, - * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, - * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, - * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, - * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, - * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, - * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, - * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, - * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, - * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, - * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, - * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, - * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, - * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, - * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, - * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, - * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, - * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, - * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, - * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, - * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, - * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, - * `zipObject`, `zipObjectDeep`, and `zipWith` + * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`, + * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`, + * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`, + * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`, + * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, + * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, + * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, + * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, + * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`, + * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`, + * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`, + * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`, + * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`, + * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`, + * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`, + * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`, + * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith` * * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, - * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, - * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, - * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, - * `findLastIndex`, `findLastKey`, `first`, `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`, `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` + * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`, + * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, + * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, + * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, + * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, + * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`, + * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`, + * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`, + * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`, + * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`, + * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`, + * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`, + * `unescape`, `uniqueId`, `value`, and `words` + * + * The wrapper method `sample` will return a wrapped value when `n` is provided, + * otherwise an unwrapped value is returned. * * @name _ * @constructor - * @category Seq + * @category Chain * @param {*} value The value to wrap in a `lodash` instance. * @returns {Object} Returns the new `lodash` wrapper instance. * @example * - * function square(n) { - * return n * n; - * } - * * var wrapped = _([1, 2, 3]); * - * // Returns an unwrapped value. - * wrapped.reduce(_.add); + * // returns an unwrapped value + * wrapped.reduce(function(total, n) { + * return total + n; + * }); * // => 6 * - * // Returns a wrapped value. - * var squares = wrapped.map(square); + * // returns a wrapped value + * var squares = wrapped.map(function(n) { + * return n * n; + * }); * * _.isArray(squares); * // => false @@ -1649,7 +892,7 @@ if (value instanceof LodashWrapper) { return value; } - if (hasOwnProperty.call(value, '__wrapped__')) { + if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) { return wrapperClone(value); } } @@ -1657,7 +900,7 @@ } /** - * The function whose prototype chain sequence wrappers inherit from. + * The function whose prototype all chaining wrappers inherit from. * * @private */ @@ -1670,16 +913,24 @@ * * @private * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable explicit method chain sequences. + * @param {boolean} [chainAll] Enable chaining for all wrapper methods. + * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value. */ - function LodashWrapper(value, chainAll) { + function LodashWrapper(value, chainAll, actions) { this.__wrapped__ = value; - this.__actions__ = []; + this.__actions__ = actions || []; this.__chain__ = !!chainAll; - this.__index__ = 0; - this.__values__ = undefined; } + /** + * An object environment feature flags. + * + * @static + * @memberOf _ + * @type Object + */ + var support = lodash.support = {}; + /** * By default, the template delimiters used by lodash are like those in * embedded Ruby (ERB). Change the following template settings to use @@ -1687,7 +938,7 @@ * * @static * @memberOf _ - * @type {Object} + * @type Object */ lodash.templateSettings = { @@ -1695,7 +946,7 @@ * Used to detect `data` property values to be HTML-escaped. * * @memberOf _.templateSettings - * @type {RegExp} + * @type RegExp */ 'escape': reEscape, @@ -1703,7 +954,7 @@ * Used to detect code to be evaluated. * * @memberOf _.templateSettings - * @type {RegExp} + * @type RegExp */ 'evaluate': reEvaluate, @@ -1711,7 +962,7 @@ * Used to detect `data` property values to inject. * * @memberOf _.templateSettings - * @type {RegExp} + * @type RegExp */ 'interpolate': reInterpolate, @@ -1719,7 +970,7 @@ * Used to reference the data object in the template text. * * @memberOf _.templateSettings - * @type {string} + * @type string */ 'variable': '', @@ -1727,7 +978,7 @@ * Used to import variables into the compiled template. * * @memberOf _.templateSettings - * @type {Object} + * @type Object */ 'imports': { @@ -1735,26 +986,18 @@ * A reference to the `lodash` function. * * @memberOf _.templateSettings.imports - * @type {Function} + * @type Function */ '_': lodash } }; - // Ensure wrappers are instances of `baseLodash`. - lodash.prototype = baseLodash.prototype; - lodash.prototype.constructor = lodash; - - LodashWrapper.prototype = baseCreate(baseLodash.prototype); - LodashWrapper.prototype.constructor = LodashWrapper; - /*------------------------------------------------------------------------*/ /** * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. * * @private - * @constructor * @param {*} value The value to wrap. */ function LazyWrapper(value) { @@ -1763,7 +1006,7 @@ this.__dir__ = 1; this.__filtered__ = false; this.__iteratees__ = []; - this.__takeCount__ = MAX_ARRAY_LENGTH; + this.__takeCount__ = POSITIVE_INFINITY; this.__views__ = []; } @@ -1777,12 +1020,12 @@ */ function lazyClone() { var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = copyArray(this.__actions__); + result.__actions__ = arrayCopy(this.__actions__); result.__dir__ = this.__dir__; result.__filtered__ = this.__filtered__; - result.__iteratees__ = copyArray(this.__iteratees__); + result.__iteratees__ = arrayCopy(this.__iteratees__); result.__takeCount__ = this.__takeCount__; - result.__views__ = copyArray(this.__views__); + result.__views__ = arrayCopy(this.__views__); return result; } @@ -1830,8 +1073,7 @@ resIndex = 0, takeCount = nativeMin(length, this.__takeCount__); - if (!isArr || arrLength < LARGE_ARRAY_SIZE || - (arrLength == length && takeCount == length)) { + if (!isArr || arrLength < LARGE_ARRAY_SIZE || (arrLength == length && takeCount == length)) { return baseWrapperValue(array, this.__actions__); } var result = []; @@ -1864,586 +1106,479 @@ return result; } - // Ensure `LazyWrapper` is an instance of `baseLodash`. - LazyWrapper.prototype = baseCreate(baseLodash.prototype); - LazyWrapper.prototype.constructor = LazyWrapper; - /*------------------------------------------------------------------------*/ /** - * Creates a hash object. + * Creates a cache object to store key/value pairs. * * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. + * @static + * @name Cache + * @memberOf _.memoize */ - 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]); - } + function MapCache() { + this.__data__ = {}; } /** - * 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. + * Removes `key` and its value from the cache. * * @private * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. + * @memberOf _.memoize.Cache * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. + * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. */ - function hashDelete(key) { + function mapDelete(key) { return this.has(key) && delete this.__data__[key]; } /** - * Gets the hash value for `key`. + * Gets the cached value for `key`. * * @private * @name get - * @memberOf Hash + * @memberOf _.memoize.Cache * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. + * @returns {*} Returns the cached value. */ - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; + function mapGet(key) { + return key == '__proto__' ? undefined : this.__data__[key]; } /** - * Checks if a hash value for `key` exists. + * Checks if a cached value for `key` exists. * * @private * @name has - * @memberOf Hash + * @memberOf _.memoize.Cache * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ - function hashHas(key) { - var data = this.__data__; - return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key); + function mapHas(key) { + return key != '__proto__' && hasOwnProperty.call(this.__data__, key); } /** - * Sets the hash `key` to `value`. + * Sets `value` to `key` of the cache. * * @private * @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. + * @memberOf _.memoize.Cache + * @param {string} key The key of the value to cache. + * @param {*} value The value to cache. + * @returns {Object} Returns the cache object. */ - function hashSet(key, value) { - var data = this.__data__; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + function mapSet(key, value) { + if (key != '__proto__') { + this.__data__[key] = value; + } return this; } - // 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. + * + * Creates a cache object to store unique values. * * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. + * @param {Array} [values] The values to cache. */ - function ListCache(entries) { - var index = -1, - length = entries ? entries.length : 0; + function SetCache(values) { + var length = values ? values.length : 0; - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); + this.data = { 'hash': nativeCreate(null), 'set': new Set }; + while (length--) { + this.push(values[length]); } } /** - * Removes all key-value entries from the list cache. + * Checks if `value` is in `cache` mimicking the return signature of + * `_.indexOf` by returning `0` if the value is found, else `-1`. * * @private - * @name clear - * @memberOf ListCache + * @param {Object} cache The cache to search. + * @param {*} value The value to search for. + * @returns {number} Returns `0` if `value` is found, else `-1`. */ - function listCacheClear() { - this.__data__ = []; + function cacheIndexOf(cache, value) { + var data = cache.data, + result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value]; + + return result ? 0 : -1; } /** - * Removes `key` and its value from the list cache. + * Adds `value` to the 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`. + * @name push + * @memberOf SetCache + * @param {*} value The value to cache. */ - 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(); + function cachePush(value) { + var data = this.data; + if (typeof value == 'string' || isObject(value)) { + data.set.add(value); } else { - splice.call(data, index, 1); + data.hash[value] = true; + } + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a new array joining `array` with `other`. + * + * @private + * @param {Array} array The array to join. + * @param {Array} other The other array to join. + * @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; + } + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function arrayCopy(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * A specialized version of `_.forEach` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @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; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.forEachRight` for arrays without support for + * callback shorthands and `this` binding. + * + * @private + * @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; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @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; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } } return true; } /** - * Gets the list cache value for `key`. + * A specialized version of `baseExtremum` for arrays which invokes `iteratee` + * with one argument: (value). * * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} comparator The function used to compare values. + * @param {*} exValue The initial extremum value. + * @returns {*} Returns the extremum 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; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function MapCache(entries) { + function arrayExtremum(array, iteratee, comparator, exValue) { var index = -1, - length = entries ? entries.length : 0; + length = array.length, + computed = exValue, + result = computed; - this.clear(); while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } + var value = array[index], + current = +iteratee(value); - /** - * Removes all key-value entries from the map. - * - * @private - * @name clear - * @memberOf MapCache - */ - function mapCacheClear() { - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash - }; - } - - /** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function mapCacheDelete(key) { - return getMapData(this, key)['delete'](key); - } - - /** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function mapCacheGet(key) { - return getMapData(this, key).get(key); - } - - /** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapCacheHas(key) { - return getMapData(this, key).has(key); - } - - /** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ - function mapCacheSet(key, value) { - getMapData(this, key).set(key, value); - return this; - } - - // Add methods to `MapCache`. - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype['delete'] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; - - /*------------------------------------------------------------------------*/ - - /** - * - * Creates an array cache object to store unique values. - * - * @private - * @constructor - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var index = -1, - length = values ? values.length : 0; - - this.__data__ = new MapCache; - while (++index < length) { - this.add(values[index]); - } - } - - /** - * Adds `value` to the array cache. - * - * @private - * @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 setCacheHas(value) { - return this.__data__.has(value); - } - - // Add methods to `SetCache`. - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a stack cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Stack(entries) { - this.__data__ = new ListCache(entries); - } - - /** - * Removes all key-value entries from the stack. - * - * @private - * @name clear - * @memberOf Stack - */ - function stackClear() { - this.__data__ = new ListCache; - } - - /** - * Removes `key` and its value from the stack. - * - * @private - * @name delete - * @memberOf Stack - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function stackDelete(key) { - return this.__data__['delete'](key); - } - - /** - * Gets the stack value for `key`. - * - * @private - * @name get - * @memberOf Stack - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function stackGet(key) { - return this.__data__.get(key); - } - - /** - * Checks if a stack value for `key` exists. - * - * @private - * @name has - * @memberOf Stack - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function stackHas(key) { - return this.__data__.has(key); - } - - /** - * Sets the stack `key` to `value`. - * - * @private - * @name set - * @memberOf Stack - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the stack cache instance. - */ - function stackSet(key, value) { - var cache = this.__data__; - if (cache instanceof ListCache) { - var pairs = cache.__data__; - if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { - pairs.push([key, value]); - return this; - } - cache = this.__data__ = new MapCache(pairs); - } - cache.set(key, value); - return this; - } - - // Add methods to `Stack`. - Stack.prototype.clear = stackClear; - Stack.prototype['delete'] = stackDelete; - Stack.prototype.get = stackGet; - Stack.prototype.has = stackHas; - Stack.prototype.set = stackSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ - function arrayLikeKeys(value, inherited) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - // Safari 9 makes `arguments.length` enumerable in strict mode. - var result = (isArray(value) || isArguments(value)) - ? baseTimes(value.length, String) - : []; - - var length = result.length, - skipIndexes = !!length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && (key == 'length' || isIndex(key, length)))) { - result.push(key); + if (comparator(current, computed)) { + computed = current; + result = value; } } return result; } /** - * Used by `_.defaults` to customize its `_.assignIn` use. + * A specialized version of `_.filter` for arrays without support for callback + * shorthands and `this` binding. * * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to assign. - * @param {Object} object The parent object of `objValue`. - * @returns {*} Returns the value to assign. + * @param {Array} array The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. */ - function assignInDefaults(objValue, srcValue, key, object) { - if (objValue === undefined || - (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { - return srcValue; - } - return objValue; - } + function arrayFilter(array, predicate) { + var index = -1, + length = array.length, + resIndex = -1, + result = []; - /** - * This function is like `assignValue` except that it doesn't assign - * `undefined` values. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignMergeValue(object, key, value) { - if ((value !== undefined && !eq(object[key], value)) || - (typeof key == 'number' && value === undefined && !(key in object))) { - object[key] = value; - } - } - - /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - object[key] = value; - } - } - - /** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @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; + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[++resIndex] = value; } } - return -1; + return result; } /** - * Aggregates elements of `collection` on `accumulator` with keys transformed - * by `iteratee` and values set by `setter`. + * A specialized version of `_.map` for arrays without support for callback + * shorthands and `this` binding. * * @private - * @param {Array|Object} collection The collection 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. - * @returns {Function} Returns `accumulator`. + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. */ - function baseAggregator(collection, setter, iteratee, accumulator) { - baseEach(collection, function(value, key, collection) { - setter(accumulator, value, iteratee(value), collection); - }); + function arrayMap(array, iteratee) { + var index = -1, + length = array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } + + /** + * A specialized version of `_.reduce` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the first element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initFromArray) { + var index = -1, + length = array.length; + + if (initFromArray && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } return accumulator; } /** - * The base implementation of `_.assign` without support for multiple sources - * or `customizer` functions. + * A specialized version of `_.reduceRight` for arrays without support for + * callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initFromArray] Specify using the last element of `array` + * as the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduceRight(array, iteratee, accumulator, initFromArray) { + var length = array.length; + if (initFromArray && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for callback + * shorthands and `this` binding. + * + * @private + * @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; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * A specialized version of `_.sum` for arrays without support for callback + * shorthands and `this` binding.. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function arraySum(array, iteratee) { + var length = array.length, + result = 0; + + while (length--) { + result += +iteratee(array[length]) || 0; + } + return result; + } + + /** + * Used by `_.defaults` to customize its `_.assign` use. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @returns {*} Returns the value to assign to the destination object. + */ + function assignDefaults(objectValue, sourceValue) { + return objectValue === undefined ? sourceValue : objectValue; + } + + /** + * Used by `_.template` to customize its `_.assign` use. + * + * **Note:** This function is like `assignDefaults` except that it ignores + * inherited property values when checking if a property is `undefined`. + * + * @private + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @param {string} key The key associated with the object and source values. + * @param {Object} object The destination object. + * @returns {*} Returns the value to assign to the destination object. + */ + function assignOwnDefaults(objectValue, sourceValue, key, object) { + return (objectValue === undefined || !hasOwnProperty.call(object, key)) + ? sourceValue + : objectValue; + } + + /** + * A specialized version of `_.assign` for customizing assigned values without + * support for argument juggling, multiple sources, and `this` binding `customizer` + * functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + */ + function assignWith(object, source, customizer) { + var index = -1, + props = keys(source), + length = props.length; + + while (++index < length) { + var key = props[index], + value = object[key], + result = customizer(value, source[key], key, object, source); + + if ((result === result ? (result !== value) : (value === value)) || + (value === undefined && !(key in object))) { + object[key] = result; + } + } + return object; + } + + /** + * The base implementation of `_.assign` without support for argument juggling, + * multiple sources, and `customizer` functions. * * @private * @param {Object} object The destination object. @@ -2451,68 +1586,107 @@ * @returns {Object} Returns `object`. */ function baseAssign(object, source) { - return object && copyObject(source, keys(source), object); + return source == null + ? object + : baseCopy(source, keys(source), object); } /** - * The base implementation of `_.at` without support for individual paths. + * The base implementation of `_.at` without support for string collections + * and individual key arguments. * * @private - * @param {Object} object The object to iterate over. - * @param {string[]} paths The property paths of elements to pick. - * @returns {Array} Returns the picked elements. + * @param {Array|Object} collection The collection to iterate over. + * @param {number[]|string[]} props The property names or indexes of elements to pick. + * @returns {Array} Returns the new array of picked elements. */ - function baseAt(object, paths) { + function baseAt(collection, props) { var index = -1, - isNil = object == null, - length = paths.length, - result = Array(length); + isNil = collection == null, + isArr = !isNil && isArrayLike(collection), + length = isArr ? collection.length : 0, + propsLength = props.length, + result = Array(propsLength); - while (++index < length) { - result[index] = isNil ? undefined : get(object, paths[index]); + while(++index < propsLength) { + var key = props[index]; + if (isArr) { + result[index] = isIndex(key, length) ? collection[key] : undefined; + } else { + result[index] = isNil ? undefined : collection[key]; + } } return result; } /** - * The base implementation of `_.clamp` which doesn't coerce arguments. + * Copies properties of `source` to `object`. * * @private - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. + * @param {Object} source The object to copy properties from. + * @param {Array} props The property names to copy. + * @param {Object} [object={}] The object to copy properties to. + * @returns {Object} Returns `object`. */ - function baseClamp(number, lower, upper) { - if (number === number) { - if (upper !== undefined) { - number = number <= upper ? number : upper; - } - if (lower !== undefined) { - number = number >= lower ? number : lower; - } + function baseCopy(source, props, object) { + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + object[key] = source[key]; } - return number; + return object; } /** - * The base implementation of `_.clone` and `_.cloneDeep` which tracks - * traversed objects. + * The base implementation of `_.callback` which supports specifying the + * number of arguments to provide to `func`. + * + * @private + * @param {*} [func=_.identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. + */ + function baseCallback(func, thisArg, argCount) { + var type = typeof func; + if (type == 'function') { + return thisArg === undefined + ? func + : bindCallback(func, thisArg, argCount); + } + if (func == null) { + return identity; + } + if (type == 'object') { + return baseMatches(func); + } + return thisArg === undefined + ? property(func) + : baseMatchesProperty(func, thisArg); + } + + /** + * The base implementation of `_.clone` without support for argument juggling + * and `this` binding `customizer` functions. * * @private * @param {*} value The value to clone. * @param {boolean} [isDeep] Specify a deep clone. - * @param {boolean} [isFull] Specify a clone including symbols. - * @param {Function} [customizer] The function to customize cloning. + * @param {Function} [customizer] The function to customize cloning values. * @param {string} [key] The key of `value`. - * @param {Object} [object] The parent object of `value`. - * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @param {Object} [object] The object `value` belongs to. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates clones with source counterparts. * @returns {*} Returns the cloned value. */ - function baseClone(value, isDeep, isFull, customizer, key, object, stack) { + function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { var result; if (customizer) { - result = object ? customizer(value, key, object, stack) : customizer(value); + result = object ? customizer(value, key, object) : customizer(value); } if (result !== undefined) { return result; @@ -2524,92 +1698,44 @@ if (isArr) { result = initCloneArray(value); if (!isDeep) { - return copyArray(value, result); + return arrayCopy(value, result); } } else { - var tag = getTag(value), - isFunc = tag == funcTag || tag == genTag; + var tag = objToString.call(value), + isFunc = tag == funcTag; - if (isBuffer(value)) { - return cloneBuffer(value, isDeep); - } if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - if (isHostObject(value)) { - return object ? value : {}; - } result = initCloneObject(isFunc ? {} : value); if (!isDeep) { - return copySymbols(value, baseAssign(result, value)); + return baseAssign(result, value); } } else { - if (!cloneableTags[tag]) { - return object ? value : {}; - } - result = initCloneByTag(value, tag, baseClone, isDeep); + return cloneableTags[tag] + ? initCloneByTag(value, tag, isDeep) + : (object ? value : {}); } } // Check for circular references and return its corresponding clone. - stack || (stack = new Stack); - var stacked = stack.get(value); - if (stacked) { - return stacked; - } - stack.set(value, result); + stackA || (stackA = []); + stackB || (stackB = []); - if (!isArr) { - var props = isFull ? getAllKeys(value) : keys(value); - } - arrayEach(props || value, function(subValue, key) { - if (props) { - key = subValue; - subValue = value[key]; + var length = stackA.length; + while (length--) { + if (stackA[length] == value) { + return stackB[length]; } - // Recursively populate clone (susceptible to call stack limits). - assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack)); + } + // Add the source value to the stack of traversed objects and associate it with its clone. + stackA.push(value); + stackB.push(result); + + // Recursively populate clone (susceptible to call stack limits). + (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { + result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); }); return result; } - /** - * The base implementation of `_.conforms` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property predicates to conform to. - * @returns {Function} Returns the new spec function. - */ - function baseConforms(source) { - var props = keys(source); - return function(object) { - return baseConformsTo(object, source, props); - }; - } - - /** - * The base implementation of `_.conformsTo` which accepts `props` to check. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - */ - function baseConformsTo(object, source, props) { - var length = props.length; - if (object == null) { - return !length; - } - object = Object(object); - while (length--) { - var key = props[length], - predicate = source[key], - value = object[key]; - - if ((value === undefined && !(key in object)) || !predicate(value)) { - return false; - } - } - return true; - } - /** * The base implementation of `_.create` without support for assigning * properties to the created object. @@ -2618,19 +1744,27 @@ * @param {Object} prototype The object to inherit from. * @returns {Object} Returns the new object. */ - function baseCreate(proto) { - return isObject(proto) ? objectCreate(proto) : {}; - } + var baseCreate = (function() { + function object() {} + return function(prototype) { + if (isObject(prototype)) { + object.prototype = prototype; + var result = new object; + object.prototype = undefined; + } + return result || {}; + }; + }()); /** - * The base implementation of `_.delay` and `_.defer` which accepts `args` - * to provide to `func`. + * The base implementation of `_.delay` and `_.defer` which accepts an index + * of where to slice the arguments to provide to `func`. * * @private * @param {Function} func The function to delay. * @param {number} wait The number of milliseconds to delay invocation. - * @param {Array} args The arguments to provide to `func`. - * @returns {number|Object} Returns the timer id or timeout object. + * @param {Object} args The arguments provide to `func`. + * @returns {number} Returns the timer id. */ function baseDelay(func, wait, args) { if (typeof func != 'function') { @@ -2640,55 +1774,46 @@ } /** - * The base implementation of methods like `_.difference` without support - * for excluding multiple arrays or iteratee shorthands. + * The base implementation of `_.difference` which accepts a single array + * of values to exclude. * * @private * @param {Array} array The array to inspect. * @param {Array} values The values to exclude. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. * @returns {Array} Returns the new array of filtered values. */ - function baseDifference(array, values, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - isCommon = true, - length = array.length, - result = [], - valuesLength = values.length; + function baseDifference(array, values) { + var length = array ? array.length : 0, + result = []; if (!length) { return result; } - if (iteratee) { - values = arrayMap(values, baseUnary(iteratee)); - } - if (comparator) { - includes = arrayIncludesWith; + var index = -1, + indexOf = getIndexOf(), + isCommon = indexOf === baseIndexOf, + cache = (isCommon && values.length >= LARGE_ARRAY_SIZE) ? createCache(values) : null, + valuesLength = values.length; + + if (cache) { + indexOf = cacheIndexOf; isCommon = false; - } - else if (values.length >= LARGE_ARRAY_SIZE) { - includes = cacheHas; - isCommon = false; - values = new SetCache(values); + values = cache; } outer: while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; + var value = array[index]; - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { + if (isCommon && value === value) { var valuesIndex = valuesLength; while (valuesIndex--) { - if (values[valuesIndex] === computed) { + if (values[valuesIndex] === value) { continue outer; } } result.push(value); } - else if (!includes(values, computed, comparator)) { + else if (indexOf(values, value, 0) < 0) { result.push(value); } } @@ -2696,30 +1821,33 @@ } /** - * The base implementation of `_.forEach` without support for iteratee shorthands. + * The base implementation of `_.forEach` without support for callback + * shorthands and `this` binding. * * @private - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. + * @returns {Array|Object|string} Returns `collection`. */ var baseEach = createBaseEach(baseForOwn); /** - * The base implementation of `_.forEachRight` without support for iteratee shorthands. + * The base implementation of `_.forEachRight` without support for callback + * shorthands and `this` binding. * * @private - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. + * @returns {Array|Object|string} Returns `collection`. */ var baseEachRight = createBaseEach(baseForOwnRight, true); /** - * The base implementation of `_.every` without support for iteratee shorthands. + * The base implementation of `_.every` without support for callback + * shorthands and `this` binding. * * @private - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if all elements pass the predicate check, * else `false` @@ -2734,31 +1862,28 @@ } /** - * The base implementation of methods like `_.max` and `_.min` which accepts a - * `comparator` to determine the extremum value. + * Gets the extremum value of `collection` invoking `iteratee` for each value + * in `collection` to generate the criterion by which the value is ranked. + * The `iteratee` is invoked with three arguments: (value, index|key, collection). * * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The iteratee invoked per iteration. - * @param {Function} comparator The comparator used to compare values. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} comparator The function used to compare values. + * @param {*} exValue The initial extremum value. * @returns {*} Returns the extremum value. */ - function baseExtremum(array, iteratee, comparator) { - var index = -1, - length = array.length; + function baseExtremum(collection, iteratee, comparator, exValue) { + var computed = exValue, + result = computed; - while (++index < length) { - var value = array[index], - current = iteratee(value); - - if (current != null && (computed === undefined - ? (current === current && !isSymbol(current)) - : comparator(current, computed) - )) { - var computed = current, - result = value; + baseEach(collection, function(value, index, collection) { + var current = +iteratee(value, index, collection); + if (comparator(current, computed) || (current === exValue && current === result)) { + computed = current; + result = value; } - } + }); return result; } @@ -2775,26 +1900,29 @@ function baseFill(array, value, start, end) { var length = array.length; - start = toInteger(start); + start = start == null ? 0 : (+start || 0); if (start < 0) { start = -start > length ? 0 : (length + start); } - end = (end === undefined || end > length) ? length : toInteger(end); + end = (end === undefined || end > length) ? length : (+end || 0); if (end < 0) { end += length; } - end = start > end ? 0 : toLength(end); - while (start < end) { + length = start > end ? 0 : (end >>> 0); + start >>>= 0; + + while (start < length) { array[start++] = value; } return array; } /** - * The base implementation of `_.filter` without support for iteratee shorthands. + * The base implementation of `_.filter` without support for callback + * shorthands and `this` binding. * * @private - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {Array} Returns the new filtered array. */ @@ -2809,29 +1937,53 @@ } /** - * The base implementation of `_.flatten` with support for restricting flattening. + * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`, + * without support for callback shorthands and `this` binding, which iterates + * over `collection` using the provided `eachFunc`. + * + * @private + * @param {Array|Object|string} 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) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = retKey ? key : value; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with added support for restricting + * flattening and specifying the start index. * * @private * @param {Array} array The array to flatten. - * @param {number} depth The maximum recursion depth. - * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. - * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param {boolean} [isStrict] Restrict flattening to arrays-like objects. * @param {Array} [result=[]] The initial result value. * @returns {Array} Returns the new flattened array. */ - function baseFlatten(array, depth, predicate, isStrict, result) { + function baseFlatten(array, isDeep, isStrict, result) { + result || (result = []); + var index = -1, length = array.length; - predicate || (predicate = isFlattenable); - result || (result = []); - while (++index < length) { var value = array[index]; - if (depth > 0 && predicate(value)) { - if (depth > 1) { + if (isObjectLike(value) && isArrayLike(value) && + (isStrict || isArray(value) || isArguments(value))) { + if (isDeep) { // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, predicate, isStrict, result); + baseFlatten(value, isDeep, isStrict, result); } else { arrayPush(result, value); } @@ -2843,9 +1995,10 @@ } /** - * The base implementation of `baseForOwn` which iterates over `object` - * properties returned by `keysFunc` and invokes `iteratee` for each property. - * Iteratee functions may exit iteration early by explicitly returning `false`. + * The base implementation of `baseForIn` and `baseForOwn` which iterates + * over `object` properties returned by `keysFunc` invoking `iteratee` for + * each property. Iteratee functions may exit iteration early by explicitly + * returning `false`. * * @private * @param {Object} object The object to iterate over. @@ -2868,7 +2021,21 @@ var baseForRight = createBaseFor(true); /** - * The base implementation of `_.forOwn` without support for iteratee shorthands. + * The base implementation of `_.forIn` without support for callback + * shorthands and `this` binding. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForIn(object, iteratee) { + return baseFor(object, iteratee, keysIn); + } + + /** + * The base implementation of `_.forOwn` without support for callback + * shorthands and `this` binding. * * @private * @param {Object} object The object to iterate over. @@ -2876,11 +2043,12 @@ * @returns {Object} Returns `object`. */ function baseForOwn(object, iteratee) { - return object && baseFor(object, iteratee, keys); + return baseFor(object, iteratee, keys); } /** - * The base implementation of `_.forOwnRight` without support for iteratee shorthands. + * The base implementation of `_.forOwnRight` without support for callback + * shorthands and `this` binding. * * @private * @param {Object} object The object to iterate over. @@ -2888,267 +2056,80 @@ * @returns {Object} Returns `object`. */ function baseForOwnRight(object, iteratee) { - return object && baseForRight(object, iteratee, keys); + return baseForRight(object, iteratee, keys); } /** * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from `props`. + * `object` function property names filtered from those provided. * * @private * @param {Object} object The object to inspect. * @param {Array} props The property names to filter. - * @returns {Array} Returns the function names. + * @returns {Array} Returns the new array of filtered property names. */ function baseFunctions(object, props) { - return arrayFilter(props, function(key) { - return isFunction(object[key]); - }); - } - - /** - * The base implementation of `_.get` without support for default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path) { - path = isKey(path, object) ? [path] : castPath(path); - - var index = 0, - length = path.length; - - while (object != null && index < length) { - object = object[toKey(path[index++])]; - } - return (index && index == length) ? object : undefined; - } - - /** - * The base implementation of `getAllKeys` and `getAllKeysIn` which uses - * `keysFunc` and `symbolsFunc` to get the enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Function} keysFunc The function to get the keys of `object`. - * @param {Function} symbolsFunc The function to get the symbols of `object`. - * @returns {Array} Returns the array of property names and symbols. - */ - function baseGetAllKeys(object, keysFunc, symbolsFunc) { - var result = keysFunc(object); - return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); - } - - /** - * The base implementation of `getTag`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - function baseGetTag(value) { - return objectToString.call(value); - } - - /** - * The base implementation of `_.gt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - */ - function baseGt(value, other) { - return value > other; - } - - /** - * The base implementation of `_.has` without support for deep paths. - * - * @private - * @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 baseHas(object, key) { - return object != null && hasOwnProperty.call(object, key); - } - - /** - * The base implementation of `_.hasIn` without support for deep paths. - * - * @private - * @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 object != null && key in Object(object); - } - - /** - * The base implementation of `_.inRange` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to check. - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - */ - function baseInRange(number, start, end) { - return number >= nativeMin(start, end) && number < nativeMax(start, end); - } - - /** - * The base implementation of methods like `_.intersection`, without support - * for iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of shared values. - */ - function baseIntersection(arrays, iteratee, comparator) { - var includes = comparator ? arrayIncludesWith : arrayIncludes, - length = arrays[0].length, - othLength = arrays.length, - othIndex = othLength, - caches = Array(othLength), - maxLength = Infinity, + var index = -1, + length = props.length, + resIndex = -1, result = []; - while (othIndex--) { - var array = arrays[othIndex]; - if (othIndex && iteratee) { - array = arrayMap(array, baseUnary(iteratee)); - } - maxLength = nativeMin(array.length, maxLength); - caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) - ? new SetCache(othIndex && array) - : undefined; - } - array = arrays[0]; - - var index = -1, - seen = caches[0]; - - outer: - while (++index < length && result.length < maxLength) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (!(seen - ? cacheHas(seen, computed) - : includes(result, computed, comparator) - )) { - othIndex = othLength; - while (--othIndex) { - var cache = caches[othIndex]; - if (!(cache - ? cacheHas(cache, computed) - : includes(arrays[othIndex], computed, comparator)) - ) { - continue outer; - } - } - if (seen) { - seen.push(computed); - } - result.push(value); + while (++index < length) { + var key = props[index]; + if (isFunction(object[key])) { + result[++resIndex] = key; } } return result; } /** - * The base implementation of `_.invert` and `_.invertBy` which inverts - * `object` with values transformed by `iteratee` and set by `setter`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform values. - * @param {Object} accumulator The initial inverted object. - * @returns {Function} Returns `accumulator`. - */ - function baseInverter(object, setter, iteratee, accumulator) { - baseForOwn(object, function(value, key, object) { - setter(accumulator, iteratee(value), key, object); - }); - return accumulator; - } - - /** - * The base implementation of `_.invoke` without support for individual - * method arguments. + * The base implementation of `get` without support for string paths + * and default values. * * @private * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. + * @param {Array} path The path of the property to get. + * @param {string} [pathKey] The key representation of path. + * @returns {*} Returns the resolved value. */ - function baseInvoke(object, path, args) { - if (!isKey(path, object)) { - path = castPath(path); - object = parent(object, path); - path = last(path); + function baseGet(object, path, pathKey) { + if (object == null) { + return; } - var func = object == null ? object : object[toKey(path)]; - return func == null ? undefined : apply(func, object, args); + if (pathKey !== undefined && pathKey in toObject(object)) { + path = [pathKey]; + } + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[path[index++]]; + } + return (index && index == length) ? object : undefined; } /** - * The base implementation of `_.isArrayBuffer` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - */ - function baseIsArrayBuffer(value) { - return isObjectLike(value) && objectToString.call(value) == arrayBufferTag; - } - - /** - * The base implementation of `_.isDate` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - */ - function baseIsDate(value) { - return isObjectLike(value) && objectToString.call(value) == dateTag; - } - - /** - * The base implementation of `_.isEqual` which supports partial comparisons - * and tracks traversed objects. + * The base implementation of `_.isEqual` without support for `this` binding + * `customizer` functions. * * @private * @param {*} value The value to compare. * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @param {boolean} [bitmask] The bitmask of comparison flags. - * The bitmask may be composed of the following flags: - * 1 - Unordered comparison - * 2 - Partial comparison - * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. */ - function baseIsEqual(value, other, customizer, bitmask, stack) { + function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) { if (value === other) { return true; } if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { return value !== value && other !== other; } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack); + return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB); } /** @@ -3160,77 +2141,86 @@ * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} [customizer] The function to customize comparisons. - * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @param {Function} [customizer] The function to customize comparing objects. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA=[]] Tracks traversed `value` objects. + * @param {Array} [stackB=[]] Tracks traversed `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ - function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) { + function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) { var objIsArr = isArray(object), othIsArr = isArray(other), objTag = arrayTag, othTag = arrayTag; if (!objIsArr) { - objTag = getTag(object); - objTag = objTag == argsTag ? objectTag : objTag; + objTag = objToString.call(object); + if (objTag == argsTag) { + objTag = objectTag; + } else if (objTag != objectTag) { + objIsArr = isTypedArray(object); + } } if (!othIsArr) { - othTag = getTag(other); - othTag = othTag == argsTag ? objectTag : othTag; + othTag = objToString.call(other); + if (othTag == argsTag) { + othTag = objectTag; + } else if (othTag != objectTag) { + othIsArr = isTypedArray(other); + } } - var objIsObj = objTag == objectTag && !isHostObject(object), - othIsObj = othTag == objectTag && !isHostObject(other), + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, isSameTag = objTag == othTag; - if (isSameTag && !objIsObj) { - stack || (stack = new Stack); - return (objIsArr || isTypedArray(object)) - ? equalArrays(object, other, equalFunc, customizer, bitmask, stack) - : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack); + if (isSameTag && !(objIsArr || objIsObj)) { + return equalByTag(object, other, objTag); } - if (!(bitmask & PARTIAL_COMPARE_FLAG)) { + if (!isLoose) { var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object.value() : object, - othUnwrapped = othIsWrapped ? other.value() : other; - - stack || (stack = new Stack); - return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack); + return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB); } } if (!isSameTag) { return false; } - stack || (stack = new Stack); - return equalObjects(object, other, equalFunc, customizer, bitmask, stack); + // Assume cyclic values are equal. + // For more information on detecting circular references see https://es5.github.io/#JO. + stackA || (stackA = []); + stackB || (stackB = []); + + var length = stackA.length; + while (length--) { + if (stackA[length] == object) { + return stackB[length] == other; + } + } + // Add `object` and `other` to the stack of traversed objects. + stackA.push(object); + stackB.push(other); + + var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB); + + stackA.pop(); + stackB.pop(); + + return result; } /** - * The base implementation of `_.isMap` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - */ - function baseIsMap(value) { - return isObjectLike(value) && getTag(value) == mapTag; - } - - /** - * The base implementation of `_.isMatch` without support for iteratee shorthands. + * The base implementation of `_.isMatch` without support for callback + * shorthands and `this` binding. * * @private * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Array} matchData The property names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparisons. + * @param {Array} matchData The propery names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparing objects. * @returns {boolean} Returns `true` if `object` is a match, else `false`. */ - function baseIsMatch(object, source, matchData, customizer) { + function baseIsMatch(object, matchData, customizer) { var index = matchData.length, length = index, noCustomizer = !customizer; @@ -3238,7 +2228,7 @@ if (object == null) { return !length; } - object = Object(object); + object = toObject(object); while (index--) { var data = matchData[index]; if ((noCustomizer && data[2]) @@ -3259,14 +2249,8 @@ return false; } } else { - var stack = new Stack; - if (customizer) { - var result = customizer(objValue, srcValue, key, object, source, stack); - } - if (!(result === undefined - ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack) - : result - )) { + var result = customizer ? customizer(objValue, srcValue, key) : undefined; + if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) { return false; } } @@ -3275,139 +2259,11 @@ } /** - * The base implementation of `_.isNative` without bad shim checks. + * The base implementation of `_.map` without support for callback shorthands + * and `this` binding. * * @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 `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ - function baseIsRegExp(value) { - return isObject(value) && objectToString.call(value) == regexpTag; - } - - /** - * The base implementation of `_.isSet` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - */ - function baseIsSet(value) { - return isObjectLike(value) && getTag(value) == setTag; - } - - /** - * The base implementation of `_.isTypedArray` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - */ - function baseIsTypedArray(value) { - return isObjectLike(value) && - isLength(value.length) && !!typedArrayTags[objectToString.call(value)]; - } - - /** - * The base implementation of `_.iteratee`. - * - * @private - * @param {*} [value=_.identity] The value to convert to an iteratee. - * @returns {Function} Returns the iteratee. - */ - function baseIteratee(value) { - // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. - // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. - if (typeof value == 'function') { - return value; - } - if (value == null) { - return identity; - } - if (typeof value == 'object') { - return isArray(value) - ? baseMatchesProperty(value[0], value[1]) - : baseMatches(value); - } - return property(value); - } - - /** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeysIn(object) { - if (!isObject(object)) { - return nativeKeysIn(object); - } - var isProto = isPrototype(object), - result = []; - - for (var key in object) { - if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.lt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - */ - function baseLt(value, other) { - return value < other; - } - - /** - * The base implementation of `_.map` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the new mapped array. */ @@ -3422,80 +2278,108 @@ } /** - * The base implementation of `_.matches` which doesn't clone `source`. + * The base implementation of `_.matches` which does not clone `source`. * * @private * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. + * @returns {Function} Returns the new function. */ function baseMatches(source) { var matchData = getMatchData(source); if (matchData.length == 1 && matchData[0][2]) { - return matchesStrictComparable(matchData[0][0], matchData[0][1]); + var key = matchData[0][0], + value = matchData[0][1]; + + return function(object) { + if (object == null) { + return false; + } + return object[key] === value && (value !== undefined || (key in toObject(object))); + }; } return function(object) { - return object === source || baseIsMatch(object, source, matchData); + return baseIsMatch(object, matchData); }; } /** - * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * The base implementation of `_.matchesProperty` which does not clone `srcValue`. * * @private * @param {string} path The path of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. + * @param {*} srcValue The value to compare. + * @returns {Function} Returns the new function. */ function baseMatchesProperty(path, srcValue) { - if (isKey(path) && isStrictComparable(srcValue)) { - return matchesStrictComparable(toKey(path), srcValue); - } + var isArr = isArray(path), + isCommon = isKey(path) && isStrictComparable(srcValue), + pathKey = (path + ''); + + path = toPath(path); return function(object) { - var objValue = get(object, path); - return (objValue === undefined && objValue === srcValue) - ? hasIn(object, path) - : baseIsEqual(srcValue, objValue, undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG); + if (object == null) { + return false; + } + var key = pathKey; + object = toObject(object); + if ((isArr || !isCommon) && !(key in object)) { + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + if (object == null) { + return false; + } + key = last(path); + object = toObject(object); + } + return object[key] === srcValue + ? (srcValue !== undefined || (key in object)) + : baseIsEqual(srcValue, object[key], undefined, true); }; } /** - * The base implementation of `_.merge` without support for multiple sources. + * The base implementation of `_.merge` without support for argument juggling, + * multiple sources, and `this` binding `customizer` functions. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. - * @param {number} srcIndex The index of `source`. * @param {Function} [customizer] The function to customize merged values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {Object} Returns `object`. */ - function baseMerge(object, source, srcIndex, customizer, stack) { - if (object === source) { - return; - } - if (!(isArray(source) || isTypedArray(source))) { - var props = baseKeysIn(source); + function baseMerge(object, source, customizer, stackA, stackB) { + if (!isObject(object)) { + return object; } + var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)), + props = isSrcArr ? undefined : keys(source); + arrayEach(props || source, function(srcValue, key) { if (props) { key = srcValue; srcValue = source[key]; } - if (isObject(srcValue)) { - stack || (stack = new Stack); - baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + if (isObjectLike(srcValue)) { + stackA || (stackA = []); + stackB || (stackB = []); + baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); } else { - var newValue = customizer - ? customizer(object[key], srcValue, (key + ''), object, source, stack) - : undefined; + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = result === undefined; - if (newValue === undefined) { - newValue = srcValue; + if (isCommon) { + result = srcValue; + } + if ((result !== undefined || (isSrcArr && !(key in object))) && + (isCommon || (result === result ? (result !== value) : (value === value)))) { + object[key] = result; } - assignMergeValue(object, key, newValue); } }); + return object; } /** @@ -3507,147 +2391,66 @@ * @param {Object} object The destination object. * @param {Object} source The source object. * @param {string} key The key of the value to merge. - * @param {number} srcIndex The index of `source`. * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize assigned values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. + * @param {Function} [customizer] The function to customize merged values. + * @param {Array} [stackA=[]] Tracks traversed source objects. + * @param {Array} [stackB=[]] Associates values with source counterparts. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ - function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { - var objValue = object[key], - srcValue = source[key], - stacked = stack.get(srcValue); + function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { + var length = stackA.length, + srcValue = source[key]; - if (stacked) { - assignMergeValue(object, key, stacked); - return; + while (length--) { + if (stackA[length] == srcValue) { + object[key] = stackB[length]; + return; + } } - var newValue = customizer - ? customizer(objValue, srcValue, (key + ''), object, source, stack) - : undefined; - - var isCommon = newValue === undefined; + var value = object[key], + result = customizer ? customizer(value, srcValue, key, object, source) : undefined, + isCommon = result === undefined; if (isCommon) { - newValue = srcValue; - if (isArray(srcValue) || isTypedArray(srcValue)) { - if (isArray(objValue)) { - newValue = objValue; - } - else if (isArrayLikeObject(objValue)) { - newValue = copyArray(objValue); - } - else { - isCommon = false; - newValue = baseClone(srcValue, true); - } + result = srcValue; + if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) { + result = isArray(value) + ? value + : (isArrayLike(value) ? arrayCopy(value) : []); } else if (isPlainObject(srcValue) || isArguments(srcValue)) { - if (isArguments(objValue)) { - newValue = toPlainObject(objValue); - } - else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { - isCommon = false; - newValue = baseClone(srcValue, true); - } - else { - newValue = objValue; - } + result = isArguments(value) + ? toPlainObject(value) + : (isPlainObject(value) ? value : {}); } else { isCommon = false; } } + // Add the source value to the stack of traversed objects and associate + // it with its merged value. + stackA.push(srcValue); + stackB.push(result); + if (isCommon) { // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, newValue); - mergeFunc(newValue, srcValue, srcIndex, customizer, stack); - stack['delete'](srcValue); + object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); + } else if (result === result ? (result !== value) : (value === value)) { + object[key] = result; } - assignMergeValue(object, key, newValue); } /** - * The base implementation of `_.nth` which doesn't coerce arguments. + * The base implementation of `_.property` without support for deep paths. * * @private - * @param {Array} array The array to query. - * @param {number} n The index of the element to return. - * @returns {*} Returns the nth element of `array`. + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new function. */ - function baseNth(array, n) { - var length = array.length; - if (!length) { - return; - } - n += n < 0 ? length : 0; - return isIndex(n, length) ? array[n] : undefined; - } - - /** - * The base implementation of `_.orderBy` without param guards. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {string[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseOrderBy(collection, iteratees, orders) { - var index = -1; - iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); - - var result = baseMap(collection, function(value, key, collection) { - var criteria = arrayMap(iteratees, function(iteratee) { - return iteratee(value); - }); - return { 'criteria': criteria, 'index': ++index, 'value': value }; - }); - - return baseSortBy(result, function(object, other) { - return compareMultiple(object, other, orders); - }); - } - - /** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property identifiers to pick. - * @returns {Object} Returns the new object. - */ - function basePick(object, props) { - object = Object(object); - return basePickBy(object, props, function(value, key) { - return key in object; - }); - } - - /** - * The base implementation of `_.pickBy` without support for iteratee shorthands. - * - * @private - * @param {Object} object The source object. - * @param {string[]} props The property identifiers to pick from. - * @param {Function} predicate The function invoked per property. - * @returns {Object} Returns the new object. - */ - function basePickBy(object, props, predicate) { - var index = -1, - length = props.length, - result = {}; - - while (++index < length) { - var key = props[index], - value = object[key]; - - if (predicate(value, key)) { - result[key] = value; - } - } - return result; + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; } /** @@ -3655,55 +2458,19 @@ * * @private * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new accessor function. + * @returns {Function} Returns the new function. */ function basePropertyDeep(path) { + var pathKey = (path + ''); + path = toPath(path); return function(object) { - return baseGet(object, path); + return baseGet(object, path, pathKey); }; } - /** - * The base implementation of `_.pullAllBy` without support for iteratee - * shorthands. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - */ - function basePullAll(array, values, iteratee, comparator) { - var indexOf = comparator ? baseIndexOfWith : baseIndexOf, - index = -1, - length = values.length, - seen = array; - - if (array === values) { - values = copyArray(values); - } - if (iteratee) { - seen = arrayMap(array, baseUnary(iteratee)); - } - while (++index < length) { - var fromIndex = 0, - value = values[index], - computed = iteratee ? iteratee(value) : value; - - while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { - if (seen !== array) { - splice.call(seen, fromIndex, 1); - } - splice.call(array, fromIndex, 1); - } - } - return array; - } - /** * The base implementation of `_.pullAt` without support for individual - * indexes or capturing the removed elements. + * index arguments and capturing the removed elements. * * @private * @param {Array} array The array to modify. @@ -3711,163 +2478,51 @@ * @returns {Array} Returns `array`. */ function basePullAt(array, indexes) { - var length = array ? indexes.length : 0, - lastIndex = length - 1; - + var length = array ? indexes.length : 0; while (length--) { var index = indexes[length]; - if (length == lastIndex || index !== previous) { + if (index != previous && isIndex(index)) { var previous = index; - if (isIndex(index)) { - splice.call(array, index, 1); - } - else if (!isKey(index, array)) { - var path = castPath(index), - object = parent(array, path); - - if (object != null) { - delete object[toKey(last(path))]; - } - } - else { - delete array[toKey(index)]; - } + splice.call(array, index, 1); } } return array; } /** - * The base implementation of `_.random` without support for returning - * floating-point numbers. + * The base implementation of `_.random` without support for argument juggling + * and returning floating-point numbers. * * @private - * @param {number} lower The lower bound. - * @param {number} upper The upper bound. + * @param {number} min The minimum possible value. + * @param {number} max The maximum possible value. * @returns {number} Returns the random number. */ - function baseRandom(lower, upper) { - return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); + function baseRandom(min, max) { + return min + nativeFloor(nativeRandom() * (max - min + 1)); } /** - * The base implementation of `_.range` and `_.rangeRight` which doesn't - * coerce arguments. + * The base implementation of `_.reduce` and `_.reduceRight` without support + * for callback shorthands and `this` binding, which iterates over `collection` + * using the provided `eachFunc`. * * @private - * @param {number} start The start of the range. - * @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 range of numbers. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initFromCollection Specify using the first or last element + * of `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. */ - function baseRange(start, end, step, fromRight) { - var index = -1, - length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), - result = Array(length); - - while (length--) { - result[fromRight ? length : ++index] = start; - start += step; - } - return result; - } - - /** - * The base implementation of `_.repeat` which doesn't coerce arguments. - * - * @private - * @param {string} string The string to repeat. - * @param {number} n The number of times to repeat the string. - * @returns {string} Returns the repeated string. - */ - function baseRepeat(string, n) { - var result = ''; - if (!string || n < 1 || n > MAX_SAFE_INTEGER) { - return result; - } - // Leverage the exponentiation by squaring algorithm for a faster repeat. - // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. - do { - if (n % 2) { - result += string; - } - n = nativeFloor(n / 2); - if (n) { - string += string; - } - } while (n); - - return result; - } - - /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ - function baseRest(func, start) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); - - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = array; - return apply(func, this, otherArgs); - }; - } - - /** - * The base implementation of `_.set`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseSet(object, path, value, customizer) { - if (!isObject(object)) { - return object; - } - path = isKey(path, object) ? [path] : castPath(path); - - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; - - while (nested != null && ++index < length) { - var key = toKey(path[index]), - newValue = value; - - if (index != lastIndex) { - var objValue = nested[key]; - newValue = customizer ? customizer(objValue, key, nested) : undefined; - if (newValue === undefined) { - newValue = isObject(objValue) - ? objValue - : (isIndex(path[index + 1]) ? [] : {}); - } - } - assignValue(nested, key, newValue); - nested = nested[key]; - } - return object; + function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initFromCollection + ? (initFromCollection = false, value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; } /** @@ -3896,10 +2551,11 @@ var index = -1, length = array.length; + start = start == null ? 0 : (+start || 0); if (start < 0) { start = -start > length ? 0 : (length + start); } - end = end > length ? length : end; + end = (end === undefined || end > length) ? length : (+end || 0); if (end < 0) { end += length; } @@ -3914,10 +2570,11 @@ } /** - * The base implementation of `_.some` without support for iteratee shorthands. + * The base implementation of `_.some` without support for callback shorthands + * and `this` binding. * * @private - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} predicate The function invoked per iteration. * @returns {boolean} Returns `true` if any element passes the predicate check, * else `false`. @@ -3933,8 +2590,188 @@ } /** - * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which - * performs a binary search of `array` to determine the index at which `value` + * The base implementation of `_.sortBy` which uses `comparer` to define + * the sort order of `array` and replaces criteria objects with their + * corresponding values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } + + /** + * The base implementation of `_.sortByOrder` without param guards. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {boolean[]} orders The sort orders of `iteratees`. + * @returns {Array} Returns the new sorted array. + */ + function baseSortByOrder(collection, iteratees, orders) { + var callback = getCallback(), + index = -1; + + iteratees = arrayMap(iteratees, function(iteratee) { return callback(iteratee); }); + + var result = baseMap(collection, function(value) { + var criteria = arrayMap(iteratees, function(iteratee) { return iteratee(value); }); + return { 'criteria': criteria, 'index': ++index, 'value': value }; + }); + + return baseSortBy(result, function(object, other) { + return compareMultiple(object, other, orders); + }); + } + + /** + * The base implementation of `_.sum` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function baseSum(collection, iteratee) { + var result = 0; + baseEach(collection, function(value, index, collection) { + result += +iteratee(value, index, collection) || 0; + }); + return result; + } + + /** + * The base implementation of `_.uniq` without support for callback shorthands + * and `this` binding. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The function invoked per iteration. + * @returns {Array} Returns the new duplicate free array. + */ + function baseUniq(array, iteratee) { + var index = -1, + indexOf = getIndexOf(), + length = array.length, + isCommon = indexOf === baseIndexOf, + isLarge = isCommon && length >= LARGE_ARRAY_SIZE, + seen = isLarge ? createCache() : null, + result = []; + + if (seen) { + indexOf = cacheIndexOf; + isCommon = false; + } else { + isLarge = false; + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value, index, array) : value; + + if (isCommon && value === value) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } + else if (indexOf(seen, computed, 0) < 0) { + if (iteratee || isLarge) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + var index = -1, + length = props.length, + result = Array(length); + + while (++index < length) { + result[index] = object[props[index]]; + } + return result; + } + + /** + * The base implementation of `_.dropRightWhile`, `_.dropWhile`, `_.takeRightWhile`, + * and `_.takeWhile` without support for callback shorthands and `this` binding. + * + * @private + * @param {Array} array The array to query. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [isDrop] Specify dropping elements instead of taking them. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the slice of `array`. + */ + function baseWhile(array, predicate, isDrop, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length) && predicate(array[index], index, array)) {} + return isDrop + ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) + : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); + } + + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to peform to resolve the unwrapped value. + * @returns {*} Returns the resolved value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + var index = -1, + length = actions.length; + + while (++index < length) { + var action = actions[index]; + result = action.func.apply(action.thisArg, arrayPush([result], action.args)); + } + return result; + } + + /** + * Performs a binary search of `array` to determine the index at which `value` * should be inserted into `array` in order to maintain its sort order. * * @private @@ -3944,7 +2781,7 @@ * @returns {number} Returns the index at which `value` should be inserted * into `array`. */ - function baseSortedIndex(array, value, retHighest) { + function binaryIndex(array, value, retHighest) { var low = 0, high = array ? array.length : low; @@ -3953,8 +2790,7 @@ var mid = (low + high) >>> 1, computed = array[mid]; - if (computed !== null && !isSymbol(computed) && - (retHighest ? (computed <= value) : (computed < value))) { + if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) { low = mid + 1; } else { high = mid; @@ -3962,49 +2798,44 @@ } return high; } - return baseSortedIndexBy(array, value, identity, retHighest); + return binaryIndexBy(array, value, identity, retHighest); } /** - * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` - * which invokes `iteratee` for `value` and each element of `array` to compute - * their sort ranking. The iteratee is invoked with one argument; (value). + * This function is like `binaryIndex` except that it invokes `iteratee` for + * `value` and each element of `array` to compute their sort ranking. The + * iteratee is invoked with one argument; (value). * * @private * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. - * @param {Function} iteratee The iteratee invoked per element. + * @param {Function} iteratee The function invoked per iteration. * @param {boolean} [retHighest] Specify returning the highest qualified index. * @returns {number} Returns the index at which `value` should be inserted * into `array`. */ - function baseSortedIndexBy(array, value, iteratee, retHighest) { + function binaryIndexBy(array, value, iteratee, retHighest) { value = iteratee(value); var low = 0, high = array ? array.length : 0, valIsNaN = value !== value, valIsNull = value === null, - valIsSymbol = isSymbol(value), - valIsUndefined = value === undefined; + valIsUndef = value === undefined; while (low < high) { var mid = nativeFloor((low + high) / 2), computed = iteratee(array[mid]), - othIsDefined = computed !== undefined, - othIsNull = computed === null, - othIsReflexive = computed === computed, - othIsSymbol = isSymbol(computed); + isDef = computed !== undefined, + isReflexive = computed === computed; if (valIsNaN) { - var setLow = retHighest || othIsReflexive; - } else if (valIsUndefined) { - setLow = othIsReflexive && (retHighest || othIsDefined); + var setLow = isReflexive || retHighest; } else if (valIsNull) { - setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); - } else if (valIsSymbol) { - setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); - } else if (othIsNull || othIsSymbol) { + setLow = isReflexive && isDef && (retHighest || computed != null); + } else if (valIsUndef) { + setLow = isReflexive && (retHighest || isDef); + } else if (computed == null) { setLow = false; } else { setLow = retHighest ? (computed <= value) : (computed < value); @@ -4019,526 +2850,81 @@ } /** - * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without - * support for iteratee shorthands. + * A specialized version of `baseCallback` which only supports `this` binding + * and specifying the number of arguments to provide to `func`. * * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {number} [argCount] The number of arguments to provide to `func`. + * @returns {Function} Returns the callback. */ - function baseSortedUniq(array, iteratee) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - if (!index || !eq(computed, seen)) { - var seen = computed; - result[resIndex++] = value === 0 ? 0 : value; - } + function bindCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; } - return result; - } - - /** - * The base implementation of `_.toNumber` which doesn't ensure correct - * conversions of binary, hexadecimal, or octal string values. - * - * @private - * @param {*} value The value to process. - * @returns {number} Returns the number. - */ - function baseToNumber(value) { - if (typeof value == 'number') { - return value; + if (thisArg === undefined) { + return func; } - if (isSymbol(value)) { - return NAN; + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + case 5: return function(value, other, key, object, source) { + return func.call(thisArg, value, other, key, object, source); + }; } - return +value; + return function() { + return func.apply(thisArg, arguments); + }; } /** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. + * Creates a clone of the given array buffer. * * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * The base implementation of `_.uniqBy` without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseUniq(array, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - length = array.length, - isCommon = true, - result = [], - seen = result; - - if (comparator) { - isCommon = false; - includes = arrayIncludesWith; - } - else if (length >= LARGE_ARRAY_SIZE) { - var set = iteratee ? null : createSet(array); - if (set) { - return setToArray(set); - } - isCommon = false; - includes = cacheHas; - seen = new SetCache; - } - else { - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } - } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } - else if (!includes(seen, computed, comparator)) { - if (seen !== result) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.unset`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - */ - function baseUnset(object, path) { - path = isKey(path, object) ? [path] : castPath(path); - object = parent(object, path); - - var key = toKey(last(path)); - return !(object != null && hasOwnProperty.call(object, key)) || delete object[key]; - } - - /** - * The base implementation of `_.update`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to update. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseUpdate(object, path, updater, customizer) { - return baseSet(object, path, updater(baseGet(object, path)), customizer); - } - - /** - * The base implementation of methods like `_.dropWhile` and `_.takeWhile` - * without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to query. - * @param {Function} predicate The function invoked per iteration. - * @param {boolean} [isDrop] Specify dropping elements instead of taking them. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the slice of `array`. - */ - function baseWhile(array, predicate, isDrop, fromRight) { - var length = array.length, - index = fromRight ? length : -1; - - while ((fromRight ? index-- : ++index < length) && - predicate(array[index], index, array)) {} - - return isDrop - ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) - : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); - } - - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to perform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - return arrayReduce(actions, function(result, action) { - return action.func.apply(action.thisArg, arrayPush([result], action.args)); - }, result); - } - - /** - * The base implementation of methods like `_.xor`, without support for - * iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of values. - */ - function baseXor(arrays, iteratee, comparator) { - var index = -1, - length = arrays.length; - - while (++index < length) { - var result = result - ? arrayPush( - baseDifference(result, arrays[index], iteratee, comparator), - baseDifference(arrays[index], result, iteratee, comparator) - ) - : arrays[index]; - } - return (result && result.length) ? baseUniq(result, iteratee, comparator) : []; - } - - /** - * This base implementation of `_.zipObject` which assigns values using `assignFunc`. - * - * @private - * @param {Array} props The property identifiers. - * @param {Array} values The property values. - * @param {Function} assignFunc The function to assign values. - * @returns {Object} Returns the new object. - */ - function baseZipObject(props, values, assignFunc) { - var index = -1, - length = props.length, - valsLength = values.length, - result = {}; - - while (++index < length) { - var value = index < valsLength ? values[index] : undefined; - assignFunc(result, props[index], value); - } - return result; - } - - /** - * Casts `value` to an empty array if it's not an array like object. - * - * @private - * @param {*} value The value to inspect. - * @returns {Array|Object} Returns the cast array-like object. - */ - function castArrayLikeObject(value) { - return isArrayLikeObject(value) ? value : []; - } - - /** - * Casts `value` to `identity` if it's not a function. - * - * @private - * @param {*} value The value to inspect. - * @returns {Function} Returns cast function. - */ - function castFunction(value) { - return typeof value == 'function' ? value : identity; - } - - /** - * Casts `value` to a path array if it's not one. - * - * @private - * @param {*} value The value to inspect. - * @returns {Array} Returns the cast property path array. - */ - function castPath(value) { - return isArray(value) ? value : stringToPath(value); - } - - /** - * Casts `array` to a slice if it's needed. - * - * @private - * @param {Array} array The array to inspect. - * @param {number} start The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the cast slice. - */ - function castSlice(array, start, end) { - var length = array.length; - end = end === undefined ? length : end; - return (!start && end >= length) ? array : baseSlice(array, start, end); - } - - /** - * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). - * - * @private - * @param {number|Object} id The timer id or timeout object of the timer to clear. - */ - var clearTimeout = ctxClearTimeout || function(id) { - return root.clearTimeout(id); - }; - - /** - * Creates a clone of `buffer`. - * - * @private - * @param {Buffer} buffer The buffer to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Buffer} Returns the cloned buffer. - */ - function cloneBuffer(buffer, isDeep) { - if (isDeep) { - return buffer.slice(); - } - var result = new buffer.constructor(buffer.length); - buffer.copy(result); - return result; - } - - /** - * Creates a clone of `arrayBuffer`. - * - * @private - * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @param {ArrayBuffer} buffer The array buffer to clone. * @returns {ArrayBuffer} Returns the cloned array buffer. */ - function cloneArrayBuffer(arrayBuffer) { - var result = new arrayBuffer.constructor(arrayBuffer.byteLength); - new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + function bufferClone(buffer) { + var result = new ArrayBuffer(buffer.byteLength), + view = new Uint8Array(result); + + view.set(new Uint8Array(buffer)); return result; } - /** - * Creates a clone of `dataView`. - * - * @private - * @param {Object} dataView The data view to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned data view. - */ - function cloneDataView(dataView, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; - return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); - } - - /** - * Creates a clone of `map`. - * - * @private - * @param {Object} map The map to clone. - * @param {Function} cloneFunc The function to clone values. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned map. - */ - function cloneMap(map, isDeep, cloneFunc) { - var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map); - return arrayReduce(array, addMapEntry, new map.constructor); - } - - /** - * Creates a clone of `regexp`. - * - * @private - * @param {Object} regexp The regexp to clone. - * @returns {Object} Returns the cloned regexp. - */ - function cloneRegExp(regexp) { - var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); - result.lastIndex = regexp.lastIndex; - return result; - } - - /** - * Creates a clone of `set`. - * - * @private - * @param {Object} set The set to clone. - * @param {Function} cloneFunc The function to clone values. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned set. - */ - function cloneSet(set, isDeep, cloneFunc) { - var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set); - return arrayReduce(array, addSetEntry, new set.constructor); - } - - /** - * Creates a clone of the `symbol` object. - * - * @private - * @param {Object} symbol The symbol object to clone. - * @returns {Object} Returns the cloned symbol object. - */ - function cloneSymbol(symbol) { - return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; - } - - /** - * Creates a clone of `typedArray`. - * - * @private - * @param {Object} typedArray The typed array to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned typed array. - */ - function cloneTypedArray(typedArray, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; - return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); - } - - /** - * Compares values to sort them in ascending order. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function compareAscending(value, other) { - if (value !== other) { - var valIsDefined = value !== undefined, - valIsNull = value === null, - valIsReflexive = value === value, - valIsSymbol = isSymbol(value); - - var othIsDefined = other !== undefined, - othIsNull = other === null, - othIsReflexive = other === other, - othIsSymbol = isSymbol(other); - - if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || - (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || - (valIsNull && othIsDefined && othIsReflexive) || - (!valIsDefined && othIsReflexive) || - !valIsReflexive) { - return 1; - } - if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || - (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || - (othIsNull && valIsDefined && valIsReflexive) || - (!othIsDefined && valIsReflexive) || - !othIsReflexive) { - return -1; - } - } - return 0; - } - - /** - * Used by `_.orderBy` to compare multiple properties of a value to another - * and stable sort them. - * - * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, - * specify an order of "desc" for descending or "asc" for ascending sort order - * of corresponding values. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {boolean[]|string[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, - objCriteria = object.criteria, - othCriteria = other.criteria, - length = objCriteria.length, - ordersLength = orders.length; - - while (++index < length) { - var result = compareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; - } - var order = orders[index]; - return result * (order == 'desc' ? -1 : 1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } - /** * Creates an array that is the composition of partially applied arguments, * placeholders, and provided arguments into a single array of arguments. * * @private - * @param {Array} args The provided arguments. + * @param {Array|Object} 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. * @returns {Array} Returns the new array of composed arguments. */ - function composeArgs(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersLength = holders.length, + function composeArgs(args, partials, holders) { + var holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), leftIndex = -1, leftLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(leftLength + rangeLength), - isUncurried = !isCurried; + result = Array(leftLength + argsLength); while (++leftIndex < leftLength) { result[leftIndex] = partials[leftIndex]; } while (++argsIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[holders[argsIndex]] = args[argsIndex]; - } + result[holders[argsIndex]] = args[argsIndex]; } - while (rangeLength--) { + while (argsLength--) { result[leftIndex++] = args[argsIndex++]; } return result; @@ -4549,24 +2935,21 @@ * is tailored for `_.partialRight`. * * @private - * @param {Array} args The provided arguments. + * @param {Array|Object} 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. * @returns {Array} Returns the new array of composed arguments. */ - function composeArgsRight(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersIndex = -1, + function composeArgsRight(args, partials, holders) { + var holdersIndex = -1, holdersLength = holders.length, + argsIndex = -1, + argsLength = nativeMax(args.length - holdersLength, 0), rightIndex = -1, rightLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(rangeLength + rightLength), - isUncurried = !isCurried; + result = Array(argsLength + rightLength); - while (++argsIndex < rangeLength) { + while (++argsIndex < argsLength) { result[argsIndex] = args[argsIndex]; } var offset = argsIndex; @@ -4574,116 +2957,71 @@ result[offset + rightIndex] = partials[rightIndex]; } while (++holdersIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } + result[offset + holders[holdersIndex]] = args[argsIndex++]; } return result; } /** - * Copies the values of `source` to `array`. + * Creates a `_.countBy`, `_.groupBy`, `_.indexBy`, or `_.partition` function. * * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function copyArray(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } - - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ - function copyObject(source, props, object, customizer) { - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; - - assignValue(object, key, newValue === undefined ? source[key] : newValue); - } - return object; - } - - /** - * Copies own symbol properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbols(source, object) { - return copyObject(source, getSymbols(source), object); - } - - /** - * Creates a function like `_.groupBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} [initializer] The accumulator object initializer. + * @param {Function} setter The function to set keys and values of the accumulator object. + * @param {Function} [initializer] The function to initialize the accumulator object. * @returns {Function} Returns the new aggregator function. */ function createAggregator(setter, initializer) { - return function(collection, iteratee) { - var func = isArray(collection) ? arrayAggregator : baseAggregator, - accumulator = initializer ? initializer() : {}; + return function(collection, iteratee, thisArg) { + var result = initializer ? initializer() : {}; + iteratee = getCallback(iteratee, thisArg, 3); - return func(collection, setter, getIteratee(iteratee, 2), accumulator); + if (isArray(collection)) { + var index = -1, + length = collection.length; + + while (++index < length) { + var value = collection[index]; + setter(result, value, iteratee(value, index, collection), collection); + } + } else { + baseEach(collection, function(value, key, collection) { + setter(result, value, iteratee(value, key, collection), collection); + }); + } + return result; }; } /** - * Creates a function like `_.assign`. + * Creates a `_.assign`, `_.defaults`, or `_.merge` function. * * @private * @param {Function} assigner The function to assign values. * @returns {Function} Returns the new assigner function. */ function createAssigner(assigner) { - return baseRest(function(object, sources) { + return restParam(function(object, sources) { var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined, - guard = length > 2 ? sources[2] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; + length = object == null ? 0 : sources.length, + customizer = length > 2 ? sources[length - 2] : undefined, + guard = length > 2 ? sources[2] : undefined, + thisArg = length > 1 ? sources[length - 1] : undefined; + if (typeof customizer == 'function') { + customizer = bindCallback(customizer, thisArg, 5); + length -= 2; + } else { + customizer = typeof thisArg == 'function' ? thisArg : undefined; + length -= (customizer ? 1 : 0); + } if (guard && isIterateeCall(sources[0], sources[1], guard)) { customizer = length < 3 ? undefined : customizer; length = 1; } - object = Object(object); while (++index < length) { var source = sources[index]; if (source) { - assigner(object, source, index, customizer); + assigner(object, source, customizer); } } return object; @@ -4700,15 +3038,12 @@ */ function createBaseEach(eachFunc, fromRight) { return function(collection, iteratee) { - if (collection == null) { - return collection; - } - if (!isArrayLike(collection)) { + var length = collection ? getLength(collection) : 0; + if (!isLength(length)) { return eachFunc(collection, iteratee); } - var length = collection.length, - index = fromRight ? length : -1, - iterable = Object(collection); + var index = fromRight ? length : -1, + iterable = toObject(collection); while ((fromRight ? index-- : ++index < length)) { if (iteratee(iterable[index], index, iterable) === false) { @@ -4720,7 +3055,7 @@ } /** - * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * Creates a base function for `_.forIn` or `_.forInRight`. * * @private * @param {boolean} [fromRight] Specify iterating from right to left. @@ -4728,13 +3063,13 @@ */ function createBaseFor(fromRight) { return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), + var iterable = toObject(object), props = keysFunc(object), - length = props.length; + length = props.length, + index = fromRight ? length : -1; - while (length--) { - var key = props[fromRight ? length : ++index]; + while ((fromRight ? index-- : ++index < length)) { + var key = props[index]; if (iteratee(iterable[key], key, iterable) === false) { break; } @@ -4744,55 +3079,38 @@ } /** - * Creates a function that wraps `func` to invoke it with the optional `this` + * Creates a function that wraps `func` and invokes it with the `this` * binding of `thisArg`. * * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} func The function to bind. * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new wrapped function. + * @returns {Function} Returns the new bound function. */ - function createBind(func, bitmask, thisArg) { - var isBind = bitmask & BIND_FLAG, - Ctor = createCtor(func); + function createBindWrapper(func, thisArg) { + var Ctor = createCtorWrapper(func); function wrapper() { var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(isBind ? thisArg : this, arguments); + return fn.apply(thisArg, arguments); } return wrapper; } /** - * Creates a function like `_.lowerFirst`. + * Creates a `Set` cache object to optimize linear searches of large arrays. * * @private - * @param {string} methodName The name of the `String` case method to use. - * @returns {Function} Returns the new case function. + * @param {Array} [values] The values to cache. + * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`. */ - function createCaseFirst(methodName) { - return function(string) { - string = toString(string); - - var strSymbols = hasUnicode(string) - ? stringToArray(string) - : undefined; - - var chr = strSymbols - ? strSymbols[0] - : string.charAt(0); - - var trailing = strSymbols - ? castSlice(strSymbols, 1).join('') - : string.slice(1); - - return chr[methodName]() + trailing; - }; + function createCache(values) { + return (nativeCreate && Set) ? new SetCache(values) : null; } /** - * Creates a function like `_.camelCase`. + * Creates a function that produces compound words out of the words in a + * given string. * * @private * @param {Function} callback The function to combine each word. @@ -4800,7 +3118,15 @@ */ function createCompounder(callback) { return function(string) { - return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); + var index = -1, + array = words(deburr(string)), + length = array.length, + result = ''; + + while (++index < length) { + result = callback(result, array[index], index); + } + return result; }; } @@ -4812,10 +3138,10 @@ * @param {Function} Ctor The constructor to wrap. * @returns {Function} Returns the new wrapped function. */ - function createCtor(Ctor) { + function createCtorWrapper(Ctor) { return function() { - // Use a `switch` statement to work with class constructors. See - // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist + // Use a `switch` statement to work with class constructors. + // See http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist // for more details. var args = arguments; switch (args.length) { @@ -4838,59 +3164,115 @@ } /** - * Creates a function that wraps `func` to enable currying. + * Creates a `_.curry` or `_.curryRight` function. * * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {number} arity The arity of `func`. - * @returns {Function} Returns the new wrapped function. + * @param {boolean} flag The curry bit flag. + * @returns {Function} Returns the new curry function. */ - function createCurry(func, bitmask, arity) { - var Ctor = createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length, - placeholder = getHolder(wrapper); - - while (index--) { - args[index] = arguments[index]; + function createCurry(flag) { + function curryFunc(func, arity, guard) { + if (guard && isIterateeCall(func, arity, guard)) { + arity = undefined; } - var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) - ? [] - : replaceHolders(args, placeholder); - - length -= holders.length; - if (length < arity) { - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, undefined, - args, holders, undefined, undefined, arity - length); - } - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return apply(fn, this, args); + var result = createWrapper(func, flag, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curryFunc.placeholder; + return result; } - return wrapper; + return curryFunc; + } + + /** + * Creates a `_.defaults` or `_.defaultsDeep` function. + * + * @private + * @param {Function} assigner The function to assign values. + * @param {Function} customizer The function to customize assigned values. + * @returns {Function} Returns the new defaults function. + */ + function createDefaults(assigner, customizer) { + return restParam(function(args) { + var object = args[0]; + if (object == null) { + return object; + } + args.push(customizer); + return assigner.apply(undefined, args); + }); + } + + /** + * Creates a `_.max` or `_.min` function. + * + * @private + * @param {Function} comparator The function used to compare values. + * @param {*} exValue The initial extremum value. + * @returns {Function} Returns the new extremum function. + */ + function createExtremum(comparator, exValue) { + return function(collection, iteratee, thisArg) { + if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + iteratee = undefined; + } + iteratee = getCallback(iteratee, thisArg, 3); + if (iteratee.length == 1) { + collection = isArray(collection) ? collection : toIterable(collection); + var result = arrayExtremum(collection, iteratee, comparator, exValue); + if (!(collection.length && result === exValue)) { + return result; + } + } + return baseExtremum(collection, iteratee, comparator, exValue); + }; } /** * Creates a `_.find` or `_.findLast` function. * * @private - * @param {Function} findIndexFunc The function to find the collection index. + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. * @returns {Function} Returns the new find function. */ - function createFind(findIndexFunc) { - return function(collection, predicate, fromIndex) { - var iterable = Object(collection); - if (!isArrayLike(collection)) { - var iteratee = getIteratee(predicate, 3); - collection = keys(collection); - predicate = function(key) { return iteratee(iterable[key], key, iterable); }; + function createFind(eachFunc, fromRight) { + return function(collection, predicate, thisArg) { + predicate = getCallback(predicate, thisArg, 3); + if (isArray(collection)) { + var index = baseFindIndex(collection, predicate, fromRight); + return index > -1 ? collection[index] : undefined; } - var index = findIndexFunc(collection, predicate, fromIndex); - return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; + return baseFind(collection, predicate, eachFunc); + }; + } + + /** + * Creates a `_.findIndex` or `_.findLastIndex` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new find function. + */ + function createFindIndex(fromRight) { + return function(array, predicate, thisArg) { + if (!(array && array.length)) { + return -1; + } + predicate = getCallback(predicate, thisArg, 3); + return baseFindIndex(array, predicate, fromRight); + }; + } + + /** + * Creates a `_.findKey` or `_.findLastKey` function. + * + * @private + * @param {Function} objectFunc The function to iterate over an object. + * @returns {Function} Returns the new find function. + */ + function createFindKey(objectFunc) { + return function(object, predicate, thisArg) { + predicate = getCallback(predicate, thisArg, 3); + return baseFind(object, predicate, objectFunc, true); }; } @@ -4902,49 +3284,40 @@ * @returns {Function} Returns the new flow function. */ function createFlow(fromRight) { - return baseRest(function(funcs) { - funcs = baseFlatten(funcs, 1); + return function() { + var wrapper, + length = arguments.length, + index = fromRight ? length : -1, + leftIndex = 0, + funcs = Array(length); - var length = funcs.length, - index = length, - prereq = LodashWrapper.prototype.thru; - - if (fromRight) { - funcs.reverse(); - } - while (index--) { - var func = funcs[index]; + while ((fromRight ? index-- : ++index < length)) { + var func = funcs[leftIndex++] = arguments[index]; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } - if (prereq && !wrapper && getFuncName(func) == 'wrapper') { - var wrapper = new LodashWrapper([], true); + if (!wrapper && LodashWrapper.prototype.thru && getFuncName(func) == 'wrapper') { + wrapper = new LodashWrapper([], true); } } - index = wrapper ? index : length; + index = wrapper ? -1 : length; while (++index < length) { func = funcs[index]; var funcName = getFuncName(func), data = funcName == 'wrapper' ? getData(func) : undefined; - if (data && isLaziable(data[0]) && - data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && - !data[4].length && data[9] == 1 - ) { + if (data && isLaziable(data[0]) && data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) && !data[4].length && data[9] == 1) { wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); } else { - wrapper = (func.length == 1 && isLaziable(func)) - ? wrapper[funcName]() - : wrapper.thru(func); + wrapper = (func.length == 1 && isLaziable(func)) ? wrapper[funcName]() : wrapper.thru(func); } } return function() { var args = arguments, value = args[0]; - if (wrapper && args.length == 1 && - isArray(value) && value.length >= LARGE_ARRAY_SIZE) { + if (wrapper && args.length == 1 && isArray(value) && value.length >= LARGE_ARRAY_SIZE) { return wrapper.plant(value).value(); } var index = 0, @@ -4955,76 +3328,207 @@ } return result; }; - }); + }; } /** - * Creates a function that wraps `func` to invoke it with optional `this` - * binding of `thisArg`, partial application, and currying. + * Creates a function for `_.forEach` or `_.forEachRight`. * * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} arrayFunc The function to iterate over an array. + * @param {Function} eachFunc The function to iterate over a collection. + * @returns {Function} Returns the new each function. + */ + function createForEach(arrayFunc, eachFunc) { + return function(collection, iteratee, thisArg) { + return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) + ? arrayFunc(collection, iteratee) + : eachFunc(collection, bindCallback(iteratee, thisArg, 3)); + }; + } + + /** + * Creates a function for `_.forIn` or `_.forInRight`. + * + * @private + * @param {Function} objectFunc The function to iterate over an object. + * @returns {Function} Returns the new each function. + */ + function createForIn(objectFunc) { + return function(object, iteratee, thisArg) { + if (typeof iteratee != 'function' || thisArg !== undefined) { + iteratee = bindCallback(iteratee, thisArg, 3); + } + return objectFunc(object, iteratee, keysIn); + }; + } + + /** + * Creates a function for `_.forOwn` or `_.forOwnRight`. + * + * @private + * @param {Function} objectFunc The function to iterate over an object. + * @returns {Function} Returns the new each function. + */ + function createForOwn(objectFunc) { + return function(object, iteratee, thisArg) { + if (typeof iteratee != 'function' || thisArg !== undefined) { + iteratee = bindCallback(iteratee, thisArg, 3); + } + return objectFunc(object, iteratee); + }; + } + + /** + * Creates a function for `_.mapKeys` or `_.mapValues`. + * + * @private + * @param {boolean} [isMapKeys] Specify mapping keys instead of values. + * @returns {Function} Returns the new map function. + */ + function createObjectMapper(isMapKeys) { + return function(object, iteratee, thisArg) { + var result = {}; + iteratee = getCallback(iteratee, thisArg, 3); + + baseForOwn(object, function(value, key, object) { + var mapped = iteratee(value, key, object); + key = isMapKeys ? mapped : key; + value = isMapKeys ? value : mapped; + result[key] = value; + }); + return result; + }; + } + + /** + * Creates a function for `_.padLeft` or `_.padRight`. + * + * @private + * @param {boolean} [fromRight] Specify padding from the right. + * @returns {Function} Returns the new pad function. + */ + function createPadDir(fromRight) { + return function(string, length, chars) { + string = baseToString(string); + return (fromRight ? string : '') + createPadding(string, length, chars) + (fromRight ? '' : string); + }; + } + + /** + * Creates a `_.partial` or `_.partialRight` function. + * + * @private + * @param {boolean} flag The partial bit flag. + * @returns {Function} Returns the new partial function. + */ + function createPartial(flag) { + var partialFunc = restParam(function(func, partials) { + var holders = replaceHolders(partials, partialFunc.placeholder); + return createWrapper(func, flag, undefined, partials, holders); + }); + return partialFunc; + } + + /** + * Creates a function for `_.reduce` or `_.reduceRight`. + * + * @private + * @param {Function} arrayFunc The function to iterate over an array. + * @param {Function} eachFunc The function to iterate over a collection. + * @returns {Function} Returns the new each function. + */ + function createReduce(arrayFunc, eachFunc) { + return function(collection, iteratee, accumulator, thisArg) { + var initFromArray = arguments.length < 3; + return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) + ? arrayFunc(collection, iteratee, accumulator, initFromArray) + : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc); + }; + } + + /** + * Creates a function that wraps `func` and invokes it with optional `this` + * binding of, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. + * @param {Array} [partials] The arguments to prepend to those provided to the new function. * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided - * to the new function. + * @param {Array} [partialsRight] The arguments to append to those provided to the new function. * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. * @param {Array} [argPos] The argument positions of the new function. * @param {number} [ary] The arity cap of `func`. * @param {number} [arity] The arity of `func`. * @returns {Function} Returns the new wrapped function. */ - function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { var isAry = bitmask & ARY_FLAG, isBind = bitmask & BIND_FLAG, isBindKey = bitmask & BIND_KEY_FLAG, - isCurried = bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG), - isFlip = bitmask & FLIP_FLAG, - Ctor = isBindKey ? undefined : createCtor(func); + isCurry = bitmask & CURRY_FLAG, + isCurryBound = bitmask & CURRY_BOUND_FLAG, + isCurryRight = bitmask & CURRY_RIGHT_FLAG, + Ctor = isBindKey ? undefined : createCtorWrapper(func); function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it to other functions. var length = arguments.length, - args = Array(length), - index = length; + index = length, + args = Array(length); while (index--) { args[index] = arguments[index]; } - if (isCurried) { - var placeholder = getHolder(wrapper), - holdersCount = countHolders(args, placeholder); - } if (partials) { - args = composeArgs(args, partials, holders, isCurried); + args = composeArgs(args, partials, holders); } if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight, isCurried); + args = composeArgsRight(args, partialsRight, holdersRight); } - length -= holdersCount; - if (isCurried && length < arity) { - var newHolders = replaceHolders(args, placeholder); - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, thisArg, - args, newHolders, argPos, ary, arity - length - ); + if (isCurry || isCurryRight) { + var placeholder = wrapper.placeholder, + argsHolders = replaceHolders(args, placeholder); + + length -= argsHolders.length; + if (length < arity) { + var newArgPos = argPos ? arrayCopy(argPos) : undefined, + newArity = nativeMax(arity - length, 0), + newsHolders = isCurry ? argsHolders : undefined, + newHoldersRight = isCurry ? undefined : argsHolders, + newPartials = isCurry ? args : undefined, + newPartialsRight = isCurry ? undefined : args; + + bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); + + if (!isCurryBound) { + bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); + } + var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity], + result = createHybridWrapper.apply(undefined, newData); + + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return result; + } } var thisBinding = isBind ? thisArg : this, fn = isBindKey ? thisBinding[func] : func; - length = args.length; if (argPos) { args = reorder(args, argPos); - } else if (isFlip && length > 1) { - args.reverse(); } - if (isAry && ary < length) { + if (isAry && ary < args.length) { args.length = ary; } if (this && this !== root && this instanceof wrapper) { - fn = Ctor || createCtor(fn); + fn = Ctor || createCtorWrapper(func); } return fn.apply(thisBinding, args); } @@ -5032,120 +3536,51 @@ } /** - * Creates a function like `_.invertBy`. + * Creates the padding required for `string` based on the given `length`. + * The `chars` string is truncated if the number of characters exceeds `length`. * * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} toIteratee The function to resolve iteratees. - * @returns {Function} Returns the new inverter function. - */ - function createInverter(setter, toIteratee) { - return function(object, iteratee) { - return baseInverter(object, setter, toIteratee(iteratee), {}); - }; - } - - /** - * Creates a function that performs a mathematical operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @param {number} [defaultValue] The value used for `undefined` arguments. - * @returns {Function} Returns the new mathematical operation function. - */ - function createMathOperation(operator, defaultValue) { - return function(value, other) { - var result; - if (value === undefined && other === undefined) { - return defaultValue; - } - if (value !== undefined) { - result = value; - } - if (other !== undefined) { - if (result === undefined) { - return other; - } - if (typeof value == 'string' || typeof other == 'string') { - value = baseToString(value); - other = baseToString(other); - } else { - value = baseToNumber(value); - other = baseToNumber(other); - } - result = operator(value, other); - } - return result; - }; - } - - /** - * Creates a function like `_.over`. - * - * @private - * @param {Function} arrayFunc The function to iterate over iteratees. - * @returns {Function} Returns the new over function. - */ - function createOver(arrayFunc) { - return baseRest(function(iteratees) { - iteratees = (iteratees.length == 1 && isArray(iteratees[0])) - ? arrayMap(iteratees[0], baseUnary(getIteratee())) - : arrayMap(baseFlatten(iteratees, 1), baseUnary(getIteratee())); - - return baseRest(function(args) { - var thisArg = this; - return arrayFunc(iteratees, function(iteratee) { - return apply(iteratee, thisArg, args); - }); - }); - }); - } - - /** - * Creates the padding for `string` based on `length`. The `chars` string - * is truncated if the number of characters exceeds `length`. - * - * @private - * @param {number} length The padding length. + * @param {string} string The string to create padding for. + * @param {number} [length=0] The padding length. * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padding for `string`. + * @returns {string} Returns the pad for `string`. */ - function createPadding(length, chars) { - chars = chars === undefined ? ' ' : baseToString(chars); + function createPadding(string, length, chars) { + var strLength = string.length; + length = +length; - var charsLength = chars.length; - if (charsLength < 2) { - return charsLength ? baseRepeat(chars, length) : chars; + if (strLength >= length || !nativeIsFinite(length)) { + return ''; } - var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); - return hasUnicode(chars) - ? castSlice(stringToArray(result), 0, length).join('') - : result.slice(0, length); + var padLength = length - strLength; + chars = chars == null ? ' ' : (chars + ''); + return repeat(chars, nativeCeil(padLength / chars.length)).slice(0, padLength); } /** - * Creates a function that wraps `func` to invoke it with the `this` binding - * of `thisArg` and `partials` prepended to the arguments it receives. + * Creates a function that wraps `func` and invokes it with the optional `this` + * binding of `thisArg` and the `partials` prepended to those provided to + * the wrapper. * * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} func The function to partially apply arguments to. + * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details. * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to - * the new function. - * @returns {Function} Returns the new wrapped function. + * @param {Array} partials The arguments to prepend to those provided to the new function. + * @returns {Function} Returns the new bound function. */ - function createPartial(func, bitmask, thisArg, partials) { + function createPartialWrapper(func, bitmask, thisArg, partials) { var isBind = bitmask & BIND_FLAG, - Ctor = createCtor(func); + Ctor = createCtorWrapper(func); function wrapper() { + // Avoid `arguments` object use disqualifying optimizations by + // converting it to an array before providing it `func`. var argsIndex = -1, argsLength = arguments.length, leftIndex = -1, leftLength = partials.length, - args = Array(leftLength + argsLength), - fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + args = Array(leftLength + argsLength); while (++leftIndex < leftLength) { args[leftIndex] = partials[leftIndex]; @@ -5153,98 +3588,14 @@ while (argsLength--) { args[leftIndex++] = arguments[++argsIndex]; } - return apply(fn, isBind ? thisArg : this, args); + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(isBind ? thisArg : this, args); } return wrapper; } /** - * Creates a `_.range` or `_.rangeRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new range function. - */ - function createRange(fromRight) { - return function(start, end, step) { - if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { - end = step = undefined; - } - // Ensure the sign of `-0` is preserved. - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); - return baseRange(start, end, step, fromRight); - }; - } - - /** - * Creates a function that performs a relational operation on two values. - * - * @private - * @param {Function} operator The function to perform the operation. - * @returns {Function} Returns the new relational operation function. - */ - function createRelationalOperation(operator) { - return function(value, other) { - if (!(typeof value == 'string' && typeof other == 'string')) { - value = toNumber(value); - other = toNumber(other); - } - return operator(value, other); - }; - } - - /** - * Creates a function that wraps `func` to continue currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {Function} wrapFunc The function to create the `func` wrapper. - * @param {*} placeholder The placeholder value. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { - var isCurry = bitmask & CURRY_FLAG, - newHolders = isCurry ? holders : undefined, - newHoldersRight = isCurry ? undefined : holders, - newPartials = isCurry ? partials : undefined, - newPartialsRight = isCurry ? undefined : partials; - - bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG); - bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG); - - if (!(bitmask & CURRY_BOUND_FLAG)) { - bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG); - } - var newData = [ - func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, - newHoldersRight, argPos, ary, arity - ]; - - var result = wrapFunc.apply(undefined, newData); - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return setWrapToString(result, func, bitmask); - } - - /** - * Creates a function like `_.round`. + * Creates a `_.ceil`, `_.floor`, or `_.round` function. * * @private * @param {string} methodName The name of the `Math` method to use when rounding. @@ -5253,49 +3604,28 @@ function createRound(methodName) { var func = Math[methodName]; return function(number, precision) { - number = toNumber(number); - precision = nativeMin(toInteger(precision), 292); + precision = precision === undefined ? 0 : (+precision || 0); if (precision) { - // Shift with exponential notation to avoid floating-point issues. - // See [MDN](https://mdn.io/round#Examples) for more details. - var pair = (toString(number) + 'e').split('e'), - value = func(pair[0] + 'e' + (+pair[1] + precision)); - - pair = (toString(value) + 'e').split('e'); - return +(pair[0] + 'e' + (+pair[1] - precision)); + precision = pow(10, precision); + return func(number * precision) / precision; } return func(number); }; } /** - * Creates a set object of `values`. + * Creates a `_.sortedIndex` or `_.sortedLastIndex` function. * * @private - * @param {Array} values The values to add to the set. - * @returns {Object} Returns the new set. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {Function} Returns the new index function. */ - var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { - 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)); + function createSortedIndex(retHighest) { + return function(array, value, iteratee, thisArg) { + var callback = getCallback(iteratee); + return (iteratee == null && callback === baseCallback) + ? binaryIndex(array, value, retHighest) + : binaryIndexBy(array, value, callback(iteratee, thisArg, 1), retHighest); }; } @@ -5304,8 +3634,8 @@ * `this` binding and partially applied arguments. * * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of flags. * The bitmask may be composed of the following flags: * 1 - `_.bind` * 2 - `_.bindKey` @@ -5316,7 +3646,6 @@ * 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. @@ -5325,7 +3654,7 @@ * @param {number} [arity] The arity of `func`. * @returns {Function} Returns the new wrapped function. */ - function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { var isBindKey = bitmask & BIND_KEY_FLAG; if (!isBindKey && typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); @@ -5335,49 +3664,34 @@ bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG); partials = holders = undefined; } - ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); - arity = arity === undefined ? arity : toInteger(arity); - length -= holders ? holders.length : 0; - + length -= (holders ? holders.length : 0); if (bitmask & PARTIAL_RIGHT_FLAG) { var partialsRight = partials, holdersRight = holders; partials = holders = undefined; } - var data = isBindKey ? undefined : getData(func); - - var newData = [ - func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, - argPos, ary, arity - ]; + var data = isBindKey ? undefined : getData(func), + newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity]; if (data) { mergeData(newData, data); + bitmask = newData[1]; + arity = newData[9]; } - func = newData[0]; - bitmask = newData[1]; - thisArg = newData[2]; - partials = newData[3]; - holders = newData[4]; - arity = newData[9] = newData[9] == null + newData[9] = arity == null ? (isBindKey ? 0 : func.length) - : nativeMax(newData[9] - length, 0); + : (nativeMax(arity - length, 0) || 0); - if (!arity && bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG)) { - bitmask &= ~(CURRY_FLAG | CURRY_RIGHT_FLAG); - } - if (!bitmask || bitmask == BIND_FLAG) { - var result = createBind(func, bitmask, thisArg); - } else if (bitmask == CURRY_FLAG || bitmask == CURRY_RIGHT_FLAG) { - result = createCurry(func, bitmask, arity); - } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !holders.length) { - result = createPartial(func, bitmask, thisArg, partials); + if (bitmask == BIND_FLAG) { + var result = createBindWrapper(newData[0], newData[2]); + } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) { + result = createPartialWrapper.apply(undefined, newData); } else { - result = createHybrid.apply(undefined, newData); + result = createHybridWrapper.apply(undefined, newData); } var setter = data ? baseSetData : setData; - return setWrapToString(setter(result, newData), func, bitmask); + return setter(result, newData); } /** @@ -5388,71 +3702,44 @@ * @param {Array} array The array to compare. * @param {Array} other The other array to compare. * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `array` and `other` objects. + * @param {Function} [customizer] The function to customize comparing arrays. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. */ - function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { - var isPartial = bitmask & PARTIAL_COMPARE_FLAG, + function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) { + var index = -1, arrLength = array.length, othLength = other.length; - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + if (arrLength != othLength && !(isLoose && othLength > arrLength)) { return false; } - // Assume cyclic values are equal. - var stacked = stack.get(array); - if (stacked && stack.get(other)) { - return stacked == other; - } - var index = -1, - result = true, - seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined; - - stack.set(array, other); - stack.set(other, array); - // Ignore non-index properties. while (++index < arrLength) { var arrValue = array[index], - othValue = other[index]; + othValue = other[index], + result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined; - if (customizer) { - var compared = isPartial - ? customizer(othValue, arrValue, index, other, array, stack) - : customizer(arrValue, othValue, index, array, other, stack); - } - if (compared !== undefined) { - if (compared) { + if (result !== undefined) { + if (result) { continue; } - result = false; - break; + return false; } // Recursively compare arrays (susceptible to call stack limits). - if (seen) { - if (!arraySome(other, function(othValue, othIndex) { - if (!seen.has(othIndex) && - (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) { - return seen.add(othIndex); - } + if (isLoose) { + if (!arraySome(other, function(othValue) { + return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB); })) { - result = false; - break; + return false; } - } else if (!( - arrValue === othValue || - equalFunc(arrValue, othValue, customizer, bitmask, stack) - )) { - result = false; - break; + } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) { + return false; } } - stack['delete'](array); - stack['delete'](other); - return result; + return true; } /** @@ -5466,74 +3753,30 @@ * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {string} tag The `toStringTag` of the objects to compare. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `object` and `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ - function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) { + function equalByTag(object, other, tag) { switch (tag) { - case dataViewTag: - if ((object.byteLength != other.byteLength) || - (object.byteOffset != other.byteOffset)) { - return false; - } - object = object.buffer; - other = other.buffer; - - case arrayBufferTag: - if ((object.byteLength != other.byteLength) || - !equalFunc(new Uint8Array(object), new Uint8Array(other))) { - return false; - } - return true; - case boolTag: case dateTag: - case numberTag: - // Coerce booleans to `1` or `0` and dates to milliseconds. - // Invalid dates are coerced to `NaN`. - return eq(+object, +other); + // Coerce dates and booleans to numbers, dates to milliseconds and booleans + // to `1` or `0` treating invalid dates coerced to `NaN` as not equal. + return +object == +other; case errorTag: return object.name == other.name && object.message == other.message; + case numberTag: + // Treat `NaN` vs. `NaN` as equal. + return (object != +object) + ? other != +other + : object == +other; + case regexpTag: case stringTag: - // Coerce regexes to strings and treat strings, primitives and objects, - // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring - // for more details. + // Coerce regexes to strings and treat strings primitives and string + // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details. return object == (other + ''); - - case mapTag: - var convert = mapToArray; - - case setTag: - var isPartial = bitmask & PARTIAL_COMPARE_FLAG; - convert || (convert = setToArray); - - if (object.size != other.size && !isPartial) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked) { - return stacked == other; - } - bitmask |= UNORDERED_COMPARE_FLAG; - - // Recursively compare objects (susceptible to call stack limits). - stack.set(object, other); - var result = equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack); - stack['delete'](object); - return result; - - case symbolTag: - if (symbolValueOf) { - return symbolValueOf.call(object) == symbolValueOf.call(other); - } } return false; } @@ -5546,60 +3789,42 @@ * @param {Object} object The object to compare. * @param {Object} other The other object to compare. * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Function} customizer The function to customize comparisons. - * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual` - * for more details. - * @param {Object} stack Tracks traversed `object` and `other` objects. + * @param {Function} [customizer] The function to customize comparing values. + * @param {boolean} [isLoose] Specify performing partial comparisons. + * @param {Array} [stackA] Tracks traversed `value` objects. + * @param {Array} [stackB] Tracks traversed `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ - function equalObjects(object, other, equalFunc, customizer, bitmask, stack) { - var isPartial = bitmask & PARTIAL_COMPARE_FLAG, - objProps = keys(object), + function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) { + var objProps = keys(object), objLength = objProps.length, othProps = keys(other), othLength = othProps.length; - if (objLength != othLength && !isPartial) { + if (objLength != othLength && !isLoose) { return false; } var index = objLength; while (index--) { var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { + if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) { return false; } } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked && stack.get(other)) { - return stacked == other; - } - var result = true; - stack.set(object, other); - stack.set(other, object); - - var skipCtor = isPartial; + var skipCtor = isLoose; while (++index < objLength) { key = objProps[index]; var objValue = object[key], - othValue = other[key]; + othValue = other[key], + result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined; - if (customizer) { - var compared = isPartial - ? customizer(othValue, objValue, key, other, object, stack) - : customizer(objValue, othValue, key, object, other, stack); - } // Recursively compare objects (susceptible to call stack limits). - if (!(compared === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack)) - : compared - )) { - result = false; - break; + if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) { + return false; } skipCtor || (skipCtor = key == 'constructor'); } - if (result && !skipCtor) { + if (!skipCtor) { var objCtor = object.constructor, othCtor = other.constructor; @@ -5608,35 +3833,25 @@ ('constructor' in object && 'constructor' in other) && !(typeof objCtor == 'function' && objCtor instanceof objCtor && typeof othCtor == 'function' && othCtor instanceof othCtor)) { - result = false; + return false; } } - stack['delete'](object); - stack['delete'](other); - return result; + return true; } /** - * Creates an array of own enumerable property names and symbols of `object`. + * Gets the appropriate "callback" function. If the `_.callback` method is + * customized this function returns the custom method, otherwise it returns + * the `baseCallback` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. * * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. + * @returns {Function} Returns the chosen function or its result. */ - function getAllKeys(object) { - return baseGetAllKeys(object, keys, getSymbols); - } - - /** - * Creates an array of own and inherited enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeysIn(object) { - return baseGetAllKeys(object, keysIn, getSymbolsIn); + function getCallback(func, thisArg, argCount) { + var result = lodash.callback || callback; + result = result === callback ? baseCallback : result; + return argCount ? result(func, thisArg, argCount) : result; } /** @@ -5660,7 +3875,7 @@ function getFuncName(func) { var result = (func.name + ''), array = realNames[result], - length = hasOwnProperty.call(realNames, result) ? array.length : 0; + length = array ? array.length : 0; while (length--) { var data = array[length], @@ -5673,65 +3888,45 @@ } /** - * Gets the argument placeholder value for `func`. + * Gets the appropriate "indexOf" function. If the `_.indexOf` method is + * customized this function returns the custom method, otherwise it returns + * the `baseIndexOf` function. If arguments are provided the chosen function + * is invoked with them and its result is returned. * * @private - * @param {Function} func The function to inspect. - * @returns {*} Returns the placeholder value. + * @returns {Function|number} Returns the chosen function or its result. */ - function getHolder(func) { - var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; - return object.placeholder; + function getIndexOf(collection, target, fromIndex) { + var result = lodash.indexOf || indexOf; + result = result === indexOf ? baseIndexOf : result; + return collection ? result(collection, target, fromIndex) : result; } /** - * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, - * this function returns the custom method, otherwise it returns `baseIteratee`. - * If arguments are provided, the chosen function is invoked with them and - * its result is returned. + * Gets the "length" property value of `object`. + * + * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) + * that affects Safari on at least iOS 8.1-8.3 ARM64. * * @private - * @param {*} [value] The value to convert to an iteratee. - * @param {number} [arity] The arity of the created iteratee. - * @returns {Function} Returns the chosen function or its result. + * @param {Object} object The object to query. + * @returns {*} Returns the "length" value. */ - function getIteratee() { - var result = lodash.iteratee || iteratee; - result = result === iteratee ? baseIteratee : result; - return arguments.length ? result(arguments[0], arguments[1]) : result; - } + 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`. + * Gets the propery names, values, and compare flags of `object`. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the match data of `object`. */ function getMatchData(object) { - var result = keys(object), + var result = pairs(object), length = result.length; while (length--) { - var key = result[length], - value = object[key]; - - result[length] = [key, value, isStrictComparable(value)]; + result[length][2] = isStrictComparable(result[length][1]); } return result; } @@ -5745,68 +3940,8 @@ * @returns {*} Returns the function if it's native, else `undefined`. */ function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; - } - - /** - * Creates an array of the own enumerable symbol properties of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbols = nativeGetSymbols ? overArg(nativeGetSymbols, Object) : stubArray; - - /** - * Creates an array of the own and inherited enumerable symbol properties - * of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { - var result = []; - while (object) { - arrayPush(result, getSymbols(object)); - object = getPrototype(object); - } - return result; - }; - - /** - * Gets the `toStringTag` of `value`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - var getTag = baseGetTag; - - // Fallback for data views, maps, sets, and weak maps in IE 11, - // for data views in Edge < 14, and promises in Node.js. - if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || - (Map && getTag(new Map) != mapTag) || - (Promise && getTag(Promise.resolve()) != promiseTag) || - (Set && getTag(new Set) != setTag) || - (WeakMap && getTag(new WeakMap) != weakMapTag)) { - getTag = function(value) { - var result = objectToString.call(value), - Ctor = result == objectTag ? value.constructor : undefined, - ctorString = Ctor ? toSource(Ctor) : undefined; - - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: return dataViewTag; - case mapCtorString: return mapTag; - case promiseCtorString: return promiseTag; - case setCtorString: return setTag; - case weakMapCtorString: return weakMapTag; - } - } - return result; - }; + var value = object == null ? undefined : object[key]; + return isNative(value) ? value : undefined; } /** @@ -5837,49 +3972,6 @@ return { 'start': start, 'end': end }; } - /** - * Extracts wrapper details from the `source` body comment. - * - * @private - * @param {string} source The source to inspect. - * @returns {Array} Returns the wrapper details. - */ - function getWrapDetails(source) { - var match = source.match(reWrapDetails); - return match ? match[1].split(reSplitDetails) : []; - } - - /** - * Checks if `path` exists on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @param {Function} hasFunc The function to check properties. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - */ - function hasPath(object, path, hasFunc) { - path = isKey(path, object) ? [path] : castPath(path); - - var result, - index = -1, - length = path.length; - - while (++index < length) { - var key = toKey(path[index]); - if (!(result = object != null && hasFunc(object, key))) { - break; - } - object = object[key]; - } - if (result) { - return result; - } - var length = object ? object.length : 0; - return !!length && isLength(length) && isIndex(key, length) && - (isArray(object) || isArguments(object)); - } - /** * Initializes an array clone. * @@ -5889,9 +3981,9 @@ */ function initCloneArray(array) { var length = array.length, - result = array.constructor(length); + result = new array.constructor(length); - // Add properties assigned by `RegExp#exec`. + // Add array properties assigned by `RegExp#exec`. if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { result.index = array.index; result.input = array.input; @@ -5907,9 +3999,11 @@ * @returns {Object} Returns the initialized clone. */ function initCloneObject(object) { - return (typeof object.constructor == 'function' && !isPrototype(object)) - ? baseCreate(getPrototype(object)) - : {}; + var Ctor = object.constructor; + if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { + Ctor = Object; + } + return new Ctor; } /** @@ -5921,73 +4015,64 @@ * @private * @param {Object} object The object to clone. * @param {string} tag The `toStringTag` of the object to clone. - * @param {Function} cloneFunc The function to clone values. * @param {boolean} [isDeep] Specify a deep clone. * @returns {Object} Returns the initialized clone. */ - function initCloneByTag(object, tag, cloneFunc, isDeep) { + function initCloneByTag(object, tag, isDeep) { var Ctor = object.constructor; switch (tag) { case arrayBufferTag: - return cloneArrayBuffer(object); + return bufferClone(object); case boolTag: case dateTag: return new Ctor(+object); - case dataViewTag: - return cloneDataView(object, isDeep); - case float32Tag: case float64Tag: case int8Tag: case int16Tag: case int32Tag: case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - return cloneTypedArray(object, isDeep); - - case mapTag: - return cloneMap(object, isDeep, cloneFunc); + var buffer = object.buffer; + return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); case numberTag: case stringTag: return new Ctor(object); case regexpTag: - return cloneRegExp(object); - - case setTag: - return cloneSet(object, isDeep, cloneFunc); - - case symbolTag: - return cloneSymbol(object); + var result = new Ctor(object.source, reFlags.exec(object)); + result.lastIndex = object.lastIndex; } + return result; } /** - * Inserts wrapper `details` in a comment at the top of the `source` body. + * Invokes the method at `path` on `object`. * * @private - * @param {string} source The source to modify. - * @returns {Array} details The details to insert. - * @returns {string} Returns the modified source. + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. */ - function insertWrapDetails(source, details) { - var length = details.length, - lastIndex = length - 1; - - details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; - details = details.join(length > 2 ? ', ' : ' '); - return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); + function invokePath(object, path, args) { + if (object != null && !isKey(path, object)) { + path = toPath(path); + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + path = last(path); + } + var func = object == null ? object : object[path]; + return func == null ? undefined : func.apply(object, args); } /** - * Checks if `value` is a flattenable `arguments` object or array. + * Checks if `value` is array-like. * * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. */ - function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); + function isArrayLike(value) { + return value != null && isLength(getLength(value)); } /** @@ -5999,21 +4084,19 @@ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. */ function isIndex(value, length) { + value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1; length = length == null ? MAX_SAFE_INTEGER : length; - return !!length && - (typeof value == 'number' || reIsUint.test(value)) && - (value > -1 && value % 1 == 0 && value < length); + return value > -1 && value % 1 == 0 && value < length; } /** - * Checks if the given arguments are from an iteratee call. + * Checks if the provided arguments are from an iteratee call. * * @private * @param {*} value The potential iteratee value argument. * @param {*} index The potential iteratee index or key argument. * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, - * else `false`. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. */ function isIterateeCall(value, index, object) { if (!isObject(object)) { @@ -6021,10 +4104,10 @@ } var type = typeof index; if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object) - ) { - return eq(object[index], value); + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object)) { + var other = object[index]; + return value === value ? (value === other) : (other !== other); } return false; } @@ -6038,30 +4121,15 @@ * @returns {boolean} Returns `true` if `value` is a property name, else `false`. */ function isKey(value, object) { + var type = typeof value; + if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') { + return true; + } if (isArray(value)) { return false; } - var type = typeof value; - if (type == 'number' || type == 'symbol' || type == 'boolean' || - value == null || isSymbol(value)) { - return true; - } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); - } - - /** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ - function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); + var result = !reIsDeepProp.test(value); + return result || (object != null && value in toObject(object)); } /** @@ -6069,8 +4137,7 @@ * * @private * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, - * else `false`. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`. */ function isLaziable(func) { var funcName = getFuncName(func), @@ -6087,37 +4154,16 @@ } /** - * Checks if `func` has its source masked. + * Checks if `value` is a valid array-like length. * - * @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. + * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). * * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `func` is maskable, else `false`. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. */ - var isMaskable = coreJsData ? isFunction : stubFalse; - - /** - * Checks if `value` is likely a prototype object. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ - function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - - return value === proto; + function isLength(value) { + return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } /** @@ -6132,35 +4178,15 @@ return value === value && !isObject(value); } - /** - * A specialized version of `matchesProperty` for source values suitable - * for strict equality comparisons, i.e. `===`. - * - * @private - * @param {string} key The key of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function matchesStrictComparable(key, srcValue) { - return function(object) { - if (object == null) { - return false; - } - return object[key] === srcValue && - (srcValue !== undefined || (key in Object(object))); - }; - } - /** * Merges the function metadata of `source` into `data`. * - * Merging metadata reduces the number of wrappers used to invoke a function. + * Merging metadata reduces the number of wrappers required to invoke a function. * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and - * `_.rearg` modify function arguments, making the order in which they are - * executed important, preventing the merging of metadata. However, we make - * an exception for a safe combined case where curried functions have `_.ary` - * and or `_.rearg` applied. + * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg` + * augment function arguments, making the order in which they are executed important, + * preventing the merging of metadata. However, we make an exception for a safe + * common case where curried functions have `_.ary` and or `_.rearg` applied. * * @private * @param {Array} data The destination metadata. @@ -6171,12 +4197,12 @@ var bitmask = data[1], srcBitmask = source[1], newBitmask = bitmask | srcBitmask, - isCommon = newBitmask < (BIND_FLAG | BIND_KEY_FLAG | ARY_FLAG); + isCommon = newBitmask < ARY_FLAG; var isCombo = - ((srcBitmask == ARY_FLAG) && (bitmask == CURRY_FLAG)) || - ((srcBitmask == ARY_FLAG) && (bitmask == REARG_FLAG) && (data[7].length <= source[8])) || - ((srcBitmask == (ARY_FLAG | REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == CURRY_FLAG)); + (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) || + (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) || + (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG); // Exit early if metadata can't be merged. if (!(isCommon || isCombo)) { @@ -6186,26 +4212,26 @@ if (srcBitmask & BIND_FLAG) { data[2] = source[2]; // Set when currying a bound function. - newBitmask |= bitmask & BIND_FLAG ? 0 : CURRY_BOUND_FLAG; + newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG; } // Compose partial arguments. var value = source[3]; if (value) { var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : value; - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; + data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value); + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]); } // Compose partial right arguments. value = source[5]; if (value) { partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value); + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]); } // Use source `argPos` if available. value = source[7]; if (value) { - data[7] = value; + data[7] = arrayCopy(value); } // Use source `ary` if it's smaller. if (srcBitmask & ARY_FLAG) { @@ -6226,54 +4252,56 @@ * Used by `_.defaultsDeep` to customize its `_.merge` use. * * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to merge. - * @param {Object} object The parent object of `objValue`. - * @param {Object} source The parent object of `srcValue`. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - * @returns {*} Returns the value to assign. + * @param {*} objectValue The destination object property value. + * @param {*} sourceValue The source object property value. + * @returns {*} Returns the value to assign to the destination object. */ - function mergeDefaults(objValue, srcValue, key, object, source, stack) { - if (isObject(objValue) && isObject(srcValue)) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, objValue); - baseMerge(objValue, srcValue, undefined, mergeDefaults, stack); - stack['delete'](srcValue); - } - return objValue; + function mergeDefaults(objectValue, sourceValue) { + return objectValue === undefined ? sourceValue : merge(objectValue, sourceValue, mergeDefaults); } /** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. + * A specialized version of `_.pick` which picks `object` properties specified + * by `props`. * * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. + * @param {Object} object The source object. + * @param {string[]} props The property names to pick. + * @returns {Object} Returns the new object. */ - function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); + function pickByArray(object, props) { + object = toObject(object); + + var index = -1, + length = props.length, + result = {}; + + while (++index < length) { + var key = props[index]; + if (key in object) { + result[key] = object[key]; } } return result; } /** - * Gets the parent value at `path` of `object`. + * A specialized version of `_.pick` which picks `object` properties `predicate` + * returns truthy for. * * @private - * @param {Object} object The object to query. - * @param {Array} path The path to get the parent value of. - * @returns {*} Returns the parent value. + * @param {Object} object The source object. + * @param {Function} predicate The function invoked per iteration. + * @returns {Object} Returns the new object. */ - function parent(object, path) { - return path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + function pickByCallback(object, predicate) { + var result = {}; + baseForIn(object, function(value, key, object) { + if (predicate(value, key, object)) { + result[key] = value; + } + }); + return result; } /** @@ -6289,7 +4317,7 @@ function reorder(array, indexes) { var arrLength = array.length, length = nativeMin(indexes.length, arrLength), - oldArray = copyArray(array); + oldArray = arrayCopy(array); while (length--) { var index = indexes[length]; @@ -6302,9 +4330,8 @@ * Sets metadata for `func`. * * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity - * function to avoid garbage collection pauses in V8. See - * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) + * period of time, it will trip its breaker and transition to an identity function + * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070) * for more details. * * @private @@ -6333,106 +4360,77 @@ }()); /** - * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). + * A fallback implementation of `Object.keys` which creates an array of the + * own enumerable property names of `object`. * * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @returns {number|Object} Returns the timer id or timeout object. + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. */ - var setTimeout = ctxSetTimeout || function(func, wait) { - return root.setTimeout(func, wait); - }; + function shimKeys(object) { + var props = keysIn(object), + propsLength = props.length, + length = propsLength && object.length; + + var allowIndexes = !!length && isLength(length) && + (isArray(object) || isArguments(object)); + + var index = -1, + result = []; + + while (++index < propsLength) { + var key = props[index]; + if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { + result.push(key); + } + } + return result; + } /** - * Sets the `toString` method of `wrapper` to mimic the source of `reference` - * with wrapper details in a comment at the top of the source body. + * Converts `value` to an array-like object if it's not one. * * @private - * @param {Function} wrapper The function to modify. - * @param {Function} reference The reference function. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Function} Returns `wrapper`. + * @param {*} value The value to process. + * @returns {Array|Object} Returns the array-like object. */ - var setWrapToString = !defineProperty ? identity : function(wrapper, reference, bitmask) { - var source = (reference + ''); - return defineProperty(wrapper, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))) - }); - }; + function toIterable(value) { + if (value == null) { + return []; + } + if (!isArrayLike(value)) { + return values(value); + } + return isObject(value) ? value : Object(value); + } /** - * Converts `string` to a property path array. + * Converts `value` to an object if it's not one. * * @private - * @param {string} string The string to convert. + * @param {*} value The value to process. + * @returns {Object} Returns the object. + */ + function toObject(value) { + return isObject(value) ? value : Object(value); + } + + /** + * Converts `value` to property path array if it's not one. + * + * @private + * @param {*} value The value to process. * @returns {Array} Returns the property path array. */ - var stringToPath = memoize(function(string) { - string = toString(string); - - var result = []; - if (reLeadingDot.test(string)) { - result.push(''); + function toPath(value) { + if (isArray(value)) { + return value; } - string.replace(rePropName, function(match, number, quote, string) { + var result = []; + baseToString(value).replace(rePropName, function(match, number, quote, string) { result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match)); }); return result; - }); - - /** - * Converts `value` to a string key if it's not a string or symbol. - * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. - */ - function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to process. - * @returns {string} Returns the source code. - */ - function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; - } - - /** - * Updates wrapper `details` based on `bitmask` flags. - * - * @private - * @returns {Array} details The details to modify. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Array} Returns `details`. - */ - function updateWrapDetails(details, bitmask) { - arrayEach(wrapFlags, function(pair) { - var value = '_.' + pair[0]; - if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { - details.push(value); - } - }); - return details.sort(); } /** @@ -6443,31 +4441,25 @@ * @returns {Object} Returns the cloned wrapper. */ function wrapperClone(wrapper) { - if (wrapper instanceof LazyWrapper) { - return wrapper.clone(); - } - var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); - result.__actions__ = copyArray(wrapper.__actions__); - result.__index__ = wrapper.__index__; - result.__values__ = wrapper.__values__; - return result; + return wrapper instanceof LazyWrapper + ? wrapper.clone() + : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__)); } /*------------------------------------------------------------------------*/ /** * Creates an array of elements split into groups the length of `size`. - * If `array` can't be split evenly, the final chunk will be the remaining + * If `collection` can't be split evenly, the final chunk will be the remaining * elements. * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @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 of chunks. + * @param {number} [size=1] The length of each chunk. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the new array containing chunks. * @example * * _.chunk(['a', 'b', 'c', 'd'], 2); @@ -6477,21 +4469,18 @@ * // => [['a', 'b', 'c'], ['d']] */ function chunk(array, size, guard) { - if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { + if (guard ? isIterateeCall(array, size, guard) : size == null) { size = 1; } else { - size = nativeMax(toInteger(size), 0); - } - var length = array ? array.length : 0; - if (!length || size < 1) { - return []; + size = nativeMax(nativeFloor(size) || 1, 1); } var index = 0, - resIndex = 0, + length = array ? array.length : 0, + resIndex = -1, result = Array(nativeCeil(length / size)); while (index < length) { - result[resIndex++] = baseSlice(array, index, (index += size)); + result[++resIndex] = baseSlice(array, index, (index += size)); } return result; } @@ -6502,7 +4491,6 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Array * @param {Array} array The array to compact. * @returns {Array} Returns the new array of filtered values. @@ -6514,146 +4502,37 @@ function compact(array) { var index = -1, length = array ? array.length : 0, - resIndex = 0, + resIndex = -1, result = []; while (++index < length) { var value = array[index]; if (value) { - result[resIndex++] = value; + result[++resIndex] = value; } } return result; } /** - * Creates a new array concatenating `array` with any additional arrays - * and/or values. + * Creates an array of unique `array` values not included in the other + * provided arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. * * @static * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to concatenate. - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var other = _.concat(array, 2, [3], [[4]]); - * - * console.log(other); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - function concat() { - var length = arguments.length, - args = Array(length ? length - 1 : 0), - array = arguments[0], - index = length; - - while (index--) { - args[index - 1] = arguments[index]; - } - return length - ? arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)) - : []; - } - - /** - * Creates an array of `array` values not included in the other given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order of result values is determined by the - * order they occur in the first array. - * - * **Note:** Unlike `_.pullAll`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 * @category Array * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.without, _.xor - * @example - * - * _.difference([2, 1], [2, 3]); - * // => [1] - */ - var difference = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : []; - }); - - /** - * This method is like `_.difference` except that it accepts `iteratee` which - * is invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. Result values are chosen from the first array. - * The iteratee is invoked with one argument: (value). - * - * **Note:** Unlike `_.pullAllBy`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @param {...Array} [values] The arrays of values to exclude. * @returns {Array} Returns the new array of filtered values. * @example * - * _.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'); - * // => [{ 'x': 2 }] + * _.difference([1, 2, 3], [4, 2]); + * // => [1, 3] */ - var differenceBy = baseRest(function(array, values) { - var iteratee = last(values); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) - : []; - }); - - /** - * This method is like `_.difference` except that it accepts `comparator` - * which is invoked to compare elements of `array` to `values`. Result values - * are chosen from the first array. The comparator is invoked with two arguments: - * (arrVal, othVal). - * - * **Note:** Unlike `_.pullAllWith`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * - * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); - * // => [{ 'x': 2, 'y': 1 }] - */ - var differenceWith = baseRest(function(array, values) { - var comparator = last(values); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) + var difference = restParam(function(array, values) { + return (isObjectLike(array) && isArrayLike(array)) + ? baseDifference(array, baseFlatten(values, false, true)) : []; }); @@ -6662,11 +4541,10 @@ * * @static * @memberOf _ - * @since 0.5.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * @@ -6687,8 +4565,10 @@ if (!length) { return []; } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, n < 0 ? 0 : n, length); + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + return baseSlice(array, n < 0 ? 0 : n); } /** @@ -6696,11 +4576,10 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * @@ -6721,91 +4600,120 @@ if (!length) { return []; } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + n = length - (+n || 0); return baseSlice(array, 0, n < 0 ? 0 : n); } /** * Creates a slice of `array` excluding elements dropped from the end. * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). + * bound to `thisArg` and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that match the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Array} Returns the slice of `array`. * @example * + * _.dropRightWhile([1, 2, 3], function(n) { + * return n > 1; + * }); + * // => [1] + * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * - * _.dropRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney'] + * // using the `_.matches` callback shorthand + * _.pluck(_.dropRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); + * // => ['barney', 'fred'] * - * // The `_.matches` iteratee shorthand. - * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['barney', 'fred'] + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.dropRightWhile(users, 'active', false), 'user'); + * // => ['barney'] * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropRightWhile(users, ['active', false]); - * // => objects for ['barney'] - * - * // The `_.property` iteratee shorthand. - * _.dropRightWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] + * // using the `_.property` callback shorthand + * _.pluck(_.dropRightWhile(users, 'active'), 'user'); + * // => ['barney', 'fred', 'pebbles'] */ - function dropRightWhile(array, predicate) { + function dropRightWhile(array, predicate, thisArg) { return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true, true) + ? baseWhile(array, getCallback(predicate, thisArg, 3), true, true) : []; } /** * Creates a slice of `array` excluding elements dropped from the beginning. * Elements are dropped until `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index, array). + * bound to `thisArg` and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Array} Returns the slice of `array`. * @example * + * _.dropWhile([1, 2, 3], function(n) { + * return n < 3; + * }); + * // => [3] + * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': true } * ]; * - * _.dropWhile(users, function(o) { return !o.active; }); - * // => objects for ['pebbles'] + * // using the `_.matches` callback shorthand + * _.pluck(_.dropWhile(users, { 'user': 'barney', 'active': false }), 'user'); + * // => ['fred', 'pebbles'] * - * // The `_.matches` iteratee shorthand. - * _.dropWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['fred', 'pebbles'] + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.dropWhile(users, 'active', false), 'user'); + * // => ['pebbles'] * - * // The `_.matchesProperty` iteratee shorthand. - * _.dropWhile(users, ['active', false]); - * // => objects for ['pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.dropWhile(users, 'active'); - * // => objects for ['barney', 'fred', 'pebbles'] + * // using the `_.property` callback shorthand + * _.pluck(_.dropWhile(users, 'active'), 'user'); + * // => ['barney', 'fred', 'pebbles'] */ - function dropWhile(array, predicate) { + function dropWhile(array, predicate, thisArg) { return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), true) + ? baseWhile(array, getCallback(predicate, thisArg, 3), true) : []; } @@ -6817,7 +4725,6 @@ * * @static * @memberOf _ - * @since 3.2.0 * @category Array * @param {Array} array The array to fill. * @param {*} value The value to fill `array` with. @@ -6835,8 +4742,8 @@ * _.fill(Array(3), 2); * // => [2, 2, 2] * - * _.fill([4, 6, 8, 10], '*', 1, 3); - * // => [4, '*', '*', 10] + * _.fill([4, 6, 8], '*', 1, 2); + * // => [4, '*', 8] */ function fill(array, value, start, end) { var length = array ? array.length : 0; @@ -6854,14 +4761,24 @@ * This method is like `_.find` except that it returns the index of the first * element `predicate` returns truthy for instead of the element itself. * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * * @static * @memberOf _ - * @since 1.1.0 * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. + * @param {Array} array The array to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {number} Returns the index of the found element, else `-1`. * @example * @@ -6871,45 +4788,47 @@ * { 'user': 'pebbles', 'active': true } * ]; * - * _.findIndex(users, function(o) { return o.user == 'barney'; }); + * _.findIndex(users, function(chr) { + * return chr.user == 'barney'; + * }); * // => 0 * - * // The `_.matches` iteratee shorthand. + * // using the `_.matches` callback shorthand * _.findIndex(users, { 'user': 'fred', 'active': false }); * // => 1 * - * // The `_.matchesProperty` iteratee shorthand. - * _.findIndex(users, ['active', false]); + * // using the `_.matchesProperty` callback shorthand + * _.findIndex(users, 'active', false); * // => 0 * - * // The `_.property` iteratee shorthand. + * // using the `_.property` callback shorthand * _.findIndex(users, 'active'); * // => 2 */ - 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); - } + var findIndex = createFindIndex(); /** * This method is like `_.findIndex` except that it iterates over elements * of `collection` from right to left. * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * * @static * @memberOf _ - * @since 2.0.0 * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param {number} [fromIndex=array.length-1] The index to search from. + * @param {Array} array The array to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {number} Returns the index of the found element, else `-1`. * @example * @@ -6919,185 +4838,136 @@ * { 'user': 'pebbles', 'active': false } * ]; * - * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); + * _.findLastIndex(users, function(chr) { + * return chr.user == 'pebbles'; + * }); * // => 2 * - * // The `_.matches` iteratee shorthand. + * // using the `_.matches` callback shorthand * _.findLastIndex(users, { 'user': 'barney', 'active': true }); * // => 0 * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastIndex(users, ['active', false]); + * // using the `_.matchesProperty` callback shorthand + * _.findLastIndex(users, 'active', false); * // => 2 * - * // The `_.property` iteratee shorthand. + * // using the `_.property` callback shorthand * _.findLastIndex(users, 'active'); * // => 0 */ - 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); - } - - /** - * Flattens `array` a single level deep. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] - */ - function flatten(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, 1) : []; - } - - /** - * Recursively flattens `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, [3, [4]], 5]]); - * // => [1, 2, 3, 4, 5] - */ - function flattenDeep(array) { - var length = array ? array.length : 0; - return length ? baseFlatten(array, INFINITY) : []; - } - - /** - * Recursively flatten `array` up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Array - * @param {Array} array The array to flatten. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * var array = [1, [2, [3, [4]], 5]]; - * - * _.flattenDepth(array, 1); - * // => [1, 2, [3, [4]], 5] - * - * _.flattenDepth(array, 2); - * // => [1, 2, 3, [4], 5] - */ - function flattenDepth(array, depth) { - var length = array ? array.length : 0; - if (!length) { - return []; - } - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(array, depth); - } - - /** - * The inverse of `_.toPairs`; this method returns an object composed - * from key-value `pairs`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} pairs The key-value pairs. - * @returns {Object} Returns the new object. - * @example - * - * _.fromPairs([['a', 1], ['b', 2]]); - * // => { 'a': 1, 'b': 2 } - */ - function fromPairs(pairs) { - var index = -1, - length = pairs ? pairs.length : 0, - result = {}; - - while (++index < length) { - var pair = pairs[index]; - result[pair[0]] = pair[1]; - } - return result; - } + var findLastIndex = createFindIndex(true); /** * Gets the first element of `array`. * * @static * @memberOf _ - * @since 0.1.0 - * @alias first + * @alias head * @category Array * @param {Array} array The array to query. * @returns {*} Returns the first element of `array`. * @example * - * _.head([1, 2, 3]); + * _.first([1, 2, 3]); * // => 1 * - * _.head([]); + * _.first([]); * // => undefined */ - function head(array) { - return (array && array.length) ? array[0] : undefined; + function first(array) { + return array ? array[0] : undefined; + } + + /** + * Flattens a nested array. If `isDeep` is `true` the array is recursively + * flattened, otherwise it's only flattened a single level. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to flatten. + * @param {boolean} [isDeep] Specify a deep flatten. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2, 3, [4]]]); + * // => [1, 2, 3, [4]] + * + * // using `isDeep` + * _.flatten([1, [2, 3, [4]]], true); + * // => [1, 2, 3, 4] + */ + function flatten(array, isDeep, guard) { + var length = array ? array.length : 0; + if (guard && isIterateeCall(array, isDeep, guard)) { + isDeep = false; + } + return length ? baseFlatten(array, isDeep) : []; + } + + /** + * Recursively flattens a nested array. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to recursively flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, 3, [4]]]); + * // => [1, 2, 3, 4] + */ + function flattenDeep(array) { + var length = array ? array.length : 0; + return length ? baseFlatten(array, true) : []; } /** * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the - * offset from the end of `array`. + * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the offset + * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` + * performs a faster binary search. * * @static * @memberOf _ - * @since 0.1.0 * @category Array - * @param {Array} array The array to inspect. + * @param {Array} array The array to search. * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. + * @param {boolean|number} [fromIndex=0] The index to search from or `true` + * to perform a binary search on a sorted array. * @returns {number} Returns the index of the matched value, else `-1`. * @example * * _.indexOf([1, 2, 1, 2], 2); * // => 1 * - * // Search from the `fromIndex`. + * // using `fromIndex` * _.indexOf([1, 2, 1, 2], 2, 2); * // => 3 + * + * // performing a binary search + * _.indexOf([1, 1, 2, 2], 2, true); + * // => 2 */ function indexOf(array, value, 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); + if (typeof fromIndex == 'number') { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex; + } else if (fromIndex) { + var index = binaryIndex(array, value); + if (index < length && + (value === value ? (value === array[index]) : (array[index] !== array[index]))) { + return index; + } + return -1; } - return baseIndexOf(array, value, index); + return baseIndexOf(array, value, fromIndex || 0); } /** @@ -7105,7 +4975,6 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Array * @param {Array} array The array to query. * @returns {Array} Returns the slice of `array`. @@ -7115,130 +4984,65 @@ * // => [1, 2] */ function initial(array) { - var length = array ? array.length : 0; - return length ? baseSlice(array, 0, -1) : []; + return dropRight(array, 1); } /** - * Creates an array of unique values that are included in all given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order of result values is determined by the - * order they occur in the first array. + * Creates an array of unique values that are included in all of the provided + * arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. * * @static * @memberOf _ - * @since 0.1.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of intersecting values. + * @returns {Array} Returns the new array of shared values. * @example - * - * _.intersection([2, 1], [2, 3]); + * _.intersection([1, 2], [4, 2], [2, 1]); * // => [2] */ - var intersection = baseRest(function(arrays) { - var mapped = arrayMap(arrays, castArrayLikeObject); - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped) - : []; - }); + var intersection = restParam(function(arrays) { + var othLength = arrays.length, + othIndex = othLength, + caches = Array(length), + indexOf = getIndexOf(), + isCommon = indexOf === baseIndexOf, + result = []; - /** - * This method is like `_.intersection` except that it accepts `iteratee` - * which is invoked for each element of each `arrays` to generate the criterion - * by which they're compared. Result values are chosen from the first array. - * The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); - * // => [2.1] - * - * // The `_.property` iteratee shorthand. - * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }] - */ - var intersectionBy = baseRest(function(arrays) { - var iteratee = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); - - if (iteratee === last(mapped)) { - iteratee = undefined; - } else { - mapped.pop(); + while (othIndex--) { + var value = arrays[othIndex] = isArrayLike(value = arrays[othIndex]) ? value : []; + caches[othIndex] = (isCommon && value.length >= 120) ? createCache(othIndex && value) : null; } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, getIteratee(iteratee, 2)) - : []; - }); + var array = arrays[0], + index = -1, + length = array ? array.length : 0, + seen = caches[0]; - /** - * This method is like `_.intersection` except that it accepts `comparator` - * which is invoked to compare elements of `arrays`. Result values are chosen - * from the first array. The comparator is invoked with two arguments: - * (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.intersectionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }] - */ - var intersectionWith = baseRest(function(arrays) { - var comparator = last(arrays), - mapped = arrayMap(arrays, castArrayLikeObject); - - if (comparator === last(mapped)) { - comparator = undefined; - } else { - mapped.pop(); + outer: + while (++index < length) { + value = array[index]; + if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) { + var othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) { + continue outer; + } + } + if (seen) { + seen.push(value); + } + result.push(value); + } } - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped, undefined, comparator) - : []; + return result; }); - /** - * Converts all elements in `array` into a string separated by `separator`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to convert. - * @param {string} [separator=','] The element separator. - * @returns {string} Returns the joined string. - * @example - * - * _.join(['a', 'b', 'c'], '~'); - * // => 'a~b~c' - */ - function join(array, separator) { - return array ? nativeJoin.call(array, separator) : ''; - } - /** * Gets the last element of `array`. * * @static * @memberOf _ - * @since 0.1.0 * @category Array * @param {Array} array The array to query. * @returns {*} Returns the last element of `array`. @@ -7258,20 +5062,24 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Array - * @param {Array} array The array to inspect. + * @param {Array} array The array to search. * @param {*} value The value to search for. - * @param {number} [fromIndex=array.length-1] The index to search from. + * @param {boolean|number} [fromIndex=array.length-1] The index to search from + * or `true` to perform a binary search on a sorted array. * @returns {number} Returns the index of the matched value, else `-1`. * @example * * _.lastIndexOf([1, 2, 1, 2], 2); * // => 3 * - * // Search from the `fromIndex`. + * // using `fromIndex` * _.lastIndexOf([1, 2, 1, 2], 2, 2); * // => 1 + * + * // performing a binary search + * _.lastIndexOf([1, 1, 2, 2], 2, true); + * // => 3 */ function lastIndexOf(array, value, fromIndex) { var length = array ? array.length : 0; @@ -7279,16 +5087,18 @@ return -1; } var index = length; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = ( - index < 0 - ? nativeMax(length + index, 0) - : nativeMin(index, length - 1) - ) + 1; + if (typeof fromIndex == 'number') { + index = (fromIndex < 0 ? nativeMax(length + fromIndex, 0) : nativeMin(fromIndex || 0, length - 1)) + 1; + } else if (fromIndex) { + index = binaryIndex(array, value, true) - 1; + var other = array[index]; + if (value === value ? (value === other) : (other !== other)) { + return index; + } + return -1; } if (value !== value) { - return baseFindIndex(array, baseIsNaN, index - 1, true); + return indexOfNaN(array, index, true); } while (index--) { if (array[index] === value) { @@ -7299,192 +5109,106 @@ } /** - * Gets the element at index `n` of `array`. If `n` is negative, the nth - * element from the end is returned. - * - * @static - * @memberOf _ - * @since 4.11.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=0] The index of the element to return. - * @returns {*} Returns the nth element of `array`. - * @example - * - * var array = ['a', 'b', 'c', 'd']; - * - * _.nth(array, 1); - * // => 'b' - * - * _.nth(array, -2); - * // => 'c'; - */ - function nth(array, n) { - return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; - } - - /** - * Removes all given values from `array` using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * Removes all provided values from `array` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) * for equality comparisons. * - * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` - * to remove elements from an array by predicate. + * **Note:** Unlike `_.without`, this method mutates `array`. * * @static * @memberOf _ - * @since 2.0.0 * @category Array * @param {Array} array The array to modify. * @param {...*} [values] The values to remove. * @returns {Array} Returns `array`. * @example * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * var array = [1, 2, 3, 1, 2, 3]; * - * _.pull(array, 'a', 'c'); + * _.pull(array, 2, 3); * console.log(array); - * // => ['b', 'b'] + * // => [1, 1] */ - var pull = baseRest(pullAll); + function pull() { + var args = arguments, + array = args[0]; - /** - * This method is like `_.pull` except that it accepts an array of values to remove. - * - * **Note:** Unlike `_.difference`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @returns {Array} Returns `array`. - * @example - * - * var array = ['a', 'b', 'c', 'a', 'b', 'c']; - * - * _.pullAll(array, ['a', 'c']); - * console.log(array); - * // => ['b', 'b'] - */ - function pullAll(array, values) { - return (array && array.length && values && values.length) - ? basePullAll(array, values) - : array; + if (!(array && array.length)) { + return array; + } + var index = 0, + indexOf = getIndexOf(), + length = args.length; + + while (++index < length) { + var fromIndex = 0, + value = args[index]; + + while ((fromIndex = indexOf(array, value, fromIndex)) > -1) { + splice.call(array, fromIndex, 1); + } + } + return array; } /** - * This method is like `_.pullAll` except that it accepts `iteratee` which is - * invoked for each element of `array` and `values` to generate the criterion - * by which they're compared. The iteratee is invoked with one argument: (value). - * - * **Note:** Unlike `_.differenceBy`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; - * - * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); - * console.log(array); - * // => [{ 'x': 2 }] - */ - function pullAllBy(array, values, iteratee) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, getIteratee(iteratee, 2)) - : array; - } - - /** - * This method is like `_.pullAll` except that it accepts `comparator` which - * is invoked to compare elements of `array` to `values`. The comparator is - * invoked with two arguments: (arrVal, othVal). - * - * **Note:** Unlike `_.differenceWith`, this method mutates `array`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Array - * @param {Array} array The array to modify. - * @param {Array} values The values to remove. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns `array`. - * @example - * - * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; - * - * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); - * console.log(array); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] - */ - function pullAllWith(array, values, comparator) { - return (array && array.length && values && values.length) - ? basePullAll(array, values, undefined, comparator) - : array; - } - - /** - * Removes elements from `array` corresponding to `indexes` and returns an - * array of removed elements. + * Removes elements from `array` corresponding to the given indexes and returns + * an array of the removed elements. Indexes may be specified as an array of + * indexes or as individual arguments. * * **Note:** Unlike `_.at`, this method mutates `array`. * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The array to modify. - * @param {...(number|number[])} [indexes] The indexes of elements to remove. + * @param {...(number|number[])} [indexes] The indexes of elements to remove, + * specified as individual indexes or arrays of indexes. * @returns {Array} Returns the new array of removed elements. * @example * - * var array = ['a', 'b', 'c', 'd']; - * var pulled = _.pullAt(array, [1, 3]); + * var array = [5, 10, 15, 20]; + * var evens = _.pullAt(array, 1, 3); * * console.log(array); - * // => ['a', 'c'] + * // => [5, 15] * - * console.log(pulled); - * // => ['b', 'd'] + * console.log(evens); + * // => [10, 20] */ - var pullAt = baseRest(function(array, indexes) { - indexes = baseFlatten(indexes, 1); - - var length = array ? array.length : 0, - result = baseAt(array, indexes); - - basePullAt(array, arrayMap(indexes, function(index) { - return isIndex(index, length) ? +index : index; - }).sort(compareAscending)); + var pullAt = restParam(function(array, indexes) { + indexes = baseFlatten(indexes); + var result = baseAt(array, indexes); + basePullAt(array, indexes.sort(baseCompareAscending)); return result; }); /** * Removes all elements from `array` that `predicate` returns truthy for - * and returns an array of the removed elements. The predicate is invoked - * with three arguments: (value, index, array). + * and returns an array of the removed elements. The predicate is bound to + * `thisArg` and invoked with three arguments: (value, index, array). * - * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` - * to pull elements from an array by value. + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * **Note:** Unlike `_.filter`, this method mutates `array`. * * @static * @memberOf _ - * @since 2.0.0 * @category Array * @param {Array} array The array to modify. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Array} Returns the new array of removed elements. * @example * @@ -7499,7 +5223,7 @@ * console.log(evens); * // => [2, 4] */ - function remove(array, predicate) { + function remove(array, predicate, thisArg) { var result = []; if (!(array && array.length)) { return result; @@ -7508,7 +5232,7 @@ indexes = [], length = array.length; - predicate = getIteratee(predicate, 3); + predicate = getCallback(predicate, thisArg, 3); while (++index < length) { var value = array[index]; if (predicate(value, index, array)) { @@ -7521,42 +5245,31 @@ } /** - * Reverses `array` so that the first element becomes the last, the second - * element becomes the second to last, and so on. - * - * **Note:** This method mutates `array` and is based on - * [`Array#reverse`](https://mdn.io/Array/reverse). + * Gets all but the first element of `array`. * * @static * @memberOf _ - * @since 4.0.0 + * @alias tail * @category Array - * @param {Array} array The array to modify. - * @returns {Array} Returns `array`. + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. * @example * - * var array = [1, 2, 3]; - * - * _.reverse(array); - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] + * _.rest([1, 2, 3]); + * // => [2, 3] */ - function reverse(array) { - return array ? nativeReverse.call(array) : array; + function rest(array) { + return drop(array, 1); } /** * Creates a slice of `array` from `start` up to, but not including, `end`. * - * **Note:** This method is used instead of - * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are - * returned. + * **Note:** This method is used instead of `Array#slice` to support node + * lists in IE < 9 and to ensure dense arrays are returned. * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The array to slice. * @param {number} [start=0] The start position. @@ -7572,90 +5285,58 @@ start = 0; end = length; } - else { - start = start == null ? 0 : toInteger(start); - end = end === undefined ? length : toInteger(end); - } return baseSlice(array, start, end); } /** - * Uses a binary search to determine the lowest index at which `value` - * should be inserted into `array` in order to maintain its sort order. + * Uses a binary search to determine the lowest index at which `value` should + * be inserted into `array` in order to maintain its sort order. If an iteratee + * function is provided it's invoked for `value` and each element of `array` + * to compute their sort ranking. The iteratee is bound to `thisArg` and + * invoked with one argument; (value). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 0.1.0 * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {number} Returns the index at which `value` should be inserted * into `array`. * @example * * _.sortedIndex([30, 50], 40); * // => 1 - */ - function sortedIndex(array, value) { - return baseSortedIndex(array, value); - } - - /** - * This method is like `_.sortedIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example + * _.sortedIndex([4, 4, 5, 5], 5); + * // => 2 * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * var dict = { 'data': { 'thirty': 30, 'forty': 40, 'fifty': 50 } }; * - * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 0 + * // using an iteratee function + * _.sortedIndex(['thirty', 'fifty'], 'forty', function(word) { + * return this.data[word]; + * }, dict); + * // => 1 * - * // The `_.property` iteratee shorthand. - * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); - * // => 0 - */ - function sortedIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); - } - - /** - * This method is like `_.indexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedIndexOf([4, 5, 5, 5, 6], 5); + * // using the `_.property` callback shorthand + * _.sortedIndex([{ 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); * // => 1 */ - function sortedIndexOf(array, value) { - var length = array ? array.length : 0; - if (length) { - var index = baseSortedIndex(array, value); - if (index < length && eq(array[index], value)) { - return index; - } - } - return -1; - } + var sortedIndex = createSortedIndex(); /** * This method is like `_.sortedIndex` except that it returns the highest @@ -7664,150 +5345,30 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The sorted array to inspect. * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {number} Returns the index at which `value` should be inserted * into `array`. * @example * - * _.sortedLastIndex([4, 5, 5, 5, 6], 5); + * _.sortedLastIndex([4, 4, 5, 5], 5); * // => 4 */ - function sortedLastIndex(array, value) { - return baseSortedIndex(array, value, true); - } - - /** - * This method is like `_.sortedLastIndex` except that it accepts `iteratee` - * which is invoked for `value` and each element of `array` to compute their - * sort ranking. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The sorted array to inspect. - * @param {*} value The value to evaluate. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {number} Returns the index at which `value` should be inserted - * into `array`. - * @example - * - * var objects = [{ 'x': 4 }, { 'x': 5 }]; - * - * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); - * // => 1 - * - * // The `_.property` iteratee shorthand. - * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); - * // => 1 - */ - function sortedLastIndexBy(array, value, iteratee) { - return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); - } - - /** - * This method is like `_.lastIndexOf` except that it performs a binary - * search on a sorted `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); - * // => 3 - */ - function sortedLastIndexOf(array, value) { - var length = array ? array.length : 0; - if (length) { - var index = baseSortedIndex(array, value, true) - 1; - if (eq(array[index], value)) { - return index; - } - } - return -1; - } - - /** - * This method is like `_.uniq` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniq([1, 1, 2]); - * // => [1, 2] - */ - function sortedUniq(array) { - return (array && array.length) - ? baseSortedUniq(array) - : []; - } - - /** - * This method is like `_.uniqBy` except that it's designed and optimized - * for sorted arrays. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); - * // => [1.1, 2.3] - */ - function sortedUniqBy(array, iteratee) { - return (array && array.length) - ? baseSortedUniq(array, getIteratee(iteratee, 2)) - : []; - } - - /** - * Gets all but the first element of `array`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.tail([1, 2, 3]); - * // => [2, 3] - */ - function tail(array) { - var length = array ? array.length : 0; - return length ? baseSlice(array, 1, length) : []; - } + var sortedLastIndex = createSortedIndex(true); /** * Creates a slice of `array` with `n` elements taken from the beginning. * * @static * @memberOf _ - * @since 0.1.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * @@ -7824,10 +5385,13 @@ * // => [] */ function take(array, n, guard) { - if (!(array && array.length)) { + var length = array ? array.length : 0; + if (!length) { return []; } - n = (guard || n === undefined) ? 1 : toInteger(n); + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } return baseSlice(array, 0, n < 0 ? 0 : n); } @@ -7836,11 +5400,10 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The array to query. * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Array} Returns the slice of `array`. * @example * @@ -7861,250 +5424,208 @@ if (!length) { return []; } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, n < 0 ? 0 : n, length); + if (guard ? isIterateeCall(array, n, guard) : n == null) { + n = 1; + } + n = length - (+n || 0); + return baseSlice(array, n < 0 ? 0 : n); } /** * Creates a slice of `array` with elements taken from the end. Elements are - * taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). + * taken until `predicate` returns falsey. The predicate is bound to `thisArg` + * and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Array} Returns the slice of `array`. * @example * + * _.takeRightWhile([1, 2, 3], function(n) { + * return n > 1; + * }); + * // => [2, 3] + * * var users = [ * { 'user': 'barney', 'active': true }, * { 'user': 'fred', 'active': false }, * { 'user': 'pebbles', 'active': false } * ]; * - * _.takeRightWhile(users, function(o) { return !o.active; }); - * // => objects for ['fred', 'pebbles'] + * // using the `_.matches` callback shorthand + * _.pluck(_.takeRightWhile(users, { 'user': 'pebbles', 'active': false }), 'user'); + * // => ['pebbles'] * - * // The `_.matches` iteratee shorthand. - * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); - * // => objects for ['pebbles'] + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.takeRightWhile(users, 'active', false), 'user'); + * // => ['fred', 'pebbles'] * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeRightWhile(users, ['active', false]); - * // => objects for ['fred', 'pebbles'] - * - * // The `_.property` iteratee shorthand. - * _.takeRightWhile(users, 'active'); + * // using the `_.property` callback shorthand + * _.pluck(_.takeRightWhile(users, 'active'), 'user'); * // => [] */ - function takeRightWhile(array, predicate) { + function takeRightWhile(array, predicate, thisArg) { return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3), false, true) + ? baseWhile(array, getCallback(predicate, thisArg, 3), false, true) : []; } /** * Creates a slice of `array` with elements taken from the beginning. Elements - * are taken until `predicate` returns falsey. The predicate is invoked with - * three arguments: (value, index, array). + * are taken until `predicate` returns falsey. The predicate is bound to + * `thisArg` and invoked with three arguments: (value, index, array). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 3.0.0 * @category Array * @param {Array} array The array to query. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Array} Returns the slice of `array`. * @example * + * _.takeWhile([1, 2, 3], function(n) { + * return n < 3; + * }); + * // => [1, 2] + * * var users = [ * { 'user': 'barney', 'active': false }, * { 'user': 'fred', 'active': false}, * { 'user': 'pebbles', 'active': true } * ]; * - * _.takeWhile(users, function(o) { return !o.active; }); - * // => objects for ['barney', 'fred'] + * // using the `_.matches` callback shorthand + * _.pluck(_.takeWhile(users, { 'user': 'barney', 'active': false }), 'user'); + * // => ['barney'] * - * // The `_.matches` iteratee shorthand. - * _.takeWhile(users, { 'user': 'barney', 'active': false }); - * // => objects for ['barney'] + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.takeWhile(users, 'active', false), 'user'); + * // => ['barney', 'fred'] * - * // The `_.matchesProperty` iteratee shorthand. - * _.takeWhile(users, ['active', false]); - * // => objects for ['barney', 'fred'] - * - * // The `_.property` iteratee shorthand. - * _.takeWhile(users, 'active'); + * // using the `_.property` callback shorthand + * _.pluck(_.takeWhile(users, 'active'), 'user'); * // => [] */ - function takeWhile(array, predicate) { + function takeWhile(array, predicate, thisArg) { return (array && array.length) - ? baseWhile(array, getIteratee(predicate, 3)) + ? baseWhile(array, getCallback(predicate, thisArg, 3)) : []; } /** - * Creates an array of unique values, in order, from all given arrays using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * Creates an array of unique values, in order, from all of the provided arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) * for equality comparisons. * * @static * @memberOf _ - * @since 0.1.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. * @returns {Array} Returns the new array of combined values. * @example * - * _.union([2], [1, 2]); - * // => [2, 1] + * _.union([1, 2], [4, 2], [2, 1]); + * // => [1, 2, 4] */ - var union = baseRest(function(arrays) { - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); - }); - - /** - * This method is like `_.union` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which uniqueness is computed. Result values are chosen from the first - * array in which the value occurs. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.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'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - var unionBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; - } - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); - }); - - /** - * This method is like `_.union` except that it accepts `comparator` which - * is invoked to compare elements of `arrays`. Result values are chosen from - * the first array in which the value occurs. The comparator is invoked - * with two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of combined values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.unionWith(objects, others, _.isEqual); - * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var unionWith = baseRest(function(arrays) { - var comparator = last(arrays); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); + var union = restParam(function(arrays) { + return baseUniq(baseFlatten(arrays, false, true)); }); /** * Creates a duplicate-free version of an array, using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons, in which only the first occurrence of each - * element is kept. + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurence of each element + * is kept. Providing `true` for `isSorted` performs a faster search algorithm + * for sorted arrays. If an iteratee function is provided it's invoked for + * each element in the array to generate the criterion by which uniqueness + * is computed. The `iteratee` is bound to `thisArg` and invoked with three + * arguments: (value, index, array). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 0.1.0 + * @alias unique * @category Array * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. + * @param {boolean} [isSorted] Specify the array is sorted. + * @param {Function|Object|string} [iteratee] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new duplicate-value-free array. * @example * * _.uniq([2, 1, 2]); * // => [2, 1] - */ - function uniq(array) { - return (array && array.length) - ? baseUniq(array) - : []; - } - - /** - * This method is like `_.uniq` except that it accepts `iteratee` which is - * invoked for each element in `array` to generate the criterion by which - * uniqueness is computed. The iteratee is invoked with one argument: (value). * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example + * // using `isSorted` + * _.uniq([1, 1, 2], true); + * // => [1, 2] * - * _.uniqBy([2.1, 1.2, 2.3], Math.floor); - * // => [2.1, 1.2] + * // using an iteratee function + * _.uniq([1, 2.5, 1.5, 2], function(n) { + * return this.floor(n); + * }, Math); + * // => [1, 2.5] * - * // The `_.property` iteratee shorthand. - * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // using the `_.property` callback shorthand + * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - function uniqBy(array, iteratee) { - return (array && array.length) - ? baseUniq(array, getIteratee(iteratee, 2)) - : []; - } - - /** - * This method is like `_.uniq` except that it accepts `comparator` which - * is invoked to compare elements of `array`. The comparator is invoked with - * two arguments: (arrVal, othVal). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * 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 }] - */ - function uniqWith(array, comparator) { - return (array && array.length) - ? baseUniq(array, undefined, comparator) - : []; + function uniq(array, isSorted, iteratee, thisArg) { + var length = array ? array.length : 0; + if (!length) { + return []; + } + if (isSorted != null && typeof isSorted != 'boolean') { + thisArg = iteratee; + iteratee = isIterateeCall(array, isSorted, thisArg) ? undefined : isSorted; + isSorted = false; + } + var callback = getCallback(); + if (!(iteratee == null && callback === baseCallback)) { + iteratee = callback(iteratee, thisArg, 3); + } + return (isSorted && getIndexOf() === baseIndexOf) + ? sortedUniq(array, iteratee) + : baseUniq(array, iteratee); } /** @@ -8114,46 +5635,48 @@ * * @static * @memberOf _ - * @since 1.2.0 * @category Array * @param {Array} array The array of grouped elements to process. * @returns {Array} Returns the new array of regrouped elements. * @example * - * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] + * var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] * * _.unzip(zipped); - * // => [['a', 'b'], [1, 2], [true, false]] + * // => [['fred', 'barney'], [30, 40], [true, false]] */ function unzip(array) { if (!(array && array.length)) { return []; } - var length = 0; + var index = -1, + length = 0; + array = arrayFilter(array, function(group) { - if (isArrayLikeObject(group)) { + if (isArrayLike(group)) { length = nativeMax(group.length, length); return true; } }); - return baseTimes(length, function(index) { - return arrayMap(array, baseProperty(index)); - }); + var result = Array(length); + while (++index < length) { + result[index] = arrayMap(array, baseProperty(index)); + } + return result; } /** - * This method is like `_.unzip` except that it accepts `iteratee` to specify - * how regrouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). + * This method is like `_.unzip` except that it accepts an iteratee to specify + * how regrouped values should be combined. The `iteratee` is bound to `thisArg` + * and invoked with four arguments: (accumulator, value, index, group). * * @static * @memberOf _ - * @since 3.8.0 * @category Array * @param {Array} array The array of grouped elements to process. - * @param {Function} [iteratee=_.identity] The function to combine - * regrouped values. + * @param {Function} [iteratee] The function to combine regrouped values. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Array} Returns the new array of regrouped elements. * @example * @@ -8163,221 +5686,170 @@ * _.unzipWith(zipped, _.add); * // => [3, 30, 300] */ - function unzipWith(array, iteratee) { - if (!(array && array.length)) { + function unzipWith(array, iteratee, thisArg) { + var length = array ? array.length : 0; + if (!length) { return []; } var result = unzip(array); if (iteratee == null) { return result; } + iteratee = bindCallback(iteratee, thisArg, 4); return arrayMap(result, function(group) { - return apply(iteratee, undefined, group); + return arrayReduce(group, iteratee, undefined, true); }); } /** - * Creates an array excluding all given values using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * Creates an array excluding all provided values using + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) * for equality comparisons. * - * **Note:** Unlike `_.pull`, this method returns a new array. - * * @static * @memberOf _ - * @since 0.1.0 * @category Array - * @param {Array} array The array to inspect. + * @param {Array} array The array to filter. * @param {...*} [values] The values to exclude. * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.xor * @example * - * _.without([2, 1, 2, 3], 1, 2); + * _.without([1, 2, 1, 3], 1, 2); * // => [3] */ - var without = baseRest(function(array, values) { - return isArrayLikeObject(array) + var without = restParam(function(array, values) { + return isArrayLike(array) ? baseDifference(array, values) : []; }); /** - * Creates an array of unique values that is the - * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) - * of the given arrays. The order of result values is determined by the order - * they occur in the arrays. + * Creates an array of unique values that is the [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) + * of the provided arrays. * * @static * @memberOf _ - * @since 2.4.0 * @category Array * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.without + * @returns {Array} Returns the new array of values. * @example * - * _.xor([2, 1], [2, 3]); - * // => [1, 3] + * _.xor([1, 2], [4, 2]); + * // => [1, 4] */ - var xor = baseRest(function(arrays) { - return baseXor(arrayFilter(arrays, isArrayLikeObject)); - }); + function xor() { + var index = -1, + length = arguments.length; - /** - * This method is like `_.xor` except that it accepts `iteratee` which is - * invoked for each element of each `arrays` to generate the criterion by - * which by which they're compared. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [iteratee=_.identity] - * The iteratee invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.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'); - * // => [{ 'x': 2 }] - */ - var xorBy = baseRest(function(arrays) { - var iteratee = last(arrays); - if (isArrayLikeObject(iteratee)) { - iteratee = undefined; + while (++index < length) { + var array = arguments[index]; + if (isArrayLike(array)) { + var result = result + ? arrayPush(baseDifference(result, array), baseDifference(array, result)) + : array; + } } - return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); - }); + return result ? baseUniq(result) : []; + } /** - * This method is like `_.xor` except that it accepts `comparator` which is - * invoked to compare elements of `arrays`. The comparator is invoked with - * two arguments: (arrVal, othVal). + * Creates an array of grouped elements, the first of which contains the first + * elements of the given arrays, the second of which contains the second elements + * of the given arrays, and so on. * * @static * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; - * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; - * - * _.xorWith(objects, others, _.isEqual); - * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] - */ - var xorWith = baseRest(function(arrays) { - var comparator = last(arrays); - if (isArrayLikeObject(comparator)) { - comparator = undefined; - } - return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); - }); - - /** - * Creates an array of grouped elements, the first of which contains the - * first elements of the given arrays, the second of which contains the - * second elements of the given arrays, and so on. - * - * @static - * @memberOf _ - * @since 0.1.0 * @category Array * @param {...Array} [arrays] The arrays to process. * @returns {Array} Returns the new array of grouped elements. * @example * - * _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] + * _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] */ - var zip = baseRest(unzip); + var zip = restParam(unzip); /** - * This method is like `_.fromPairs` except that it accepts two arrays, - * one of property identifiers and one of corresponding values. + * The inverse of `_.pairs`; this method returns an object composed from arrays + * of property names and values. Provide either a single two dimensional array, + * e.g. `[[key1, value1], [key2, value2]]` or two arrays, one of property names + * and one of corresponding values. * * @static * @memberOf _ - * @since 0.4.0 + * @alias object * @category Array - * @param {Array} [props=[]] The property identifiers. + * @param {Array} props The property names. * @param {Array} [values=[]] The property values. * @returns {Object} Returns the new object. * @example * - * _.zipObject(['a', 'b'], [1, 2]); - * // => { 'a': 1, 'b': 2 } + * _.zipObject([['fred', 30], ['barney', 40]]); + * // => { 'fred': 30, 'barney': 40 } + * + * _.zipObject(['fred', 'barney'], [30, 40]); + * // => { 'fred': 30, 'barney': 40 } */ function zipObject(props, values) { - return baseZipObject(props || [], values || [], assignValue); + var index = -1, + length = props ? props.length : 0, + result = {}; + + if (length && !values && !isArray(props[0])) { + values = []; + } + while (++index < length) { + var key = props[index]; + if (values) { + result[key] = values[index]; + } else if (key) { + result[key[0]] = key[1]; + } + } + return result; } /** - * This method is like `_.zipObject` except that it supports property paths. + * This method is like `_.zip` except that it accepts an iteratee to specify + * how grouped values should be combined. The `iteratee` is bound to `thisArg` + * and invoked with four arguments: (accumulator, value, index, group). * * @static * @memberOf _ - * @since 4.1.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); - * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } - */ - function zipObjectDeep(props, values) { - return baseZipObject(props || [], values || [], baseSet); - } - - /** - * This method is like `_.zip` except that it accepts `iteratee` to specify - * how grouped values should be combined. The iteratee is invoked with the - * elements of each group: (...group). - * - * @static - * @memberOf _ - * @since 3.8.0 * @category Array * @param {...Array} [arrays] The arrays to process. - * @param {Function} [iteratee=_.identity] The function to combine grouped values. + * @param {Function} [iteratee] The function to combine grouped values. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Array} Returns the new array of grouped elements. * @example * - * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { - * return a + b + c; - * }); + * _.zipWith([1, 2], [10, 20], [100, 200], _.add); * // => [111, 222] */ - var zipWith = baseRest(function(arrays) { + var zipWith = restParam(function(arrays) { var length = arrays.length, - iteratee = length > 1 ? arrays[length - 1] : undefined; + iteratee = length > 2 ? arrays[length - 2] : undefined, + thisArg = length > 1 ? arrays[length - 1] : undefined; - iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; - return unzipWith(arrays, iteratee); + if (length > 2 && typeof iteratee == 'function') { + length -= 2; + } else { + iteratee = (length > 1 && typeof thisArg == 'function') ? (--length, thisArg) : undefined; + thisArg = undefined; + } + arrays.length = length; + return unzipWith(arrays, iteratee, thisArg); }); /*------------------------------------------------------------------------*/ /** - * Creates a `lodash` wrapper instance that wraps `value` with explicit method - * chain sequences enabled. The result of such sequences must be unwrapped - * with `_#value`. + * Creates a `lodash` object that wraps `value` with explicit method + * chaining enabled. * * @static * @memberOf _ - * @since 1.3.0 - * @category Seq + * @category Chain * @param {*} value The value to wrap. * @returns {Object} Returns the new `lodash` wrapper instance. * @example @@ -8388,13 +5860,12 @@ * { 'user': 'pebbles', 'age': 1 } * ]; * - * var youngest = _ - * .chain(users) + * var youngest = _.chain(users) * .sortBy('age') - * .map(function(o) { - * return o.user + ' is ' + o.age; + * .map(function(chr) { + * return chr.user + ' is ' + chr.age; * }) - * .head() + * .first() * .value(); * // => 'pebbles is 1' */ @@ -8405,44 +5876,42 @@ } /** - * This method invokes `interceptor` and returns `value`. The interceptor - * is invoked with one argument; (value). The purpose of this method is to - * "tap into" a method chain sequence in order to modify intermediate results. + * This method invokes `interceptor` and returns `value`. The interceptor is + * bound to `thisArg` and invoked with one argument; (value). The purpose of + * this method is to "tap into" a method chain in order to perform operations + * on intermediate results within the chain. * * @static * @memberOf _ - * @since 0.1.0 - * @category Seq + * @category Chain * @param {*} value The value to provide to `interceptor`. * @param {Function} interceptor The function to invoke. + * @param {*} [thisArg] The `this` binding of `interceptor`. * @returns {*} Returns `value`. * @example * * _([1, 2, 3]) * .tap(function(array) { - * // Mutate input array. * array.pop(); * }) * .reverse() * .value(); * // => [2, 1] */ - function tap(value, interceptor) { - interceptor(value); + function tap(value, interceptor, thisArg) { + interceptor.call(thisArg, value); return value; } /** * This method is like `_.tap` except that it returns the result of `interceptor`. - * The purpose of this method is to "pass thru" values replacing intermediate - * results in a method chain sequence. * * @static * @memberOf _ - * @since 3.0.0 - * @category Seq + * @category Chain * @param {*} value The value to provide to `interceptor`. * @param {Function} interceptor The function to invoke. + * @param {*} [thisArg] The `this` binding of `interceptor`. * @returns {*} Returns the result of `interceptor`. * @example * @@ -8455,58 +5924,16 @@ * .value(); * // => ['abc'] */ - function thru(value, interceptor) { - return interceptor(value); + function thru(value, interceptor, thisArg) { + return interceptor.call(thisArg, value); } /** - * This method is the wrapper version of `_.at`. - * - * @name at - * @memberOf _ - * @since 1.0.0 - * @category Seq - * @param {...(string|string[])} [paths] The property paths of elements to pick. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _(object).at(['a[0].b.c', 'a[1]']).value(); - * // => [3, 4] - */ - var wrapperAt = baseRest(function(paths) { - paths = baseFlatten(paths, 1); - var length = paths.length, - start = length ? paths[0] : 0, - value = this.__wrapped__, - interceptor = function(object) { return baseAt(object, paths); }; - - if (length > 1 || this.__actions__.length || - !(value instanceof LazyWrapper) || !isIndex(start)) { - return this.thru(interceptor); - } - value = value.slice(start, +start + (length ? 1 : 0)); - value.__actions__.push({ - 'func': thru, - 'args': [interceptor], - 'thisArg': undefined - }); - return new LodashWrapper(value, this.__chain__).thru(function(array) { - if (length && !array.length) { - array.push(undefined); - } - return array; - }); - }); - - /** - * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. + * Enables explicit method chaining on the wrapper object. * * @name chain * @memberOf _ - * @since 0.1.0 - * @category Seq + * @category Chain * @returns {Object} Returns the new `lodash` wrapper instance. * @example * @@ -8515,14 +5942,13 @@ * { 'user': 'fred', 'age': 40 } * ]; * - * // A sequence without explicit chaining. - * _(users).head(); + * // without explicit chaining + * _(users).first(); * // => { 'user': 'barney', 'age': 36 } * - * // A sequence with explicit chaining. - * _(users) - * .chain() - * .head() + * // with explicit chaining + * _(users).chain() + * .first() * .pick('user') * .value(); * // => { 'user': 'barney' } @@ -8532,12 +5958,11 @@ } /** - * Executes the chain sequence and returns the wrapped result. + * Executes the chained sequence and returns the wrapped result. * * @name commit * @memberOf _ - * @since 3.2.0 - * @category Seq + * @category Chain * @returns {Object} Returns the new `lodash` wrapper instance. * @example * @@ -8562,78 +5987,50 @@ } /** - * Gets the next value on a wrapped object following the - * [iterator protocol](https://mdn.io/iteration_protocols#iterator). + * Creates a new array joining a wrapped array with any additional arrays + * and/or values. * - * @name next + * @name concat * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the next iterator value. + * @category Chain + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. * @example * - * var wrapped = _([1, 2]); + * var array = [1]; + * var wrapped = _(array).concat(2, [3], [[4]]); * - * wrapped.next(); - * // => { 'done': false, 'value': 1 } + * console.log(wrapped.value()); + * // => [1, 2, 3, [4]] * - * wrapped.next(); - * // => { 'done': false, 'value': 2 } - * - * wrapped.next(); - * // => { 'done': true, 'value': undefined } + * console.log(array); + * // => [1] */ - function wrapperNext() { - if (this.__values__ === undefined) { - this.__values__ = toArray(this.value()); - } - var done = this.__index__ >= this.__values__.length, - value = done ? undefined : this.__values__[this.__index__++]; - - return { 'done': done, 'value': value }; - } + var wrapperConcat = restParam(function(values) { + values = baseFlatten(values); + return this.thru(function(array) { + return arrayConcat(isArray(array) ? array : [toObject(array)], values); + }); + }); /** - * Enables the wrapper to be iterable. - * - * @name Symbol.iterator - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the wrapper object. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped[Symbol.iterator]() === wrapped; - * // => true - * - * Array.from(wrapped); - * // => [1, 2] - */ - function wrapperToIterator() { - return this; - } - - /** - * Creates a clone of the chain sequence planting `value` as the wrapped value. + * Creates a clone of the chained sequence planting `value` as the wrapped value. * * @name plant * @memberOf _ - * @since 3.2.0 - * @category Seq - * @param {*} value The value to plant. + * @category Chain * @returns {Object} Returns the new `lodash` wrapper instance. * @example * - * function square(n) { - * return n * n; - * } + * var array = [1, 2]; + * var wrapped = _(array).map(function(value) { + * return Math.pow(value, 2); + * }); * - * var wrapped = _([1, 2]).map(square); - * var other = wrapped.plant([3, 4]); + * var other = [3, 4]; + * var otherWrapped = wrapped.plant(other); * - * other.value(); + * otherWrapped.value(); * // => [9, 16] * * wrapped.value(); @@ -8645,8 +6042,6 @@ while (parent instanceof baseLodash) { var clone = wrapperClone(parent); - clone.__index__ = 0; - clone.__values__ = undefined; if (result) { previous.__wrapped__ = clone; } else { @@ -8660,15 +6055,15 @@ } /** - * This method is the wrapper version of `_.reverse`. + * Reverses the wrapped array so the first element becomes the last, the + * second element becomes the second to last, and so on. * * **Note:** This method mutates the wrapped array. * * @name reverse * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. + * @category Chain + * @returns {Object} Returns the new reversed `lodash` wrapper instance. * @example * * var array = [1, 2, 3]; @@ -8681,30 +6076,45 @@ */ function wrapperReverse() { var value = this.__wrapped__; + + var interceptor = function(value) { + return value.reverse(); + }; if (value instanceof LazyWrapper) { var wrapped = value; if (this.__actions__.length) { wrapped = new LazyWrapper(this); } wrapped = wrapped.reverse(); - wrapped.__actions__.push({ - 'func': thru, - 'args': [reverse], - 'thisArg': undefined - }); + wrapped.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined }); return new LodashWrapper(wrapped, this.__chain__); } - return this.thru(reverse); + return this.thru(interceptor); } /** - * Executes the chain sequence to resolve the unwrapped value. + * Produces the result of coercing the unwrapped value to a string. + * + * @name toString + * @memberOf _ + * @category Chain + * @returns {string} Returns the coerced string value. + * @example + * + * _([1, 2, 3]).toString(); + * // => '1,2,3' + */ + function wrapperToString() { + return (this.value() + ''); + } + + /** + * Executes the chained sequence to extract the unwrapped value. * * @name value * @memberOf _ - * @since 0.1.0 - * @alias toJSON, valueOf - * @category Seq + * @alias run, toJSON, valueOf + * @category Chain * @returns {*} Returns the resolved unwrapped value. * @example * @@ -8718,25 +6128,67 @@ /*------------------------------------------------------------------------*/ /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the number of times the key was returned by `iteratee`. The - * iteratee is invoked with one argument: (value). + * Creates an array of elements corresponding to the given keys, or indexes, + * of `collection`. Keys may be specified as individual arguments or as arrays + * of keys. * * @static * @memberOf _ - * @since 0.5.0 * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The iteratee to transform keys. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(number|number[]|string|string[])} [props] The property names + * or indexes of elements to pick, specified individually or in arrays. + * @returns {Array} Returns the new array of picked elements. + * @example + * + * _.at(['a', 'b', 'c'], [0, 2]); + * // => ['a', 'c'] + * + * _.at(['barney', 'fred', 'pebbles'], 0, 2); + * // => ['barney', 'pebbles'] + */ + var at = restParam(function(collection, props) { + return baseAt(collection, baseFlatten(props)); + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is the number of times the key was returned by `iteratee`. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns the composed aggregate object. * @example * - * _.countBy([6.1, 4.2, 6.3], Math.floor); + * _.countBy([4.3, 6.1, 6.4], function(n) { + * return Math.floor(n); + * }); + * // => { '4': 1, '6': 2 } + * + * _.countBy([4.3, 6.1, 6.4], function(n) { + * return this.floor(n); + * }, Math); * // => { '4': 1, '6': 2 } * - * // The `_.property` iteratee shorthand. * _.countBy(['one', 'two', 'three'], 'length'); * // => { '3': 2, '5': 1 } */ @@ -8746,22 +6198,28 @@ /** * Checks if `predicate` returns truthy for **all** elements of `collection`. - * Iteration is stopped once `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index|key, collection). + * The predicate is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). * - * **Note:** This method returns `true` for - * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because - * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of - * elements of empty collections. + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 0.1.0 + * @alias all * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {boolean} Returns `true` if all elements pass the predicate check, * else `false`. * @example @@ -8770,86 +6228,112 @@ * // => false * * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': false } + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false } * ]; * - * // The `_.matches` iteratee shorthand. + * // using the `_.matches` callback shorthand * _.every(users, { 'user': 'barney', 'active': false }); * // => false * - * // The `_.matchesProperty` iteratee shorthand. - * _.every(users, ['active', false]); + * // using the `_.matchesProperty` callback shorthand + * _.every(users, 'active', false); * // => true * - * // The `_.property` iteratee shorthand. + * // using the `_.property` callback shorthand * _.every(users, 'active'); * // => false */ - function every(collection, predicate, guard) { + function every(collection, predicate, thisArg) { var func = isArray(collection) ? arrayEvery : baseEvery; - if (guard && isIterateeCall(collection, predicate, guard)) { + if (thisArg && isIterateeCall(collection, predicate, thisArg)) { predicate = undefined; } - return func(collection, getIteratee(predicate, 3)); + if (typeof predicate != 'function' || thisArg !== undefined) { + predicate = getCallback(predicate, thisArg, 3); + } + return func(collection, predicate); } /** * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments: (value, index|key, collection). * - * **Note:** Unlike `_.remove`, this method returns a new array. + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 0.1.0 + * @alias select * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Array} Returns the new filtered array. - * @see _.reject * @example * + * _.filter([4, 5, 6], function(n) { + * return n % 2 == 0; + * }); + * // => [4, 6] + * * var users = [ * { 'user': 'barney', 'age': 36, 'active': true }, * { 'user': 'fred', 'age': 40, 'active': false } * ]; * - * _.filter(users, function(o) { return !o.active; }); - * // => objects for ['fred'] + * // using the `_.matches` callback shorthand + * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user'); + * // => ['barney'] * - * // The `_.matches` iteratee shorthand. - * _.filter(users, { 'age': 36, 'active': true }); - * // => objects for ['barney'] + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.filter(users, 'active', false), 'user'); + * // => ['fred'] * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.filter(users, 'active'); - * // => objects for ['barney'] + * // using the `_.property` callback shorthand + * _.pluck(_.filter(users, 'active'), 'user'); + * // => ['barney'] */ - function filter(collection, predicate) { + function filter(collection, predicate, thisArg) { var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, getIteratee(predicate, 3)); + predicate = getCallback(predicate, thisArg, 3); + return func(collection, predicate); } /** * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). + * `predicate` returns truthy for. The predicate is bound to `thisArg` and + * invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 0.1.0 + * @alias detect * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {*} Returns the matched element, else `undefined`. * @example * @@ -8859,22 +6343,24 @@ * { 'user': 'pebbles', 'age': 1, 'active': true } * ]; * - * _.find(users, function(o) { return o.age < 40; }); - * // => object for 'barney' + * _.result(_.find(users, function(chr) { + * return chr.age < 40; + * }), 'user'); + * // => 'barney' * - * // The `_.matches` iteratee shorthand. - * _.find(users, { 'age': 1, 'active': true }); - * // => object for 'pebbles' + * // using the `_.matches` callback shorthand + * _.result(_.find(users, { 'age': 1, 'active': true }), 'user'); + * // => 'pebbles' * - * // The `_.matchesProperty` iteratee shorthand. - * _.find(users, ['active', false]); - * // => object for 'fred' + * // using the `_.matchesProperty` callback shorthand + * _.result(_.find(users, 'active', false), 'user'); + * // => 'fred' * - * // The `_.property` iteratee shorthand. - * _.find(users, 'active'); - * // => object for 'barney' + * // using the `_.property` callback shorthand + * _.result(_.find(users, 'active'), 'user'); + * // => 'barney' */ - var find = createFind(findIndex); + var find = createFind(baseEach); /** * This method is like `_.find` except that it iterates over elements of @@ -8882,12 +6368,11 @@ * * @static * @memberOf _ - * @since 2.0.0 * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] - * The function invoked per iteration. - * @param {number} [fromIndex=collection.length-1] The index to search from. + * @param {Array|Object|string} collection The collection to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {*} Returns the matched element, else `undefined`. * @example * @@ -8896,120 +6381,72 @@ * }); * // => 3 */ - var findLast = createFind(findLastIndex); + var findLast = createFind(baseEachRight, true); /** - * Creates a flattened array of values by running each element in `collection` - * thru `iteratee` and flattening the mapped results. The iteratee is invoked - * with three arguments: (value, index|key, collection). + * Performs a deep comparison between each element in `collection` and the + * source object, returning the first element that has equivalent property + * values. + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Objects are compared by + * their own, not inherited, enumerable properties. For comparing a single + * own or inherited property value see `_.matchesProperty`. * * @static * @memberOf _ - * @since 4.0.0 * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the new flattened array. + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {*} Returns the matched element, else `undefined`. * @example * - * function duplicate(n) { - * return [n, n]; - * } + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; * - * _.flatMap([1, 2], duplicate); - * // => [1, 1, 2, 2] + * _.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user'); + * // => 'barney' + * + * _.result(_.findWhere(users, { 'age': 40, 'active': false }), 'user'); + * // => 'fred' */ - function flatMap(collection, iteratee) { - return baseFlatten(map(collection, iteratee), 1); + function findWhere(collection, source) { + return find(collection, baseMatches(source)); } /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results. + * Iterates over elements of `collection` invoking `iteratee` for each element. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). Iteratee functions may exit iteration early + * by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. * * @static * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The function invoked per iteration. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDeep([1, 2], duplicate); - * // => [1, 1, 2, 2] - */ - function flatMapDeep(collection, iteratee) { - return baseFlatten(map(collection, iteratee), INFINITY); - } - - /** - * This method is like `_.flatMap` except that it recursively flattens the - * mapped results up to `depth` times. - * - * @static - * @memberOf _ - * @since 4.7.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The function invoked per iteration. - * @param {number} [depth=1] The maximum recursion depth. - * @returns {Array} Returns the new flattened array. - * @example - * - * function duplicate(n) { - * return [[[n, n]]]; - * } - * - * _.flatMapDepth([1, 2], duplicate, 2); - * // => [[1, 1], [2, 2]] - */ - function flatMapDepth(collection, iteratee, depth) { - depth = depth === undefined ? 1 : toInteger(depth); - return baseFlatten(map(collection, iteratee), depth); - } - - /** - * Iterates over elements of `collection` and invokes `iteratee` for each element. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" - * property are iterated like arrays. To avoid this behavior use `_.forIn` - * or `_.forOwn` for object iteration. - * - * @static - * @memberOf _ - * @since 0.1.0 * @alias each * @category Collection - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEachRight + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. * @example * - * _([1, 2]).forEach(function(value) { - * console.log(value); - * }); - * // => Logs `1` then `2`. + * _([1, 2]).forEach(function(n) { + * console.log(n); + * }).value(); + * // => logs each value from left to right and returns the array * - * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { - * console.log(key); + * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) { + * console.log(n, key); * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). + * // => logs each value-key pair and returns the object (iteration order is not guaranteed) */ - function forEach(collection, iteratee) { - var func = isArray(collection) ? arrayEach : baseEach; - return func(collection, getIteratee(iteratee, 3)); - } + var forEach = createForEach(arrayEach, baseEach); /** * This method is like `_.forEach` except that it iterates over elements of @@ -9017,46 +6454,60 @@ * * @static * @memberOf _ - * @since 2.0.0 * @alias eachRight * @category Collection - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEach + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array|Object|string} Returns `collection`. * @example * - * _.forEachRight([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `2` then `1`. + * _([1, 2]).forEachRight(function(n) { + * console.log(n); + * }).value(); + * // => logs each value from right to left and returns the array */ - function forEachRight(collection, iteratee) { - var func = isArray(collection) ? arrayEachRight : baseEachRight; - return func(collection, getIteratee(iteratee, 3)); - } + var forEachRight = createForEach(arrayEachRight, baseEachRight); /** * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The order of grouped values - * is determined by the order they occur in `collection`. The corresponding - * value of each key is an array of elements responsible for generating the - * key. The iteratee is invoked with one argument: (value). + * each element of `collection` through `iteratee`. The corresponding value + * of each key is an array of the elements responsible for generating the key. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 0.1.0 * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The iteratee to transform keys. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns the composed aggregate object. * @example * - * _.groupBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': [4.2], '6': [6.1, 6.3] } + * _.groupBy([4.2, 6.1, 6.4], function(n) { + * return Math.floor(n); + * }); + * // => { '4': [4.2], '6': [6.1, 6.4] } * - * // The `_.property` iteratee shorthand. + * _.groupBy([4.2, 6.1, 6.4], function(n) { + * return this.floor(n); + * }, Math); + * // => { '4': [4.2], '6': [6.1, 6.4] } + * + * // using the `_.property` callback shorthand * _.groupBy(['one', 'two', 'three'], 'length'); * // => { '3': ['one', 'two'], '5': ['three'] } */ @@ -9069,21 +6520,20 @@ }); /** - * Checks if `value` is in `collection`. If `collection` is a string, it's - * checked for a substring of `value`, otherwise - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * is used for equality comparisons. If `fromIndex` is negative, it's used as - * the offset from the end of `collection`. + * Checks if `target` is in `collection` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the offset + * from the end of `collection`. * * @static * @memberOf _ - * @since 0.1.0 + * @alias contains, include * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @param {*} value The value to search for. + * @param {Array|Object|string} collection The collection to search. + * @param {*} target The value to search for. * @param {number} [fromIndex=0] The index to search from. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. + * @returns {boolean} Returns `true` if a matching element is found, else `false`. * @example * * _.includes([1, 2, 3], 1); @@ -9092,49 +6542,101 @@ * _.includes([1, 2, 3], 1, 2); * // => false * - * _.includes({ 'a': 1, 'b': 2 }, 1); + * _.includes({ 'user': 'fred', 'age': 40 }, 'fred'); * // => true * - * _.includes('abcd', 'bc'); + * _.includes('pebbles', 'eb'); * // => true */ - function includes(collection, value, fromIndex, guard) { - collection = isArrayLike(collection) ? collection : values(collection); - fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; - - var length = collection.length; - if (fromIndex < 0) { - fromIndex = nativeMax(length + fromIndex, 0); + function includes(collection, target, fromIndex, guard) { + var length = collection ? getLength(collection) : 0; + if (!isLength(length)) { + collection = values(collection); + length = collection.length; } - return isString(collection) - ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) - : (!!length && baseIndexOf(collection, value, fromIndex) > -1); + if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) { + fromIndex = 0; + } else { + fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); + } + return (typeof collection == 'string' || !isArray(collection) && isString(collection)) + ? (fromIndex <= length && collection.indexOf(target, fromIndex) > -1) + : (!!length && getIndexOf(collection, target, fromIndex) > -1); } + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` through `iteratee`. The corresponding value + * of each key is the last element responsible for generating the key. The + * iteratee function is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var keyData = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.indexBy(keyData, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keyData, function(object) { + * return String.fromCharCode(object.code); + * }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.indexBy(keyData, function(object) { + * return this.fromCharCode(object.code); + * }, String); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + */ + var indexBy = createAggregator(function(result, value, key) { + result[key] = value; + }); + /** * Invokes the method at `path` of each element in `collection`, returning * an array of the results of each invoked method. Any additional arguments - * are provided to each invoked method. If `path` is a function, it's invoked - * for, and `this` bound to, each element in `collection`. + * are provided to each invoked method. If `methodName` is a function it's + * invoked for, and `this` bound to, each element in `collection`. * * @static * @memberOf _ - * @since 4.0.0 * @category Collection - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Array|Function|string} path The path of the method to invoke or * the function invoked per iteration. - * @param {...*} [args] The arguments to invoke each method with. + * @param {...*} [args] The arguments to invoke the method with. * @returns {Array} Returns the array of results. * @example * - * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); + * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); * // => [[1, 5, 7], [1, 2, 3]] * - * _.invokeMap([123, 456], String.prototype.split, ''); + * _.invoke([123, 456], String.prototype.split, ''); * // => [['1', '2', '3'], ['4', '5', '6']] */ - var invokeMap = baseRest(function(collection, path, args) { + var invoke = restParam(function(collection, path, args) { var index = -1, isFunc = typeof path == 'function', isProp = isKey(path), @@ -9142,217 +6644,201 @@ baseEach(collection, function(value) { var func = isFunc ? path : ((isProp && value != null) ? value[path] : undefined); - result[++index] = func ? apply(func, value, args) : baseInvoke(value, path, args); + result[++index] = func ? func.apply(value, args) : invokePath(value, path, args); }); return result; }); /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the last element responsible for generating the key. The - * iteratee is invoked with one argument: (value). + * Creates an array of values by running each element in `collection` through + * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three + * arguments: (value, index|key, collection). * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] - * The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. * - * var array = [ - * { 'dir': 'left', 'code': 97 }, - * { 'dir': 'right', 'code': 100 } - * ]; + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. * - * _.keyBy(array, function(o) { - * return String.fromCharCode(o.code); - * }); - * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } - * - * _.keyBy(array, 'dir'); - * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } - */ - var keyBy = createAggregator(function(result, value, key) { - result[key] = value; - }); - - /** - * Creates an array of values by running each element in `collection` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, index|key, collection). + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * Many lodash methods are guarded to work as iteratees for methods like * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. * * The guarded methods are: - * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, - * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, - * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, - * `template`, `trim`, `trimEnd`, `trimStart`, and `words` + * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`, + * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`, + * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`, + * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`, + * `sum`, `uniq`, and `words` * * @static * @memberOf _ - * @since 0.1.0 + * @alias collect * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Array} Returns the new mapped array. * @example * - * function square(n) { - * return n * n; + * function timesThree(n) { + * return n * 3; * } * - * _.map([4, 8], square); - * // => [16, 64] + * _.map([1, 2], timesThree); + * // => [3, 6] * - * _.map({ 'a': 4, 'b': 8 }, square); - * // => [16, 64] (iteration order is not guaranteed) + * _.map({ 'a': 1, 'b': 2 }, timesThree); + * // => [3, 6] (iteration order is not guaranteed) * * var users = [ * { 'user': 'barney' }, * { 'user': 'fred' } * ]; * - * // The `_.property` iteratee shorthand. + * // using the `_.property` callback shorthand * _.map(users, 'user'); * // => ['barney', 'fred'] */ - function map(collection, iteratee) { + function map(collection, iteratee, thisArg) { var func = isArray(collection) ? arrayMap : baseMap; - return func(collection, getIteratee(iteratee, 3)); - } - - /** - * This method is like `_.sortBy` except that it allows specifying the sort - * orders of the iteratees to sort by. If `orders` is unspecified, all values - * are sorted in ascending order. Otherwise, specify an order of "desc" for - * descending or "asc" for ascending sort order of corresponding values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] - * The iteratees to sort by. - * @param {string[]} [orders] The sort orders of `iteratees`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 34 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 36 } - * ]; - * - * // Sort by `user` in ascending order and by `age` in descending order. - * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - */ - function orderBy(collection, iteratees, orders, guard) { - if (collection == null) { - return []; - } - if (!isArray(iteratees)) { - iteratees = iteratees == null ? [] : [iteratees]; - } - orders = guard ? undefined : orders; - if (!isArray(orders)) { - orders = orders == null ? [] : [orders]; - } - return baseOrderBy(collection, iteratees, orders); + iteratee = getCallback(iteratee, thisArg, 3); + return func(collection, iteratee); } /** * Creates an array of elements split into two groups, the first of which - * contains elements `predicate` returns truthy for, the second of which - * contains elements `predicate` returns falsey for. The predicate is - * invoked with one argument: (value). + * contains elements `predicate` returns truthy for, while the second of which + * contains elements `predicate` returns falsey for. The predicate is bound + * to `thisArg` and invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 3.0.0 * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Array} Returns the array of grouped elements. * @example * + * _.partition([1, 2, 3], function(n) { + * return n % 2; + * }); + * // => [[1, 3], [2]] + * + * _.partition([1.2, 2.3, 3.4], function(n) { + * return this.floor(n) % 2; + * }, Math); + * // => [[1.2, 3.4], [2.3]] + * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true }, * { 'user': 'pebbles', 'age': 1, 'active': false } * ]; * - * _.partition(users, function(o) { return o.active; }); - * // => objects for [['fred'], ['barney', 'pebbles']] + * var mapper = function(array) { + * return _.pluck(array, 'user'); + * }; * - * // The `_.matches` iteratee shorthand. - * _.partition(users, { 'age': 1, 'active': false }); - * // => objects for [['pebbles'], ['barney', 'fred']] + * // using the `_.matches` callback shorthand + * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); + * // => [['pebbles'], ['barney', 'fred']] * - * // The `_.matchesProperty` iteratee shorthand. - * _.partition(users, ['active', false]); - * // => objects for [['barney', 'pebbles'], ['fred']] + * // using the `_.matchesProperty` callback shorthand + * _.map(_.partition(users, 'active', false), mapper); + * // => [['barney', 'pebbles'], ['fred']] * - * // The `_.property` iteratee shorthand. - * _.partition(users, 'active'); - * // => objects for [['fred'], ['barney', 'pebbles']] + * // using the `_.property` callback shorthand + * _.map(_.partition(users, 'active'), mapper); + * // => [['fred'], ['barney', 'pebbles']] */ var partition = createAggregator(function(result, value, key) { result[key ? 0 : 1].push(value); }, function() { return [[], []]; }); + /** + * Gets the property value of `path` from all elements in `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Array|string} path The path of the property to pluck. + * @returns {Array} Returns the property values. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * _.pluck(users, 'user'); + * // => ['barney', 'fred'] + * + * var userIndex = _.indexBy(users, 'user'); + * _.pluck(userIndex, 'age'); + * // => [36, 40] (iteration order is not guaranteed) + */ + function pluck(collection, path) { + return map(collection, property(path)); + } + /** * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` thru `iteratee`, where each successive + * each element in `collection` through `iteratee`, where each successive * invocation is supplied the return value of the previous. If `accumulator` - * is not given, the first element of `collection` is used as the initial - * value. The iteratee is invoked with four arguments: + * is not provided the first element of `collection` is used as the initial + * value. The `iteratee` is bound to `thisArg` and invoked with four arguments: * (accumulator, value, index|key, collection). * * Many lodash methods are guarded to work as iteratees for methods like * `_.reduce`, `_.reduceRight`, and `_.transform`. * * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, - * and `sortBy` + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `sortByAll`, + * and `sortByOrder` * * @static * @memberOf _ - * @since 0.1.0 + * @alias foldl, inject * @category Collection - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {*} Returns the accumulated value. - * @see _.reduceRight * @example * - * _.reduce([1, 2], function(sum, n) { - * return sum + n; - * }, 0); + * _.reduce([1, 2], function(total, n) { + * return total + n; + * }); * // => 3 * - * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); + * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) { + * result[key] = n * 3; * return result; * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) + * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed) */ - function reduce(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduce : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); - } + var reduce = createReduce(arrayReduce, baseEach); /** * This method is like `_.reduce` except that it iterates over elements of @@ -9360,13 +6846,13 @@ * * @static * @memberOf _ - * @since 0.1.0 + * @alias foldr * @category Collection - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object|string} collection The collection to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The initial value. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {*} Returns the accumulated value. - * @see _.reduce * @example * * var array = [[0, 1], [2, 3], [4, 5]]; @@ -9376,12 +6862,7 @@ * }, []); * // => [4, 5, 2, 3, 0, 1] */ - function reduceRight(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduceRight : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); - } + var reduceRight = createReduce(arrayReduceRight, baseEachRight); /** * The opposite of `_.filter`; this method returns the elements of `collection` @@ -9389,91 +6870,74 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Array} Returns the new filtered array. - * @see _.filter * @example * + * _.reject([1, 2, 3, 4], function(n) { + * return n % 2 == 0; + * }); + * // => [1, 3] + * * var users = [ * { 'user': 'barney', 'age': 36, 'active': false }, * { 'user': 'fred', 'age': 40, 'active': true } * ]; * - * _.reject(users, function(o) { return !o.active; }); - * // => objects for ['fred'] + * // using the `_.matches` callback shorthand + * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user'); + * // => ['barney'] * - * // The `_.matches` iteratee shorthand. - * _.reject(users, { 'age': 40, 'active': true }); - * // => objects for ['barney'] + * // using the `_.matchesProperty` callback shorthand + * _.pluck(_.reject(users, 'active', false), 'user'); + * // => ['fred'] * - * // The `_.matchesProperty` iteratee shorthand. - * _.reject(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.reject(users, 'active'); - * // => objects for ['barney'] + * // using the `_.property` callback shorthand + * _.pluck(_.reject(users, 'active'), 'user'); + * // => ['barney'] */ - function reject(collection, predicate) { + function reject(collection, predicate, thisArg) { var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, negate(getIteratee(predicate, 3))); + predicate = getCallback(predicate, thisArg, 3); + return func(collection, function(value, index, collection) { + return !predicate(value, index, collection); + }); } /** - * Gets a random element from `collection`. + * Gets a random element or `n` random elements from a collection. * * @static * @memberOf _ - * @since 2.0.0 * @category Collection - * @param {Array|Object} collection The collection to sample. - * @returns {*} Returns the random element. + * @param {Array|Object|string} collection The collection to sample. + * @param {number} [n] The number of elements to sample. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {*} Returns the random sample(s). * @example * * _.sample([1, 2, 3, 4]); * // => 2 - */ - function sample(collection) { - var array = isArrayLike(collection) ? collection : values(collection), - length = array.length; - - return length > 0 ? array[baseRandom(0, length - 1)] : undefined; - } - - /** - * Gets `n` random elements at unique keys from `collection` up to the - * size of `collection`. * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Collection - * @param {Array|Object} collection The collection to sample. - * @param {number} [n=1] The number of elements to sample. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the random elements. - * @example - * - * _.sampleSize([1, 2, 3], 2); + * _.sample([1, 2, 3, 4], 2); * // => [3, 1] - * - * _.sampleSize([1, 2, 3], 4); - * // => [2, 3, 1] */ - function sampleSize(collection, n, guard) { + function sample(collection, n, guard) { + if (guard ? isIterateeCall(collection, n, guard) : n == null) { + collection = toIterable(collection); + var length = collection.length; + return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; + } var index = -1, result = toArray(collection), length = result.length, lastIndex = length - 1; - if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { - n = 1; - } else { - n = baseClamp(toInteger(n), 0, length); - } + n = nativeMin(n < 0 ? 0 : (+n || 0), length); while (++index < n) { var rand = baseRandom(index, lastIndex), value = result[rand]; @@ -9491,9 +6955,8 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Collection - * @param {Array|Object} collection The collection to shuffle. + * @param {Array|Object|string} collection The collection to shuffle. * @returns {Array} Returns the new shuffled array. * @example * @@ -9501,19 +6964,18 @@ * // => [4, 1, 3, 2] */ function shuffle(collection) { - return sampleSize(collection, MAX_ARRAY_LENGTH); + return sample(collection, POSITIVE_INFINITY); } /** * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable string keyed properties for objects. + * values or the number of own enumerable properties for objects. * * @static * @memberOf _ - * @since 0.1.0 * @category Collection * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the collection size. + * @returns {number} Returns the size of `collection`. * @example * * _.size([1, 2, 3]); @@ -9526,31 +6988,35 @@ * // => 7 */ function size(collection) { - if (collection == null) { - return 0; - } - if (isArrayLike(collection)) { - return isString(collection) ? stringSize(collection) : collection.length; - } - var tag = getTag(collection); - if (tag == mapTag || tag == setTag) { - return collection.size; - } - return baseKeys(collection).length; + var length = collection ? getLength(collection) : 0; + return isLength(length) ? length : keys(collection).length; } /** * Checks if `predicate` returns truthy for **any** element of `collection`. - * Iteration is stopped once `predicate` returns truthy. The predicate is - * invoked with three arguments: (value, index|key, collection). + * The function returns as soon as it finds a passing value and does not iterate + * over the entire collection. The predicate is bound to `thisArg` and invoked + * with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 0.1.0 + * @alias any * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {boolean} Returns `true` if any element passes the predicate check, * else `false`. * @example @@ -9563,93 +7029,240 @@ * { 'user': 'fred', 'active': false } * ]; * - * // The `_.matches` iteratee shorthand. + * // using the `_.matches` callback shorthand * _.some(users, { 'user': 'barney', 'active': false }); * // => false * - * // The `_.matchesProperty` iteratee shorthand. - * _.some(users, ['active', false]); + * // using the `_.matchesProperty` callback shorthand + * _.some(users, 'active', false); * // => true * - * // The `_.property` iteratee shorthand. + * // using the `_.property` callback shorthand * _.some(users, 'active'); * // => true */ - function some(collection, predicate, guard) { + function some(collection, predicate, thisArg) { var func = isArray(collection) ? arraySome : baseSome; - if (guard && isIterateeCall(collection, predicate, guard)) { + if (thisArg && isIterateeCall(collection, predicate, thisArg)) { predicate = undefined; } - return func(collection, getIteratee(predicate, 3)); + if (typeof predicate != 'function' || thisArg !== undefined) { + predicate = getCallback(predicate, thisArg, 3); + } + return func(collection, predicate); } /** * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection thru each iteratee. This method - * performs a stable sort, that is, it preserves the original sort order of - * equal elements. The iteratees are invoked with one argument: (value). + * running each element in a collection through `iteratee`. This method performs + * a stable sort, that is, it preserves the original sort order of equal elements. + * The `iteratee` is bound to `thisArg` and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. * * @static * @memberOf _ - * @since 0.1.0 * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {...(Function|Function[])} [iteratees=[_.identity]] - * The iteratees to sort by. + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @returns {Array} Returns the new sorted array. + * @example + * + * _.sortBy([1, 2, 3], function(n) { + * return Math.sin(n); + * }); + * // => [3, 1, 2] + * + * _.sortBy([1, 2, 3], function(n) { + * return this.sin(n); + * }, Math); + * // => [3, 1, 2] + * + * var users = [ + * { 'user': 'fred' }, + * { 'user': 'pebbles' }, + * { 'user': 'barney' } + * ]; + * + * // using the `_.property` callback shorthand + * _.pluck(_.sortBy(users, 'user'), 'user'); + * // => ['barney', 'fred', 'pebbles'] + */ + function sortBy(collection, iteratee, thisArg) { + if (collection == null) { + return []; + } + if (thisArg && isIterateeCall(collection, iteratee, thisArg)) { + iteratee = undefined; + } + var index = -1; + iteratee = getCallback(iteratee, thisArg, 3); + + var result = baseMap(collection, function(value, key, collection) { + return { 'criteria': iteratee(value, key, collection), 'index': ++index, 'value': value }; + }); + return baseSortBy(result, compareAscending); + } + + /** + * This method is like `_.sortBy` except that it can sort by multiple iteratees + * or property names. + * + * If a property name is provided for an iteratee the created `_.property` + * style callback returns the property value of the given element. + * + * If an object is provided for an iteratee the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {...(Function|Function[]|Object|Object[]|string|string[])} iteratees + * The iteratees to sort by, specified as individual values or arrays of values. * @returns {Array} Returns the new sorted array. * @example * * var users = [ * { 'user': 'fred', 'age': 48 }, * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, + * { 'user': 'fred', 'age': 42 }, * { 'user': 'barney', 'age': 34 } * ]; * - * _.sortBy(users, function(o) { return o.user; }); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + * _.map(_.sortByAll(users, ['user', 'age']), _.values); + * // => [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]] * - * _.sortBy(users, ['user', 'age']); - * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] - * - * _.sortBy(users, 'user', function(o) { - * return Math.floor(o.age / 10); - * }); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + * _.map(_.sortByAll(users, 'user', function(chr) { + * return Math.floor(chr.age / 10); + * }), _.values); + * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] */ - var sortBy = baseRest(function(collection, iteratees) { + var sortByAll = restParam(function(collection, iteratees) { if (collection == null) { return []; } - var length = iteratees.length; - if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { - iteratees = []; - } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { - iteratees = [iteratees[0]]; + var guard = iteratees[2]; + if (guard && isIterateeCall(iteratees[0], iteratees[1], guard)) { + iteratees.length = 1; } - return baseOrderBy(collection, baseFlatten(iteratees, 1), []); + return baseSortByOrder(collection, baseFlatten(iteratees), []); }); + /** + * This method is like `_.sortByAll` except that it allows specifying the + * sort orders of the iteratees to sort by. If `orders` is unspecified, all + * values are sorted in ascending order. Otherwise, a value is sorted in + * ascending order if its corresponding order is "asc", and descending if "desc". + * + * If a property name is provided for an iteratee the created `_.property` + * style callback returns the property value of the given element. + * + * If an object is provided for an iteratee the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {boolean[]} [orders] The sort orders of `iteratees`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 34 }, + * { 'user': 'fred', 'age': 42 }, + * { 'user': 'barney', 'age': 36 } + * ]; + * + * // sort by `user` in ascending order and by `age` in descending order + * _.map(_.sortByOrder(users, ['user', 'age'], ['asc', 'desc']), _.values); + * // => [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] + */ + function sortByOrder(collection, iteratees, orders, guard) { + if (collection == null) { + return []; + } + if (guard && isIterateeCall(iteratees, orders, guard)) { + orders = undefined; + } + if (!isArray(iteratees)) { + iteratees = iteratees == null ? [] : [iteratees]; + } + if (!isArray(orders)) { + orders = orders == null ? [] : [orders]; + } + return baseSortByOrder(collection, iteratees, orders); + } + + /** + * Performs a deep comparison between each element in `collection` and the + * source object, returning an array of all elements that have equivalent + * property values. + * + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Objects are compared by + * their own, not inherited, enumerable properties. For comparing a single + * own or inherited property value see `_.matchesProperty`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to search. + * @param {Object} source The object of property values to match. + * @returns {Array} Returns the new filtered array. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false, 'pets': ['hoppy'] }, + * { 'user': 'fred', 'age': 40, 'active': true, 'pets': ['baby puss', 'dino'] } + * ]; + * + * _.pluck(_.where(users, { 'age': 36, 'active': false }), 'user'); + * // => ['barney'] + * + * _.pluck(_.where(users, { 'pets': ['dino'] }), 'user'); + * // => ['fred'] + */ + function where(collection, source) { + return filter(collection, baseMatches(source)); + } + /*------------------------------------------------------------------------*/ /** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). * * @static * @memberOf _ - * @since 2.4.0 * @category Date - * @returns {number} Returns the timestamp. * @example * * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. + * // => logs the number of milliseconds it took for the deferred function to be invoked */ - var now = ctxNow || function() { - return root.Date.now(); + var now = nativeNow || function() { + return new Date().getTime(); }; /*------------------------------------------------------------------------*/ @@ -9660,7 +7273,6 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Function * @param {number} n The number of calls before `func` is invoked. * @param {Function} func The function to restrict. @@ -9676,13 +7288,19 @@ * _.forEach(saves, function(type) { * asyncSave({ 'type': type, 'complete': done }); * }); - * // => Logs 'done saving!' after the two async saves have completed. + * // => logs 'done saving!' after the two async saves have completed */ function after(n, func) { if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); + if (typeof n == 'function') { + var temp = n; + n = func; + func = temp; + } else { + throw new TypeError(FUNC_ERROR_TEXT); + } } - n = toInteger(n); + n = nativeIsFinite(n = +n) ? n : 0; return function() { if (--n < 1) { return func.apply(this, arguments); @@ -9691,26 +7309,27 @@ } /** - * Creates a function that invokes `func`, with up to `n` arguments, - * ignoring any additional arguments. + * Creates a function that accepts up to `n` arguments ignoring any + * additional arguments. * * @static * @memberOf _ - * @since 3.0.0 * @category Function * @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 capped function. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. + * @returns {Function} Returns the new function. * @example * * _.map(['6', '8', '10'], _.ary(parseInt, 1)); * // => [6, 8, 10] */ function ary(func, n, guard) { - n = guard ? undefined : n; - n = (func && n == null) ? func.length : n; - return createWrap(func, ARY_FLAG, undefined, undefined, undefined, undefined, n); + if (guard && isIterateeCall(func, n, guard)) { + n = undefined; + } + n = (func && n == null) ? func.length : nativeMax(+n || 0, 0); + return createWrapper(func, ARY_FLAG, undefined, undefined, undefined, undefined, n); } /** @@ -9720,22 +7339,26 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category Function * @param {number} n The number of calls at which `func` is no longer invoked. * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * - * jQuery(element).on('click', _.before(5, addContactToList)); - * // => Allows adding up to 4 contacts to the list. + * jQuery('#add').on('click', _.before(5, addContactToList)); + * // => allows adding up to 4 contacts to the list */ function before(n, func) { var result; if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); + if (typeof n == 'function') { + var temp = n; + n = func; + func = temp; + } else { + throw new TypeError(FUNC_ERROR_TEXT); + } } - n = toInteger(n); return function() { if (--n > 0) { result = func.apply(this, arguments); @@ -9749,17 +7372,17 @@ /** * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and `partials` prepended to the arguments it receives. + * and prepends any additional `_.bind` arguments to those provided to the + * bound function. * * 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 does not set the "length" * property of bound functions. * * @static * @memberOf _ - * @since 0.1.0 * @category Function * @param {Function} func The function to bind. * @param {*} thisArg The `this` binding of `func`. @@ -9767,9 +7390,9 @@ * @returns {Function} Returns the new bound function. * @example * - * function greet(greeting, punctuation) { + * var greet = function(greeting, punctuation) { * return greeting + ' ' + this.user + punctuation; - * } + * }; * * var object = { 'user': 'fred' }; * @@ -9777,27 +7400,68 @@ * bound('!'); * // => 'hi fred!' * - * // Bound with placeholders. + * // using placeholders * var bound = _.bind(greet, object, _, '!'); * bound('hi'); * // => 'hi fred!' */ - var bind = baseRest(function(func, thisArg, partials) { + var bind = restParam(function(func, thisArg, partials) { var bitmask = BIND_FLAG; if (partials.length) { - var holders = replaceHolders(partials, getHolder(bind)); + var holders = replaceHolders(partials, bind.placeholder); bitmask |= PARTIAL_FLAG; } - return createWrap(func, bitmask, thisArg, partials, holders); + return createWrapper(func, bitmask, thisArg, partials, holders); }); /** - * Creates a function that invokes the method at `object[key]` with `partials` - * prepended to the arguments it receives. + * Binds methods of an object to the object itself, overwriting the existing + * method. Method names may be specified as individual arguments or as arrays + * of method names. If no method names are provided all enumerable function + * properties, own and inherited, of `object` are bound. + * + * **Note:** This method does not set the "length" property of bound functions. + * + * @static + * @memberOf _ + * @category Function + * @param {Object} object The object to bind and assign the bound methods to. + * @param {...(string|string[])} [methodNames] The object method names to bind, + * specified as individual method names or arrays of method names. + * @returns {Object} Returns `object`. + * @example + * + * var view = { + * 'label': 'docs', + * 'onClick': function() { + * console.log('clicked ' + this.label); + * } + * }; + * + * _.bindAll(view); + * jQuery('#docs').on('click', view.onClick); + * // => logs 'clicked docs' when the element is clicked + */ + var bindAll = restParam(function(object, methodNames) { + methodNames = methodNames.length ? baseFlatten(methodNames) : functions(object); + + var index = -1, + length = methodNames.length; + + while (++index < length) { + var key = methodNames[index]; + object[key] = createWrapper(object[key], BIND_FLAG, object); + } + return object; + }); + + /** + * Creates a function that invokes the method at `object[key]` and prepends + * any additional `_.bindKey` arguments to those provided to the bound function. * * This method differs from `_.bind` by allowing bound functions to reference - * methods that may be redefined or don't yet exist. See - * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) + * methods that may be redefined or don't yet exist. + * See [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) * for more details. * * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic @@ -9805,9 +7469,8 @@ * * @static * @memberOf _ - * @since 0.10.0 * @category Function - * @param {Object} object The object to invoke the method on. + * @param {Object} object The object the method belongs to. * @param {string} key The key of the method. * @param {...*} [partials] The arguments to be partially applied. * @returns {Function} Returns the new bound function. @@ -9831,39 +7494,38 @@ * bound('!'); * // => 'hiya fred!' * - * // Bound with placeholders. + * // using placeholders * var bound = _.bindKey(object, 'greet', _, '!'); * bound('hi'); * // => 'hiya fred!' */ - var bindKey = baseRest(function(object, key, partials) { + var bindKey = restParam(function(object, key, partials) { var bitmask = BIND_FLAG | BIND_KEY_FLAG; if (partials.length) { - var holders = replaceHolders(partials, getHolder(bindKey)); + var holders = replaceHolders(partials, bindKey.placeholder); bitmask |= PARTIAL_FLAG; } - return createWrap(key, bitmask, object, partials, holders); + return createWrapper(key, bitmask, object, partials, holders); }); /** - * Creates a function that accepts arguments of `func` and either invokes - * `func` returning its result, if at least `arity` number of arguments have - * been provided, or returns a function that accepts the remaining `func` - * arguments, and so on. The arity of `func` may be specified if `func.length` - * is not sufficient. + * Creates a function that accepts one or more arguments of `func` that when + * called either invokes `func` returning its result, if all `func` arguments + * have been provided, or returns a function that accepts one or more of the + * remaining `func` arguments, and so on. The arity of `func` may be specified + * if `func.length` is not sufficient. * * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, * may be used as a placeholder for provided arguments. * - * **Note:** This method doesn't set the "length" property of curried functions. + * **Note:** This method does not set the "length" property of curried functions. * * @static * @memberOf _ - * @since 2.0.0 * @category Function * @param {Function} func The function to curry. * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Function} Returns the new curried function. * @example * @@ -9882,16 +7544,11 @@ * curried(1, 2, 3); * // => [1, 2, 3] * - * // Curried with placeholders. + * // using placeholders * curried(1)(_, 3)(2); * // => [1, 2, 3] */ - function curry(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curry.placeholder; - return result; - } + var curry = createCurry(CURRY_FLAG); /** * This method is like `_.curry` except that arguments are applied to `func` @@ -9900,15 +7557,14 @@ * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for provided arguments. * - * **Note:** This method doesn't set the "length" property of curried functions. + * **Note:** This method does not set the "length" property of curried functions. * * @static * @memberOf _ - * @since 3.0.0 * @category Function * @param {Function} func The function to curry. * @param {number} [arity=func.length] The arity of `func`. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Function} Returns the new curried function. * @example * @@ -9927,190 +7583,180 @@ * curried(1, 2, 3); * // => [1, 2, 3] * - * // Curried with placeholders. + * // using placeholders * curried(3)(1, _)(2); * // => [1, 2, 3] */ - function curryRight(func, arity, guard) { - arity = guard ? undefined : arity; - var result = createWrap(func, CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); - result.placeholder = curryRight.placeholder; - return result; - } + var curryRight = createCurry(CURRY_RIGHT_FLAG); /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. + * delayed invocations. Provide an options object to indicate that `func` + * should be invoked on the leading and/or trailing edge of the `wait` timeout. + * Subsequent calls to the debounced function return the result of the last + * `func` invocation. * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the debounced function is + * invoked more than once during the `wait` timeout. * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberOf _ - * @since 0.1.0 * @category Function * @param {Function} func The function to debounce. * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=false] Specify invoking on the leading + * edge of the timeout. + * @param {number} [options.maxWait] The maximum time `func` is allowed to be + * delayed before it's invoked. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * - * // Avoid costly calculations while the window size is in flux. + * // avoid costly calculations while the window size is in flux * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { + * // invoke `sendMail` when the click event is fired, debouncing subsequent calls + * jQuery('#postbox').on('click', _.debounce(sendMail, 300, { * 'leading': true, * 'trailing': false * })); * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * // ensure `batchLog` is invoked once after 1 second of debounced calls * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); + * jQuery(source).on('message', _.debounce(batchLog, 250, { + * 'maxWait': 1000 + * })); * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); + * // cancel a debounced call + * var todoChanges = _.debounce(batchLog, 1000); + * Object.observe(models.todo, todoChanges); + * + * Object.observe(models, function(changes) { + * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) { + * todoChanges.cancel(); + * } + * }, ['delete']); + * + * // ...at some point `models.todo` is changed + * models.todo.completed = true; + * + * // ...before 1 second has passed `models.todo` is deleted + * // which cancels the debounced `todoChanges` call + * delete models.todo; */ function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, + var args, + maxTimeoutId, result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, + stamp, + thisArg, + timeoutId, + trailingCall, + lastCalled = 0, + maxWait = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } - wait = toNumber(wait) || 0; - if (isObject(options)) { + wait = wait < 0 ? 0 : (+wait || 0); + if (options === true) { + var leading = true; + trailing = false; + } else if (isObject(options)) { leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait); trailing = 'trailing' in options ? !!options.trailing : trailing; } - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; - - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } - - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - result = wait - timeSinceLastCall; - - return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; - } - - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; - - // 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 === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } - - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } - - function trailingEdge(time) { - timerId = undefined; - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); + if (timeoutId) { + clearTimeout(timeoutId); } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; + if (maxTimeoutId) { + clearTimeout(maxTimeoutId); + } + lastCalled = 0; + maxTimeoutId = timeoutId = trailingCall = undefined; } - function flush() { - return timerId === undefined ? result : trailingEdge(now()); + function complete(isCalled, id) { + if (id) { + clearTimeout(id); + } + maxTimeoutId = timeoutId = trailingCall = undefined; + if (isCalled) { + lastCalled = now(); + result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = undefined; + } + } + } + + function delayed() { + var remaining = wait - (now() - stamp); + if (remaining <= 0 || remaining > wait) { + complete(trailingCall, maxTimeoutId); + } else { + timeoutId = setTimeout(delayed, remaining); + } + } + + function maxDelayed() { + complete(trailing, timeoutId); } function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); + args = arguments; + stamp = now(); + thisArg = this; + trailingCall = trailing && (timeoutId || !leading); - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); + if (maxWait === false) { + var leadingCall = leading && !timeoutId; + } else { + if (!maxTimeoutId && !leading) { + lastCalled = stamp; } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0 || remaining > maxWait; + + if (isCalled) { + if (maxTimeoutId) { + maxTimeoutId = clearTimeout(maxTimeoutId); + } + lastCalled = stamp; + result = func.apply(thisArg, args); + } + else if (!maxTimeoutId) { + maxTimeoutId = setTimeout(maxDelayed, remaining); } } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { + timeoutId = setTimeout(delayed, wait); + } + if (leadingCall) { + isCalled = true; + result = func.apply(thisArg, args); + } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = undefined; } return result; } debounced.cancel = cancel; - debounced.flush = flush; return debounced; } @@ -10120,19 +7766,18 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Function * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke `func` with. + * @param {...*} [args] The arguments to invoke the function with. * @returns {number} Returns the timer id. * @example * * _.defer(function(text) { * console.log(text); * }, 'deferred'); - * // => Logs 'deferred' after one or more milliseconds. + * // logs 'deferred' after one or more milliseconds */ - var defer = baseRest(function(func, args) { + var defer = restParam(function(func, args) { return baseDelay(func, 1, args); }); @@ -10142,88 +7787,116 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Function * @param {Function} func The function to delay. * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke `func` with. + * @param {...*} [args] The arguments to invoke the function with. * @returns {number} Returns the timer id. * @example * * _.delay(function(text) { * console.log(text); * }, 1000, 'later'); - * // => Logs 'later' after one second. + * // => logs 'later' after one second */ - var delay = baseRest(function(func, wait, args) { - return baseDelay(func, toNumber(wait) || 0, args); + var delay = restParam(function(func, wait, args) { + return baseDelay(func, wait, args); }); /** - * Creates a function that invokes `func` with arguments reversed. + * Creates a function that returns the result of invoking the provided + * functions with the `this` binding of the created function, where each + * successive invocation is supplied the return value of the previous. * * @static * @memberOf _ - * @since 4.0.0 * @category Function - * @param {Function} func The function to flip arguments for. - * @returns {Function} Returns the new flipped function. + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. * @example * - * var flipped = _.flip(function() { - * return _.toArray(arguments); - * }); + * function square(n) { + * return n * n; + * } * - * flipped('a', 'b', 'c', 'd'); - * // => ['d', 'c', 'b', 'a'] + * var addSquare = _.flow(_.add, square); + * addSquare(1, 2); + * // => 9 */ - function flip(func) { - return createWrap(func, FLIP_FLAG); - } + var flow = createFlow(); + + /** + * This method is like `_.flow` except that it creates a function that + * invokes the provided functions from right to left. + * + * @static + * @memberOf _ + * @alias backflow, compose + * @category Function + * @param {...Function} [funcs] Functions to invoke. + * @returns {Function} Returns the new function. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var addSquare = _.flowRight(square, _.add); + * addSquare(1, 2); + * // => 9 + */ + var flowRight = createFlow(true); /** * Creates a function that memoizes the result of `func`. If `resolver` is - * provided, it determines the cache key for storing the result based on the + * provided it determines the cache key for storing the result based on the * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is used as the map cache key. The `func` - * is invoked with the `this` binding of the memoized function. + * provided to the memoized function is coerced to a string and used as the + * cache key. The `func` is invoked with the `this` binding of the memoized + * function. * * **Note:** The cache is exposed as the `cache` property on the memoized * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the - * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `delete`, `get`, `has`, and `set`. + * constructor with one whose instances implement the [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object) + * method interface of `get`, `has`, and `set`. * * @static * @memberOf _ - * @since 0.1.0 * @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 memoized function. + * @returns {Function} Returns the new memoizing function. * @example * - * var object = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; + * var upperCase = _.memoize(function(string) { + * return string.toUpperCase(); + * }); * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] + * upperCase('fred'); + * // => 'FRED' * - * values(other); - * // => [3, 4] + * // modifying the result cache + * upperCase.cache.set('fred', 'BARNEY'); + * upperCase('fred'); + * // => 'BARNEY' * - * object.a = 2; - * values(object); - * // => [1, 2] + * // replacing `_.memoize.Cache` + * var object = { 'user': 'fred' }; + * var other = { 'user': 'barney' }; + * var identity = _.memoize(_.identity); * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] + * identity(object); + * // => { 'user': 'fred' } + * identity(other); + * // => { 'user': 'fred' } * - * // Replace `_.memoize.Cache`. * _.memoize.Cache = WeakMap; + * var identity = _.memoize(_.identity); + * + * identity(object); + * // => { 'user': 'fred' } + * identity(other); + * // => { 'user': 'barney' } */ function memoize(func, resolver) { if (typeof func != 'function' || (resolver && typeof resolver != 'function')) { @@ -10241,12 +7914,55 @@ memoized.cache = cache.set(key, result); return result; }; - memoized.cache = new (memoize.Cache || MapCache); + memoized.cache = new memoize.Cache; return memoized; } - // Assign cache to `_.memoize`. - memoize.Cache = MapCache; + /** + * Creates a function that runs each argument through a corresponding + * transform function. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms] The functions to transform + * arguments, specified as individual functions or arrays of functions. + * @returns {Function} Returns the new function. + * @example + * + * function doubled(n) { + * return n * 2; + * } + * + * function square(n) { + * return n * n; + * } + * + * var modded = _.modArgs(function(x, y) { + * return [x, y]; + * }, square, doubled); + * + * modded(1, 2); + * // => [1, 4] + * + * modded(5, 10); + * // => [25, 20] + */ + var modArgs = restParam(function(func, transforms) { + transforms = baseFlatten(transforms); + if (typeof func != 'function' || !arrayEvery(transforms, baseIsFunction)) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = transforms.length; + return restParam(function(args) { + var index = nativeMin(args.length, length); + while (index--) { + args[index] = transforms[index](args[index]); + } + return func.apply(this, args); + }); + }); /** * Creates a function that negates the result of the predicate `func`. The @@ -10255,10 +7971,9 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category Function * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new negated function. + * @returns {Function} Returns the new function. * @example * * function isEven(n) { @@ -10273,25 +7988,17 @@ throw new TypeError(FUNC_ERROR_TEXT); } return function() { - var args = arguments; - switch (args.length) { - case 0: return !predicate.call(this); - case 1: return !predicate.call(this, args[0]); - case 2: return !predicate.call(this, args[0], args[1]); - case 3: return !predicate.call(this, args[0], args[1], args[2]); - } - return !predicate.apply(this, args); + return !predicate.apply(this, arguments); }; } /** * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first invocation. The `func` is - * invoked with the `this` binding and arguments of the created function. + * to the function return the value of the first call. The `func` is invoked + * with the `this` binding and arguments of the created function. * * @static * @memberOf _ - * @since 0.1.0 * @category Function * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. @@ -10300,179 +8007,126 @@ * var initialize = _.once(createApplication); * initialize(); * initialize(); - * // => `createApplication` is invoked once + * // `initialize` invokes `createApplication` once */ function once(func) { return before(2, func); } /** - * Creates a function that invokes `func` with its arguments transformed. - * - * @static - * @since 4.0.0 - * @memberOf _ - * @category Function - * @param {Function} func The function to wrap. - * @param {...(Function|Function[])} [transforms=[_.identity]] - * The argument transforms. - * @returns {Function} Returns the new function. - * @example - * - * function doubled(n) { - * return n * 2; - * } - * - * function square(n) { - * return n * n; - * } - * - * var func = _.overArgs(function(x, y) { - * return [x, y]; - * }, [square, doubled]); - * - * func(9, 3); - * // => [81, 6] - * - * func(10, 5); - * // => [100, 10] - */ - var overArgs = baseRest(function(func, transforms) { - transforms = (transforms.length == 1 && isArray(transforms[0])) - ? arrayMap(transforms[0], baseUnary(getIteratee())) - : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); - - var funcsLength = transforms.length; - return baseRest(function(args) { - var index = -1, - length = nativeMin(args.length, funcsLength); - - while (++index < length) { - args[index] = transforms[index].call(this, args[index]); - } - return apply(func, this, args); - }); - }); - - /** - * Creates a function that invokes `func` with `partials` prepended to the - * arguments it receives. This method is like `_.bind` except it does **not** - * alter the `this` binding. + * Creates a function that invokes `func` with `partial` arguments prepended + * to those provided to the new function. This method is like `_.bind` except + * it does **not** alter the `this` binding. * * The `_.partial.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for partially applied arguments. * - * **Note:** This method doesn't set the "length" property of partially + * **Note:** This method does not set the "length" property of partially * applied functions. * * @static * @memberOf _ - * @since 0.2.0 * @category Function * @param {Function} func The function to partially apply arguments to. * @param {...*} [partials] The arguments to be partially applied. * @returns {Function} Returns the new partially applied function. * @example * - * function greet(greeting, name) { + * var greet = function(greeting, name) { * return greeting + ' ' + name; - * } + * }; * * var sayHelloTo = _.partial(greet, 'hello'); * sayHelloTo('fred'); * // => 'hello fred' * - * // Partially applied with placeholders. + * // using placeholders * var greetFred = _.partial(greet, _, 'fred'); * greetFred('hi'); * // => 'hi fred' */ - var partial = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partial)); - return createWrap(func, PARTIAL_FLAG, undefined, partials, holders); - }); + var partial = createPartial(PARTIAL_FLAG); /** * This method is like `_.partial` except that partially applied arguments - * are appended to the arguments it receives. + * are appended to those provided to the new function. * * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic * builds, may be used as a placeholder for partially applied arguments. * - * **Note:** This method doesn't set the "length" property of partially + * **Note:** This method does not set the "length" property of partially * applied functions. * * @static * @memberOf _ - * @since 1.0.0 * @category Function * @param {Function} func The function to partially apply arguments to. * @param {...*} [partials] The arguments to be partially applied. * @returns {Function} Returns the new partially applied function. * @example * - * function greet(greeting, name) { + * var greet = function(greeting, name) { * return greeting + ' ' + name; - * } + * }; * * var greetFred = _.partialRight(greet, 'fred'); * greetFred('hi'); * // => 'hi fred' * - * // Partially applied with placeholders. + * // using placeholders * var sayHelloTo = _.partialRight(greet, 'hello', _); * sayHelloTo('fred'); * // => 'hello fred' */ - var partialRight = baseRest(function(func, partials) { - var holders = replaceHolders(partials, getHolder(partialRight)); - return createWrap(func, PARTIAL_RIGHT_FLAG, undefined, partials, holders); - }); + var partialRight = createPartial(PARTIAL_RIGHT_FLAG); /** * Creates a function that invokes `func` with arguments arranged according - * to the specified `indexes` where the argument value at the first index is + * to the specified indexes where the argument value at the first index is * provided as the first argument, the argument value at the second index is * provided as the second argument, and so on. * * @static * @memberOf _ - * @since 3.0.0 * @category Function * @param {Function} func The function to rearrange arguments for. - * @param {...(number|number[])} indexes The arranged argument indexes. + * @param {...(number|number[])} indexes The arranged argument indexes, + * specified as individual indexes or arrays of indexes. * @returns {Function} Returns the new function. * @example * * var rearged = _.rearg(function(a, b, c) { * return [a, b, c]; - * }, [2, 0, 1]); + * }, 2, 0, 1); * * rearged('b', 'c', 'a') * // => ['a', 'b', 'c'] + * + * var map = _.rearg(_.map, [1, 0]); + * map(function(n) { + * return n * 3; + * }, [1, 2, 3]); + * // => [3, 6, 9] */ - var rearg = baseRest(function(func, indexes) { - return createWrap(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes, 1)); + var rearg = restParam(function(func, indexes) { + return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes)); }); /** * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as - * an array. + * created function and arguments from `start` and beyond provided as an array. * - * **Note:** This method is based on the - * [rest parameter](https://mdn.io/rest_parameters). + * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters). * * @static * @memberOf _ - * @since 4.0.0 * @category Function * @param {Function} func The function to apply a rest parameter to. * @param {number} [start=func.length-1] The start position of the rest parameter. * @returns {Function} Returns the new function. * @example * - * var say = _.rest(function(what, names) { + * var say = _.restParam(function(what, names) { * return what + ' ' + _.initial(names).join(', ') + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); * }); @@ -10480,28 +8134,45 @@ * say('hello', 'fred', 'barney', 'pebbles'); * // => 'hello fred, barney, & pebbles' */ - function rest(func, start) { + function restParam(func, start) { if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } - start = start === undefined ? start : toInteger(start); - return baseRest(func, start); + start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + rest = Array(length); + + while (++index < length) { + rest[index] = args[start + index]; + } + switch (start) { + case 0: return func.call(this, rest); + case 1: return func.call(this, args[0], rest); + case 2: return func.call(this, args[0], args[1], rest); + } + var otherArgs = Array(start + 1); + index = -1; + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = rest; + return func.apply(this, otherArgs); + }; } /** - * Creates a function that invokes `func` with the `this` binding of the - * create function and an array of arguments much like - * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). + * Creates a function that invokes `func` with the `this` binding of the created + * function and an array of arguments much like [`Function#apply`](https://es5.github.io/#x15.3.4.3). * - * **Note:** This method is based on the - * [spread operator](https://mdn.io/spread_operator). + * **Note:** This method is based on the [spread operator](https://developer.mozilla.org/Web/JavaScript/Reference/Operators/Spread_operator). * * @static * @memberOf _ - * @since 3.2.0 * @category Function * @param {Function} func The function to spread arguments over. - * @param {number} [start=0] The start position of the spread. * @returns {Function} Returns the new function. * @example * @@ -10512,6 +8183,7 @@ * say(['fred', 'hello']); * // => 'fred says hello' * + * // with a Promise * var numbers = Promise.all([ * Promise.resolve(40), * Promise.resolve(36) @@ -10522,64 +8194,52 @@ * })); * // => a Promise of 76 */ - function spread(func, start) { + function spread(func) { if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } - start = start === undefined ? 0 : nativeMax(toInteger(start), 0); - return baseRest(function(args) { - var array = args[start], - otherArgs = castSlice(args, 0, start); - - if (array) { - arrayPush(otherArgs, array); - } - return apply(func, this, otherArgs); - }); + return function(array) { + return func.apply(this, array); + }; } /** * Creates a throttled function that only invokes `func` at most once per * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed `func` invocations and a `flush` method to - * immediately invoke them. Provide `options` to indicate whether `func` - * should be invoked on the leading and/or trailing edge of the `wait` - * timeout. The `func` is invoked with the last arguments provided to the - * throttled function. Subsequent calls to the throttled function return the - * result of the last `func` invocation. + * method to cancel delayed invocations. Provide an options object to indicate + * that `func` should be invoked on the leading and/or trailing edge of the + * `wait` timeout. Subsequent calls to the throttled function return the + * result of the last `func` call. * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the throttled function - * is invoked more than once during the `wait` timeout. + * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked + * on the trailing edge of the timeout only if the the throttled function is + * invoked more than once during the `wait` timeout. * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation) * for details over the differences between `_.throttle` and `_.debounce`. * * @static * @memberOf _ - * @since 0.1.0 * @category Function * @param {Function} func The function to throttle. * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=true] - * Specify invoking on the leading edge of the timeout. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. + * @param {Object} [options] The options object. + * @param {boolean} [options.leading=true] Specify invoking on the leading + * edge of the timeout. + * @param {boolean} [options.trailing=true] Specify invoking on the trailing + * edge of the timeout. * @returns {Function} Returns the new throttled function. * @example * - * // Avoid excessively updating the position while scrolling. + * // avoid excessively updating the position while scrolling * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); * - * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. - * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); - * jQuery(element).on('click', throttled); + * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes + * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, { + * 'trailing': false + * })); * - * // Cancel the trailing throttled invocation. + * // cancel a trailing throttled call * jQuery(window).on('popstate', throttled.cancel); */ function throttle(func, wait, options) { @@ -10589,48 +8249,26 @@ if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } - if (isObject(options)) { + if (options === false) { + leading = false; + } else if (isObject(options)) { leading = 'leading' in options ? !!options.leading : leading; trailing = 'trailing' in options ? !!options.trailing : trailing; } - return debounce(func, wait, { - 'leading': leading, - 'maxWait': wait, - 'trailing': trailing - }); + return debounce(func, wait, { 'leading': leading, 'maxWait': +wait, 'trailing': trailing }); } /** - * Creates a function that accepts up to one argument, ignoring any - * additional arguments. + * Creates a function that provides `value` to the wrapper function as its + * first argument. Any additional arguments provided to the function are + * appended to those provided to the wrapper function. The wrapper is invoked + * with the `this` binding of the created function. * * @static * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - * @example - * - * _.map(['6', '8', '10'], _.unary(parseInt)); - * // => [6, 8, 10] - */ - function unary(func) { - return ary(func, 1); - } - - /** - * Creates a function that provides `value` to `wrapper` as its first - * argument. Any additional arguments provided to the function are appended - * to those provided to the `wrapper`. The wrapper is invoked with the `this` - * binding of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 * @category Function * @param {*} value The value to wrap. - * @param {Function} [wrapper=identity] The wrapper function. + * @param {Function} wrapper The wrapper function. * @returns {Function} Returns the new function. * @example * @@ -10643,233 +8281,125 @@ */ function wrap(value, wrapper) { wrapper = wrapper == null ? identity : wrapper; - return partial(wrapper, value); + return createWrapper(wrapper, PARTIAL_FLAG, undefined, [value], []); } /*------------------------------------------------------------------------*/ /** - * Casts `value` as an array if it's not one. - * - * @static - * @memberOf _ - * @since 4.4.0 - * @category Lang - * @param {*} value The value to inspect. - * @returns {Array} Returns the cast array. - * @example - * - * _.castArray(1); - * // => [1] - * - * _.castArray({ 'a': 1 }); - * // => [{ 'a': 1 }] - * - * _.castArray('abc'); - * // => ['abc'] - * - * _.castArray(null); - * // => [null] - * - * _.castArray(undefined); - * // => [undefined] - * - * _.castArray(); - * // => [] - * - * var array = [1, 2, 3]; - * console.log(_.castArray(array) === array); - * // => true - */ - function castArray() { - if (!arguments.length) { - return []; - } - var value = arguments[0]; - return isArray(value) ? value : [value]; - } - - /** - * Creates a shallow clone of `value`. + * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned, + * otherwise they are assigned by reference. If `customizer` is provided it's + * invoked to produce the cloned values. If `customizer` returns `undefined` + * cloning is handled by the method instead. The `customizer` is bound to + * `thisArg` and invoked with up to three argument; (value [, index|key, object]). * * **Note:** This method is loosely based on the - * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) - * and supports cloning arrays, array buffers, booleans, date objects, maps, - * numbers, `Object` objects, regexes, sets, strings, symbols, and typed - * arrays. The own enumerable properties of `arguments` objects are cloned - * as plain objects. An empty object is returned for uncloneable values such - * as error objects, functions, DOM nodes, and WeakMaps. + * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {*} Returns the cloned value. - * @see _.cloneDeep * @example * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; * - * var shallow = _.clone(objects); - * console.log(shallow[0] === objects[0]); + * var shallow = _.clone(users); + * shallow[0] === users[0]; * // => true - */ - function clone(value) { - return baseClone(value, false, true); - } - - /** - * This method is like `_.clone` except that it accepts `customizer` which - * is invoked to produce the cloned value. If `customizer` returns `undefined`, - * cloning is handled by the method instead. The `customizer` is invoked with - * up to four arguments; (value [, index|key, object, stack]). * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the cloned value. - * @see _.cloneDeepWith - * @example + * var deep = _.clone(users, true); + * deep[0] === users[0]; + * // => false * - * function customizer(value) { + * // using a customizer callback + * var el = _.clone(document.body, function(value) { * if (_.isElement(value)) { * return value.cloneNode(false); * } - * } + * }); * - * var el = _.cloneWith(document.body, customizer); - * - * console.log(el === document.body); + * el === document.body * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); + * el.nodeName + * // => BODY + * el.childNodes.length; * // => 0 */ - function cloneWith(value, customizer) { - return baseClone(value, false, true, customizer); + function clone(value, isDeep, customizer, thisArg) { + if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) { + isDeep = false; + } + else if (typeof isDeep == 'function') { + thisArg = customizer; + customizer = isDeep; + isDeep = false; + } + return typeof customizer == 'function' + ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 3)) + : baseClone(value, isDeep); } /** - * This method is like `_.clone` except that it recursively clones `value`. + * Creates a deep clone of `value`. If `customizer` is provided it's invoked + * to produce the cloned values. If `customizer` returns `undefined` cloning + * is handled by the method instead. The `customizer` is bound to `thisArg` + * and invoked with up to three argument; (value [, index|key, object]). + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm). + * The enumerable properties of `arguments` objects and objects created by + * constructors other than `Object` are cloned to plain `Object` objects. An + * empty object is returned for uncloneable values such as functions, DOM nodes, + * Maps, Sets, and WeakMaps. * * @static * @memberOf _ - * @since 1.0.0 * @category Lang - * @param {*} value The value to recursively clone. + * @param {*} value The value to deep clone. + * @param {Function} [customizer] The function to customize cloning values. + * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {*} Returns the deep cloned value. - * @see _.clone * @example * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; * - * var deep = _.cloneDeep(objects); - * console.log(deep[0] === objects[0]); + * var deep = _.cloneDeep(users); + * deep[0] === users[0]; * // => false - */ - function cloneDeep(value) { - return baseClone(value, true, true); - } - - /** - * This method is like `_.cloneWith` except that it recursively clones `value`. * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @param {Function} [customizer] The function to customize cloning. - * @returns {*} Returns the deep cloned value. - * @see _.cloneWith - * @example - * - * function customizer(value) { + * // using a customizer callback + * var el = _.cloneDeep(document.body, function(value) { * if (_.isElement(value)) { * return value.cloneNode(true); * } - * } + * }); * - * var el = _.cloneDeepWith(document.body, customizer); - * - * console.log(el === document.body); + * el === document.body * // => false - * console.log(el.nodeName); - * // => 'BODY' - * console.log(el.childNodes.length); + * el.nodeName + * // => BODY + * el.childNodes.length; * // => 20 */ - function cloneDeepWith(value, customizer) { - return baseClone(value, true, true, customizer); - } - - /** - * Checks if `object` conforms to `source` by invoking the predicate - * properties of `source` with the corresponding property values of `object`. - * - * **Note:** This method is equivalent to `_.conforms` when `source` is - * partially applied. - * - * @static - * @memberOf _ - * @since 4.14.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property predicates to conform to. - * @returns {boolean} Returns `true` if `object` conforms, else `false`. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * - * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); - * // => true - * - * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); - * // => false - */ - function conformsTo(object, source) { - return source == null || baseConformsTo(object, source, keys(source)); - } - - /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ - function eq(value, other) { - return value === other || (value !== value && other !== other); + function cloneDeep(value, customizer, thisArg) { + return typeof customizer == 'function' + ? baseClone(value, true, bindCallback(customizer, thisArg, 3)) + : baseClone(value, true); } /** @@ -10877,13 +8407,10 @@ * * @static * @memberOf _ - * @since 3.9.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - * @see _.lt + * @returns {boolean} Returns `true` if `value` is greater than `other`, else `false`. * @example * * _.gt(3, 1); @@ -10895,20 +8422,19 @@ * _.gt(1, 3); * // => false */ - var gt = createRelationalOperation(baseGt); + function gt(value, other) { + return value > other; + } /** * Checks if `value` is greater than or equal to `other`. * * @static * @memberOf _ - * @since 3.9.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than or equal to - * `other`, else `false`. - * @see _.lte + * @returns {boolean} Returns `true` if `value` is greater than or equal to `other`, else `false`. * @example * * _.gte(3, 1); @@ -10920,20 +8446,18 @@ * _.gte(1, 3); * // => false */ - var gte = createRelationalOperation(function(value, other) { + function gte(value, other) { return value >= other; - }); + } /** - * Checks if `value` is likely an `arguments` object. + * Checks if `value` is classified as an `arguments` object. * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isArguments(function() { return arguments; }()); @@ -10943,9 +8467,8 @@ * // => false */ function isArguments(value) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && - (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); + return isObjectLike(value) && isArrayLike(value) && + hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee'); } /** @@ -10953,112 +8476,29 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isArray([1, 2, 3]); * // => true * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); + * _.isArray(function() { return arguments; }()); * // => false */ - var isArray = Array.isArray; - - /** - * Checks if `value` is classified as an `ArrayBuffer` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. - * @example - * - * _.isArrayBuffer(new ArrayBuffer(2)); - * // => true - * - * _.isArrayBuffer(new Array(2)); - * // => false - */ - var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; - - /** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } - - /** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ - function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); - } + var isArray = nativeIsArray || function(value) { + return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; + }; /** * Checks if `value` is classified as a boolean primitive or object. * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isBoolean(false); @@ -11068,38 +8508,17 @@ * // => false */ function isBoolean(value) { - return value === true || value === false || - (isObjectLike(value) && objectToString.call(value) == boolTag); + return value === true || value === false || (isObjectLike(value) && objToString.call(value) == boolTag); } - /** - * Checks if `value` is a buffer. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. - * @example - * - * _.isBuffer(new Buffer(2)); - * // => true - * - * _.isBuffer(new Uint8Array(2)); - * // => false - */ - var isBuffer = nativeIsBuffer || stubFalse; - /** * Checks if `value` is classified as a `Date` object. * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isDate(new Date); @@ -11108,14 +8527,15 @@ * _.isDate('Mon April 23 2012'); * // => false */ - var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; + function isDate(value) { + return isObjectLike(value) && objToString.call(value) == dateTag; + } /** - * Checks if `value` is likely a DOM element. + * Checks if `value` is a DOM element. * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. @@ -11132,20 +8552,14 @@ } /** - * Checks if `value` is an empty object, collection, map, or set. - * - * Objects are considered empty if they have no own enumerable string keyed - * properties. - * - * Array-like values such as `arguments` objects, arrays, buffers, strings, or - * jQuery-like collections are considered empty if they have a `length` of `0`. - * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * Checks if `value` is empty. A value is considered empty unless it's an + * `arguments` object, array, string, or jQuery-like collection with a length + * greater than `0` or an object with own enumerable properties. * * @static * @memberOf _ - * @since 0.1.0 * @category Lang - * @param {*} value The value to check. + * @param {Array|Object|string} value The value to inspect. * @returns {boolean} Returns `true` if `value` is empty, else `false`. * @example * @@ -11165,94 +8579,64 @@ * // => false */ function isEmpty(value) { - if (isArrayLike(value) && - (isArray(value) || typeof value == 'string' || - typeof value.splice == 'function' || isBuffer(value) || isArguments(value))) { + if (value == null) { + return true; + } + if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) || + (isObjectLike(value) && isFunction(value.splice)))) { return !value.length; } - var tag = getTag(value); - if (tag == mapTag || tag == setTag) { - return !value.size; - } - if (nonEnumShadows || isPrototype(value)) { - return !nativeKeys(value).length; - } - for (var key in value) { - if (hasOwnProperty.call(value, key)) { - return false; - } - } - return true; + return !keys(value).length; } /** * Performs a deep comparison between two values to determine if they are - * equivalent. + * equivalent. If `customizer` is provided it's invoked to compare values. + * If `customizer` returns `undefined` comparisons are handled by the method + * instead. The `customizer` is bound to `thisArg` and invoked with up to + * three arguments: (value, other [, index|key]). * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are **not** supported. + * **Note:** This method supports comparing arrays, booleans, `Date` objects, + * numbers, `Object` objects, regexes, and strings. Objects are compared by + * their own, not inherited, enumerable properties. Functions and DOM nodes + * are **not** supported. Provide a customizer function to extend support + * for comparing other values. * * @static * @memberOf _ - * @since 0.1.0 + * @alias eq * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize value comparisons. + * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; + * var object = { 'user': 'fred' }; + * var other = { 'user': 'fred' }; + * + * object == other; + * // => false * * _.isEqual(object, other); * // => true * - * object === other; - * // => false - */ - function isEqual(value, other) { - return baseIsEqual(value, other); - } - - /** - * This method is like `_.isEqual` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with up to - * six arguments: (objValue, othValue [, index|key, object, other, stack]). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, othValue) { - * if (isGreeting(objValue) && isGreeting(othValue)) { - * return true; - * } - * } - * + * // using a customizer callback * var array = ['hello', 'goodbye']; * var other = ['hi', 'goodbye']; * - * _.isEqualWith(array, other, customizer); + * _.isEqual(array, other, function(value, other) { + * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) { + * return true; + * } + * }); * // => true */ - function isEqualWith(value, other, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; + function isEqual(value, other, customizer, thisArg) { + customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; var result = customizer ? customizer(value, other) : undefined; - return result === undefined ? baseIsEqual(value, other, customizer) : !!result; + return result === undefined ? baseIsEqual(value, other, customizer) : !!result; } /** @@ -11261,7 +8645,6 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an error object, else `false`. @@ -11274,37 +8657,34 @@ * // => false */ function isError(value) { - if (!isObjectLike(value)) { - return false; - } - return (objectToString.call(value) == errorTag) || - (typeof value.message == 'string' && typeof value.name == 'string'); + return isObjectLike(value) && typeof value.message == 'string' && objToString.call(value) == errorTag; } /** * Checks if `value` is a finite primitive number. * - * **Note:** This method is based on - * [`Number.isFinite`](https://mdn.io/Number/isFinite). + * **Note:** This method is based on [`Number.isFinite`](http://ecma-international.org/ecma-262/6.0/#sec-number.isfinite). * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. * @example * - * _.isFinite(3); + * _.isFinite(10); * // => true * - * _.isFinite(Number.MIN_VALUE); - * // => true - * - * _.isFinite(Infinity); + * _.isFinite('10'); * // => false * - * _.isFinite('3'); + * _.isFinite(true); + * // => false + * + * _.isFinite(Object(10)); + * // => false + * + * _.isFinite(Infinity); * // => false */ function isFinite(value) { @@ -11316,10 +8696,9 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isFunction(_); @@ -11330,80 +8709,17 @@ */ function isFunction(value) { // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 8-9 which returns 'object' for typed array and other constructors. - var tag = isObject(value) ? objectToString.call(value) : ''; - return tag == funcTag || tag == genTag; + // in older versions of Chrome and Safari which return 'function' for regexes + // and Safari 8 which returns 'object' for typed array constructors. + return isObject(value) && objToString.call(value) == funcTag; } /** - * Checks if `value` is an integer. - * - * **Note:** This method is based on - * [`Number.isInteger`](https://mdn.io/Number/isInteger). + * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an integer, else `false`. - * @example - * - * _.isInteger(3); - * // => true - * - * _.isInteger(Number.MIN_VALUE); - * // => false - * - * _.isInteger(Infinity); - * // => false - * - * _.isInteger('3'); - * // => false - */ - function isInteger(value) { - return typeof value == 'number' && value == toInteger(value); - } - - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ - function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. @@ -11415,144 +8731,68 @@ * _.isObject([1, 2, 3]); * // => true * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); + * _.isObject(1); * // => false */ function isObject(value) { + // Avoid a V8 JIT bug in Chrome 19-20. + // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. var type = typeof value; return !!value && (type == 'object' || type == 'function'); } /** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". + * Performs a deep comparison between `object` and `source` to determine if + * `object` contains equivalent property values. If `customizer` is provided + * it's invoked to compare values. If `customizer` returns `undefined` + * comparisons are handled by the method instead. The `customizer` is bound + * to `thisArg` and invoked with three arguments: (value, other, index|key). + * + * **Note:** This method supports comparing properties of arrays, booleans, + * `Date` objects, numbers, `Object` objects, regexes, and strings. Functions + * and DOM nodes are **not** supported. Provide a customizer function to extend + * support for comparing other values. * * @static * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ - function isObjectLike(value) { - return !!value && typeof value == 'object'; - } - - /** - * Checks if `value` is classified as a `Map` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - * @example - * - * _.isMap(new Map); - * // => true - * - * _.isMap(new WeakMap); - * // => false - */ - var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; - - /** - * Performs a partial deep comparison between `object` and `source` to - * determine if `object` contains equivalent property values. - * - * **Note:** This method is equivalent to `_.matches` when `source` is - * partially applied. - * - * Partial comparisons will match empty array and empty object `source` - * values against any array or object value, respectively. See `_.isEqual` - * for a list of supported value comparisons. - * - * @static - * @memberOf _ - * @since 3.0.0 * @category Lang * @param {Object} object The object to inspect. * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize value comparisons. + * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {boolean} Returns `true` if `object` is a match, else `false`. * @example * - * var object = { 'a': 1, 'b': 2 }; + * var object = { 'user': 'fred', 'age': 40 }; * - * _.isMatch(object, { 'b': 2 }); + * _.isMatch(object, { 'age': 40 }); * // => true * - * _.isMatch(object, { 'b': 1 }); + * _.isMatch(object, { 'age': 36 }); * // => false - */ - function isMatch(object, source) { - return object === source || baseIsMatch(object, source, getMatchData(source)); - } - - /** - * This method is like `_.isMatch` except that it accepts `customizer` which - * is invoked to compare values. If `customizer` returns `undefined`, comparisons - * are handled by the method instead. The `customizer` is invoked with five - * arguments: (objValue, srcValue, index|key, object, source). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - * @example - * - * function isGreeting(value) { - * return /^h(?:i|ello)$/.test(value); - * } - * - * function customizer(objValue, srcValue) { - * if (isGreeting(objValue) && isGreeting(srcValue)) { - * return true; - * } - * } * + * // using a customizer callback * var object = { 'greeting': 'hello' }; * var source = { 'greeting': 'hi' }; * - * _.isMatchWith(object, source, customizer); + * _.isMatch(object, source, function(value, other) { + * return _.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/) || undefined; + * }); * // => true */ - function isMatchWith(object, source, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return baseIsMatch(object, source, getMatchData(source), customizer); + function isMatch(object, source, customizer, thisArg) { + customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined; + return baseIsMatch(object, getMatchData(source), customizer); } /** * Checks if `value` is `NaN`. * - * **Note:** This method is based on - * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as - * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for - * `undefined` and other non-number values. + * **Note:** This method is not the same as [`isNaN`](https://es5.github.io/#x15.1.2.4) + * which returns `true` for `undefined` and other non-numeric values. * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. @@ -11572,29 +8812,18 @@ */ function isNaN(value) { // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some - // ActiveX objects in IE. + // Perform the `toStringTag` check first to avoid errors with some host objects in IE. return isNumber(value) && value != +value; } /** - * 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. + * Checks if `value` is a native function. * * @static * @memberOf _ - * @since 3.0.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. + * @returns {boolean} Returns `true` if `value` is a native function, else `false`. * @example * * _.isNative(Array.prototype.push); @@ -11604,10 +8833,13 @@ * // => false */ function isNative(value) { - if (isMaskable(value)) { - throw new Error('This method is not supported with core-js. Try https://github.com/es-shims.'); + if (value == null) { + return false; } - return baseIsNative(value); + if (isFunction(value)) { + return reIsNative.test(fnToString.call(value)); + } + return isObjectLike(value) && reIsHostCtor.test(value); } /** @@ -11615,7 +8847,6 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is `null`, else `false`. @@ -11631,68 +8862,41 @@ return value === null; } - /** - * Checks if `value` is `null` or `undefined`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is nullish, else `false`. - * @example - * - * _.isNil(null); - * // => true - * - * _.isNil(void 0); - * // => true - * - * _.isNil(NaN); - * // => false - */ - function isNil(value) { - return value == null; - } - /** * Checks if `value` is classified as a `Number` primitive or object. * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are - * classified as numbers, use the `_.isFinite` method. + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are classified + * as numbers, use the `_.isFinite` method. * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * - * _.isNumber(3); + * _.isNumber(8.4); * // => true * - * _.isNumber(Number.MIN_VALUE); + * _.isNumber(NaN); * // => true * - * _.isNumber(Infinity); - * // => true - * - * _.isNumber('3'); + * _.isNumber('8.4'); * // => false */ function isNumber(value) { - return typeof value == 'number' || - (isObjectLike(value) && objectToString.call(value) == numberTag); + return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag); } /** * Checks if `value` is a plain object, that is, an object created by the * `Object` constructor or one with a `[[Prototype]]` of `null`. * + * **Note:** This method assumes objects created by the `Object` constructor + * have no inherited enumerable properties. + * * @static * @memberOf _ - * @since 0.8.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. @@ -11715,17 +8919,24 @@ * // => true */ function isPlainObject(value) { - if (!isObjectLike(value) || - objectToString.call(value) != objectTag || isHostObject(value)) { + var Ctor; + + // Exit early for non `Object` objects. + if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isArguments(value)) || + (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { return false; } - var proto = getPrototype(value); - if (proto === null) { - return true; - } - var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return (typeof Ctor == 'function' && - Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString); + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + var result; + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + baseForIn(value, function(subValue, key) { + result = key; + }); + return result === undefined || hasOwnProperty.call(value, result); } /** @@ -11733,10 +8944,9 @@ * * @static * @memberOf _ - * @since 0.1.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isRegExp(/abc/); @@ -11745,67 +8955,18 @@ * _.isRegExp('/abc/'); * // => false */ - var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; - - /** - * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 - * double precision number which isn't the result of a rounded unsafe integer. - * - * **Note:** This method is based on - * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. - * @example - * - * _.isSafeInteger(3); - * // => true - * - * _.isSafeInteger(Number.MIN_VALUE); - * // => false - * - * _.isSafeInteger(Infinity); - * // => false - * - * _.isSafeInteger('3'); - * // => false - */ - function isSafeInteger(value) { - return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; + function isRegExp(value) { + return isObject(value) && objToString.call(value) == regexpTag; } - /** - * Checks if `value` is classified as a `Set` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - * @example - * - * _.isSet(new Set); - * // => true - * - * _.isSet(new WeakSet); - * // => false - */ - var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; - /** * Checks if `value` is classified as a `String` primitive or object. * * @static - * @since 0.1.0 * @memberOf _ * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isString('abc'); @@ -11815,30 +8976,7 @@ * // => false */ function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag); - } - - /** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ - function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && objectToString.call(value) == symbolTag); + return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag); } /** @@ -11846,10 +8984,9 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category Lang * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isTypedArray(new Uint8Array); @@ -11858,13 +8995,14 @@ * _.isTypedArray([]); * // => false */ - var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + function isTypedArray(value) { + return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)]; + } /** * Checks if `value` is `undefined`. * * @static - * @since 0.1.0 * @memberOf _ * @category Lang * @param {*} value The value to check. @@ -11881,60 +9019,15 @@ return value === undefined; } - /** - * Checks if `value` is classified as a `WeakMap` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. - * @example - * - * _.isWeakMap(new WeakMap); - * // => true - * - * _.isWeakMap(new Map); - * // => false - */ - function isWeakMap(value) { - return isObjectLike(value) && getTag(value) == weakMapTag; - } - - /** - * Checks if `value` is classified as a `WeakSet` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. - * @example - * - * _.isWeakSet(new WeakSet); - * // => true - * - * _.isWeakSet(new Set); - * // => false - */ - function isWeakSet(value) { - return isObjectLike(value) && objectToString.call(value) == weakSetTag; - } - /** * Checks if `value` is less than `other`. * * @static * @memberOf _ - * @since 3.9.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - * @see _.gt + * @returns {boolean} Returns `true` if `value` is less than `other`, else `false`. * @example * * _.lt(1, 3); @@ -11946,20 +9039,19 @@ * _.lt(3, 1); * // => false */ - var lt = createRelationalOperation(baseLt); + function lt(value, other) { + return value < other; + } /** * Checks if `value` is less than or equal to `other`. * * @static * @memberOf _ - * @since 3.9.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than or equal to - * `other`, else `false`. - * @see _.gte + * @returns {boolean} Returns `true` if `value` is less than or equal to `other`, else `false`. * @example * * _.lte(1, 3); @@ -11971,199 +9063,42 @@ * _.lte(3, 1); * // => false */ - var lte = createRelationalOperation(function(value, other) { + function lte(value, other) { return value <= other; - }); + } /** * Converts `value` to an array. * * @static - * @since 0.1.0 * @memberOf _ * @category Lang * @param {*} value The value to convert. * @returns {Array} Returns the converted array. * @example * - * _.toArray({ 'a': 1, 'b': 2 }); - * // => [1, 2] - * - * _.toArray('abc'); - * // => ['a', 'b', 'c'] - * - * _.toArray(1); - * // => [] - * - * _.toArray(null); - * // => [] + * (function() { + * return _.toArray(arguments).slice(1); + * }(1, 2, 3)); + * // => [2, 3] */ function toArray(value) { - if (!value) { + var length = value ? getLength(value) : 0; + if (!isLength(length)) { + return values(value); + } + if (!length) { return []; } - if (isArrayLike(value)) { - return isString(value) ? stringToArray(value) : copyArray(value); - } - if (iteratorSymbol && value[iteratorSymbol]) { - return iteratorToArray(value[iteratorSymbol]()); - } - var tag = getTag(value), - func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); - - return func(value); + return arrayCopy(value); } /** - * Converts `value` to a finite number. + * Converts `value` to a plain object flattening inherited enumerable + * properties of `value` to own properties of the plain object. * * @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 method is loosely based on - * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toInteger(3.2); - * // => 3 - * - * _.toInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toInteger(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toInteger('3.2'); - * // => 3 - */ - function toInteger(value) { - var result = toFinite(value), - remainder = result % 1; - - return result === result ? (remainder ? result - remainder : result) : 0; - } - - /** - * Converts `value` to an integer suitable for use as the length of an - * array-like object. - * - * **Note:** This method is based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toLength(3.2); - * // => 3 - * - * _.toLength(Number.MIN_VALUE); - * // => 0 - * - * _.toLength(Infinity); - * // => 4294967295 - * - * _.toLength('3.2'); - * // => 3 - */ - function toLength(value) { - return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; - } - - /** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ - function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); - } - - /** - * Converts `value` to a plain object flattening inherited enumerable string - * keyed properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @since 3.0.0 * @category Lang * @param {*} value The value to convert. * @returns {Object} Returns the converted plain object. @@ -12182,240 +9117,110 @@ * // => { 'a': 1, 'b': 2, 'c': 3 } */ function toPlainObject(value) { - return copyObject(value, keysIn(value)); - } - - /** - * Converts `value` to a safe integer. A safe integer can be compared and - * represented correctly. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toSafeInteger(3.2); - * // => 3 - * - * _.toSafeInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toSafeInteger(Infinity); - * // => 9007199254740991 - * - * _.toSafeInteger('3.2'); - * // => 3 - */ - function toSafeInteger(value) { - return baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER); - } - - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {string} Returns the string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ - function toString(value) { - return value == null ? '' : baseToString(value); + return baseCopy(value, keysIn(value)); } /*------------------------------------------------------------------------*/ /** - * Assigns own enumerable string keyed properties of source objects to the - * destination object. Source objects are applied from left to right. - * Subsequent sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object` and is loosely based on - * [`Object.assign`](https://mdn.io/Object/assign). + * Recursively merges own enumerable properties of the source object(s), that + * don't resolve to `undefined` into the destination object. Subsequent sources + * overwrite property assignments of previous sources. If `customizer` is + * provided it's invoked to produce the merged values of the destination and + * source properties. If `customizer` returns `undefined` merging is handled + * by the method instead. The `customizer` is bound to `thisArg` and invoked + * with five arguments: (objectValue, sourceValue, key, object, source). * * @static * @memberOf _ - * @since 0.10.0 * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {Object} Returns `object`. - * @see _.assignIn * @example * - * function Foo() { - * this.a = 1; - * } + * var users = { + * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] + * }; * - * function Bar() { - * this.c = 3; - * } + * var ages = { + * 'data': [{ 'age': 36 }, { 'age': 40 }] + * }; * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; + * _.merge(users, ages); + * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } * - * _.assign({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'c': 3 } + * // using a customizer callback + * var object = { + * 'fruits': ['apple'], + * 'vegetables': ['beet'] + * }; + * + * var other = { + * 'fruits': ['banana'], + * 'vegetables': ['carrot'] + * }; + * + * _.merge(object, other, function(a, b) { + * if (_.isArray(a)) { + * return a.concat(b); + * } + * }); + * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } */ - var assign = createAssigner(function(object, source) { - if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) { - copyObject(source, keys(source), object); - return; - } - for (var key in source) { - if (hasOwnProperty.call(source, key)) { - assignValue(object, key, source[key]); - } - } - }); + var merge = createAssigner(baseMerge); /** - * This method is like `_.assign` except that it iterates over own and - * inherited source properties. + * Assigns own enumerable properties of source object(s) to the destination + * object. Subsequent sources overwrite property assignments of previous sources. + * If `customizer` is provided it's invoked to produce the assigned values. + * The `customizer` is bound to `thisArg` and invoked with five arguments: + * (objectValue, sourceValue, key, object, source). * - * **Note:** This method mutates `object`. + * **Note:** This method mutates `object` and is based on + * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign). * * @static * @memberOf _ - * @since 4.0.0 * @alias extend * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assign - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assignIn({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } - */ - var assignIn = createAssigner(function(object, source) { - copyObject(source, keysIn(source), object); - }); - - /** - * This method is like `_.assignIn` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extendWith - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. * @param {Function} [customizer] The function to customize assigned values. + * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {Object} Returns `object`. - * @see _.assignWith * @example * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } + * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' }); + * // => { 'user': 'fred', 'age': 40 } * - * var defaults = _.partialRight(_.assignInWith, customizer); + * // using a customizer callback + * var defaults = _.partialRight(_.assign, function(value, other) { + * return _.isUndefined(value) ? other : value; + * }); * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } + * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } */ - var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keysIn(source), object, customizer); + var assign = createAssigner(function(object, source, customizer) { + return customizer + ? assignWith(object, source, customizer) + : baseAssign(object, source); }); /** - * This method is like `_.assign` except that it accepts `customizer` - * which is invoked to produce the assigned values. If `customizer` returns - * `undefined`, assignment is handled by the method instead. The `customizer` - * is invoked with five arguments: (objValue, srcValue, key, object, source). - * - * **Note:** This method mutates `object`. + * Creates an object that inherits from the given `prototype` object. If a + * `properties` object is provided its own enumerable properties are assigned + * to the created object. * * @static * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @see _.assignInWith - * @example - * - * function customizer(objValue, srcValue) { - * return _.isUndefined(objValue) ? srcValue : objValue; - * } - * - * var defaults = _.partialRight(_.assignWith, customizer); - * - * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var assignWith = createAssigner(function(object, source, srcIndex, customizer) { - copyObject(source, keys(source), object, customizer); - }); - - /** - * Creates an array of values corresponding to `paths` of `object`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @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 picked values. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _.at(object, ['a[0].b.c', 'a[1]']); - * // => [3, 4] - */ - var at = baseRest(function(object, paths) { - return baseAt(object, baseFlatten(paths, 1)); - }); - - /** - * Creates an object that inherits from the `prototype` object. If a - * `properties` object is given, its own enumerable string keyed properties - * are assigned to the created object. - * - * @static - * @memberOf _ - * @since 2.3.0 * @category Object * @param {Object} prototype The object to inherit from. * @param {Object} [properties] The properties to assign to the object. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Object} Returns the new object. * @example * @@ -12439,36 +9244,33 @@ * circle instanceof Shape; * // => true */ - function create(prototype, properties) { + function create(prototype, properties, guard) { var result = baseCreate(prototype); + if (guard && isIterateeCall(prototype, properties, guard)) { + properties = undefined; + } return properties ? baseAssign(result, properties) : result; } /** - * Assigns own and inherited enumerable string keyed properties of source - * objects to the destination object for all destination properties that - * resolve to `undefined`. Source objects are applied from left to right. - * Once a property is set, additional values of the same property are ignored. + * Assigns own enumerable properties of source object(s) to the destination + * object for all destination properties that resolve to `undefined`. Once a + * property is set, additional values of the same property are ignored. * * **Note:** This method mutates `object`. * * @static - * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @returns {Object} Returns `object`. - * @see _.defaultsDeep * @example * - * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } + * _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' }); + * // => { 'user': 'barney', 'age': 36 } */ - var defaults = baseRest(function(args) { - args.push(undefined, assignInDefaults); - return apply(assignInWith, undefined, args); - }); + var defaults = createDefaults(assign, assignDefaults); /** * This method is like `_.defaults` except that it recursively assigns @@ -12478,34 +9280,41 @@ * * @static * @memberOf _ - * @since 3.10.0 * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @returns {Object} Returns `object`. - * @see _.defaults * @example * - * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); - * // => { 'a': { 'b': 2, 'c': 3 } } + * _.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } }); + * // => { 'user': { 'name': 'barney', 'age': 36 } } + * */ - var defaultsDeep = baseRest(function(args) { - args.push(undefined, mergeDefaults); - return apply(mergeWith, undefined, args); - }); + var defaultsDeep = createDefaults(merge, mergeDefaults); /** * This method is like `_.find` except that it returns the key of the first * element `predicate` returns truthy for instead of the element itself. * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * * @static * @memberOf _ - * @since 1.1.0 * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. + * @param {Object} object The object to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {string|undefined} Returns the key of the matched element, else `undefined`. * @example * * var users = { @@ -12514,37 +9323,48 @@ * 'pebbles': { 'age': 1, 'active': true } * }; * - * _.findKey(users, function(o) { return o.age < 40; }); + * _.findKey(users, function(chr) { + * return chr.age < 40; + * }); * // => 'barney' (iteration order is not guaranteed) * - * // The `_.matches` iteratee shorthand. + * // using the `_.matches` callback shorthand * _.findKey(users, { 'age': 1, 'active': true }); * // => 'pebbles' * - * // The `_.matchesProperty` iteratee shorthand. - * _.findKey(users, ['active', false]); + * // using the `_.matchesProperty` callback shorthand + * _.findKey(users, 'active', false); * // => 'fred' * - * // The `_.property` iteratee shorthand. + * // using the `_.property` callback shorthand * _.findKey(users, 'active'); * // => 'barney' */ - function findKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); - } + var findKey = createFindKey(baseForOwn); /** * This method is like `_.findKey` except that it iterates over elements of * a collection in the opposite order. * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * * @static * @memberOf _ - * @since 2.0.0 * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. + * @param {Object} object The object to search. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {string|undefined} Returns the key of the matched element, else `undefined`. * @example * * var users = { @@ -12553,39 +9373,38 @@ * 'pebbles': { 'age': 1, 'active': true } * }; * - * _.findLastKey(users, function(o) { return o.age < 40; }); - * // => returns 'pebbles' assuming `_.findKey` returns 'barney' + * _.findLastKey(users, function(chr) { + * return chr.age < 40; + * }); + * // => returns `pebbles` assuming `_.findKey` returns `barney` * - * // The `_.matches` iteratee shorthand. + * // using the `_.matches` callback shorthand * _.findLastKey(users, { 'age': 36, 'active': true }); * // => 'barney' * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastKey(users, ['active', false]); + * // using the `_.matchesProperty` callback shorthand + * _.findLastKey(users, 'active', false); * // => 'fred' * - * // The `_.property` iteratee shorthand. + * // using the `_.property` callback shorthand * _.findLastKey(users, 'active'); * // => 'pebbles' */ - function findLastKey(object, predicate) { - return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); - } + var findLastKey = createFindKey(baseForOwnRight); /** - * Iterates over own and inherited enumerable string keyed properties of an - * object and invokes `iteratee` for each property. The iteratee is invoked + * Iterates over own and inherited enumerable properties of an object invoking + * `iteratee` for each property. The `iteratee` is bound to `thisArg` and invoked * with three arguments: (value, key, object). Iteratee functions may exit * iteration early by explicitly returning `false`. * * @static * @memberOf _ - * @since 0.3.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns `object`. - * @see _.forInRight * @example * * function Foo() { @@ -12598,13 +9417,9 @@ * _.forIn(new Foo, function(value, key) { * console.log(key); * }); - * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). + * // => logs 'a', 'b', and 'c' (iteration order is not guaranteed) */ - function forIn(object, iteratee) { - return object == null - ? object - : baseFor(object, getIteratee(iteratee, 3), keysIn); - } + var forIn = createForIn(baseFor); /** * This method is like `_.forIn` except that it iterates over properties of @@ -12612,12 +9427,11 @@ * * @static * @memberOf _ - * @since 2.0.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns `object`. - * @see _.forIn * @example * * function Foo() { @@ -12630,28 +9444,23 @@ * _.forInRight(new Foo, function(value, key) { * console.log(key); * }); - * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. + * // => logs 'c', 'b', and 'a' assuming `_.forIn ` logs 'a', 'b', and 'c' */ - function forInRight(object, iteratee) { - return object == null - ? object - : baseForRight(object, getIteratee(iteratee, 3), keysIn); - } + var forInRight = createForIn(baseForRight); /** - * Iterates over own enumerable string keyed properties of an object and - * invokes `iteratee` for each property. The iteratee is invoked with three - * arguments: (value, key, object). Iteratee functions may exit iteration + * Iterates over own enumerable properties of an object invoking `iteratee` + * for each property. The `iteratee` is bound to `thisArg` and invoked with + * three arguments: (value, key, object). Iteratee functions may exit iteration * early by explicitly returning `false`. * * @static * @memberOf _ - * @since 0.3.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns `object`. - * @see _.forOwnRight * @example * * function Foo() { @@ -12664,11 +9473,9 @@ * _.forOwn(new Foo, function(value, key) { * console.log(key); * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). + * // => logs 'a' and 'b' (iteration order is not guaranteed) */ - function forOwn(object, iteratee) { - return object && baseForOwn(object, getIteratee(iteratee, 3)); - } + var forOwn = createForOwn(baseForOwn); /** * This method is like `_.forOwn` except that it iterates over properties of @@ -12676,12 +9483,11 @@ * * @static * @memberOf _ - * @since 2.0.0 * @category Object * @param {Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns `object`. - * @see _.forOwn * @example * * function Foo() { @@ -12694,77 +9500,39 @@ * _.forOwnRight(new Foo, function(value, key) { * console.log(key); * }); - * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. + * // => logs 'b' and 'a' assuming `_.forOwn` logs 'a' and 'b' */ - function forOwnRight(object, iteratee) { - return object && baseForOwnRight(object, getIteratee(iteratee, 3)); - } + var forOwnRight = createForOwn(baseForOwnRight); /** - * Creates an array of function property names from own enumerable properties - * of `object`. + * Creates an array of function property names from all enumerable properties, + * own and inherited, of `object`. * * @static - * @since 0.1.0 * @memberOf _ + * @alias methods * @category Object * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functionsIn + * @returns {Array} Returns the new array of property names. * @example * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functions(new Foo); - * // => ['a', 'b'] + * _.functions(_); + * // => ['after', 'ary', 'assign', ...] */ function functions(object) { - return object == null ? [] : baseFunctions(object, keys(object)); + return baseFunctions(object, keysIn(object)); } /** - * Creates an array of function property names from own and inherited - * enumerable properties of `object`. + * Gets the property value at `path` of `object`. If the resolved value is + * `undefined` the `defaultValue` is used in its place. * * @static * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @returns {Array} Returns the function names. - * @see _.functions - * @example - * - * function Foo() { - * this.a = _.constant('a'); - * this.b = _.constant('b'); - * } - * - * Foo.prototype.c = _.constant('c'); - * - * _.functionsIn(new Foo); - * // => ['a', 'b', 'c'] - */ - function functionsIn(object) { - return object == null ? [] : baseFunctions(object, keysIn(object)); - } - - /** - * Gets the value at `path` of `object`. If the resolved value is - * `undefined`, the `defaultValue` is returned in its place. - * - * @static - * @memberOf _ - * @since 3.7.0 * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. * @returns {*} Returns the resolved value. * @example * @@ -12780,81 +9548,61 @@ * // => 'default' */ function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, path); + var result = object == null ? undefined : baseGet(object, toPath(path), (path + '')); return result === undefined ? defaultValue : result; } /** - * Checks if `path` is a direct property of `object`. + * Checks if `path` is a direct property. * * @static - * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @returns {boolean} Returns `true` if `path` is a direct property, else `false`. * @example * - * var object = { 'a': { 'b': 2 } }; - * var other = _.create({ 'a': _.create({ 'b': 2 }) }); + * var object = { 'a': { 'b': { 'c': 3 } } }; * * _.has(object, 'a'); * // => true * - * _.has(object, 'a.b'); + * _.has(object, 'a.b.c'); * // => true * - * _.has(object, ['a', 'b']); + * _.has(object, ['a', 'b', 'c']); * // => true - * - * _.has(other, 'a'); - * // => false */ function has(object, path) { - return object != null && hasPath(object, path, baseHas); - } - - /** - * Checks if `path` is a direct or inherited property of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.hasIn(object, 'a'); - * // => true - * - * _.hasIn(object, 'a.b'); - * // => true - * - * _.hasIn(object, ['a', 'b']); - * // => true - * - * _.hasIn(object, 'b'); - * // => false - */ - function hasIn(object, path) { - return object != null && hasPath(object, path, baseHasIn); + if (object == null) { + return false; + } + var result = hasOwnProperty.call(object, path); + if (!result && !isKey(path)) { + path = toPath(path); + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + if (object == null) { + return false; + } + path = last(path); + result = hasOwnProperty.call(object, path); + } + return result || (isLength(object.length) && isIndex(path, object.length) && + (isArray(object) || isArguments(object))); } /** * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite - * property assignments of previous values. + * If `object` contains duplicate values, subsequent values overwrite property + * assignments of previous values unless `multiValue` is `true`. * * @static * @memberOf _ - * @since 0.7.0 * @category Object * @param {Object} object The object to invert. + * @param {boolean} [multiValue] Allow multiple values per key. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {Object} Returns the new inverted object. * @example * @@ -12862,74 +9610,46 @@ * * _.invert(object); * // => { '1': 'c', '2': 'b' } - */ - var invert = createInverter(function(result, value, key) { - result[value] = key; - }, constant(identity)); - - /** - * This method is like `_.invert` except that the inverted object is generated - * from the results of running each element of `object` thru `iteratee`. The - * corresponding inverted value of each inverted key is an array of keys - * responsible for generating the inverted value. The iteratee is invoked - * with one argument: (value). * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Object - * @param {Object} object The object to invert. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invertBy(object); + * // with `multiValue` + * _.invert(object, true); * // => { '1': ['a', 'c'], '2': ['b'] } - * - * _.invertBy(object, function(value) { - * return 'group' + value; - * }); - * // => { 'group1': ['a', 'c'], 'group2': ['b'] } */ - var invertBy = createInverter(function(result, value, key) { - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; + function invert(object, multiValue, guard) { + if (guard && isIterateeCall(object, multiValue, guard)) { + multiValue = undefined; } - }, getIteratee); + var index = -1, + props = keys(object), + length = props.length, + result = {}; - /** - * Invokes the method at `path` of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {...*} [args] The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - * @example - * - * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; - * - * _.invoke(object, 'a[0].b.c.slice', 1, 3); - * // => [2, 3] - */ - var invoke = baseRest(baseInvoke); + while (++index < length) { + var key = props[index], + value = object[key]; + + if (multiValue) { + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + } + else { + result[value] = key; + } + } + return result; + } /** * Creates an array of the own enumerable property names of `object`. * * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys) * for more details. * * @static - * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to query. @@ -12949,9 +9669,14 @@ * _.keys('hi'); * // => ['0', '1'] */ - function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); - } + var keys = !nativeKeys ? shimKeys : function(object) { + var Ctor = object == null ? undefined : object.constructor; + if ((typeof Ctor == 'function' && Ctor.prototype === object) || + (typeof object != 'function' && isArrayLike(object))) { + return shimKeys(object); + } + return isObject(object) ? nativeKeys(object) : []; + }; /** * Creates an array of the own and inherited enumerable property names of `object`. @@ -12960,7 +9685,6 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. @@ -12977,23 +9701,47 @@ * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysIn(object) { - return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); + if (object == null) { + return []; + } + if (!isObject(object)) { + object = Object(object); + } + var length = object.length; + length = (length && isLength(length) && + (isArray(object) || isArguments(object)) && length) || 0; + + var Ctor = object.constructor, + index = -1, + isProto = typeof Ctor == 'function' && Ctor.prototype === object, + result = Array(length), + skipIndexes = length > 0; + + while (++index < length) { + result[index] = (index + ''); + } + for (var key in object) { + if (!(skipIndexes && isIndex(key, length)) && + !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; } /** * The opposite of `_.mapValues`; this method creates an object with the * same values as `object` and keys generated by running each own enumerable - * string keyed property of `object` thru `iteratee`. The iteratee is invoked - * with three arguments: (value, key, object). + * property of `object` through `iteratee`. * * @static * @memberOf _ - * @since 3.8.0 * @category Object * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns the new mapped object. - * @see _.mapValues * @example * * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { @@ -13001,230 +9749,163 @@ * }); * // => { 'a1': 1, 'b2': 2 } */ - function mapKeys(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); - - baseForOwn(object, function(value, key, object) { - result[iteratee(value, key, object)] = value; - }); - return result; - } + var mapKeys = createObjectMapper(true); /** - * Creates an object with the same keys as `object` and values generated - * by running each own enumerable string keyed property of `object` thru - * `iteratee`. The iteratee is invoked with three arguments: + * Creates an object with the same keys as `object` and values generated by + * running each own enumerable property of `object` through `iteratee`. The + * iteratee function is bound to `thisArg` and invoked with three arguments: * (value, key, object). * + * If a property name is provided for `iteratee` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `iteratee` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * * @static * @memberOf _ - * @since 2.4.0 * @category Object * @param {Object} object The object to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {Object} Returns the new mapped object. - * @see _.mapKeys * @example * + * _.mapValues({ 'a': 1, 'b': 2 }, function(n) { + * return n * 3; + * }); + * // => { 'a': 3, 'b': 6 } + * * var users = { * 'fred': { 'user': 'fred', 'age': 40 }, * 'pebbles': { 'user': 'pebbles', 'age': 1 } * }; * - * _.mapValues(users, function(o) { return o.age; }); - * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) - * - * // The `_.property` iteratee shorthand. + * // using the `_.property` callback shorthand * _.mapValues(users, 'age'); * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) */ - function mapValues(object, iteratee) { - var result = {}; - iteratee = getIteratee(iteratee, 3); + var mapValues = createObjectMapper(); - baseForOwn(object, function(value, key, object) { - result[key] = iteratee(value, key, object); + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable properties of `object` that are not omitted. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|...(string|string[])} [predicate] The function invoked per + * iteration or property names to omit, specified as individual property + * names or arrays of property names. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.omit(object, 'age'); + * // => { 'user': 'fred' } + * + * _.omit(object, _.isNumber); + * // => { 'user': 'fred' } + */ + var omit = restParam(function(object, props) { + if (object == null) { + return {}; + } + if (typeof props[0] != 'function') { + var props = arrayMap(baseFlatten(props), String); + return pickByArray(object, baseDifference(keysIn(object), props)); + } + var predicate = bindCallback(props[0], props[1], 3); + return pickByCallback(object, function(value, key, object) { + return !predicate(value, key, object); }); + }); + + /** + * Creates a two dimensional array of the key-value pairs for `object`, + * e.g. `[[key1, value1], [key2, value2]]`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the new array of key-value pairs. + * @example + * + * _.pairs({ 'barney': 36, 'fred': 40 }); + * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed) + */ + function pairs(object) { + object = toObject(object); + + var index = -1, + props = keys(object), + length = props.length, + result = Array(length); + + while (++index < length) { + var key = props[index]; + result[index] = [key, object[key]]; + } return result; } /** - * This method is like `_.assign` except that it recursively merges own and - * 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 - * assignment. Source objects are applied from left to right. Subsequent - * sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object`. + * Creates an object composed of the picked `object` properties. Property + * names may be specified as individual arguments or as arrays of property + * names. If `predicate` is provided it's invoked for each property of `object` + * picking the properties `predicate` returns truthy for. The predicate is + * bound to `thisArg` and invoked with three arguments: (value, key, object). * * @static * @memberOf _ - * @since 0.5.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * var object = { - * 'a': [{ 'b': 2 }, { 'd': 4 }] - * }; - * - * var other = { - * 'a': [{ 'c': 3 }, { 'e': 5 }] - * }; - * - * _.merge(object, other); - * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } - */ - var merge = createAssigner(function(object, source, srcIndex) { - baseMerge(object, source, srcIndex); - }); - - /** - * This method is like `_.merge` except that it accepts `customizer` which - * is invoked to produce the merged values of the destination and source - * properties. If `customizer` returns `undefined`, merging is handled by the - * method instead. The `customizer` is invoked with seven arguments: - * (objValue, srcValue, key, object, source, stack). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * function customizer(objValue, srcValue) { - * if (_.isArray(objValue)) { - * return objValue.concat(srcValue); - * } - * } - * - * var object = { 'a': [1], 'b': [2] }; - * var other = { 'a': [3], 'b': [4] }; - * - * _.mergeWith(object, other, customizer); - * // => { 'a': [1, 3], 'b': [2, 4] } - */ - var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { - baseMerge(object, source, srcIndex, customizer); - }); - - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable string keyed properties of `object` that are - * not omitted. - * - * @static - * @since 0.1.0 - * @memberOf _ * @category Object * @param {Object} object The source object. - * @param {...(string|string[])} [props] The property identifiers to omit. + * @param {Function|...(string|string[])} [predicate] The function invoked per + * iteration or property names to pick, specified as individual property + * names or arrays of property names. + * @param {*} [thisArg] The `this` binding of `predicate`. * @returns {Object} Returns the new object. * @example * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * var object = { 'user': 'fred', 'age': 40 }; * - * _.omit(object, ['a', 'c']); - * // => { 'b': '2' } + * _.pick(object, 'user'); + * // => { 'user': 'fred' } + * + * _.pick(object, _.isString); + * // => { 'user': 'fred' } */ - var omit = baseRest(function(object, props) { + var pick = restParam(function(object, props) { if (object == null) { return {}; } - props = arrayMap(baseFlatten(props, 1), toKey); - return basePick(object, baseDifference(getAllKeysIn(object), props)); + return typeof props[0] == 'function' + ? pickByCallback(object, bindCallback(props[0], props[1], 3)) + : pickByArray(object, baseFlatten(props)); }); /** - * The opposite of `_.pickBy`; this method creates an object composed of - * the own and inherited enumerable string keyed properties of `object` that - * `predicate` doesn't return truthy for. The predicate is invoked with two - * arguments: (value, key). + * This method is like `_.get` except that if the resolved value is a function + * it's invoked with the `this` binding of its parent object and its result + * is returned. * * @static * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omitBy(object, _.isNumber); - * // => { 'b': '2' } - */ - function omitBy(object, predicate) { - return pickBy(object, negate(getIteratee(predicate))); - } - - /** - * Creates an object composed of the picked `object` properties. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [props] The property identifiers to pick. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pick(object, ['a', 'c']); - * // => { 'a': 1, 'c': 3 } - */ - var pick = baseRest(function(object, props) { - return object == null ? {} : basePick(object, arrayMap(baseFlatten(props, 1), toKey)); - }); - - /** - * Creates an object composed of the `object` properties `predicate` returns - * truthy for. The predicate is invoked with two arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pickBy(object, _.isNumber); - * // => { 'a': 1, 'c': 3 } - */ - function pickBy(object, predicate) { - return object == null ? {} : basePickBy(object, getAllKeysIn(object), getIteratee(predicate)); - } - - /** - * This method is like `_.get` except that if the resolved value is a - * function it's invoked with the `this` binding of its parent object and - * its result is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ * @category Object * @param {Object} object The object to query. * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @param {*} [defaultValue] The value returned if the resolved value is `undefined`. * @returns {*} Returns the resolved value. * @example * @@ -13236,47 +9917,33 @@ * _.result(object, 'a[0].b.c2'); * // => 4 * - * _.result(object, 'a[0].b.c3', 'default'); + * _.result(object, 'a.b.c', 'default'); * // => 'default' * - * _.result(object, 'a[0].b.c3', _.constant('default')); + * _.result(object, 'a.b.c', _.constant('default')); * // => 'default' */ function result(object, path, defaultValue) { - path = isKey(path, object) ? [path] : castPath(path); - - var index = -1, - length = path.length; - - // Ensure the loop is entered when path is empty. - if (!length) { - object = undefined; - length = 1; - } - while (++index < length) { - var value = object == null ? undefined : object[toKey(path[index])]; - if (value === undefined) { - index = length; - value = defaultValue; + var result = object == null ? undefined : object[path]; + if (result === undefined) { + if (object != null && !isKey(path, object)) { + path = toPath(path); + object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1)); + result = object == null ? undefined : object[last(path)]; } - object = isFunction(value) ? value.call(object) : value; + result = result === undefined ? defaultValue : result; } - return object; + return isFunction(result) ? result.call(object) : result; } /** - * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, - * it's created. Arrays are created for missing index properties while objects - * are created for all other missing properties. Use `_.setWith` to customize - * `path` creation. - * - * **Note:** This method mutates `object`. + * Sets the property value of `path` on `object`. If a portion of `path` + * does not exist it's created. * * @static * @memberOf _ - * @since 3.7.0 * @category Object - * @param {Object} object The object to modify. + * @param {Object} object The object to augment. * @param {Array|string} path The path of the property to set. * @param {*} value The value to set. * @returns {Object} Returns `object`. @@ -13288,128 +9955,68 @@ * console.log(object.a[0].b.c); * // => 4 * - * _.set(object, ['x', '0', 'y', 'z'], 5); + * _.set(object, 'x[0].y.z', 5); * console.log(object.x[0].y.z); * // => 5 */ function set(object, path, value) { - return object == null ? object : baseSet(object, path, value); + if (object == null) { + return object; + } + var pathKey = (path + ''); + path = (object[pathKey] != null || isKey(path, object)) ? [pathKey] : toPath(path); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = path[index]; + if (isObject(nested)) { + if (index == lastIndex) { + nested[key] = value; + } else if (nested[key] == null) { + nested[key] = isIndex(path[index + 1]) ? [] : {}; + } + } + nested = nested[key]; + } + return object; } - /** - * This method is like `_.set` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.setWith(object, '[0][1]', 'a', Object); - * // => { '0': { '1': 'a' } } - */ - function setWith(object, path, value, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseSet(object, path, value, customizer); - } - - /** - * Creates an array of own enumerable string keyed-value pairs for `object` - * which can be consumed by `_.fromPairs`. If `object` is a map or set, its - * entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entries - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairs(new Foo); - * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) - */ - var toPairs = createToPairs(keys); - - /** - * Creates an array of own and inherited enumerable string keyed-value pairs - * for `object` which can be consumed by `_.fromPairs`. If `object` is a map - * or set, its entries are returned. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias entriesIn - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the key-value pairs. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.toPairsIn(new Foo); - * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) - */ - 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. 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`. + * `accumulator` object which is the result of running each of its own enumerable + * properties through `iteratee`, with each invocation potentially mutating + * the `accumulator` object. The `iteratee` is bound to `thisArg` and 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 {Object} object The object to iterate over. + * @param {Array|Object} object The object to iterate over. * @param {Function} [iteratee=_.identity] The function invoked per iteration. * @param {*} [accumulator] The custom accumulator value. + * @param {*} [thisArg] The `this` binding of `iteratee`. * @returns {*} Returns the accumulated value. * @example * * _.transform([2, 3, 4], function(result, n) { * result.push(n *= n); * return n % 2 == 0; - * }, []); + * }); * // => [4, 9] * - * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } + * _.transform({ 'a': 1, 'b': 2 }, function(result, n, key) { + * result[key] = n * 3; + * }); + * // => { 'a': 3, 'b': 6 } */ - function transform(object, iteratee, accumulator) { + function transform(object, iteratee, accumulator, thisArg) { var isArr = isArray(object) || isTypedArray(object); - iteratee = getIteratee(iteratee, 4); + iteratee = getCallback(iteratee, thisArg, 4); if (accumulator == null) { if (isArr || isObject(object)) { @@ -13417,7 +10024,7 @@ if (isArr) { accumulator = isArray(object) ? new Ctor : []; } else { - accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; + accumulator = baseCreate(isFunction(Ctor) ? Ctor.prototype : undefined); } } else { accumulator = {}; @@ -13430,103 +10037,11 @@ } /** - * Removes the property at `path` of `object`. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 7 } }] }; - * _.unset(object, 'a[0].b.c'); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - * - * _.unset(object, ['a', '0', 'b', 'c']); - * // => true - * - * console.log(object); - * // => { 'a': [{ 'b': {} }] }; - */ - function unset(object, path) { - return object == null ? true : baseUnset(object, path); - } - - /** - * This method is like `_.set` except that accepts `updater` to produce the - * value to set. Use `_.updateWith` to customize `path` creation. The `updater` - * is invoked with one argument: (value). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.update(object, 'a[0].b.c', function(n) { return n * n; }); - * console.log(object.a[0].b.c); - * // => 9 - * - * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); - * console.log(object.x[0].y.z); - * // => 0 - */ - function update(object, path, updater) { - return object == null ? object : baseUpdate(object, path, castFunction(updater)); - } - - /** - * This method is like `_.update` except that it accepts `customizer` which is - * invoked to produce the objects of `path`. If `customizer` returns `undefined` - * path creation is handled by the method instead. The `customizer` is invoked - * with three arguments: (nsValue, key, nsObject). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.6.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {Function} updater The function to produce the updated value. - * @param {Function} [customizer] The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * var object = {}; - * - * _.updateWith(object, '[0][1]', _.constant('a'), Object); - * // => { '0': { '1': 'a' } } - */ - function updateWith(object, path, updater, customizer) { - customizer = typeof customizer == 'function' ? customizer : undefined; - return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); - } - - /** - * Creates an array of the own enumerable string keyed property values of `object`. + * Creates an array of the own enumerable property values of `object`. * * **Note:** Non-object values are coerced to objects. * * @static - * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The object to query. @@ -13547,18 +10062,17 @@ * // => ['h', 'i'] */ function values(object) { - return object ? baseValues(object, keys(object)) : []; + return baseValues(object, keys(object)); } /** - * Creates an array of the own and inherited enumerable string keyed property - * values of `object`. + * Creates an array of the own and inherited enumerable property values + * of `object`. * * **Note:** Non-object values are coerced to objects. * * @static * @memberOf _ - * @since 3.0.0 * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the array of property values. @@ -13575,61 +10089,22 @@ * // => [1, 2, 3] (iteration order is not guaranteed) */ function valuesIn(object) { - return object == null ? [] : baseValues(object, keysIn(object)); + return baseValues(object, keysIn(object)); } /*------------------------------------------------------------------------*/ /** - * Clamps `number` within the inclusive `lower` and `upper` bounds. + * Checks if `n` is between `start` and up to but not including, `end`. If + * `end` is not specified it's set to `start` with `start` then set to `0`. * * @static * @memberOf _ - * @since 4.0.0 * @category Number - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - * @example - * - * _.clamp(-10, -5, 5); - * // => -5 - * - * _.clamp(10, -5, 5); - * // => 5 - */ - function clamp(number, lower, upper) { - if (upper === undefined) { - upper = lower; - lower = undefined; - } - if (upper !== undefined) { - upper = toNumber(upper); - upper = upper === upper ? upper : 0; - } - if (lower !== undefined) { - lower = toNumber(lower); - lower = lower === lower ? lower : 0; - } - return baseClamp(toNumber(number), lower, upper); - } - - /** - * Checks if `n` is between `start` and up to, but not including, `end`. If - * `end` is not specified, it's set to `start` with `start` then set to `0`. - * If `start` is greater than `end` the params are swapped to support - * negative ranges. - * - * @static - * @memberOf _ - * @since 3.3.0 - * @category Number - * @param {number} number The number to check. + * @param {number} n The number to check. * @param {number} [start=0] The start of the range. * @param {number} end The end of the range. - * @returns {boolean} Returns `true` if `number` is in the range, else `false`. - * @see _.range, _.rangeRight + * @returns {boolean} Returns `true` if `n` is in the range, else `false`. * @example * * _.inRange(3, 2, 4); @@ -13649,37 +10124,29 @@ * * _.inRange(5.2, 4); * // => false - * - * _.inRange(-3, -2, -6); - * // => true */ - function inRange(number, start, end) { - start = toFinite(start); + function inRange(value, start, end) { + start = +start || 0; if (end === undefined) { end = start; start = 0; } else { - end = toFinite(end); + end = +end || 0; } - number = toNumber(number); - return baseInRange(number, start, end); + return value >= nativeMin(start, end) && value < nativeMax(start, end); } /** - * Produces a random number between the inclusive `lower` and `upper` bounds. - * If only one argument is provided a number between `0` and the given number - * is returned. If `floating` is `true`, or either `lower` or `upper` are - * floats, a floating-point number is returned instead of an integer. - * - * **Note:** JavaScript follows the IEEE-754 standard for resolving - * floating-point values which can produce unexpected results. + * Produces a random number between `min` and `max` (inclusive). If only one + * argument is provided a number between `0` and the given number is returned. + * If `floating` is `true`, or either `min` or `max` are floats, a floating-point + * number is returned instead of an integer. * * @static * @memberOf _ - * @since 0.7.0 * @category Number - * @param {number} [lower=0] The lower bound. - * @param {number} [upper=1] The upper bound. + * @param {number} [min=0] The minimum possible value. + * @param {number} [max=1] The maximum possible value. * @param {boolean} [floating] Specify returning a floating-point number. * @returns {number} Returns the random number. * @example @@ -13696,43 +10163,39 @@ * _.random(1.2, 5.2); * // => a floating-point number between 1.2 and 5.2 */ - function random(lower, upper, floating) { - if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { - upper = floating = undefined; + function random(min, max, floating) { + if (floating && isIterateeCall(min, max, floating)) { + max = floating = undefined; } - if (floating === undefined) { - if (typeof upper == 'boolean') { - floating = upper; - upper = undefined; + var noMin = min == null, + noMax = max == null; + + if (floating == null) { + if (noMax && typeof min == 'boolean') { + floating = min; + min = 1; } - else if (typeof lower == 'boolean') { - floating = lower; - lower = undefined; + else if (typeof max == 'boolean') { + floating = max; + noMax = true; } } - if (lower === undefined && upper === undefined) { - lower = 0; - upper = 1; + if (noMin && noMax) { + max = 1; + noMax = false; } - else { - lower = toFinite(lower); - if (upper === undefined) { - upper = lower; - lower = 0; - } else { - upper = toFinite(upper); - } + min = +min || 0; + if (noMax) { + max = min; + min = 0; + } else { + max = +max || 0; } - if (lower > upper) { - var temp = lower; - lower = upper; - upper = temp; - } - if (floating || lower % 1 || upper % 1) { + if (floating || min % 1 || max % 1) { var rand = nativeRandom(); - return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); + return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand + '').length - 1)))), max); } - return baseRandom(lower, upper); + return baseRandom(min, max); } /*------------------------------------------------------------------------*/ @@ -13742,7 +10205,6 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the camel cased string. @@ -13751,46 +10213,41 @@ * _.camelCase('Foo Bar'); * // => 'fooBar' * - * _.camelCase('--foo-bar--'); + * _.camelCase('--foo-bar'); * // => 'fooBar' * - * _.camelCase('__FOO_BAR__'); + * _.camelCase('__foo_bar__'); * // => 'fooBar' */ var camelCase = createCompounder(function(result, word, index) { word = word.toLowerCase(); - return result + (index ? capitalize(word) : word); + return result + (index ? (word.charAt(0).toUpperCase() + word.slice(1)) : word); }); /** - * Converts the first character of `string` to upper case and the remaining - * to lower case. + * Capitalizes the first character of `string`. * * @static * @memberOf _ - * @since 3.0.0 * @category String * @param {string} [string=''] The string to capitalize. * @returns {string} Returns the capitalized string. * @example * - * _.capitalize('FRED'); + * _.capitalize('fred'); * // => 'Fred' */ function capitalize(string) { - return upperFirst(toString(string).toLowerCase()); + string = baseToString(string); + return string && (string.charAt(0).toUpperCase() + string.slice(1)); } /** - * Deburrs `string` by converting - * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) - * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) - * letters to basic Latin letters and removing - * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). + * Deburrs `string` by converting [latin-1 supplementary letters](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) + * to basic latin letters and removing [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). * * @static * @memberOf _ - * @since 3.0.0 * @category String * @param {string} [string=''] The string to deburr. * @returns {string} Returns the deburred string. @@ -13800,8 +10257,8 @@ * // => 'deja vu' */ function deburr(string) { - string = toString(string); - return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); + string = baseToString(string); + return string && string.replace(reLatin1, deburrLetter).replace(reComboMark, ''); } /** @@ -13809,13 +10266,11 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category String - * @param {string} [string=''] The string to inspect. + * @param {string} [string=''] The string to search. * @param {string} [target] The string to search for. - * @param {number} [position=string.length] The position to search up to. - * @returns {boolean} Returns `true` if `string` ends with `target`, - * else `false`. + * @param {number} [position=string.length] The position to search from. + * @returns {boolean} Returns `true` if `string` ends with `target`, else `false`. * @example * * _.endsWith('abc', 'c'); @@ -13828,44 +10283,41 @@ * // => true */ function endsWith(string, target, position) { - string = toString(string); - target = baseToString(target); + string = baseToString(string); + target = (target + ''); var length = string.length; position = position === undefined ? length - : baseClamp(toInteger(position), 0, length); + : nativeMin(position < 0 ? 0 : (+position || 0), length); - var end = position; position -= target.length; - return position >= 0 && string.slice(position, end) == target; + return position >= 0 && string.indexOf(target, position) == position; } /** - * Converts the characters "&", "<", ">", '"', "'", and "\`" in `string` to + * Converts the characters "&", "<", ">", '"', "'", and "\`", in `string` to * their corresponding HTML entities. * - * **Note:** No other characters are escaped. To escape additional - * characters use a third-party library like [_he_](https://mths.be/he). + * **Note:** No other characters are escaped. To escape additional characters + * use a third-party library like [_he_](https://mths.be/he). * * Though the ">" character is escaped for symmetry, characters like * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. See - * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * unless they're part of a tag or unquoted attribute value. + * See [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) * (under "semi-related fun fact") for more details. * - * Backticks are escaped because in IE < 9, they can break out of - * attribute values or HTML comments. See [#59](https://html5sec.org/#59), + * Backticks are escaped because in Internet Explorer < 9, they can break out + * of attribute values or HTML comments. See [#59](https://html5sec.org/#59), * [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and - * [#133](https://html5sec.org/#133) of the - * [HTML5 Security Cheatsheet](https://html5sec.org/) for more details. + * [#133](https://html5sec.org/#133) of the [HTML5 Security Cheatsheet](https://html5sec.org/) + * for more details. * - * When working with HTML you should always - * [quote attribute values](http://wonko.com/post/html-escaping) to reduce - * XSS vectors. + * When working with HTML you should always [quote attribute values](http://wonko.com/post/html-escaping) + * to reduce XSS vectors. * * @static - * @since 0.1.0 * @memberOf _ * @category String * @param {string} [string=''] The string to escape. @@ -13876,41 +10328,39 @@ * // => 'fred, barney, & pebbles' */ function escape(string) { - string = toString(string); + // Reset `lastIndex` because in IE < 9 `String#replace` does not. + string = baseToString(string); return (string && reHasUnescapedHtml.test(string)) ? string.replace(reUnescapedHtml, escapeHtmlChar) : string; } /** - * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", - * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. + * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?", + * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`. * * @static * @memberOf _ - * @since 3.0.0 * @category String * @param {string} [string=''] The string to escape. * @returns {string} Returns the escaped string. * @example * * _.escapeRegExp('[lodash](https://lodash.com/)'); - * // => '\[lodash\]\(https://lodash\.com/\)' + * // => '\[lodash\]\(https:\/\/lodash\.com\/\)' */ function escapeRegExp(string) { - string = toString(string); - return (string && reHasRegExpChar.test(string)) - ? string.replace(reRegExpChar, '\\$&') - : string; + string = baseToString(string); + return (string && reHasRegExpChars.test(string)) + ? string.replace(reRegExpChars, escapeRegExpChar) + : (string || '(?:)'); } /** - * Converts `string` to - * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). + * Converts `string` to [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). * * @static * @memberOf _ - * @since 3.0.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the kebab cased string. @@ -13922,63 +10372,19 @@ * _.kebabCase('fooBar'); * // => 'foo-bar' * - * _.kebabCase('__FOO_BAR__'); + * _.kebabCase('__foo_bar__'); * // => 'foo-bar' */ var kebabCase = createCompounder(function(result, word, index) { return result + (index ? '-' : '') + word.toLowerCase(); }); - /** - * Converts `string`, as space separated words, to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the lower cased string. - * @example - * - * _.lowerCase('--Foo-Bar--'); - * // => 'foo bar' - * - * _.lowerCase('fooBar'); - * // => 'foo bar' - * - * _.lowerCase('__FOO_BAR__'); - * // => 'foo bar' - */ - var lowerCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + word.toLowerCase(); - }); - - /** - * Converts the first character of `string` to lower case. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.lowerFirst('Fred'); - * // => 'fred' - * - * _.lowerFirst('FRED'); - * // => 'fRED' - */ - var lowerFirst = createCaseFirst('toLowerCase'); - /** * Pads `string` on the left and right sides if it's shorter than `length`. * Padding characters are truncated if they can't be evenly divided by `length`. * * @static * @memberOf _ - * @since 3.0.0 * @category String * @param {string} [string=''] The string to pad. * @param {number} [length=0] The padding length. @@ -13996,52 +10402,19 @@ * // => 'abc' */ function pad(string, length, chars) { - string = toString(string); - length = toInteger(length); + string = baseToString(string); + length = +length; - var strLength = length ? stringSize(string) : 0; - if (!length || strLength >= length) { + var strLength = string.length; + if (strLength >= length || !nativeIsFinite(length)) { return string; } - var mid = (length - strLength) / 2; - return ( - createPadding(nativeFloor(mid), chars) + - string + - createPadding(nativeCeil(mid), chars) - ); - } + var mid = (length - strLength) / 2, + leftLength = nativeFloor(mid), + rightLength = nativeCeil(mid); - /** - * Pads `string` on the right side if it's shorter than `length`. Padding - * characters are truncated if they exceed `length`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to pad. - * @param {number} [length=0] The padding length. - * @param {string} [chars=' '] The string used as padding. - * @returns {string} Returns the padded string. - * @example - * - * _.padEnd('abc', 6); - * // => 'abc ' - * - * _.padEnd('abc', 6, '_-'); - * // => 'abc_-_' - * - * _.padEnd('abc', 3); - * // => 'abc' - */ - function padEnd(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (string + createPadding(length - strLength, chars)) - : string; + chars = createPadding('', rightLength, chars); + return chars.slice(0, leftLength) + string + chars; } /** @@ -14050,7 +10423,6 @@ * * @static * @memberOf _ - * @since 4.0.0 * @category String * @param {string} [string=''] The string to pad. * @param {number} [length=0] The padding length. @@ -14058,40 +10430,55 @@ * @returns {string} Returns the padded string. * @example * - * _.padStart('abc', 6); + * _.padLeft('abc', 6); * // => ' abc' * - * _.padStart('abc', 6, '_-'); + * _.padLeft('abc', 6, '_-'); * // => '_-_abc' * - * _.padStart('abc', 3); + * _.padLeft('abc', 3); * // => 'abc' */ - function padStart(string, length, chars) { - string = toString(string); - length = toInteger(length); - - var strLength = length ? stringSize(string) : 0; - return (length && strLength < length) - ? (createPadding(length - strLength, chars) + string) - : string; - } + var padLeft = createPadDir(); /** - * Converts `string` to an integer of the specified radix. If `radix` is - * `undefined` or `0`, a `radix` of `10` is used unless `value` is a - * hexadecimal, in which case a `radix` of `16` is used. - * - * **Note:** This method aligns with the - * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. + * Pads `string` on the right side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padRight('abc', 6); + * // => 'abc ' + * + * _.padRight('abc', 6, '_-'); + * // => 'abc_-_' + * + * _.padRight('abc', 3); + * // => 'abc' + */ + var padRight = createPadDir(true); + + /** + * Converts `string` to an integer of the specified radix. If `radix` is + * `undefined` or `0`, a `radix` of `10` is used unless `value` is a hexadecimal, + * in which case a `radix` of `16` is used. + * + * **Note:** This method aligns with the [ES5 implementation](https://es5.github.io/#E) + * of `parseInt`. * * @static * @memberOf _ - * @since 1.1.0 * @category String * @param {string} string The string to convert. - * @param {number} [radix=10] The radix to interpret `value` by. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param {number} [radix] The radix to interpret `value` by. + * @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @returns {number} Returns the converted integer. * @example * @@ -14102,14 +10489,15 @@ * // => [6, 8, 10] */ function parseInt(string, radix, guard) { + // Firefox < 21 and Opera < 15 follow ES3 for `parseInt`. // Chrome fails to trim leading whitespace characters. - // See https://bugs.chromium.org/p/v8/issues/detail?id=3109 for more details. - if (guard || radix == null) { + // See https://code.google.com/p/v8/issues/detail?id=3109 for more details. + if (guard ? isIterateeCall(string, radix, guard) : radix == null) { radix = 0; } else if (radix) { radix = +radix; } - string = toString(string).replace(reTrim, ''); + string = trim(string); return nativeParseInt(string, radix || (reHasHexPrefix.test(string) ? 16 : 10)); } @@ -14118,11 +10506,9 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category String * @param {string} [string=''] The string to repeat. - * @param {number} [n=1] The number of times to repeat the string. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param {number} [n=0] The number of times to repeat the string. * @returns {string} Returns the repeated string. * @example * @@ -14135,48 +10521,31 @@ * _.repeat('abc', 0); * // => '' */ - function repeat(string, n, guard) { - if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { - n = 1; - } else { - n = toInteger(n); + function repeat(string, n) { + var result = ''; + string = baseToString(string); + n = +n; + if (n < 1 || !string || !nativeIsFinite(n)) { + return result; } - return baseRepeat(toString(string), n); + // Leverage the exponentiation by squaring algorithm for a faster repeat. + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. + do { + if (n % 2) { + result += string; + } + n = nativeFloor(n / 2); + string += string; + } while (n); + + return result; } /** - * Replaces matches for `pattern` in `string` with `replacement`. - * - * **Note:** This method is based on - * [`String#replace`](https://mdn.io/String/replace). + * Converts `string` to [snake case](https://en.wikipedia.org/wiki/Snake_case). * * @static * @memberOf _ - * @since 4.0.0 - * @category String - * @param {string} [string=''] The string to modify. - * @param {RegExp|string} pattern The pattern to replace. - * @param {Function|string} replacement The match replacement. - * @returns {string} Returns the modified string. - * @example - * - * _.replace('Hi Fred', 'Fred', 'Barney'); - * // => 'Hi Barney' - */ - function replace() { - var args = arguments, - string = toString(args[0]); - - return args.length < 3 ? string : string.replace(args[1], args[2]); - } - - /** - * Converts `string` to - * [snake case](https://en.wikipedia.org/wiki/Snake_case). - * - * @static - * @memberOf _ - * @since 3.0.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the snake cased string. @@ -14188,7 +10557,7 @@ * _.snakeCase('fooBar'); * // => 'foo_bar' * - * _.snakeCase('--FOO-BAR--'); + * _.snakeCase('--foo-bar'); * // => 'foo_bar' */ var snakeCase = createCompounder(function(result, word, index) { @@ -14196,68 +10565,26 @@ }); /** - * Splits `string` by `separator`. - * - * **Note:** This method is based on - * [`String#split`](https://mdn.io/String/split). + * Converts `string` to [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). * * @static * @memberOf _ - * @since 4.0.0 - * @category String - * @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 string segments. - * @example - * - * _.split('a-b-c', '-', 2); - * // => ['a', 'b'] - */ - function split(string, separator, limit) { - if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { - separator = limit = undefined; - } - limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; - if (!limit) { - return []; - } - string = toString(string); - if (string && ( - typeof separator == 'string' || - (separator != null && !isRegExp(separator)) - )) { - separator = baseToString(separator); - if (!separator && hasUnicode(string)) { - return castSlice(stringToArray(string), 0, limit); - } - } - return string.split(separator, limit); - } - - /** - * Converts `string` to - * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). - * - * @static - * @memberOf _ - * @since 3.1.0 * @category String * @param {string} [string=''] The string to convert. * @returns {string} Returns the start cased string. * @example * - * _.startCase('--foo-bar--'); + * _.startCase('--foo-bar'); * // => 'Foo Bar' * * _.startCase('fooBar'); * // => 'Foo Bar' * - * _.startCase('__FOO_BAR__'); - * // => 'FOO BAR' + * _.startCase('__foo_bar__'); + * // => 'Foo Bar' */ var startCase = createCompounder(function(result, word, index) { - return result + (index ? ' ' : '') + upperFirst(word); + return result + (index ? ' ' : '') + (word.charAt(0).toUpperCase() + word.slice(1)); }); /** @@ -14265,13 +10592,11 @@ * * @static * @memberOf _ - * @since 3.0.0 * @category String - * @param {string} [string=''] The string to inspect. + * @param {string} [string=''] The string to search. * @param {string} [target] The string to search for. * @param {number} [position=0] The position to search from. - * @returns {boolean} Returns `true` if `string` starts with `target`, - * else `false`. + * @returns {boolean} Returns `true` if `string` starts with `target`, else `false`. * @example * * _.startsWith('abc', 'a'); @@ -14284,10 +10609,12 @@ * // => true */ function startsWith(string, target, position) { - string = toString(string); - position = baseClamp(toInteger(position), 0, string.length); - target = baseToString(target); - return string.slice(position, position + target.length) == target; + string = baseToString(string); + position = position == null + ? 0 + : nativeMin(position < 0 ? 0 : (+position || 0), string.length); + + return string.lastIndexOf(target, position) == position; } /** @@ -14295,7 +10622,7 @@ * in "interpolate" delimiters, HTML-escape interpolated data properties in * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data * properties may be accessed as free variables in the template. If a setting - * object is given, it takes precedence over `_.templateSettings` values. + * object is provided it takes precedence over `_.templateSettings` values. * * **Note:** In the development build `_.template` utilizes * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) @@ -14308,69 +10635,68 @@ * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). * * @static - * @since 0.1.0 * @memberOf _ * @category String * @param {string} [string=''] The template string. - * @param {Object} [options={}] The options object. - * @param {RegExp} [options.escape=_.templateSettings.escape] - * The HTML "escape" delimiter. - * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] - * The "evaluate" delimiter. - * @param {Object} [options.imports=_.templateSettings.imports] - * An object to import into the template as free variables. - * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] - * The "interpolate" delimiter. - * @param {string} [options.sourceURL='lodash.templateSources[n]'] - * The sourceURL of the compiled template. - * @param {string} [options.variable='obj'] - * The data object variable name. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @param {Object} [options] The options object. + * @param {RegExp} [options.escape] The HTML "escape" delimiter. + * @param {RegExp} [options.evaluate] The "evaluate" delimiter. + * @param {Object} [options.imports] An object to import into the template as free variables. + * @param {RegExp} [options.interpolate] The "interpolate" delimiter. + * @param {string} [options.sourceURL] The sourceURL of the template's compiled source. + * @param {string} [options.variable] The data object variable name. + * @param- {Object} [otherOptions] Enables the legacy `options` param signature. * @returns {Function} Returns the compiled template function. * @example * - * // Use the "interpolate" delimiter to create a compiled template. + * // using the "interpolate" delimiter to create a compiled template * var compiled = _.template('hello <%= user %>!'); * compiled({ 'user': 'fred' }); * // => 'hello fred!' * - * // Use the HTML "escape" delimiter to escape data property values. + * // using the HTML "escape" delimiter to escape data property values * var compiled = _.template('<%- value %>'); * compiled({ 'value': ' - - - - - - - - - - - diff --git a/public/vendor/lodash/perf/perf.js b/public/vendor/lodash/perf/perf.js deleted file mode 100644 index 3588c7dc3aa..00000000000 --- a/public/vendor/lodash/perf/perf.js +++ /dev/null @@ -1,1978 +0,0 @@ -;(function() { - 'use strict'; - - /** Used to access the Firebug Lite panel (set by `run`). */ - var fbPanel; - - /** Used as a safe reference for `undefined` in pre ES5 environments. */ - var undefined; - - /** Used as a reference to the global object. */ - var root = typeof global == 'object' && global || this; - - /** Method and object shortcuts. */ - var phantom = root.phantom, - amd = root.define && define.amd, - argv = root.process && process.argv, - document = !phantom && root.document, - noop = function() {}, - params = root.arguments, - system = root.system; - - /** Add `console.log()` support for Rhino and RingoJS. */ - var console = root.console || (root.console = { 'log': root.print }); - - /** The file path of the lodash file to test. */ - var filePath = (function() { - var min = 0, - result = []; - - if (phantom) { - result = params = phantom.args; - } else if (system) { - min = 1; - result = params = system.args; - } else if (argv) { - min = 2; - result = params = argv; - } else if (params) { - result = params; - } - var last = result[result.length - 1]; - result = (result.length > min && !/perf(?:\.js)?$/.test(last)) ? last : '../lodash.js'; - - if (!amd) { - try { - result = require('fs').realpathSync(result); - } catch (e) {} - - try { - result = require.resolve(result); - } catch (e) {} - } - return result; - }()); - - /** Used to match path separators. */ - var rePathSeparator = /[\/\\]/; - - /** Used to detect primitive types. */ - var rePrimitive = /^(?:boolean|number|string|undefined)$/; - - /** Used to match RegExp special characters. */ - var reSpecialChars = /[.*+?^=!:${}()|[\]\/\\]/g; - - /** The `ui` object. */ - var ui = root.ui || (root.ui = { - 'buildPath': basename(filePath, '.js'), - 'otherPath': 'underscore' - }); - - /** The lodash build basename. */ - var buildName = root.buildName = basename(ui.buildPath, '.js'); - - /** The other library basename. */ - var otherName = root.otherName = (function() { - var result = basename(ui.otherPath, '.js'); - return result + (result == buildName ? ' (2)' : ''); - }()); - - /** Used to score performance. */ - var score = { 'a': [], 'b': [] }; - - /** Used to queue benchmark suites. */ - var suites = []; - - /** Use a single "load" function. */ - var load = (typeof require == 'function' && !amd) - ? require - : noop; - - /** Load lodash. */ - var lodash = root.lodash || (root.lodash = ( - lodash = load(filePath) || root._, - lodash = lodash._ || lodash, - (lodash.runInContext ? lodash.runInContext(root) : lodash), - lodash.noConflict() - )); - - /** Load Underscore. */ - var _ = root.underscore || (root.underscore = ( - _ = load('../vendor/underscore/underscore.js') || root._, - _._ || _ - )); - - /** Load Benchmark.js. */ - var Benchmark = root.Benchmark || (root.Benchmark = ( - Benchmark = load('../node_modules/benchmark/benchmark.js') || root.Benchmark, - Benchmark = Benchmark.Benchmark || Benchmark, - Benchmark.runInContext(lodash.extend({}, root, { '_': lodash })) - )); - - /*--------------------------------------------------------------------------*/ - - /** - * Gets the basename of the given `filePath`. If the file `extension` is passed, - * it will be removed from the basename. - * - * @private - * @param {string} path The file path to inspect. - * @param {string} extension The extension to remove. - * @returns {string} Returns the basename. - */ - function basename(filePath, extension) { - var result = (filePath || '').split(rePathSeparator).pop(); - return (arguments.length < 2) - ? result - : result.replace(RegExp(extension.replace(reSpecialChars, '\\$&') + '$'), ''); - } - - /** - * Computes the geometric mean (log-average) of an array of values. - * See http://en.wikipedia.org/wiki/Geometric_mean#Relationship_with_arithmetic_mean_of_logarithms. - * - * @private - * @param {Array} array The array of values. - * @returns {number} The geometric mean. - */ - function getGeometricMean(array) { - return Math.pow(Math.E, lodash.reduce(array, function(sum, x) { - return sum + Math.log(x); - }, 0) / array.length) || 0; - } - - /** - * Gets the Hz, i.e. operations per second, of `bench` adjusted for the - * margin of error. - * - * @private - * @param {Object} bench The benchmark object. - * @returns {number} Returns the adjusted Hz. - */ - function getHz(bench) { - var result = 1 / (bench.stats.mean + bench.stats.moe); - return isFinite(result) ? result : 0; - } - - /** - * Host objects can return type values that are different from their actual - * data type. The objects we are concerned with usually return non-primitive - * types of "object", "function", or "unknown". - * - * @private - * @param {*} object The owner of the property. - * @param {string} property The property to check. - * @returns {boolean} Returns `true` if the property value is a non-primitive, else `false`. - */ - function isHostType(object, property) { - if (object == null) { - return false; - } - var type = typeof object[property]; - return !rePrimitive.test(type) && (type != 'object' || !!object[property]); - } - - /** - * Logs text to the console. - * - * @private - * @param {string} text The text to log. - */ - function log(text) { - console.log(text + ''); - if (fbPanel) { - // Scroll the Firebug Lite panel down. - fbPanel.scrollTop = fbPanel.scrollHeight; - } - } - - /** - * Runs all benchmark suites. - * - * @private (@public in the browser) - */ - function run() { - fbPanel = (fbPanel = root.document && document.getElementById('FirebugUI')) && - (fbPanel = (fbPanel = fbPanel.contentWindow || fbPanel.contentDocument).document || fbPanel) && - fbPanel.getElementById('fbPanel1'); - - log('\nSit back and relax, this may take a while.'); - suites[0].run({ 'async': true }); - } - - /*--------------------------------------------------------------------------*/ - - lodash.extend(Benchmark.Suite.options, { - 'onStart': function() { - log('\n' + this.name + ':'); - }, - 'onCycle': function(event) { - log(event.target); - }, - 'onComplete': function() { - for (var index = 0, length = this.length; index < length; index++) { - var bench = this[index]; - if (bench.error) { - var errored = true; - } - } - if (errored) { - log('There was a problem, skipping...'); - } - else { - var formatNumber = Benchmark.formatNumber, - fastest = this.filter('fastest'), - fastestHz = getHz(fastest[0]), - slowest = this.filter('slowest'), - slowestHz = getHz(slowest[0]), - aHz = getHz(this[0]), - bHz = getHz(this[1]); - - if (fastest.length > 1) { - log('It\'s too close to call.'); - aHz = bHz = slowestHz; - } - else { - var percent = ((fastestHz / slowestHz) - 1) * 100; - - log( - fastest[0].name + ' is ' + - formatNumber(percent < 1 ? percent.toFixed(2) : Math.round(percent)) + - '% faster.' - ); - } - // Add score adjusted for margin of error. - score.a.push(aHz); - score.b.push(bHz); - } - // Remove current suite from queue. - suites.shift(); - - if (suites.length) { - // Run next suite. - suites[0].run({ 'async': true }); - } - else { - var aMeanHz = getGeometricMean(score.a), - bMeanHz = getGeometricMean(score.b), - fastestMeanHz = Math.max(aMeanHz, bMeanHz), - slowestMeanHz = Math.min(aMeanHz, bMeanHz), - xFaster = fastestMeanHz / slowestMeanHz, - percentFaster = formatNumber(Math.round((xFaster - 1) * 100)), - message = 'is ' + percentFaster + '% ' + (xFaster == 1 ? '' : '(' + formatNumber(xFaster.toFixed(2)) + 'x) ') + 'faster than'; - - // Report results. - if (aMeanHz >= bMeanHz) { - log('\n' + buildName + ' ' + message + ' ' + otherName + '.'); - } else { - log('\n' + otherName + ' ' + message + ' ' + buildName + '.'); - } - } - } - }); - - /*--------------------------------------------------------------------------*/ - - lodash.extend(Benchmark.options, { - 'async': true, - 'setup': '\ - var _ = global.underscore,\ - lodash = global.lodash,\ - belt = this.name == buildName ? lodash : _;\ - \ - var date = new Date,\ - limit = 50,\ - regexp = /x/,\ - object = {},\ - objects = Array(limit),\ - numbers = Array(limit),\ - fourNumbers = [5, 25, 10, 30],\ - nestedNumbers = [1, [2], [3, [[4]]]],\ - nestedObjects = [{}, [{}], [{}, [[{}]]]],\ - twoNumbers = [12, 23];\ - \ - for (var index = 0; index < limit; index++) {\ - numbers[index] = index;\ - object["key" + index] = index;\ - objects[index] = { "num": index };\ - }\ - var strNumbers = numbers + "";\ - \ - if (typeof assign != "undefined") {\ - var _assign = _.assign || _.extend,\ - lodashAssign = lodash.assign;\ - }\ - if (typeof bind != "undefined") {\ - var thisArg = { "name": "fred" };\ - \ - var func = function(greeting, punctuation) {\ - return (greeting || "hi") + " " + this.name + (punctuation || ".");\ - };\ - \ - var _boundNormal = _.bind(func, thisArg),\ - _boundMultiple = _boundNormal,\ - _boundPartial = _.bind(func, thisArg, "hi");\ - \ - var lodashBoundNormal = lodash.bind(func, thisArg),\ - lodashBoundMultiple = lodashBoundNormal,\ - lodashBoundPartial = lodash.bind(func, thisArg, "hi");\ - \ - for (index = 0; index < 10; index++) {\ - _boundMultiple = _.bind(_boundMultiple, { "name": "fred" + index });\ - lodashBoundMultiple = lodash.bind(lodashBoundMultiple, { "name": "fred" + index });\ - }\ - }\ - if (typeof bindAll != "undefined") {\ - var bindAllCount = -1,\ - bindAllObjects = Array(this.count);\ - \ - var funcNames = belt.reject(belt.functions(belt).slice(0, 40), function(funcName) {\ - return /^_/.test(funcName);\ - });\ - \ - // Potentially expensive.\n\ - for (index = 0; index < this.count; index++) {\ - bindAllObjects[index] = belt.reduce(funcNames, function(object, funcName) {\ - object[funcName] = belt[funcName];\ - return object;\ - }, {});\ - }\ - }\ - if (typeof chaining != "undefined") {\ - var even = function(v) { return v % 2 == 0; },\ - square = function(v) { return v * v; };\ - \ - var largeArray = belt.range(10000),\ - _chaining = _(largeArray).chain(),\ - lodashChaining = lodash(largeArray).chain();\ - }\ - if (typeof compact != "undefined") {\ - var uncompacted = numbers.slice();\ - uncompacted[2] = false;\ - uncompacted[6] = null;\ - uncompacted[18] = "";\ - }\ - if (typeof flowRight != "undefined") {\ - var compAddOne = function(n) { return n + 1; },\ - compAddTwo = function(n) { return n + 2; },\ - compAddThree = function(n) { return n + 3; };\ - \ - var _composed = _.flowRight && _.flowRight(compAddThree, compAddTwo, compAddOne),\ - lodashComposed = lodash.flowRight && lodash.flowRight(compAddThree, compAddTwo, compAddOne);\ - }\ - if (typeof countBy != "undefined" || typeof omit != "undefined") {\ - var wordToNumber = {\ - "one": 1,\ - "two": 2,\ - "three": 3,\ - "four": 4,\ - "five": 5,\ - "six": 6,\ - "seven": 7,\ - "eight": 8,\ - "nine": 9,\ - "ten": 10,\ - "eleven": 11,\ - "twelve": 12,\ - "thirteen": 13,\ - "fourteen": 14,\ - "fifteen": 15,\ - "sixteen": 16,\ - "seventeen": 17,\ - "eighteen": 18,\ - "nineteen": 19,\ - "twenty": 20,\ - "twenty-one": 21,\ - "twenty-two": 22,\ - "twenty-three": 23,\ - "twenty-four": 24,\ - "twenty-five": 25,\ - "twenty-six": 26,\ - "twenty-seven": 27,\ - "twenty-eight": 28,\ - "twenty-nine": 29,\ - "thirty": 30,\ - "thirty-one": 31,\ - "thirty-two": 32,\ - "thirty-three": 33,\ - "thirty-four": 34,\ - "thirty-five": 35,\ - "thirty-six": 36,\ - "thirty-seven": 37,\ - "thirty-eight": 38,\ - "thirty-nine": 39,\ - "forty": 40\ - };\ - \ - var words = belt.keys(wordToNumber).slice(0, limit);\ - }\ - if (typeof flatten != "undefined") {\ - var _flattenDeep = _.flatten([[1]])[0] !== 1,\ - lodashFlattenDeep = lodash.flatten([[1]])[0] !== 1;\ - }\ - if (typeof isEqual != "undefined") {\ - var objectOfPrimitives = {\ - "boolean": true,\ - "number": 1,\ - "string": "a"\ - };\ - \ - var objectOfObjects = {\ - "boolean": new Boolean(true),\ - "number": new Number(1),\ - "string": new String("a")\ - };\ - \ - var objectOfObjects2 = {\ - "boolean": new Boolean(true),\ - "number": new Number(1),\ - "string": new String("A")\ - };\ - \ - var object2 = {},\ - object3 = {},\ - objects2 = Array(limit),\ - objects3 = Array(limit),\ - numbers2 = Array(limit),\ - numbers3 = Array(limit),\ - nestedNumbers2 = [1, [2], [3, [[4]]]],\ - nestedNumbers3 = [1, [2], [3, [[6]]]];\ - \ - for (index = 0; index < limit; index++) {\ - object2["key" + index] = index;\ - object3["key" + index] = index;\ - objects2[index] = { "num": index };\ - objects3[index] = { "num": index };\ - numbers2[index] = index;\ - numbers3[index] = index;\ - }\ - object3["key" + (limit - 1)] = -1;\ - objects3[limit - 1].num = -1;\ - numbers3[limit - 1] = -1;\ - }\ - if (typeof matches != "undefined") {\ - var source = { "num": 9 };\ - \ - var _matcher = (_.matches || _.noop)(source),\ - lodashMatcher = (lodash.matches || lodash.noop)(source);\ - }\ - if (typeof multiArrays != "undefined") {\ - var twentyValues = belt.shuffle(belt.range(20)),\ - fortyValues = belt.shuffle(belt.range(40)),\ - hundredSortedValues = belt.range(100),\ - hundredValues = belt.shuffle(hundredSortedValues),\ - hundredValues2 = belt.shuffle(hundredValues),\ - hundredTwentyValues = belt.shuffle(belt.range(120)),\ - hundredTwentyValues2 = belt.shuffle(hundredTwentyValues),\ - twoHundredValues = belt.shuffle(belt.range(200)),\ - twoHundredValues2 = belt.shuffle(twoHundredValues);\ - }\ - if (typeof partial != "undefined") {\ - var func = function(greeting, punctuation) {\ - return greeting + " fred" + (punctuation || ".");\ - };\ - \ - var _partial = _.partial(func, "hi"),\ - lodashPartial = lodash.partial(func, "hi");\ - }\ - if (typeof template != "undefined") {\ - var tplData = {\ - "header1": "Header1",\ - "header2": "Header2",\ - "header3": "Header3",\ - "header4": "Header4",\ - "header5": "Header5",\ - "header6": "Header6",\ - "list": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]\ - };\ - \ - var tpl =\ - "
" +\ - "

<%= header1 %>

" +\ - "

<%= header2 %>

" +\ - "

<%= header3 %>

" +\ - "

<%= header4 %>

" +\ - "
<%= header5 %>
" +\ - "
<%= header6 %>
" +\ - "
    " +\ - "<% for (var index = 0, length = list.length; index < length; index++) { %>" +\ - "
  • <%= list[index] %>
  • " +\ - "<% } %>" +\ - "
" +\ - "
";\ - \ - var tplVerbose =\ - "
" +\ - "

<%= data.header1 %>

" +\ - "

<%= data.header2 %>

" +\ - "

<%= data.header3 %>

" +\ - "

<%= data.header4 %>

" +\ - "
<%= data.header5 %>
" +\ - "
<%= data.header6 %>
" +\ - "
    " +\ - "<% for (var index = 0, length = data.list.length; index < length; index++) { %>" +\ - "
  • <%= data.list[index] %>
  • " +\ - "<% } %>" +\ - "
" +\ - "
";\ - \ - var settingsObject = { "variable": "data" };\ - \ - var _tpl = _.template(tpl),\ - _tplVerbose = _.template(tplVerbose, null, settingsObject);\ - \ - var lodashTpl = lodash.template(tpl),\ - lodashTplVerbose = lodash.template(tplVerbose, null, settingsObject);\ - }\ - if (typeof wrap != "undefined") {\ - var add = function(a, b) {\ - return a + b;\ - };\ - \ - var average = function(func, a, b) {\ - return (func(a, b) / 2).toFixed(2);\ - };\ - \ - var _wrapped = _.wrap(add, average);\ - lodashWrapped = lodash.wrap(add, average);\ - }\ - if (typeof zip != "undefined") {\ - var unzipped = [["a", "b", "c"], [1, 2, 3], [true, false, true]];\ - }' - }); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_(...).map(...).filter(...).take(...).value()`') - .add(buildName, { - 'fn': 'lodashChaining.map(square).filter(even).take(100).value()', - 'teardown': 'function chaining(){}' - }) - .add(otherName, { - 'fn': '_chaining.map(square).filter(even).take(100).value()', - 'teardown': 'function chaining(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.assign`') - .add(buildName, { - 'fn': 'lodashAssign({}, { "a": 1, "b": 2, "c": 3 })', - 'teardown': 'function assign(){}' - }) - .add(otherName, { - 'fn': '_assign({}, { "a": 1, "b": 2, "c": 3 })', - 'teardown': 'function assign(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.assign` with multiple sources') - .add(buildName, { - 'fn': 'lodashAssign({}, { "a": 1, "b": 2 }, { "c": 3, "d": 4 })', - 'teardown': 'function assign(){}' - }) - .add(otherName, { - 'fn': '_assign({}, { "a": 1, "b": 2 }, { "c": 3, "d": 4 })', - 'teardown': 'function assign(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.bind` (slow path)') - .add(buildName, { - 'fn': 'lodash.bind(function() { return this.name; }, { "name": "fred" })', - 'teardown': 'function bind(){}' - }) - .add(otherName, { - 'fn': '_.bind(function() { return this.name; }, { "name": "fred" })', - 'teardown': 'function bind(){}' - }) - ); - - suites.push( - Benchmark.Suite('bound call with arguments') - .add(buildName, { - 'fn': 'lodashBoundNormal("hi", "!")', - 'teardown': 'function bind(){}' - }) - .add(otherName, { - 'fn': '_boundNormal("hi", "!")', - 'teardown': 'function bind(){}' - }) - ); - - suites.push( - Benchmark.Suite('bound and partially applied call with arguments') - .add(buildName, { - 'fn': 'lodashBoundPartial("!")', - 'teardown': 'function bind(){}' - }) - .add(otherName, { - 'fn': '_boundPartial("!")', - 'teardown': 'function bind(){}' - }) - ); - - suites.push( - Benchmark.Suite('bound multiple times') - .add(buildName, { - 'fn': 'lodashBoundMultiple()', - 'teardown': 'function bind(){}' - }) - .add(otherName, { - 'fn': '_boundMultiple()', - 'teardown': 'function bind(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.bindAll`') - .add(buildName, { - 'fn': 'lodash.bindAll(bindAllObjects[++bindAllCount], funcNames)', - 'teardown': 'function bindAll(){}' - }) - .add(otherName, { - 'fn': '_.bindAll(bindAllObjects[++bindAllCount], funcNames)', - 'teardown': 'function bindAll(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.clone` with an array') - .add(buildName, '\ - lodash.clone(numbers)' - ) - .add(otherName, '\ - _.clone(numbers)' - ) - ); - - suites.push( - Benchmark.Suite('`_.clone` with an object') - .add(buildName, '\ - lodash.clone(object)' - ) - .add(otherName, '\ - _.clone(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.compact`') - .add(buildName, { - 'fn': 'lodash.compact(uncompacted)', - 'teardown': 'function compact(){}' - }) - .add(otherName, { - 'fn': '_.compact(uncompacted)', - 'teardown': 'function compact(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.countBy` with `callback` iterating an array') - .add(buildName, '\ - lodash.countBy(numbers, function(num) { return num >> 1; })' - ) - .add(otherName, '\ - _.countBy(numbers, function(num) { return num >> 1; })' - ) - ); - - suites.push( - Benchmark.Suite('`_.countBy` with `property` name iterating an array') - .add(buildName, { - 'fn': 'lodash.countBy(words, "length")', - 'teardown': 'function countBy(){}' - }) - .add(otherName, { - 'fn': '_.countBy(words, "length")', - 'teardown': 'function countBy(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.countBy` with `callback` iterating an object') - .add(buildName, { - 'fn': 'lodash.countBy(wordToNumber, function(num) { return num >> 1; })', - 'teardown': 'function countBy(){}' - }) - .add(otherName, { - 'fn': '_.countBy(wordToNumber, function(num) { return num >> 1; })', - 'teardown': 'function countBy(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.defaults`') - .add(buildName, '\ - lodash.defaults({ "key2": 2, "key6": 6, "key18": 18 }, object)' - ) - .add(otherName, '\ - _.defaults({ "key2": 2, "key6": 6, "key18": 18 }, object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.difference`') - .add(buildName, '\ - lodash.difference(numbers, twoNumbers, fourNumbers)' - ) - .add(otherName, '\ - _.difference(numbers, twoNumbers, fourNumbers)' - ) - ); - - suites.push( - Benchmark.Suite('`_.difference` iterating 20 and 40 elements') - .add(buildName, { - 'fn': 'lodash.difference(twentyValues, fortyValues)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.difference(twentyValues, fortyValues)', - 'teardown': 'function multiArrays(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.difference` iterating 200 elements') - .add(buildName, { - 'fn': 'lodash.difference(twoHundredValues, twoHundredValues2)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.difference(twoHundredValues, twoHundredValues2)', - 'teardown': 'function multiArrays(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.each` iterating an array') - .add(buildName, '\ - var result = [];\ - lodash.each(numbers, function(num) {\ - result.push(num * 2);\ - })' - ) - .add(otherName, '\ - var result = [];\ - _.each(numbers, function(num) {\ - result.push(num * 2);\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.each` iterating an object') - .add(buildName, '\ - var result = [];\ - lodash.each(object, function(num) {\ - result.push(num * 2);\ - })' - ) - .add(otherName, '\ - var result = [];\ - _.each(object, function(num) {\ - result.push(num * 2);\ - })' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.every` iterating an array') - .add(buildName, '\ - lodash.every(numbers, function(num) {\ - return num < limit;\ - })' - ) - .add(otherName, '\ - _.every(numbers, function(num) {\ - return num < limit;\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.every` iterating an object') - .add(buildName, '\ - lodash.every(object, function(num) {\ - return num < limit;\ - })' - ) - .add(otherName, '\ - _.every(object, function(num) {\ - return num < limit;\ - })' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.filter` iterating an array') - .add(buildName, '\ - lodash.filter(numbers, function(num) {\ - return num % 2;\ - })' - ) - .add(otherName, '\ - _.filter(numbers, function(num) {\ - return num % 2;\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.filter` iterating an object') - .add(buildName, '\ - lodash.filter(object, function(num) {\ - return num % 2\ - })' - ) - .add(otherName, '\ - _.filter(object, function(num) {\ - return num % 2\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.filter` with `_.matches` shorthand') - .add(buildName, { - 'fn': 'lodash.filter(objects, source)', - 'teardown': 'function matches(){}' - }) - .add(otherName, { - 'fn': '_.filter(objects, source)', - 'teardown': 'function matches(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.filter` with `_.matches` predicate') - .add(buildName, { - 'fn': 'lodash.filter(objects, lodashMatcher)', - 'teardown': 'function matches(){}' - }) - .add(otherName, { - 'fn': '_.filter(objects, _matcher)', - 'teardown': 'function matches(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.find` iterating an array') - .add(buildName, '\ - lodash.find(numbers, function(num) {\ - return num === (limit - 1);\ - })' - ) - .add(otherName, '\ - _.find(numbers, function(num) {\ - return num === (limit - 1);\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.find` iterating an object') - .add(buildName, '\ - lodash.find(object, function(value, key) {\ - return /\D9$/.test(key);\ - })' - ) - .add(otherName, '\ - _.find(object, function(value, key) {\ - return /\D9$/.test(key);\ - })' - ) - ); - - // Avoid Underscore induced `OutOfMemoryError` in Rhino and Ringo. - suites.push( - Benchmark.Suite('`_.find` with `_.matches` shorthand') - .add(buildName, { - 'fn': 'lodash.find(objects, source)', - 'teardown': 'function matches(){}' - }) - .add(otherName, { - 'fn': '_.find(objects, source)', - 'teardown': 'function matches(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.flatten`') - .add(buildName, { - 'fn': 'lodash.flatten(nestedNumbers, !lodashFlattenDeep)', - 'teardown': 'function flatten(){}' - }) - .add(otherName, { - 'fn': '_.flatten(nestedNumbers, !_flattenDeep)', - 'teardown': 'function flatten(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.flattenDeep` nested arrays of numbers') - .add(buildName, { - 'fn': 'lodash.flattenDeep(nestedNumbers)', - 'teardown': 'function flatten(){}' - }) - .add(otherName, { - 'fn': '_.flattenDeep(nestedNumbers)', - 'teardown': 'function flatten(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.flattenDeep` nest arrays of objects') - .add(buildName, { - 'fn': 'lodash.flattenDeep(nestedObjects)', - 'teardown': 'function flatten(){}' - }) - .add(otherName, { - 'fn': '_.flattenDeep(nestedObjects)', - 'teardown': 'function flatten(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.flowRight`') - .add(buildName, { - 'fn': 'lodash.flowRight(compAddThree, compAddTwo, compAddOne)', - 'teardown': 'function flowRight(){}' - }) - .add(otherName, { - 'fn': '_.flowRight(compAddThree, compAddTwo, compAddOne)', - 'teardown': 'function flowRight(){}' - }) - ); - - suites.push( - Benchmark.Suite('composed call') - .add(buildName, { - 'fn': 'lodashComposed(0)', - 'teardown': 'function flowRight(){}' - }) - .add(otherName, { - 'fn': '_composed(0)', - 'teardown': 'function flowRight(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.functions`') - .add(buildName, '\ - lodash.functions(lodash)' - ) - .add(otherName, '\ - _.functions(lodash)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.groupBy` with `callback` iterating an array') - .add(buildName, '\ - lodash.groupBy(numbers, function(num) { return num >> 1; })' - ) - .add(otherName, '\ - _.groupBy(numbers, function(num) { return num >> 1; })' - ) - ); - - suites.push( - Benchmark.Suite('`_.groupBy` with `property` name iterating an array') - .add(buildName, { - 'fn': 'lodash.groupBy(words, "length")', - 'teardown': 'function countBy(){}' - }) - .add(otherName, { - 'fn': '_.groupBy(words, "length")', - 'teardown': 'function countBy(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.groupBy` with `callback` iterating an object') - .add(buildName, { - 'fn': 'lodash.groupBy(wordToNumber, function(num) { return num >> 1; })', - 'teardown': 'function countBy(){}' - }) - .add(otherName, { - 'fn': '_.groupBy(wordToNumber, function(num) { return num >> 1; })', - 'teardown': 'function countBy(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.includes` searching an array') - .add(buildName, '\ - lodash.includes(numbers, limit - 1)' - ) - .add(otherName, '\ - _.includes(numbers, limit - 1)' - ) - ); - - suites.push( - Benchmark.Suite('`_.includes` searching an object') - .add(buildName, '\ - lodash.includes(object, limit - 1)' - ) - .add(otherName, '\ - _.includes(object, limit - 1)' - ) - ); - - if (lodash.includes('ab', 'ab') && _.includes('ab', 'ab')) { - suites.push( - Benchmark.Suite('`_.includes` searching a string') - .add(buildName, '\ - lodash.includes(strNumbers, "," + (limit - 1))' - ) - .add(otherName, '\ - _.includes(strNumbers, "," + (limit - 1))' - ) - ); - } - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.indexOf`') - .add(buildName, { - 'fn': 'lodash.indexOf(hundredSortedValues, 99)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.indexOf(hundredSortedValues, 99)', - 'teardown': 'function multiArrays(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.intersection`') - .add(buildName, '\ - lodash.intersection(numbers, twoNumbers, fourNumbers)' - ) - .add(otherName, '\ - _.intersection(numbers, twoNumbers, fourNumbers)' - ) - ); - - suites.push( - Benchmark.Suite('`_.intersection` iterating 120 elements') - .add(buildName, { - 'fn': 'lodash.intersection(hundredTwentyValues, hundredTwentyValues2)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.intersection(hundredTwentyValues, hundredTwentyValues2)', - 'teardown': 'function multiArrays(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.invert`') - .add(buildName, '\ - lodash.invert(object)' - ) - .add(otherName, '\ - _.invert(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.invokeMap` iterating an array') - .add(buildName, '\ - lodash.invokeMap(numbers, "toFixed")' - ) - .add(otherName, '\ - _.invokeMap(numbers, "toFixed")' - ) - ); - - suites.push( - Benchmark.Suite('`_.invokeMap` with arguments iterating an array') - .add(buildName, '\ - lodash.invokeMap(numbers, "toFixed", 1)' - ) - .add(otherName, '\ - _.invokeMap(numbers, "toFixed", 1)' - ) - ); - - suites.push( - Benchmark.Suite('`_.invokeMap` with a function for `path` iterating an array') - .add(buildName, '\ - lodash.invokeMap(numbers, Number.prototype.toFixed, 1)' - ) - .add(otherName, '\ - _.invokeMap(numbers, Number.prototype.toFixed, 1)' - ) - ); - - suites.push( - Benchmark.Suite('`_.invokeMap` iterating an object') - .add(buildName, '\ - lodash.invokeMap(object, "toFixed", 1)' - ) - .add(otherName, '\ - _.invokeMap(object, "toFixed", 1)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.isEqual` comparing primitives') - .add(buildName, { - 'fn': '\ - lodash.isEqual(1, "1");\ - lodash.isEqual(1, 1)', - 'teardown': 'function isEqual(){}' - }) - .add(otherName, { - 'fn': '\ - _.isEqual(1, "1");\ - _.isEqual(1, 1);', - 'teardown': 'function isEqual(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.isEqual` comparing primitives and their object counterparts (edge case)') - .add(buildName, { - 'fn': '\ - lodash.isEqual(objectOfPrimitives, objectOfObjects);\ - lodash.isEqual(objectOfPrimitives, objectOfObjects2)', - 'teardown': 'function isEqual(){}' - }) - .add(otherName, { - 'fn': '\ - _.isEqual(objectOfPrimitives, objectOfObjects);\ - _.isEqual(objectOfPrimitives, objectOfObjects2)', - 'teardown': 'function isEqual(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.isEqual` comparing arrays') - .add(buildName, { - 'fn': '\ - lodash.isEqual(numbers, numbers2);\ - lodash.isEqual(numbers2, numbers3)', - 'teardown': 'function isEqual(){}' - }) - .add(otherName, { - 'fn': '\ - _.isEqual(numbers, numbers2);\ - _.isEqual(numbers2, numbers3)', - 'teardown': 'function isEqual(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.isEqual` comparing nested arrays') - .add(buildName, { - 'fn': '\ - lodash.isEqual(nestedNumbers, nestedNumbers2);\ - lodash.isEqual(nestedNumbers2, nestedNumbers3)', - 'teardown': 'function isEqual(){}' - }) - .add(otherName, { - 'fn': '\ - _.isEqual(nestedNumbers, nestedNumbers2);\ - _.isEqual(nestedNumbers2, nestedNumbers3)', - 'teardown': 'function isEqual(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.isEqual` comparing arrays of objects') - .add(buildName, { - 'fn': '\ - lodash.isEqual(objects, objects2);\ - lodash.isEqual(objects2, objects3)', - 'teardown': 'function isEqual(){}' - }) - .add(otherName, { - 'fn': '\ - _.isEqual(objects, objects2);\ - _.isEqual(objects2, objects3)', - 'teardown': 'function isEqual(){}' - }) - ); - - suites.push( - Benchmark.Suite('`_.isEqual` comparing objects') - .add(buildName, { - 'fn': '\ - lodash.isEqual(object, object2);\ - lodash.isEqual(object2, object3)', - 'teardown': 'function isEqual(){}' - }) - .add(otherName, { - 'fn': '\ - _.isEqual(object, object2);\ - _.isEqual(object2, object3)', - 'teardown': 'function isEqual(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.isArguments`, `_.isDate`, `_.isFunction`, `_.isNumber`, `_.isObject`, `_.isRegExp`') - .add(buildName, '\ - lodash.isArguments(arguments);\ - lodash.isArguments(object);\ - lodash.isDate(date);\ - lodash.isDate(object);\ - lodash.isFunction(lodash);\ - lodash.isFunction(object);\ - lodash.isNumber(1);\ - lodash.isNumber(object);\ - lodash.isObject(object);\ - lodash.isObject(1);\ - lodash.isRegExp(regexp);\ - lodash.isRegExp(object)' - ) - .add(otherName, '\ - _.isArguments(arguments);\ - _.isArguments(object);\ - _.isDate(date);\ - _.isDate(object);\ - _.isFunction(_);\ - _.isFunction(object);\ - _.isNumber(1);\ - _.isNumber(object);\ - _.isObject(object);\ - _.isObject(1);\ - _.isRegExp(regexp);\ - _.isRegExp(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.keys` (uses native `Object.keys` if available)') - .add(buildName, '\ - lodash.keys(object)' - ) - .add(otherName, '\ - _.keys(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.lastIndexOf`') - .add(buildName, { - 'fn': 'lodash.lastIndexOf(hundredSortedValues, 0)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.lastIndexOf(hundredSortedValues, 0)', - 'teardown': 'function multiArrays(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.map` iterating an array') - .add(buildName, '\ - lodash.map(objects, function(value) {\ - return value.num;\ - })' - ) - .add(otherName, '\ - _.map(objects, function(value) {\ - return value.num;\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.map` iterating an object') - .add(buildName, '\ - lodash.map(object, function(value) {\ - return value;\ - })' - ) - .add(otherName, '\ - _.map(object, function(value) {\ - return value;\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.map` with `_.property` shorthand') - .add(buildName, '\ - lodash.map(objects, "num")' - ) - .add(otherName, '\ - _.map(objects, "num")' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.max`') - .add(buildName, '\ - lodash.max(numbers)' - ) - .add(otherName, '\ - _.max(numbers)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.min`') - .add(buildName, '\ - lodash.min(numbers)' - ) - .add(otherName, '\ - _.min(numbers)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.omit` iterating 20 properties, omitting 2 keys') - .add(buildName, '\ - lodash.omit(object, "key6", "key13")' - ) - .add(otherName, '\ - _.omit(object, "key6", "key13")' - ) - ); - - suites.push( - Benchmark.Suite('`_.omit` iterating 40 properties, omitting 20 keys') - .add(buildName, { - 'fn': 'lodash.omit(wordToNumber, words)', - 'teardown': 'function omit(){}' - }) - .add(otherName, { - 'fn': '_.omit(wordToNumber, words)', - 'teardown': 'function omit(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.partial` (slow path)') - .add(buildName, { - 'fn': 'lodash.partial(function(greeting) { return greeting + " " + this.name; }, "hi")', - 'teardown': 'function partial(){}' - }) - .add(otherName, { - 'fn': '_.partial(function(greeting) { return greeting + " " + this.name; }, "hi")', - 'teardown': 'function partial(){}' - }) - ); - - suites.push( - Benchmark.Suite('partially applied call with arguments') - .add(buildName, { - 'fn': 'lodashPartial("!")', - 'teardown': 'function partial(){}' - }) - .add(otherName, { - 'fn': '_partial("!")', - 'teardown': 'function partial(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.partition` iterating an array') - .add(buildName, '\ - lodash.partition(numbers, function(num) {\ - return num % 2;\ - })' - ) - .add(otherName, '\ - _.partition(numbers, function(num) {\ - return num % 2;\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.partition` iterating an object') - .add(buildName, '\ - lodash.partition(object, function(num) {\ - return num % 2;\ - })' - ) - .add(otherName, '\ - _.partition(object, function(num) {\ - return num % 2;\ - })' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.pick`') - .add(buildName, '\ - lodash.pick(object, "key6", "key13")' - ) - .add(otherName, '\ - _.pick(object, "key6", "key13")' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.reduce` iterating an array') - .add(buildName, '\ - lodash.reduce(numbers, function(result, value, index) {\ - result[index] = value;\ - return result;\ - }, {})' - ) - .add(otherName, '\ - _.reduce(numbers, function(result, value, index) {\ - result[index] = value;\ - return result;\ - }, {})' - ) - ); - - suites.push( - Benchmark.Suite('`_.reduce` iterating an object') - .add(buildName, '\ - lodash.reduce(object, function(result, value, key) {\ - result.push(key, value);\ - return result;\ - }, [])' - ) - .add(otherName, '\ - _.reduce(object, function(result, value, key) {\ - result.push(key, value);\ - return result;\ - }, [])' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.reduceRight` iterating an array') - .add(buildName, '\ - lodash.reduceRight(numbers, function(result, value, index) {\ - result[index] = value;\ - return result;\ - }, {})' - ) - .add(otherName, '\ - _.reduceRight(numbers, function(result, value, index) {\ - result[index] = value;\ - return result;\ - }, {})' - ) - ); - - suites.push( - Benchmark.Suite('`_.reduceRight` iterating an object') - .add(buildName, '\ - lodash.reduceRight(object, function(result, value, key) {\ - result.push(key, value);\ - return result;\ - }, [])' - ) - .add(otherName, '\ - _.reduceRight(object, function(result, value, key) {\ - result.push(key, value);\ - return result;\ - }, [])' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.reject` iterating an array') - .add(buildName, '\ - lodash.reject(numbers, function(num) {\ - return num % 2;\ - })' - ) - .add(otherName, '\ - _.reject(numbers, function(num) {\ - return num % 2;\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.reject` iterating an object') - .add(buildName, '\ - lodash.reject(object, function(num) {\ - return num % 2;\ - })' - ) - .add(otherName, '\ - _.reject(object, function(num) {\ - return num % 2;\ - })' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.sampleSize`') - .add(buildName, '\ - lodash.sampleSize(numbers, limit / 2)' - ) - .add(otherName, '\ - _.sampleSize(numbers, limit / 2)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.shuffle`') - .add(buildName, '\ - lodash.shuffle(numbers)' - ) - .add(otherName, '\ - _.shuffle(numbers)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.size` with an object') - .add(buildName, '\ - lodash.size(object)' - ) - .add(otherName, '\ - _.size(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.some` iterating an array') - .add(buildName, '\ - lodash.some(numbers, function(num) {\ - return num == (limit - 1);\ - })' - ) - .add(otherName, '\ - _.some(numbers, function(num) {\ - return num == (limit - 1);\ - })' - ) - ); - - suites.push( - Benchmark.Suite('`_.some` iterating an object') - .add(buildName, '\ - lodash.some(object, function(num) {\ - return num == (limit - 1);\ - })' - ) - .add(otherName, '\ - _.some(object, function(num) {\ - return num == (limit - 1);\ - })' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.sortBy` with `callback`') - .add(buildName, '\ - lodash.sortBy(numbers, function(num) { return Math.sin(num); })' - ) - .add(otherName, '\ - _.sortBy(numbers, function(num) { return Math.sin(num); })' - ) - ); - - suites.push( - Benchmark.Suite('`_.sortBy` with `property` name') - .add(buildName, { - 'fn': 'lodash.sortBy(words, "length")', - 'teardown': 'function countBy(){}' - }) - .add(otherName, { - 'fn': '_.sortBy(words, "length")', - 'teardown': 'function countBy(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.sortedIndex`') - .add(buildName, '\ - lodash.sortedIndex(numbers, limit)' - ) - .add(otherName, '\ - _.sortedIndex(numbers, limit)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.sortedIndexBy`') - .add(buildName, { - 'fn': '\ - lodash.sortedIndexBy(words, "twenty-five", function(value) {\ - return wordToNumber[value];\ - })', - 'teardown': 'function countBy(){}' - }) - .add(otherName, { - 'fn': '\ - _.sortedIndexBy(words, "twenty-five", function(value) {\ - return wordToNumber[value];\ - })', - 'teardown': 'function countBy(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.sortedIndexOf`') - .add(buildName, { - 'fn': 'lodash.sortedIndexOf(hundredSortedValues, 99)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.sortedIndexOf(hundredSortedValues, 99)', - 'teardown': 'function multiArrays(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.sortedLastIndexOf`') - .add(buildName, { - 'fn': 'lodash.sortedLastIndexOf(hundredSortedValues, 0)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.sortedLastIndexOf(hundredSortedValues, 0)', - 'teardown': 'function multiArrays(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.sum`') - .add(buildName, '\ - lodash.sum(numbers)' - ) - .add(otherName, '\ - _.sum(numbers)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.template` (slow path)') - .add(buildName, { - 'fn': 'lodash.template(tpl)(tplData)', - 'teardown': 'function template(){}' - }) - .add(otherName, { - 'fn': '_.template(tpl)(tplData)', - 'teardown': 'function template(){}' - }) - ); - - suites.push( - Benchmark.Suite('compiled template') - .add(buildName, { - 'fn': 'lodashTpl(tplData)', - 'teardown': 'function template(){}' - }) - .add(otherName, { - 'fn': '_tpl(tplData)', - 'teardown': 'function template(){}' - }) - ); - - suites.push( - Benchmark.Suite('compiled template without a with-statement') - .add(buildName, { - 'fn': 'lodashTplVerbose(tplData)', - 'teardown': 'function template(){}' - }) - .add(otherName, { - 'fn': '_tplVerbose(tplData)', - 'teardown': 'function template(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.times`') - .add(buildName, '\ - var result = [];\ - lodash.times(limit, function(n) { result.push(n); })' - ) - .add(otherName, '\ - var result = [];\ - _.times(limit, function(n) { result.push(n); })' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.toArray` with an array (edge case)') - .add(buildName, '\ - lodash.toArray(numbers)' - ) - .add(otherName, '\ - _.toArray(numbers)' - ) - ); - - suites.push( - Benchmark.Suite('`_.toArray` with an object') - .add(buildName, '\ - lodash.toArray(object)' - ) - .add(otherName, '\ - _.toArray(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.toPairs`') - .add(buildName, '\ - lodash.toPairs(object)' - ) - .add(otherName, '\ - _.toPairs(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.unescape` string without html entities') - .add(buildName, '\ - lodash.unescape("`&`, `<`, `>`, `\\"`, and `\'`")' - ) - .add(otherName, '\ - _.unescape("`&`, `<`, `>`, `\\"`, and `\'`")' - ) - ); - - suites.push( - Benchmark.Suite('`_.unescape` string with html entities') - .add(buildName, '\ - lodash.unescape("`&`, `<`, `>`, `"`, and `'`")' - ) - .add(otherName, '\ - _.unescape("`&`, `<`, `>`, `"`, and `'`")' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.union`') - .add(buildName, '\ - lodash.union(numbers, twoNumbers, fourNumbers)' - ) - .add(otherName, '\ - _.union(numbers, twoNumbers, fourNumbers)' - ) - ); - - suites.push( - Benchmark.Suite('`_.union` iterating an array of 200 elements') - .add(buildName, { - 'fn': 'lodash.union(hundredValues, hundredValues2)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.union(hundredValues, hundredValues2)', - 'teardown': 'function multiArrays(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.uniq`') - .add(buildName, '\ - lodash.uniq(numbers.concat(twoNumbers, fourNumbers))' - ) - .add(otherName, '\ - _.uniq(numbers.concat(twoNumbers, fourNumbers))' - ) - ); - - suites.push( - Benchmark.Suite('`_.uniq` iterating an array of 200 elements') - .add(buildName, { - 'fn': 'lodash.uniq(twoHundredValues)', - 'teardown': 'function multiArrays(){}' - }) - .add(otherName, { - 'fn': '_.uniq(twoHundredValues)', - 'teardown': 'function multiArrays(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.uniqBy`') - .add(buildName, '\ - lodash.uniqBy(numbers.concat(twoNumbers, fourNumbers), function(num) {\ - return num % 2;\ - })' - ) - .add(otherName, '\ - _.uniqBy(numbers.concat(twoNumbers, fourNumbers), function(num) {\ - return num % 2;\ - })' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.values`') - .add(buildName, '\ - lodash.values(object)' - ) - .add(otherName, '\ - _.values(object)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.without`') - .add(buildName, '\ - lodash.without(numbers, 9, 12, 14, 15)' - ) - .add(otherName, '\ - _.without(numbers, 9, 12, 14, 15)' - ) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.wrap` result called') - .add(buildName, { - 'fn': 'lodashWrapped(2, 5)', - 'teardown': 'function wrap(){}' - }) - .add(otherName, { - 'fn': '_wrapped(2, 5)', - 'teardown': 'function wrap(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - suites.push( - Benchmark.Suite('`_.zip`') - .add(buildName, { - 'fn': 'lodash.zip.apply(lodash, unzipped)', - 'teardown': 'function zip(){}' - }) - .add(otherName, { - 'fn': '_.zip.apply(_, unzipped)', - 'teardown': 'function zip(){}' - }) - ); - - /*--------------------------------------------------------------------------*/ - - if (Benchmark.platform + '') { - log(Benchmark.platform); - } - // Expose `run` to be called later when executing in a browser. - if (document) { - root.run = run; - } else { - run(); - } -}.call(this)); diff --git a/public/vendor/lodash/test/asset/test-ui.js b/public/vendor/lodash/test/asset/test-ui.js deleted file mode 100644 index 968f0f8ec83..00000000000 --- a/public/vendor/lodash/test/asset/test-ui.js +++ /dev/null @@ -1,155 +0,0 @@ -;(function(window) { - 'use strict'; - - /** The base path of the lodash builds. */ - var basePath = '../'; - - /** The lodash build to load. */ - var build = (build = /build=([^&]+)/.exec(location.search)) && decodeURIComponent(build[1]); - - /** The module loader to use. */ - var loader = (loader = /loader=([^&]+)/.exec(location.search)) && decodeURIComponent(loader[1]); - - /** The `ui` object. */ - var ui = {}; - - /*--------------------------------------------------------------------------*/ - - // Initialize controls. - addEventListener('load', function() { - function eventHandler(event) { - var buildIndex = buildList.selectedIndex, - loaderIndex = loaderList.selectedIndex, - search = location.search.replace(/^\?|&?(?:build|loader)=[^&]*&?/g, ''); - - if (event.stopPropagation) { - event.stopPropagation(); - } else { - event.cancelBubble = true; - } - location.href = - location.href.split('?')[0] + '?' + - (search ? search + '&' : '') + - 'build=' + (buildIndex < 0 ? build : buildList[buildIndex].value) + '&' + - 'loader=' + (loaderIndex < 0 ? loader : loaderList[loaderIndex].value); - } - - function init() { - var toolbar = document.getElementById('qunit-testrunner-toolbar'); - if (!toolbar) { - setTimeout(init, 15); - return; - } - toolbar.insertBefore(span2, toolbar.lastChild); - toolbar.insertBefore(span1, span2); - - buildList.selectedIndex = (function() { - switch (build) { - case 'lodash': return 1; - case 'lodash-core-dev': return 2; - case 'lodash-core': return 3; - case 'lodash-dev': - case null: return 0; - } - return -1; - }()); - - loaderList.selectedIndex = (function() { - switch (loader) { - case 'curl': return 1; - case 'dojo': return 2; - case 'requirejs': return 3; - case 'none': - case null: return 0; - } - return -1; - }()); - - buildList.addEventListener('change', eventHandler); - loaderList.addEventListener('change', eventHandler); - } - - var span1 = document.createElement('span'); - span1.innerHTML = - '' + - ''; - - var span2 = document.createElement('span'); - span2.innerHTML = - '' + - ''; - - span1.style.cssText = - span2.style.cssText = 'display:inline-block;float:right;line-height:2.1em;margin-left:1em;margin-top:0;'; - - span1.firstChild.style.cssText = - span2.firstChild.style.cssText = 'display:inline-block;margin-right:.5em;'; - - var buildList = span1.lastChild, - loaderList = span2.lastChild; - - setTimeout(function() { - ui.timing.loadEventEnd = +new Date; - }, 1); - - init(); - }); - - // The lodash build file path. - ui.buildPath = (function() { - var result; - switch (build) { - case 'lodash': result = 'dist/lodash.min.js'; break; - case 'lodash-core-dev': result = 'dist/lodash.core.js'; break; - case 'lodash-core': result = 'dist/lodash.core.min.js'; break; - case null: build = 'lodash-dev'; - case 'lodash-dev': result = 'lodash.js'; break; - default: return build; - } - return basePath + result; - }()); - - // The module loader file path. - ui.loaderPath = (function() { - var result; - switch (loader) { - case 'curl': result = 'node_modules/curl-amd/dist/curl-kitchen-sink/curl.js'; break; - case 'dojo': result = 'node_modules/dojo/dojo.js'; break; - case 'requirejs': result = 'node_modules/requirejs/require.js'; break; - case null: loader = 'none'; return ''; - default: return loader; - } - return basePath + result; - }()); - - // Used to indicate testing a core build. - ui.isCore = /\bcore(\.min)?\.js\b/.test(ui.buildPath); - - // Used to indicate testing a foreign file. - ui.isForeign = RegExp('^(\\w+:)?//').test(build); - - // Used to indicate testing a modularized build. - ui.isModularize = /\b(?:amd|commonjs|es|node|npm|(index|main)\.js)\b/.test([location.pathname, location.search]); - - // Used to indicate testing in Sauce Labs' automated test cloud. - ui.isSauceLabs = location.port == '9001'; - - // Used to indicate that lodash is in strict mode. - ui.isStrict = /\bes\b/.test([location.pathname, location.search]); - - ui.urlParams = { 'build': build, 'loader': loader }; - ui.timing = { 'loadEventEnd': 0 }; - - window.ui = ui; - -}(this)); diff --git a/public/vendor/lodash/test/asset/worker.js b/public/vendor/lodash/test/asset/worker.js deleted file mode 100644 index 95e3ab8a8e0..00000000000 --- a/public/vendor/lodash/test/asset/worker.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -self.console || (self.console = { 'log': function() {} }); - -addEventListener('message', function(e) { - if (e.data) { - try { - importScripts('../' + e.data); - } catch (e) { - var lineNumber = e.lineNumber, - message = (lineNumber == null ? '' : (lineNumber + ': ')) + e.message; - - self._ = { 'VERSION': message }; - } - postMessage(_.VERSION); - } -}, false); diff --git a/public/vendor/lodash/test/backbone.html b/public/vendor/lodash/test/backbone.html deleted file mode 100644 index dd3df9fe05e..00000000000 --- a/public/vendor/lodash/test/backbone.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - - Backbone Test Suite - - - - - - - - - - - - - - - diff --git a/public/vendor/lodash/test/fp.html b/public/vendor/lodash/test/fp.html deleted file mode 100644 index 712296664f1..00000000000 --- a/public/vendor/lodash/test/fp.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - lodash-fp Test Suite - - - - - - - - - - - -
- - - diff --git a/public/vendor/lodash/test/index.html b/public/vendor/lodash/test/index.html deleted file mode 100644 index aee39424991..00000000000 --- a/public/vendor/lodash/test/index.html +++ /dev/null @@ -1,351 +0,0 @@ - - - - - lodash Test Suite - - - - - - - - - - - -
-
-
- - - - - diff --git a/public/vendor/lodash/test/remove.js b/public/vendor/lodash/test/remove.js deleted file mode 100644 index bd5aaf9271a..00000000000 --- a/public/vendor/lodash/test/remove.js +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -var _ = require('../lodash'), - fs = require('fs'), - path = require('path'); - -var args = (args = process.argv) - .slice((args[0] === process.execPath || args[0] === 'node') ? 2 : 0); - -var filePath = path.resolve(args[1]), - reLine = /.*/gm; - -var pattern = (function() { - var result = args[0], - delimiter = result.charAt(0), - lastIndex = result.lastIndexOf(delimiter); - - return RegExp(result.slice(1, lastIndex), result.slice(lastIndex + 1)); -}()); - -/*----------------------------------------------------------------------------*/ - -fs.writeFileSync(filePath, fs.readFileSync(filePath, 'utf8').replace(pattern, function(match) { - var snippet = _.slice(arguments, -3, -2)[0]; - return match.replace(snippet, snippet.replace(reLine, '')); -})); diff --git a/public/vendor/lodash/test/saucelabs.js b/public/vendor/lodash/test/saucelabs.js deleted file mode 100644 index 38c8bb7b3cd..00000000000 --- a/public/vendor/lodash/test/saucelabs.js +++ /dev/null @@ -1,914 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -/** Environment shortcut. */ -var env = process.env; - -if (env.TRAVIS_SECURE_ENV_VARS == 'false') { - console.log('Skipping Sauce Labs jobs; secure environment variables are unavailable'); - process.exit(0); -} - -/** Load Node.js modules. */ -var EventEmitter = require('events').EventEmitter, - http = require('http'), - path = require('path'), - url = require('url'), - util = require('util'); - -/** Load other modules. */ -var _ = require('../lodash.js'), - chalk = require('chalk'), - ecstatic = require('ecstatic'), - request = require('request'), - SauceTunnel = require('sauce-tunnel'); - -/** Used for Sauce Labs credentials. */ -var accessKey = env.SAUCE_ACCESS_KEY, - username = env.SAUCE_USERNAME; - -/** Used as the default maximum number of times to retry a job and tunnel. */ -var maxJobRetries = 3, - maxTunnelRetries = 3; - -/** Used as the static file server middleware. */ -var mount = ecstatic({ - 'cache': 'no-cache', - 'root': process.cwd() -}); - -/** Used as the list of ports supported by Sauce Connect. */ -var ports = [ - 80, 443, 888, 2000, 2001, 2020, 2109, 2222, 2310, 3000, 3001, 3030, 3210, - 3333, 4000, 4001, 4040, 4321, 4502, 4503, 4567, 5000, 5001, 5050, 5555, 5432, - 6000, 6001, 6060, 6666, 6543, 7000, 7070, 7774, 7777, 8000, 8001, 8003, 8031, - 8080, 8081, 8765, 8777, 8888, 9000, 9001, 9080, 9090, 9876, 9877, 9999, 49221, - 55001 -]; - -/** Used by `logInline` to clear previously logged messages. */ -var prevLine = ''; - -/** Method shortcut. */ -var push = Array.prototype.push; - -/** Used to detect error messages. */ -var reError = /(?:\be|E)rror\b/; - -/** Used to detect valid job ids. */ -var reJobId = /^[a-z0-9]{32}$/; - -/** Used to display the wait throbber. */ -var throbberDelay = 500, - waitCount = -1; - -/** - * Used as Sauce Labs config values. - * See the [Sauce Labs documentation](https://docs.saucelabs.com/reference/test-configuration/) - * for more details. - */ -var advisor = getOption('advisor', false), - build = getOption('build', (env.TRAVIS_COMMIT || '').slice(0, 10)), - commandTimeout = getOption('commandTimeout', 90), - compatMode = getOption('compatMode', null), - customData = Function('return {' + getOption('customData', '').replace(/^\{|}$/g, '') + '}')(), - deviceOrientation = getOption('deviceOrientation', 'portrait'), - framework = getOption('framework', 'qunit'), - idleTimeout = getOption('idleTimeout', 60), - jobName = getOption('name', 'unit tests'), - maxDuration = getOption('maxDuration', 180), - port = ports[Math.min(_.sortedIndex(ports, getOption('port', 9001)), ports.length - 1)], - publicAccess = getOption('public', true), - queueTimeout = getOption('queueTimeout', 240), - recordVideo = getOption('recordVideo', true), - recordScreenshots = getOption('recordScreenshots', false), - runner = getOption('runner', 'test/index.html').replace(/^\W+/, ''), - runnerUrl = getOption('runnerUrl', 'http://localhost:' + port + '/' + runner), - statusInterval = getOption('statusInterval', 5), - tags = getOption('tags', []), - throttled = getOption('throttled', 10), - tunneled = getOption('tunneled', true), - tunnelId = getOption('tunnelId', 'tunnel_' + (env.TRAVIS_JOB_ID || 0)), - tunnelTimeout = getOption('tunnelTimeout', 120), - videoUploadOnPass = getOption('videoUploadOnPass', false); - -/** Used to convert Sauce Labs browser identifiers to their formal names. */ -var browserNameMap = { - 'googlechrome': 'Chrome', - 'iehta': 'Internet Explorer', - 'ipad': 'iPad', - 'iphone': 'iPhone', - 'microsoftedge': 'Edge' -}; - -/** List of platforms to load the runner on. */ -var platforms = [ - ['Linux', 'android', '5.1'], - ['Windows 10', 'chrome', '51'], - ['Windows 10', 'chrome', '50'], - ['Windows 10', 'firefox', '47'], - ['Windows 10', 'firefox', '46'], - ['Windows 10', 'microsoftedge', '13'], - ['Windows 10', 'internet explorer', '11'], - ['Windows 8', 'internet explorer', '10'], - ['Windows 7', 'internet explorer', '9'], - // ['OS X 10.10', 'ipad', '9.1'], - ['OS X 10.11', 'safari', '9'], - ['OS X 10.10', 'safari', '8'] -]; - -/** Used to tailor the `platforms` array. */ -var isAMD = _.includes(tags, 'amd'), - isBackbone = _.includes(tags, 'backbone'), - isModern = _.includes(tags, 'modern'); - -// The platforms to test IE compatibility modes. -if (compatMode) { - platforms = [ - ['Windows 10', 'internet explorer', '11'], - ['Windows 8', 'internet explorer', '10'], - ['Windows 7', 'internet explorer', '9'], - ['Windows 7', 'internet explorer', '8'] - ]; -} -// The platforms for AMD tests. -if (isAMD) { - platforms = _.filter(platforms, function(platform) { - var browser = browserName(platform[1]), - version = +platform[2]; - - switch (browser) { - case 'Android': return version >= 4.4; - case 'Opera': return version >= 10; - } - return true; - }); -} -// The platforms for Backbone tests. -if (isBackbone) { - platforms = _.filter(platforms, function(platform) { - var browser = browserName(platform[1]), - version = +platform[2]; - - switch (browser) { - case 'Firefox': return version >= 4; - case 'Internet Explorer': return version >= 7; - case 'iPad': return version >= 5; - case 'Opera': return version >= 12; - } - return true; - }); -} -// The platforms for modern builds. -if (isModern) { - platforms = _.filter(platforms, function(platform) { - var browser = browserName(platform[1]), - version = +platform[2]; - - switch (browser) { - case 'Android': return version >= 4.1; - case 'Firefox': return version >= 10; - case 'Internet Explorer': return version >= 9; - case 'iPad': return version >= 6; - case 'Opera': return version >= 12; - case 'Safari': return version >= 6; - } - return true; - }); -} - -/** Used as the default `Job` options object. */ -var jobOptions = { - 'build': build, - 'command-timeout': commandTimeout, - 'custom-data': customData, - 'device-orientation': deviceOrientation, - 'framework': framework, - 'idle-timeout': idleTimeout, - 'max-duration': maxDuration, - 'name': jobName, - 'public': publicAccess, - 'platforms': platforms, - 'record-screenshots': recordScreenshots, - 'record-video': recordVideo, - 'sauce-advisor': advisor, - 'tags': tags, - 'url': runnerUrl, - 'video-upload-on-pass': videoUploadOnPass -}; - -if (publicAccess === true) { - jobOptions['public'] = 'public'; -} -if (tunneled) { - jobOptions['tunnel-identifier'] = tunnelId; -} - -/*----------------------------------------------------------------------------*/ - -/** - * Resolves the formal browser name for a given Sauce Labs browser identifier. - * - * @private - * @param {string} identifier The browser identifier. - * @returns {string} Returns the formal browser name. - */ -function browserName(identifier) { - return browserNameMap[identifier] || _.startCase(identifier); -} - -/** - * Gets the value for the given option name. If no value is available the - * `defaultValue` is returned. - * - * @private - * @param {string} name The name of the option. - * @param {*} defaultValue The default option value. - * @returns {*} Returns the option value. - */ -function getOption(name, defaultValue) { - var isArr = _.isArray(defaultValue); - return _.reduce(process.argv, function(result, value) { - if (isArr) { - value = optionToArray(name, value); - return _.isEmpty(value) ? result : value; - } - value = optionToValue(name, value); - - return value == null ? result : value; - }, defaultValue); -} - -/** - * Checks if `value` is a job ID. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a job ID, else `false`. - */ -function isJobId(value) { - return reJobId.test(value); -} - -/** - * Writes an inline message to standard output. - * - * @private - * @param {string} [text=''] The text to log. - */ -function logInline(text) { - var blankLine = _.repeat(' ', _.size(prevLine)); - prevLine = text = _.truncate(text, { 'length': 40 }); - process.stdout.write(text + blankLine.slice(text.length) + '\r'); -} - -/** - * Writes the wait throbber to standard output. - * - * @private - */ -function logThrobber() { - logInline('Please wait' + _.repeat('.', (++waitCount % 3) + 1)); -} - -/** - * Converts a comma separated option value into an array. - * - * @private - * @param {string} name The name of the option to inspect. - * @param {string} string The options string. - * @returns {Array} Returns the new converted array. - */ -function optionToArray(name, string) { - return _.compact(_.invokeMap((optionToValue(name, string) || '').split(/, */), 'trim')); -} - -/** - * Extracts the option value from an option string. - * - * @private - * @param {string} name The name of the option to inspect. - * @param {string} string The options string. - * @returns {string|undefined} Returns the option value, else `undefined`. - */ -function optionToValue(name, string) { - var result = string.match(RegExp('^' + name + '(?:=([\\s\\S]+))?$')); - if (result) { - result = _.get(result, 1); - result = result ? _.trim(result) : true; - } - if (result === 'false') { - return false; - } - return result || undefined; -} - -/*----------------------------------------------------------------------------*/ - -/** - * The `Job#remove` and `Tunnel#stop` callback used by `Jobs#restart` - * and `Tunnel#restart` respectively. - * - * @private - */ -function onGenericRestart() { - this.restarting = false; - this.emit('restart'); - this.start(); -} - -/** - * The `request.put` and `SauceTunnel#stop` callback used by `Jobs#stop` - * and `Tunnel#stop` respectively. - * - * @private - * @param {Object} [error] The error object. - */ -function onGenericStop(error) { - this.running = this.stopping = false; - this.emit('stop', error); -} - -/** - * The `request.del` callback used by `Jobs#remove`. - * - * @private - */ -function onJobRemove(error, res, body) { - this.id = this.taskId = this.url = null; - this.removing = false; - this.emit('remove'); -} - -/** - * The `Job#remove` callback used by `Jobs#reset`. - * - * @private - */ -function onJobReset() { - this.attempts = 0; - this.failed = this.resetting = false; - this._pollerId = this.id = this.result = this.taskId = this.url = null; - this.emit('reset'); -} - -/** - * The `request.post` callback used by `Jobs#start`. - * - * @private - * @param {Object} [error] The error object. - * @param {Object} res The response data object. - * @param {Object} body The response body JSON object. - */ -function onJobStart(error, res, body) { - this.starting = false; - - if (this.stopping) { - return; - } - var statusCode = _.get(res, 'statusCode'), - taskId = _.first(_.get(body, 'js tests')); - - if (error || !taskId || statusCode != 200) { - if (this.attempts < this.retries) { - this.restart(); - return; - } - var na = 'unavailable', - bodyStr = _.isObject(body) ? '\n' + JSON.stringify(body) : na, - statusStr = _.isFinite(statusCode) ? statusCode : na; - - logInline(); - console.error('Failed to start job; status: %s, body: %s', statusStr, bodyStr); - if (error) { - console.error(error); - } - this.failed = true; - this.emit('complete'); - return; - } - this.running = true; - this.taskId = taskId; - this.timestamp = _.now(); - this.emit('start'); - this.status(); -} - -/** - * The `request.post` callback used by `Job#status`. - * - * @private - * @param {Object} [error] The error object. - * @param {Object} res The response data object. - * @param {Object} body The response body JSON object. - */ -function onJobStatus(error, res, body) { - this.checking = false; - - if (!this.running || this.stopping) { - return; - } - var completed = _.get(body, 'completed', false), - data = _.first(_.get(body, 'js tests')), - elapsed = (_.now() - this.timestamp) / 1000, - jobId = _.get(data, 'job_id', null), - jobResult = _.get(data, 'result', null), - jobStatus = _.get(data, 'status', ''), - jobUrl = _.get(data, 'url', null), - expired = (elapsed >= queueTimeout && !_.includes(jobStatus, 'in progress')), - options = this.options, - platform = options.platforms[0]; - - if (_.isObject(jobResult)) { - var message = _.get(jobResult, 'message'); - } else { - if (typeof jobResult == 'string') { - message = jobResult; - } - jobResult = null; - } - if (isJobId(jobId)) { - this.id = jobId; - this.result = jobResult; - this.url = jobUrl; - } else { - completed = false; - } - this.emit('status', jobStatus); - - if (!completed && !expired) { - this._pollerId = _.delay(_.bind(this.status, this), this.statusInterval * 1000); - return; - } - var description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + _.startCase(platform[0]), - errored = !jobResult || !jobResult.passed || reError.test(message) || reError.test(jobStatus), - failures = _.get(jobResult, 'failed'), - label = options.name + ':', - tunnel = this.tunnel; - - if (errored || failures) { - if (errored && this.attempts < this.retries) { - this.restart(); - return; - } - var details = 'See ' + jobUrl + ' for details.'; - this.failed = true; - - logInline(); - if (failures) { - console.error(label + ' %s ' + chalk.red('failed') + ' %d test' + (failures > 1 ? 's' : '') + '. %s', description, failures, details); - } - else if (tunnel.attempts < tunnel.retries) { - tunnel.restart(); - return; - } - else { - if (message === undefined) { - message = 'Results are unavailable. ' + details; - } - console.error(label, description, chalk.red('failed') + ';', message); - } - } - else { - logInline(); - console.log(label, description, chalk.green('passed')); - } - this.running = false; - this.emit('complete'); -} - -/** - * The `SauceTunnel#start` callback used by `Tunnel#start`. - * - * @private - * @param {boolean} success The connection success indicator. - */ -function onTunnelStart(success) { - this.starting = false; - - if (this._timeoutId) { - clearTimeout(this._timeoutId); - this._timeoutId = null; - } - if (!success) { - if (this.attempts < this.retries) { - this.restart(); - return; - } - logInline(); - console.error('Failed to open Sauce Connect tunnel'); - process.exit(2); - } - logInline(); - console.log('Sauce Connect tunnel opened'); - - var jobs = this.jobs; - push.apply(jobs.queue, jobs.all); - - this.running = true; - this.emit('start'); - - console.log('Starting jobs...'); - this.dequeue(); -} - -/*----------------------------------------------------------------------------*/ - -/** - * The Job constructor. - * - * @private - * @param {Object} [properties] The properties to initialize a job with. - */ -function Job(properties) { - EventEmitter.call(this); - - this.options = {}; - _.merge(this, properties); - _.defaults(this.options, _.cloneDeep(jobOptions)); - - this.attempts = 0; - this.checking = this.failed = this.removing = this.resetting = this.restarting = this.running = this.starting = this.stopping = false; - this._pollerId = this.id = this.result = this.taskId = this.url = null; -} - -util.inherits(Job, EventEmitter); - -/** - * Removes the job. - * - * @memberOf Job - * @param {Function} callback The function called once the job is removed. - * @param {Object} Returns the job instance. - */ -Job.prototype.remove = function(callback) { - this.once('remove', _.iteratee(callback)); - if (this.removing) { - return this; - } - this.removing = true; - return this.stop(function() { - var onRemove = _.bind(onJobRemove, this); - if (!this.id) { - _.defer(onRemove); - return; - } - request.del(_.template('https://saucelabs.com/rest/v1/${user}/jobs/${id}')(this), { - 'auth': { 'user': this.user, 'pass': this.pass } - }, onRemove); - }); -}; - -/** - * Resets the job. - * - * @memberOf Job - * @param {Function} callback The function called once the job is reset. - * @param {Object} Returns the job instance. - */ -Job.prototype.reset = function(callback) { - this.once('reset', _.iteratee(callback)); - if (this.resetting) { - return this; - } - this.resetting = true; - return this.remove(onJobReset); -}; - -/** - * Restarts the job. - * - * @memberOf Job - * @param {Function} callback The function called once the job is restarted. - * @param {Object} Returns the job instance. - */ -Job.prototype.restart = function(callback) { - this.once('restart', _.iteratee(callback)); - if (this.restarting) { - return this; - } - this.restarting = true; - - var options = this.options, - platform = options.platforms[0], - description = browserName(platform[1]) + ' ' + platform[2] + ' on ' + _.startCase(platform[0]), - label = options.name + ':'; - - logInline(); - console.log('%s %s restart %d of %d', label, description, ++this.attempts, this.retries); - - return this.remove(onGenericRestart); -}; - -/** - * Starts the job. - * - * @memberOf Job - * @param {Function} callback The function called once the job is started. - * @param {Object} Returns the job instance. - */ -Job.prototype.start = function(callback) { - this.once('start', _.iteratee(callback)); - if (this.starting || this.running) { - return this; - } - this.starting = true; - request.post(_.template('https://saucelabs.com/rest/v1/${user}/js-tests')(this), { - 'auth': { 'user': this.user, 'pass': this.pass }, - 'json': this.options - }, _.bind(onJobStart, this)); - - return this; -}; - -/** - * Checks the status of a job. - * - * @memberOf Job - * @param {Function} callback The function called once the status is resolved. - * @param {Object} Returns the job instance. - */ -Job.prototype.status = function(callback) { - this.once('status', _.iteratee(callback)); - if (this.checking || this.removing || this.resetting || this.restarting || this.starting || this.stopping) { - return this; - } - this._pollerId = null; - this.checking = true; - request.post(_.template('https://saucelabs.com/rest/v1/${user}/js-tests/status')(this), { - 'auth': { 'user': this.user, 'pass': this.pass }, - 'json': { 'js tests': [this.taskId] } - }, _.bind(onJobStatus, this)); - - return this; -}; - -/** - * Stops the job. - * - * @memberOf Job - * @param {Function} callback The function called once the job is stopped. - * @param {Object} Returns the job instance. - */ -Job.prototype.stop = function(callback) { - this.once('stop', _.iteratee(callback)); - if (this.stopping) { - return this; - } - this.stopping = true; - if (this._pollerId) { - clearTimeout(this._pollerId); - this._pollerId = null; - this.checking = false; - } - var onStop = _.bind(onGenericStop, this); - if (!this.running || !this.id) { - _.defer(onStop); - return this; - } - request.put(_.template('https://saucelabs.com/rest/v1/${user}/jobs/${id}/stop')(this), { - 'auth': { 'user': this.user, 'pass': this.pass } - }, onStop); - - return this; -}; - -/*----------------------------------------------------------------------------*/ - -/** - * The Tunnel constructor. - * - * @private - * @param {Object} [properties] The properties to initialize the tunnel with. - */ -function Tunnel(properties) { - EventEmitter.call(this); - - _.merge(this, properties); - - var active = [], - queue = []; - - var all = _.map(this.platforms, _.bind(function(platform) { - return new Job(_.merge({ - 'user': this.user, - 'pass': this.pass, - 'tunnel': this, - 'options': { 'platforms': [platform] } - }, this.job)); - }, this)); - - var completed = 0, - restarted = [], - success = true, - total = all.length, - tunnel = this; - - _.invokeMap(all, 'on', 'complete', function() { - _.pull(active, this); - if (success) { - success = !this.failed; - } - if (++completed == total) { - tunnel.stop(_.partial(tunnel.emit, 'complete', success)); - return; - } - tunnel.dequeue(); - }); - - _.invokeMap(all, 'on', 'restart', function() { - if (!_.includes(restarted, this)) { - restarted.push(this); - } - // Restart tunnel if all active jobs have restarted. - var threshold = Math.min(all.length, _.isFinite(throttled) ? throttled : 3); - if (tunnel.attempts < tunnel.retries && - active.length >= threshold && _.isEmpty(_.difference(active, restarted))) { - tunnel.restart(); - } - }); - - this.on('restart', function() { - completed = 0; - success = true; - restarted.length = 0; - }); - - this._timeoutId = null; - this.attempts = 0; - this.restarting = this.running = this.starting = this.stopping = false; - this.jobs = { 'active': active, 'all': all, 'queue': queue }; - this.connection = new SauceTunnel(this.user, this.pass, this.id, this.tunneled, ['-P', '0']); -} - -util.inherits(Tunnel, EventEmitter); - -/** - * Restarts the tunnel. - * - * @memberOf Tunnel - * @param {Function} callback The function called once the tunnel is restarted. - */ -Tunnel.prototype.restart = function(callback) { - this.once('restart', _.iteratee(callback)); - if (this.restarting) { - return this; - } - this.restarting = true; - - logInline(); - console.log('Tunnel %s: restart %d of %d', this.id, ++this.attempts, this.retries); - - var jobs = this.jobs, - active = jobs.active, - all = jobs.all; - - var reset = _.after(all.length, _.bind(this.stop, this, onGenericRestart)), - stop = _.after(active.length, _.partial(_.invokeMap, all, 'reset', reset)); - - if (_.isEmpty(active)) { - _.defer(stop); - } - if (_.isEmpty(all)) { - _.defer(reset); - } - _.invokeMap(active, 'stop', function() { - _.pull(active, this); - stop(); - }); - - if (this._timeoutId) { - clearTimeout(this._timeoutId); - this._timeoutId = null; - } - return this; -}; - -/** - * Starts the tunnel. - * - * @memberOf Tunnel - * @param {Function} callback The function called once the tunnel is started. - * @param {Object} Returns the tunnel instance. - */ -Tunnel.prototype.start = function(callback) { - this.once('start', _.iteratee(callback)); - if (this.starting || this.running) { - return this; - } - this.starting = true; - - logInline(); - console.log('Opening Sauce Connect tunnel...'); - - var onStart = _.bind(onTunnelStart, this); - if (this.timeout) { - this._timeoutId = _.delay(onStart, this.timeout * 1000, false); - } - this.connection.start(onStart); - return this; -}; - -/** - * Removes jobs from the queue and starts them. - * - * @memberOf Tunnel - * @param {Object} Returns the tunnel instance. - */ -Tunnel.prototype.dequeue = function() { - var count = 0, - jobs = this.jobs, - active = jobs.active, - queue = jobs.queue, - throttled = this.throttled; - - while (queue.length && (active.length < throttled)) { - var job = queue.shift(); - active.push(job); - _.delay(_.bind(job.start, job), ++count * 1000); - } - return this; -}; - -/** - * Stops the tunnel. - * - * @memberOf Tunnel - * @param {Function} callback The function called once the tunnel is stopped. - * @param {Object} Returns the tunnel instance. - */ -Tunnel.prototype.stop = function(callback) { - this.once('stop', _.iteratee(callback)); - if (this.stopping) { - return this; - } - this.stopping = true; - - logInline(); - console.log('Shutting down Sauce Connect tunnel...'); - - var jobs = this.jobs, - active = jobs.active; - - var stop = _.after(active.length, _.bind(function() { - var onStop = _.bind(onGenericStop, this); - if (this.running) { - this.connection.stop(onStop); - } else { - onStop(); - } - }, this)); - - jobs.queue.length = 0; - if (_.isEmpty(active)) { - _.defer(stop); - } - _.invokeMap(active, 'stop', function() { - _.pull(active, this); - stop(); - }); - - if (this._timeoutId) { - clearTimeout(this._timeoutId); - this._timeoutId = null; - } - return this; -}; - -/*----------------------------------------------------------------------------*/ - -// Cleanup any inline logs when exited via `ctrl+c`. -process.on('SIGINT', function() { - logInline(); - process.exit(); -}); - -// Create a web server for the current working directory. -http.createServer(function(req, res) { - // See http://msdn.microsoft.com/en-us/library/ff955275(v=vs.85).aspx. - if (compatMode && path.extname(url.parse(req.url).pathname) == '.html') { - res.setHeader('X-UA-Compatible', 'IE=' + compatMode); - } - mount(req, res); -}).listen(port); - -// Setup Sauce Connect so we can use this server from Sauce Labs. -var tunnel = new Tunnel({ - 'user': username, - 'pass': accessKey, - 'id': tunnelId, - 'job': { 'retries': maxJobRetries, 'statusInterval': statusInterval }, - 'platforms': platforms, - 'retries': maxTunnelRetries, - 'throttled': throttled, - 'tunneled': tunneled, - 'timeout': tunnelTimeout -}); - -tunnel.on('complete', function(success) { - process.exit(success ? 0 : 1); -}); - -tunnel.start(); - -setInterval(logThrobber, throbberDelay); diff --git a/public/vendor/lodash/test/test-fp.js b/public/vendor/lodash/test/test-fp.js deleted file mode 100644 index f06ac71c370..00000000000 --- a/public/vendor/lodash/test/test-fp.js +++ /dev/null @@ -1,2301 +0,0 @@ -;(function() { - 'use strict'; - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the size to cover large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Used as a reference to the global object. */ - var root = (typeof global == 'object' && global) || this; - - /** Used for native method references. */ - var arrayProto = Array.prototype; - - /** Method and object shortcuts. */ - var phantom = root.phantom, - argv = root.process && process.argv, - document = !phantom && root.document, - slice = arrayProto.slice, - WeakMap = root.WeakMap; - - /** Math helpers. */ - var add = function(x, y) { return x + y; }, - isEven = function(n) { return n % 2 == 0; }, - isEvenIndex = function(n, index) { return isEven(index); }, - square = function(n) { return n * n; }; - - // Leak to avoid sporadic `noglobals` fails on Edge in Sauce Labs. - root.msWDfn = undefined; - - /*--------------------------------------------------------------------------*/ - - /** Load QUnit and extras. */ - var QUnit = root.QUnit || require('qunit-extras'); - - /** Load stable Lodash. */ - var _ = root._ || require('../lodash.js'); - - var convert = (function() { - var baseConvert = root.fp || require('../fp/_baseConvert.js'); - if (!root.fp) { - return function(name, func, options) { - return baseConvert(_, name, func, options); - }; - } - return function(name, func, options) { - if (typeof name == 'function') { - options = func; - func = name; - name = undefined; - } - return name === undefined - ? baseConvert(func, options) - : baseConvert(_.runInContext(), options)[name]; - }; - }()); - - var allFalseOptions = { - 'cap': false, - 'curry': false, - 'fixed': false, - 'immutable': false, - 'rearg': false - }; - - var fp = root.fp - ? (fp = _.noConflict(), _ = root._, fp) - : convert(_.runInContext()); - - var mapping = root.mapping || require('../fp/_mapping.js'); - - /*--------------------------------------------------------------------------*/ - - /** - * Skips a given number of tests with a passing result. - * - * @private - * @param {Object} assert The QUnit assert object. - * @param {number} [count=1] The number of tests to skip. - */ - function skipAssert(assert, count) { - count || (count = 1); - while (count--) { - assert.ok(true, 'test skipped'); - } - } - - /*--------------------------------------------------------------------------*/ - - if (argv) { - console.log('Running lodash/fp tests.'); - } - - QUnit.module('convert module'); - - (function() { - QUnit.test('should work with `name` and `func`', function(assert) { - assert.expect(2); - - var array = [1, 2, 3, 4], - remove = convert('remove', _.remove), - actual = remove(isEven)(array); - - assert.deepEqual(array, [1, 2, 3, 4]); - assert.deepEqual(actual, [1, 3]); - }); - - QUnit.test('should work with `name`, `func`, and `options`', function(assert) { - assert.expect(3); - - var array = [1, 2, 3, 4], - remove = convert('remove', _.remove, allFalseOptions); - - var actual = remove(array, function(n, index) { - return isEven(index); - }); - - assert.deepEqual(array, [2, 4]); - assert.deepEqual(actual, [1, 3]); - assert.deepEqual(remove(), []); - }); - - QUnit.test('should work with an object', function(assert) { - assert.expect(2); - - if (!document) { - var array = [1, 2, 3, 4], - lodash = convert({ 'remove': _.remove }), - actual = lodash.remove(isEven)(array); - - assert.deepEqual(array, [1, 2, 3, 4]); - assert.deepEqual(actual, [1, 3]); - } - else { - skipAssert(assert, 2); - } - }); - - QUnit.test('should work with an object and `options`', function(assert) { - assert.expect(3); - - if (!document) { - var array = [1, 2, 3, 4], - lodash = convert({ 'remove': _.remove }, allFalseOptions), - actual = lodash.remove(array, isEvenIndex); - - assert.deepEqual(array, [2, 4]); - assert.deepEqual(actual, [1, 3]); - assert.deepEqual(lodash.remove(), []); - } - else { - skipAssert(assert, 3); - } - }); - - QUnit.test('should work with lodash and `options`', function(assert) { - assert.expect(3); - - var array = [1, 2, 3, 4], - lodash = convert(_.runInContext(), allFalseOptions), - actual = lodash.remove(array, isEvenIndex); - - assert.deepEqual(array, [2, 4]); - assert.deepEqual(actual, [1, 3]); - assert.deepEqual(lodash.remove(), []); - }); - - QUnit.test('should work with `runInContext` and `options`', function(assert) { - assert.expect(3); - - var array = [1, 2, 3, 4], - runInContext = convert('runInContext', _.runInContext, allFalseOptions), - lodash = runInContext(), - actual = lodash.remove(array, isEvenIndex); - - assert.deepEqual(array, [2, 4]); - assert.deepEqual(actual, [1, 3]); - assert.deepEqual(lodash.remove(), []); - }); - - QUnit.test('should accept a variety of options', function(assert) { - assert.expect(8); - - var array = [1, 2, 3, 4], - value = _.clone(array), - remove = convert('remove', _.remove, { 'cap': false }), - actual = remove(isEvenIndex)(value); - - assert.deepEqual(value, [1, 2, 3, 4]); - assert.deepEqual(actual, [2, 4]); - - remove = convert('remove', _.remove, { 'curry': false }); - actual = remove(isEven); - - assert.deepEqual(actual, []); - - var trim = convert('trim', _.trim, { 'fixed': false }); - assert.strictEqual(trim('_-abc-_', '_-'), 'abc'); - - value = _.clone(array); - remove = convert('remove', _.remove, { 'immutable': false }); - actual = remove(isEven)(value); - - assert.deepEqual(value, [1, 3]); - assert.deepEqual(actual, [2, 4]); - - value = _.clone(array); - remove = convert('remove', _.remove, { 'rearg': false }); - actual = remove(value)(isEven); - - assert.deepEqual(value, [1, 2, 3, 4]); - assert.deepEqual(actual, [1, 3]); - }); - - QUnit.test('should respect the `cap` option', function(assert) { - assert.expect(1); - - var iteratee = convert('iteratee', _.iteratee, { 'cap': false }); - - var func = iteratee(function(a, b, c) { - return [a, b, c]; - }, 3); - - assert.deepEqual(func(1, 2, 3), [1, 2, 3]); - }); - - QUnit.test('should respect the `rearg` option', function(assert) { - assert.expect(1); - - var add = convert('add', _.add, { 'rearg': true }); - - assert.strictEqual(add('2')('1'), '12'); - }); - - QUnit.test('should only add a `placeholder` property if needed', function(assert) { - assert.expect(2); - - if (!document) { - var methodNames = _.keys(mapping.placeholder), - expected = _.map(methodNames, _.constant(true)); - - var actual = _.map(methodNames, function(methodName) { - var object = {}; - object[methodName] = _[methodName]; - - var lodash = convert(object); - return methodName in lodash; - }); - - assert.deepEqual(actual, expected); - - var lodash = convert({ 'add': _.add }); - assert.notOk('placeholder' in lodash); - } - else { - skipAssert(assert, 2); - } - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('method.convert'); - - (function() { - QUnit.test('should exist on unconverted methods', function(assert) { - assert.expect(2); - - var array = [], - isArray = fp.isArray.convert({ 'curry': true }); - - assert.strictEqual(fp.isArray(array), true); - assert.strictEqual(isArray()(array), true); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('convert methods'); - - _.each(['fp.convert', 'method.convert'], function(methodName) { - var isFp = methodName == 'fp.convert', - func = isFp ? fp.convert : fp.remove.convert; - - QUnit.test('`' + methodName + '` should work with an object', function(assert) { - assert.expect(3); - - var array = [1, 2, 3, 4], - lodash = func(allFalseOptions), - remove = isFp ? lodash.remove : lodash, - actual = remove(array, isEvenIndex); - - assert.deepEqual(array, [2, 4]); - assert.deepEqual(actual, [1, 3]); - assert.deepEqual(remove(), []); - }); - - QUnit.test('`' + methodName + '` should extend existing configs', function(assert) { - assert.expect(2); - - var array = [1, 2, 3, 4], - lodash = func({ 'cap': false }), - remove = (isFp ? lodash.remove : lodash).convert({ 'rearg': false }), - actual = remove(array)(isEvenIndex); - - assert.deepEqual(array, [1, 2, 3, 4]); - assert.deepEqual(actual, [2, 4]); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('method arity checks'); - - (function() { - QUnit.test('should wrap methods with an arity > `1`', function(assert) { - assert.expect(1); - - var methodNames = _.filter(_.functions(fp), function(methodName) { - return fp[methodName].length > 1; - }); - - assert.deepEqual(methodNames, []); - }); - - QUnit.test('should have >= arity of `aryMethod` designation', function(assert) { - assert.expect(4); - - _.times(4, function(index) { - var aryCap = index + 1; - - var methodNames = _.filter(mapping.aryMethod[aryCap], function(methodName) { - var key = _.get(mapping.remap, methodName, methodName), - arity = _[key].length; - - return arity != 0 && arity < aryCap; - }); - - assert.deepEqual(methodNames, [], '`aryMethod[' + aryCap + ']`'); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('method aliases'); - - (function() { - QUnit.test('should have correct aliases', function(assert) { - assert.expect(1); - - var actual = _.transform(mapping.aliasToReal, function(result, realName, alias) { - result.push([alias, fp[alias] === fp[realName]]); - }, []); - - assert.deepEqual(_.reject(actual, 1), []); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('method ary caps'); - - (function() { - QUnit.test('should have a cap of 1', function(assert) { - assert.expect(1); - - var funcMethods = [ - 'curry', 'iteratee', 'memoize', 'over', 'overEvery', 'overSome', - 'method', 'methodOf', 'rest', 'runInContext' - ]; - - var exceptions = funcMethods.concat('mixin', 'nthArg', 'template'), - expected = _.map(mapping.aryMethod[1], _.constant(true)); - - var actual = _.map(mapping.aryMethod[1], function(methodName) { - var arg = _.includes(funcMethods, methodName) ? _.noop : 1, - result = _.attempt(function() { return fp[methodName](arg); }); - - if (_.includes(exceptions, methodName) - ? typeof result == 'function' - : typeof result != 'function' - ) { - return true; - } - console.log(methodName, result); - return false; - }); - - assert.deepEqual(actual, expected); - }); - - QUnit.test('should have a cap of 2', function(assert) { - assert.expect(1); - - var funcMethods = [ - 'after', 'ary', 'before', 'bind', 'bindKey', 'curryN', 'debounce', - 'delay', 'overArgs', 'partial', 'partialRight', 'rearg', 'throttle', - 'wrap' - ]; - - var exceptions = _.without(funcMethods.concat('matchesProperty'), 'delay'), - expected = _.map(mapping.aryMethod[2], _.constant(true)); - - var actual = _.map(mapping.aryMethod[2], function(methodName) { - var args = _.includes(funcMethods, methodName) ? [methodName == 'curryN' ? 1 : _.noop, _.noop] : [1, []], - result = _.attempt(function() { return fp[methodName](args[0])(args[1]); }); - - if (_.includes(exceptions, methodName) - ? typeof result == 'function' - : typeof result != 'function' - ) { - return true; - } - console.log(methodName, result); - return false; - }); - - assert.deepEqual(actual, expected); - }); - - QUnit.test('should have a cap of 3', function(assert) { - assert.expect(1); - - var funcMethods = [ - 'assignWith', 'extendWith', 'isEqualWith', 'isMatchWith', 'reduce', - 'reduceRight', 'transform', 'zipWith' - ]; - - var expected = _.map(mapping.aryMethod[3], _.constant(true)); - - var actual = _.map(mapping.aryMethod[3], function(methodName) { - var args = _.includes(funcMethods, methodName) ? [_.noop, 0, 1] : [0, 1, []], - result = _.attempt(function() { return fp[methodName](args[0])(args[1])(args[2]); }); - - if (typeof result != 'function') { - return true; - } - console.log(methodName, result); - return false; - }); - - assert.deepEqual(actual, expected); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('methods that use `indexOf`'); - - (function() { - QUnit.test('should work with `fp.indexOf`', function(assert) { - assert.expect(10); - - var array = ['a', 'b', 'c'], - other = ['b', 'd', 'b'], - object = { 'a': 1, 'b': 2, 'c': 2 }, - actual = fp.difference(array)(other); - - assert.deepEqual(actual, ['a', 'c'], 'fp.difference'); - - actual = fp.includes('b')(array); - assert.strictEqual(actual, true, 'fp.includes'); - - actual = fp.intersection(other)(array); - assert.deepEqual(actual, ['b'], 'fp.intersection'); - - actual = fp.omit(other)(object); - assert.deepEqual(actual, { 'a': 1, 'c': 2 }, 'fp.omit'); - - actual = fp.union(other)(array); - assert.deepEqual(actual, ['a', 'b', 'c', 'd'], 'fp.union'); - - actual = fp.uniq(other); - assert.deepEqual(actual, ['b', 'd'], 'fp.uniq'); - - actual = fp.uniqBy(_.identity, other); - assert.deepEqual(actual, ['b', 'd'], 'fp.uniqBy'); - - actual = fp.without(other)(array); - assert.deepEqual(actual, ['a', 'c'], 'fp.without'); - - actual = fp.xor(other)(array); - assert.deepEqual(actual, ['a', 'c', 'd'], 'fp.xor'); - - actual = fp.pull('b')(array); - assert.deepEqual(actual, ['a', 'c'], 'fp.pull'); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('cherry-picked methods'); - - (function() { - QUnit.test('should provide the correct `iteratee` arguments', function(assert) { - assert.expect(4); - - var args, - array = [1, 2, 3], - object = { 'a': 1, 'b': 2 }, - isFIFO = _.keys(object)[0] == 'a', - map = convert('map', _.map), - reduce = convert('reduce', _.reduce); - - map(function() { - args || (args = slice.call(arguments)); - })(array); - - assert.deepEqual(args, [1]); - - args = undefined; - map(function() { - args || (args = slice.call(arguments)); - })(object); - - assert.deepEqual(args, isFIFO ? [1] : [2]); - - args = undefined; - reduce(function() { - args || (args = slice.call(arguments)); - })(0)(array); - - assert.deepEqual(args, [0, 1]); - - args = undefined; - reduce(function() { - args || (args = slice.call(arguments)); - })(0)(object); - - assert.deepEqual(args, isFIFO ? [0, 1] : [0, 2]); - }); - - QUnit.test('should not support shortcut fusion', function(assert) { - assert.expect(3); - - var array = fp.range(0, LARGE_ARRAY_SIZE), - filterCount = 0, - mapCount = 0; - - var iteratee = function(value) { - mapCount++; - return value * value; - }; - - var predicate = function(value) { - filterCount++; - return isEven(value); - }; - - var map1 = convert('map', _.map), - filter1 = convert('filter', _.filter), - take1 = convert('take', _.take); - - var filter2 = filter1(predicate), - map2 = map1(iteratee), - take2 = take1(2); - - var combined = fp.flow(map2, filter2, fp.compact, take2); - - assert.deepEqual(combined(array), [4, 16]); - assert.strictEqual(filterCount, 200, 'filterCount'); - assert.strictEqual(mapCount, 200, 'mapCount'); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('iteratee shorthands'); - - (function() { - var objects = [{ 'a': 1, 'b': 2 }, { 'a': 3, 'b': 4 }]; - - QUnit.test('should work with "_.matches" shorthands', function(assert) { - assert.expect(1); - - assert.deepEqual(fp.filter({ 'a': 3 })(objects), [objects[1]]); - }); - - QUnit.test('should work with "_.matchesProperty" shorthands', function(assert) { - assert.expect(1); - - assert.deepEqual(fp.filter(['a', 3])(objects), [objects[1]]); - }); - - QUnit.test('should work with "_.property" shorthands', function(assert) { - assert.expect(1); - - assert.deepEqual(fp.map('a')(objects), [1, 3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('placeholder methods'); - - (function() { - QUnit.test('should use `fp` as the default placeholder', function(assert) { - assert.expect(3); - - var actual = fp.add(fp, 'b')('a'); - assert.strictEqual(actual, 'ab'); - - actual = fp.fill(fp, 2)(1, '*')([1, 2, 3]); - assert.deepEqual(actual, [1, '*', 3]); - - actual = fp.slice(fp, 2)(1)(['a', 'b', 'c']); - assert.deepEqual(actual, ['b']); - }); - - QUnit.test('should support `fp.placeholder`', function(assert) { - assert.expect(6); - - _.each([[], fp.__], function(ph) { - fp.placeholder = ph; - - var actual = fp.add(ph, 'b')('a'); - assert.strictEqual(actual, 'ab'); - - actual = fp.fill(ph, 2)(1, '*')([1, 2, 3]); - assert.deepEqual(actual, [1, '*', 3]); - - actual = fp.slice(ph, 2)(1)(['a', 'b', 'c']); - assert.deepEqual(actual, ['b']); - }); - }); - - _.forOwn(mapping.placeholder, function(truthy, methodName) { - var func = fp[methodName]; - - QUnit.test('`_.' + methodName + '` should have a `placeholder` property', function(assert) { - assert.expect(2); - - assert.ok(_.isObject(func.placeholder)); - assert.strictEqual(func.placeholder, fp.__); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('setter methods'); - - (function() { - QUnit.test('should only clone objects in `path`', function(assert) { - assert.expect(11); - - var object = { 'a': { 'b': 2, 'c': 3 }, 'd': { 'e': 4 } }, - value = _.cloneDeep(object), - actual = fp.set('a.b.c.d', 5, value); - - assert.ok(_.isObject(actual.a.b), 'fp.set'); - assert.ok(_.isNumber(actual.a.b), 'fp.set'); - - assert.strictEqual(actual.a.b.c.d, 5, 'fp.set'); - assert.strictEqual(actual.d, value.d, 'fp.set'); - - value = _.cloneDeep(object); - actual = fp.setWith(Object)('[0][1]')('a')(value); - - assert.deepEqual(actual[0], { '1': 'a' }, 'fp.setWith'); - - value = _.cloneDeep(object); - actual = fp.unset('a.b')(value); - - assert.notOk('b' in actual.a, 'fp.unset'); - assert.strictEqual(actual.a.c, value.a.c, 'fp.unset'); - - value = _.cloneDeep(object); - actual = fp.update('a.b')(square)(value); - - assert.strictEqual(actual.a.b, 4, 'fp.update'); - assert.strictEqual(actual.d, value.d, 'fp.update'); - - value = _.cloneDeep(object); - actual = fp.updateWith(Object)('[0][1]')(_.constant('a'))(value); - - assert.deepEqual(actual[0], { '1': 'a' }, 'fp.updateWith'); - assert.strictEqual(actual.d, value.d, 'fp.updateWith'); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.add and fp.subtract'); - - _.each(['add', 'subtract'], function(methodName) { - var func = fp[methodName], - isAdd = methodName == 'add'; - - QUnit.test('`fp.' + methodName + '` should not have `rearg` applied', function(assert) { - assert.expect(1); - - assert.strictEqual(func('1')('2'), isAdd ? '12' : -1); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('assign methods'); - - _.each(['assign', 'assignIn', 'defaults', 'defaultsDeep', 'merge'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should not mutate values', function(assert) { - assert.expect(2); - - var object = { 'a': 1 }, - actual = func(object)({ 'b': 2 }); - - assert.deepEqual(object, { 'a': 1 }); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }); - }); - }); - - _.each(['assignAll', 'assignInAll', 'defaultsAll', 'defaultsDeepAll', 'mergeAll'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should not mutate values', function(assert) { - assert.expect(2); - - var objects = [{ 'a': 1 }, { 'b': 2 }], - actual = func(objects); - - assert.deepEqual(objects[0], { 'a': 1 }); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('assignWith methods'); - - _.each(['assignWith', 'assignInWith', 'extendWith'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should provide the correct `customizer` arguments', function(assert) { - assert.expect(1); - - var args; - - func(function() { - args || (args = _.map(arguments, _.cloneDeep)); - })({ 'a': 1 })({ 'b': 2 }); - - assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }]); - }); - - QUnit.test('`fp.' + methodName + '` should not mutate values', function(assert) { - assert.expect(2); - - var objects = [{ 'a': 1 }, { 'b': 2 }], - actual = func(_.nthArg(1))(objects[0])(objects[1]); - - assert.deepEqual(objects[0], { 'a': 1 }); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }); - }); - }); - - _.each(['assignAllWith', 'assignInAllWith', 'extendAllWith'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should provide the correct `customizer` arguments', function(assert) { - assert.expect(1); - - var args; - - func(function() { - args || (args = _.map(arguments, _.cloneDeep)); - })([{ 'a': 1 }, { 'b': 2 }]); - - assert.deepEqual(args, [undefined, 2, 'b', { 'a': 1 }, { 'b': 2 }]); - }); - - QUnit.test('`fp.' + methodName + '` should not mutate values', function(assert) { - assert.expect(2); - - var objects = [{ 'a': 1 }, { 'b': 2 }], - actual = func(_.nthArg(1))(objects); - - assert.deepEqual(objects[0], { 'a': 1 }); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.castArray'); - - (function() { - QUnit.test('should shallow clone array values', function(assert) { - assert.expect(2); - - var array = [1], - actual = fp.castArray(array); - - assert.deepEqual(actual, array); - assert.notStrictEqual(actual, array); - }); - - QUnit.test('should not shallow clone non-array values', function(assert) { - assert.expect(2); - - var object = { 'a': 1 }, - actual = fp.castArray(object); - - assert.deepEqual(actual, [object]); - assert.strictEqual(actual[0], object); - }); - - QUnit.test('should convert by name', function(assert) { - assert.expect(4); - - var array = [1], - object = { 'a': 1 }, - castArray = convert('castArray', _.castArray), - actual = castArray(array); - - assert.deepEqual(actual, array); - assert.notStrictEqual(actual, array); - - actual = castArray(object); - assert.deepEqual(actual, [object]); - assert.strictEqual(actual[0], object); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('curry methods'); - - _.each(['curry', 'curryRight'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`_.' + methodName + '` should only accept a `func` param', function(assert) { - assert.expect(1); - - assert.raises(function() { func(1, _.noop); }, TypeError); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('curryN methods'); - - _.each(['curryN', 'curryRightN'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`_.' + methodName + '` should accept an `arity` param', function(assert) { - assert.expect(1); - - var actual = func(1)(function(a, b) { return [a, b]; })('a'); - assert.deepEqual(actual, ['a', undefined]); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.defaultTo'); - - (function() { - QUnit.test('should have an argument order of `defaultValue` then `value`', function(assert) { - assert.expect(2); - - assert.strictEqual(fp.defaultTo(1)(0), 0); - assert.strictEqual(fp.defaultTo(1)(undefined), 1); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.difference'); - - (function() { - QUnit.test('should return the elements of the first array not included in the second array', function(assert) { - assert.expect(1); - - var actual = fp.difference([2, 1], [2, 3]); - assert.deepEqual(actual, [1]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.differenceBy'); - - (function() { - QUnit.test('should have an argument order of `iteratee`, `array`, then `values`', function(assert) { - assert.expect(1); - - var actual = fp.differenceBy(Math.floor, [2.1, 1.2], [2.3, 3.4]); - assert.deepEqual(actual, [1.2]); - }); - - QUnit.test('should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); - - var args; - - fp.differenceBy(function() { - args || (args = slice.call(arguments)); - })([2.1, 1.2], [2.3, 3.4]); - - assert.deepEqual(args, [2.3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.differenceWith'); - - (function() { - QUnit.test('should have an argument order of `comparator`, `array`, then `values`', function(assert) { - assert.expect(1); - - var actual = fp.differenceWith(fp.eq)([2, 1])([2, 3]); - assert.deepEqual(actual, [1]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.divide and fp.multiply'); - - _.each(['divide', 'multiply'], function(methodName) { - var func = fp[methodName], - isDivide = methodName == 'divide'; - - QUnit.test('`fp.' + methodName + '` should not have `rearg` applied', function(assert) { - assert.expect(1); - - assert.strictEqual(func('2')('4'), isDivide ? 0.5 : 8); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.extend'); - - (function() { - QUnit.test('should convert by name', function(assert) { - assert.expect(2); - - function Foo() {} - Foo.prototype = { 'b': 2 }; - - var object = { 'a': 1 }, - extend = convert('extend', _.extend), - actual = extend(object)(new Foo); - - assert.deepEqual(object, { 'a': 1 }); - assert.deepEqual(actual, { 'a': 1, 'b': 2 }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.fill'); - - (function() { - QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) { - assert.expect(1); - - var array = [1, 2, 3]; - assert.deepEqual(fp.fill(1)(2)('*')(array), [1, '*', 3]); - }); - - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var array = [1, 2, 3], - actual = fp.fill(1)(2)('*')(array); - - assert.deepEqual(array, [1, 2, 3]); - assert.deepEqual(actual, [1, '*', 3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.findFrom methods'); - - _.each(['findFrom', 'findIndexFrom', 'findLastFrom', 'findLastIndexFrom'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`_.' + methodName + '` should provide the correct `predicate` arguments', function(assert) { - assert.expect(1); - - var args; - - func(function() { - args || (args = slice.call(arguments)); - })(1)([1, 2, 3]); - - assert.deepEqual(args, [2]); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.findFrom'); - - (function() { - function resolve(value) { - return fp.flow(fp.property('a'), fp.eq(value)); - } - - QUnit.test('should have an argument order of `value`, `fromIndex`, then `array`', function(assert) { - assert.expect(2); - - var objects = [{ 'a': 1 }, { 'a': 2 }, { 'a': 1 }, { 'a': 2 }]; - - assert.strictEqual(fp.findFrom(resolve(1))(1)(objects), objects[2]); - assert.strictEqual(fp.findFrom(resolve(2))(-2)(objects), objects[3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.findLastFrom'); - - (function() { - function resolve(value) { - return fp.flow(fp.property('a'), fp.eq(value)); - } - - QUnit.test('should have an argument order of `value`, `fromIndex`, then `array`', function(assert) { - assert.expect(2); - - var objects = [{ 'a': 1 }, { 'a': 2 }, { 'a': 1 }, { 'a': 2 }]; - - assert.strictEqual(fp.findLastFrom(resolve(1))(1)(objects), objects[0]); - assert.strictEqual(fp.findLastFrom(resolve(2))(-2)(objects), objects[1]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.findIndexFrom and fp.indexOfFrom'); - - _.each(['findIndexFrom', 'indexOfFrom'], function(methodName) { - var func = fp[methodName], - resolve = methodName == 'findIndexFrom' ? fp.eq : _.identity; - - QUnit.test('`_.' + methodName + '` should have an argument order of `value`, `fromIndex`, then `array`', function(assert) { - assert.expect(2); - - var array = [1, 2, 3, 1, 2, 3]; - - assert.strictEqual(func(resolve(1))(2)(array), 3); - assert.strictEqual(func(resolve(2))(-3)(array), 4); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.findLastIndexFrom and fp.lastIndexOfFrom'); - - _.each(['findLastIndexFrom', 'lastIndexOfFrom'], function(methodName) { - var func = fp[methodName], - resolve = methodName == 'findLastIndexFrom' ? fp.eq : _.identity; - - QUnit.test('`_.' + methodName + '` should have an argument order of `value`, `fromIndex`, then `array`', function(assert) { - assert.expect(2); - - var array = [1, 2, 3, 1, 2, 3]; - - assert.strictEqual(func(resolve(2))(3)(array), 1); - assert.strictEqual(func(resolve(3))(-3)(array), 2); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.flatMapDepth'); - - (function() { - QUnit.test('should have an argument order of `iteratee`, `depth`, then `collection`', function(assert) { - assert.expect(2); - - function duplicate(n) { - return [[[n, n]]]; - } - - var array = [1, 2], - object = { 'a': 1, 'b': 2 }, - expected = [[1, 1], [2, 2]]; - - assert.deepEqual(fp.flatMapDepth(duplicate)(2)(array), expected); - assert.deepEqual(fp.flatMapDepth(duplicate)(2)(object), expected); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('flow methods'); - - _.each(['flow', 'flowRight'], function(methodName) { - var func = fp[methodName], - isFlow = methodName == 'flow'; - - QUnit.test('`fp.' + methodName + '` should support shortcut fusion', function(assert) { - assert.expect(6); - - var filterCount, - mapCount, - array = fp.range(0, LARGE_ARRAY_SIZE); - - var iteratee = function(value) { - mapCount++; - return square(value); - }; - - var predicate = function(value) { - filterCount++; - return isEven(value); - }; - - var filter = fp.filter(predicate), - map = fp.map(iteratee), - take = fp.take(2); - - _.times(2, function(index) { - var combined = isFlow - ? func(map, filter, fp.compact, take) - : func(take, fp.compact, filter, map); - - filterCount = mapCount = 0; - - if (WeakMap && WeakMap.name) { - assert.deepEqual(combined(array), [4, 16]); - assert.strictEqual(filterCount, 5, 'filterCount'); - assert.strictEqual(mapCount, 5, 'mapCount'); - } - else { - skipAssert(assert, 3); - } - }); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('forEach methods'); - - _.each(['forEach', 'forEachRight', 'forIn', 'forInRight', 'forOwn', 'forOwnRight'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should provide `value` to `iteratee`', function(assert) { - assert.expect(2); - - var args; - - func(function() { - args || (args = slice.call(arguments)); - })(['a']); - - assert.deepEqual(args, ['a']); - - args = undefined; - - func(function() { - args || (args = slice.call(arguments)); - })({ 'a': 1 }); - - assert.deepEqual(args, [1]); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.getOr'); - - (function() { - QUnit.test('should accept a `defaultValue` param', function(assert) { - assert.expect(1); - - var actual = fp.getOr('default')('path')({}); - assert.strictEqual(actual, 'default'); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.gt and fp.gte'); - - _.each(['gt', 'gte'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) { - assert.expect(1); - - assert.strictEqual(func(2)(1), true); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.inRange'); - - (function() { - QUnit.test('should have an argument order of `start`, `end`, then `value`', function(assert) { - assert.expect(2); - - assert.strictEqual(fp.inRange(2)(4)(3), true); - assert.strictEqual(fp.inRange(-2)(-6)(-3), true); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.intersectionBy'); - - (function() { - QUnit.test('should have an argument order of `iteratee`, `array`, then `values`', function(assert) { - assert.expect(1); - - var actual = fp.intersectionBy(Math.floor, [2.1, 1.2], [2.3, 3.4]); - assert.deepEqual(actual, [2.1]); - }); - - QUnit.test('should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); - - var args; - - fp.intersectionBy(function() { - args || (args = slice.call(arguments)); - })([2.1, 1.2], [2.3, 3.4]); - - assert.deepEqual(args, [2.3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.intersectionWith'); - - (function() { - QUnit.test('should have an argument order of `comparator`, `array`, then `values`', function(assert) { - assert.expect(1); - - var actual = fp.intersectionWith(fp.eq)([2, 1])([2, 3]); - assert.deepEqual(actual, [2]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.invoke'); - - (function() { - QUnit.test('should not accept an `args` param', function(assert) { - assert.expect(1); - - var actual = fp.invoke('toUpperCase')('a'); - assert.strictEqual(actual, 'A'); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.invokeMap'); - - (function() { - QUnit.test('should not accept an `args` param', function(assert) { - assert.expect(1); - - var actual = fp.invokeMap('toUpperCase')(['a', 'b']); - assert.deepEqual(actual, ['A', 'B']); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.invokeArgs'); - - (function() { - QUnit.test('should accept an `args` param', function(assert) { - assert.expect(1); - - var actual = fp.invokeArgs('concat')(['b', 'c'])('a'); - assert.strictEqual(actual, 'abc'); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.invokeArgsMap'); - - (function() { - QUnit.test('should accept an `args` param', function(assert) { - assert.expect(1); - - var actual = fp.invokeArgsMap('concat')(['b', 'c'])(['a', 'A']); - assert.deepEqual(actual, ['abc', 'Abc']); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.isEqualWith'); - - (function() { - QUnit.test('should provide the correct `customizer` arguments', function(assert) { - assert.expect(1); - - var args, - iteration = 0, - objects = [{ 'a': 1 }, { 'a': 2 }], - stack = { '__data__': { '__data__': [objects, objects.slice().reverse()] } }, - expected = [1, 2, 'a', objects[0], objects[1], stack]; - - fp.isEqualWith(function() { - if (++iteration == 2) { - args = _.map(arguments, _.cloneDeep); - } - })(objects[0])(objects[1]); - - args[5] = _.omitBy(args[5], _.isFunction); - args[5].__data__ = _.omitBy(args[5].__data__, _.isFunction); - - assert.deepEqual(args, expected); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.isMatchWith'); - - (function() { - QUnit.test('should provide the correct `customizer` arguments', function(assert) { - assert.expect(1); - - var args, - objects = [{ 'a': 1 }, { 'a': 2 }], - stack = { '__data__': { '__data__': [] } }, - expected = [2, 1, 'a', objects[1], objects[0], stack]; - - fp.isMatchWith(function() { - args || (args = _.map(arguments, _.cloneDeep)); - })(objects[0])(objects[1]); - - args[5] = _.omitBy(args[5], _.isFunction); - args[5].__data__ = _.omitBy(args[5].__data__, _.isFunction); - - assert.deepEqual(args, expected); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.iteratee'); - - (function() { - QUnit.test('should return a iteratee with capped params', function(assert) { - assert.expect(1); - - var func = fp.iteratee(function(a, b, c) { return [a, b, c]; }, 3); - assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]); - }); - - QUnit.test('should convert by name', function(assert) { - assert.expect(1); - - var iteratee = convert('iteratee', _.iteratee), - func = iteratee(function(a, b, c) { return [a, b, c]; }, 3); - - assert.deepEqual(func(1, 2, 3), [1, undefined, undefined]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.lt and fp.lte'); - - _.each(['lt', 'lte'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should have `rearg` applied', function(assert) { - assert.expect(1); - - assert.strictEqual(func(1)(2), true); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.mapKeys'); - - (function() { - QUnit.test('should only provide `key` to `iteratee`', function(assert) { - assert.expect(1); - - var args; - - fp.mapKeys(function() { - args || (args = slice.call(arguments)); - }, { 'a': 1 }); - - assert.deepEqual(args, ['a']); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.maxBy and fp.minBy'); - - _.each(['maxBy', 'minBy'], function(methodName) { - var array = [1, 2, 3], - func = fp[methodName], - isMax = methodName == 'maxBy'; - - QUnit.test('`fp.' + methodName + '` should work with an `iteratee` argument', function(assert) { - assert.expect(1); - - var actual = func(function(num) { - return -num; - })(array); - - assert.strictEqual(actual, isMax ? 1 : 3); - }); - - QUnit.test('`fp.' + methodName + '` should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); - - var args; - - func(function() { - args || (args = slice.call(arguments)); - })(array); - - assert.deepEqual(args, [1]); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.mergeWith'); - - (function() { - QUnit.test('should provide the correct `customizer` arguments', function(assert) { - assert.expect(1); - - var args, - stack = { '__data__': { '__data__': [] } }, - expected = [[1, 2], [3], 'a', { 'a': [1, 2] }, { 'a': [3] }, stack]; - - fp.mergeWith(function() { - args || (args = _.map(arguments, _.cloneDeep)); - })({ 'a': [1, 2] })({ 'a': [3] }); - - args[5] = _.omitBy(args[5], _.isFunction); - args[5].__data__ = _.omitBy(args[5].__data__, _.isFunction); - - assert.deepEqual(args, expected); - }); - - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var objects = [{ 'a': [1, 2] }, { 'a': [3] }], - actual = fp.mergeWith(_.noop, objects[0], objects[1]); - - assert.deepEqual(objects[0], { 'a': [1, 2] }); - assert.deepEqual(actual, { 'a': [3, 2] }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.mergeAllWith'); - - (function() { - QUnit.test('should provide the correct `customizer` arguments', function(assert) { - assert.expect(1); - - var args, - stack = { '__data__': { '__data__': [] } }, - expected = [[1, 2], [3], 'a', { 'a': [1, 2] }, { 'a': [3] }, stack]; - - fp.mergeAllWith(function() { - args || (args = _.map(arguments, _.cloneDeep)); - })([{ 'a': [1, 2] }, { 'a': [3] }]); - - args[5] = _.omitBy(args[5], _.isFunction); - args[5].__data__ = _.omitBy(args[5].__data__, _.isFunction); - - assert.deepEqual(args, expected); - }); - - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var objects = [{ 'a': [1, 2] }, { 'a': [3] }], - actual = fp.mergeAllWith(_.noop, objects); - - assert.deepEqual(objects[0], { 'a': [1, 2] }); - assert.deepEqual(actual, { 'a': [3, 2] }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.mixin'); - - (function() { - var source = { 'a': _.noop }; - - QUnit.test('should mixin static methods but not prototype methods', function(assert) { - assert.expect(2); - - fp.mixin(source); - - assert.strictEqual(typeof fp.a, 'function'); - assert.notOk('a' in fp.prototype); - - delete fp.a; - delete fp.prototype.a; - }); - - QUnit.test('should not assign inherited `source` methods', function(assert) { - assert.expect(2); - - function Foo() {} - Foo.prototype.a = _.noop; - fp.mixin(new Foo); - - assert.notOk('a' in fp); - assert.notOk('a' in fp.prototype); - - delete fp.a; - delete fp.prototype.a; - }); - - QUnit.test('should not remove existing prototype methods', function(assert) { - assert.expect(2); - - var each1 = fp.each, - each2 = fp.prototype.each; - - fp.mixin({ 'each': source.a }); - - assert.strictEqual(fp.each, source.a); - assert.strictEqual(fp.prototype.each, each2); - - fp.each = each1; - fp.prototype.each = each2; - }); - - QUnit.test('should not export to the global when `source` is not an object', function(assert) { - assert.expect(2); - - var props = _.without(_.keys(_), '_'); - - _.times(2, function(index) { - fp.mixin.apply(fp, index ? [1] : []); - - assert.ok(_.every(props, function(key) { - return root[key] !== fp[key]; - })); - - _.each(props, function(key) { - if (root[key] === fp[key]) { - delete root[key]; - } - }); - }); - }); - - QUnit.test('should convert by name', function(assert) { - assert.expect(3); - - var object = { 'mixin': convert('mixin', _.mixin) }; - - function Foo() {} - Foo.mixin = object.mixin; - Foo.mixin(source); - - assert.ok('a' in Foo); - assert.notOk('a' in Foo.prototype); - - object.mixin(source); - assert.ok('a' in object); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.nthArg'); - - (function() { - QUnit.test('should return a curried function', function(assert) { - assert.expect(2); - - var func = fp.nthArg(1); - assert.strictEqual(func(1)(2), 2); - - func = fp.nthArg(-1); - assert.strictEqual(func(1), 1); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.over'); - - (function() { - QUnit.test('should not cap iteratee args', function(assert) { - assert.expect(2); - - _.each([fp.over, convert('over', _.over)], function(func) { - var over = func([Math.max, Math.min]); - assert.deepEqual(over(1, 2, 3, 4), [4, 1]); - }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.omitBy and fp.pickBy'); - - _.each(['omitBy', 'pickBy'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should provide `value` and `key` to `iteratee`', function(assert) { - assert.expect(1); - - var args; - - func(function() { - args || (args = slice.call(arguments)); - })({ 'a': 1 }); - - assert.deepEqual(args, [1, 'a']); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('padChars methods'); - - _.each(['padChars', 'padCharsStart', 'padCharsEnd'], function(methodName) { - var func = fp[methodName], - isPad = methodName == 'padChars', - isStart = methodName == 'padCharsStart'; - - QUnit.test('`_.' + methodName + '` should truncate pad characters to fit the pad length', function(assert) { - assert.expect(1); - - if (isPad) { - assert.strictEqual(func('_-')(8)('abc'), '_-abc_-_'); - } else { - assert.strictEqual(func('_-')(6)('abc'), isStart ? '_-_abc' : 'abc_-_'); - } - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('partial methods'); - - _.each(['partial', 'partialRight'], function(methodName) { - var func = fp[methodName], - isPartial = methodName == 'partial'; - - QUnit.test('`_.' + methodName + '` should accept an `args` param', function(assert) { - assert.expect(1); - - var expected = isPartial ? [1, 2, 3] : [0, 1, 2]; - - var actual = func(function(a, b, c) { - return [a, b, c]; - })([1, 2])(isPartial ? 3 : 0); - - assert.deepEqual(actual, expected); - }); - - QUnit.test('`_.' + methodName + '` should convert by name', function(assert) { - assert.expect(2); - - var expected = isPartial ? [1, 2, 3] : [0, 1, 2], - par = convert(methodName, _[methodName]), - ph = par.placeholder; - - var actual = par(function(a, b, c) { - return [a, b, c]; - })([1, 2])(isPartial ? 3 : 0); - - assert.deepEqual(actual, expected); - - actual = par(function(a, b, c) { - return [a, b, c]; - })([ph, 2])(isPartial ? 1 : 0, isPartial ? 3 : 1); - - assert.deepEqual(actual, expected); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.propertyOf'); - - (function() { - QUnit.test('should be curried', function(assert) { - assert.expect(2); - - var object = { 'a': 1 }; - - assert.strictEqual(fp.propertyOf(object, 'a'), 1); - assert.strictEqual(fp.propertyOf(object)('a'), 1); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.pull'); - - (function() { - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var array = [1, 2, 3], - actual = fp.pull(2)(array); - - assert.deepEqual(array, [1, 2, 3]); - assert.deepEqual(actual, [1, 3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.pullAll'); - - (function() { - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var array = [1, 2, 3], - actual = fp.pullAll([1, 3])(array); - - assert.deepEqual(array, [1, 2, 3]); - assert.deepEqual(actual, [2]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.pullAt'); - - (function() { - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var array = [1, 2, 3], - actual = fp.pullAt([0, 2])(array); - - assert.deepEqual(array, [1, 2, 3]); - assert.deepEqual(actual, [2]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.random'); - - (function() { - var array = Array(1000); - - QUnit.test('should support a `min` and `max` argument', function(assert) { - assert.expect(1); - - var min = 5, - max = 10; - - assert.ok(_.some(array, function() { - var result = fp.random(min)(max); - return result >= min && result <= max; - })); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.range'); - - (function() { - QUnit.test('should have an argument order of `start` then `end`', function(assert) { - assert.expect(1); - - assert.deepEqual(fp.range(1)(4), [1, 2, 3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.rearg'); - - (function() { - function fn(a, b, c) { - return [a, b, c]; - } - - QUnit.test('should be curried', function(assert) { - assert.expect(1); - - var rearged = fp.rearg([1, 2, 0])(fn); - assert.deepEqual(rearged('c', 'a', 'b'), ['a', 'b', 'c']); - }); - - QUnit.test('should return a curried function', function(assert) { - assert.expect(1); - - var rearged = fp.rearg([1, 2, 0], fn); - assert.deepEqual(rearged('c')('a')('b'), ['a', 'b', 'c']); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('reduce methods'); - - _.each(['reduce', 'reduceRight'], function(methodName) { - var func = fp[methodName], - isReduce = methodName == 'reduce'; - - QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an array', function(assert) { - assert.expect(1); - - var args; - - func(function() { - args || (args = slice.call(arguments)); - })(0)([1, 2, 3]); - - assert.deepEqual(args, isReduce ? [0, 1] : [0, 3]); - }); - - QUnit.test('`_.' + methodName + '` should provide the correct `iteratee` arguments when iterating an object', function(assert) { - assert.expect(1); - - var args, - object = { 'a': 1, 'b': 2 }, - isFIFO = _.keys(object)[0] == 'a'; - - var expected = isFIFO - ? (isReduce ? [0, 1] : [0, 2]) - : (isReduce ? [0, 2] : [0, 1]); - - func(function() { - args || (args = slice.call(arguments)); - })(0)(object); - - assert.deepEqual(args, expected); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.remove'); - - (function() { - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var array = [1, 2, 3], - actual = fp.remove(fp.eq(2))(array); - - assert.deepEqual(array, [1, 2, 3]); - assert.deepEqual(actual, [1, 3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.restFrom'); - - (function() { - QUnit.test('should accept a `start` param', function(assert) { - assert.expect(1); - - var actual = fp.restFrom(2)(function() { - return slice.call(arguments); - })('a', 'b', 'c', 'd'); - - assert.deepEqual(actual, ['a', 'b', ['c', 'd']]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.reverse'); - - (function() { - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var array = [1, 2, 3], - actual = fp.reverse(array); - - assert.deepEqual(array, [1, 2, 3]); - assert.deepEqual(actual, [3, 2, 1]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.runInContext'); - - (function() { - QUnit.test('should return a converted lodash instance', function(assert) { - assert.expect(1); - - assert.strictEqual(typeof fp.runInContext({}).curryN, 'function'); - }); - - QUnit.test('should convert by name', function(assert) { - assert.expect(1); - - var runInContext = convert('runInContext', _.runInContext); - assert.strictEqual(typeof runInContext({}).curryN, 'function'); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.set'); - - (function() { - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var object = { 'a': { 'b': 2, 'c': 3 } }, - actual = fp.set('a.b')(3)(object); - - assert.deepEqual(object, { 'a': { 'b': 2, 'c': 3 } }); - assert.deepEqual(actual, { 'a': { 'b': 3, 'c': 3 } }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.setWith'); - - (function() { - QUnit.test('should provide the correct `customizer` arguments', function(assert) { - assert.expect(1); - - var args; - - fp.setWith(function() { - args || (args = _.map(arguments, _.cloneDeep)); - })('b.c')(2)({ 'a': 1 }); - - assert.deepEqual(args, [undefined, 'b', { 'a': 1 }]); - }); - - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var object = { 'a': { 'b': 2, 'c': 3 } }, - actual = fp.setWith(Object)('d.e')(4)(object); - - assert.deepEqual(object, { 'a': { 'b': 2, 'c': 3 } }); - assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3 }, 'd': { 'e': 4 } }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.spreadFrom'); - - (function() { - QUnit.test('should accept a `start` param', function(assert) { - assert.expect(1); - - var actual = fp.spreadFrom(2)(function() { - return slice.call(arguments); - })('a', 'b', ['c', 'd']); - - assert.deepEqual(actual, ['a', 'b', 'c', 'd']); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('trimChars methods'); - - _.each(['trimChars', 'trimCharsStart', 'trimCharsEnd'], function(methodName, index) { - var func = fp[methodName], - parts = []; - - if (index != 2) { - parts.push('leading'); - } - if (index != 1) { - parts.push('trailing'); - } - parts = parts.join(' and '); - - QUnit.test('`_.' + methodName + '` should remove ' + parts + ' `chars`', function(assert) { - assert.expect(1); - - var string = '-_-a-b-c-_-', - expected = (index == 2 ? '-_-' : '') + 'a-b-c' + (index == 1 ? '-_-' : ''); - - assert.strictEqual(func('_-')(string), expected); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.unionBy'); - - (function() { - QUnit.test('should have an argument order of `iteratee`, `array`, then `other`', function(assert) { - assert.expect(1); - - var actual = fp.unionBy(Math.floor, [2.1], [1.2, 2.3]); - assert.deepEqual(actual, [2.1, 1.2]); - }); - - QUnit.test('should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); - - var args; - - fp.unionBy(function() { - args || (args = slice.call(arguments)); - })([2.1], [1.2, 2.3]); - - assert.deepEqual(args, [2.1]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.unionWith'); - - (function() { - QUnit.test('should have an argument order of `comparator`, `array`, then `values`', function(assert) { - assert.expect(1); - - var actual = fp.unionWith(fp.eq)([2, 1])([2, 3]); - assert.deepEqual(actual, [2, 1, 3]); - }); - - QUnit.test('should provide the correct `comparator` arguments', function(assert) { - assert.expect(1); - - var args; - - fp.unionWith(function() { - args || (args = slice.call(arguments)); - })([2, 1])([2, 3]); - - assert.deepEqual(args, [1, 2]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.uniqBy'); - - (function() { - var objects = [{ 'a': 2 }, { 'a': 3 }, { 'a': 1 }, { 'a': 2 }, { 'a': 3 }, { 'a': 1 }]; - - QUnit.test('should work with an `iteratee` argument', function(assert) { - assert.expect(1); - - var expected = objects.slice(0, 3), - actual = fp.uniqBy(_.property('a'))(objects); - - assert.deepEqual(actual, expected); - }); - - QUnit.test('should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); - - var args; - - fp.uniqBy(function() { - args || (args = slice.call(arguments)); - })(objects); - - assert.deepEqual(args, [objects[0]]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.uniqWith'); - - (function() { - QUnit.test('should have an argument order of `comparator`, `array`, then `values`', function(assert) { - assert.expect(1); - - var actual = fp.uniqWith(fp.eq)([2, 1, 2]); - assert.deepEqual(actual, [2, 1]); - }); - - QUnit.test('should provide the correct `comparator` arguments', function(assert) { - assert.expect(1); - - var args; - - fp.uniqWith(function() { - args || (args = slice.call(arguments)); - })([2, 1, 2]); - - assert.deepEqual(args, [1, 2]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.update'); - - (function() { - QUnit.test('should not convert end of `path` to an object', function(assert) { - assert.expect(1); - - var actual = fp.update('a.b')(_.identity)({ 'a': { 'b': 1 } }); - assert.strictEqual(typeof actual.a.b, 'number'); - }); - - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var object = { 'a': { 'b': 2, 'c': 3 } }, - actual = fp.update('a.b')(square)(object); - - assert.deepEqual(object, { 'a': { 'b': 2, 'c': 3 } }); - assert.deepEqual(actual, { 'a': { 'b': 4, 'c': 3 } }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.updateWith'); - - (function() { - QUnit.test('should provide the correct `customizer` arguments', function(assert) { - var args; - - fp.updateWith(function() { - args || (args = _.map(arguments, _.cloneDeep)); - })('b.c')(_.constant(2))({ 'a': 1 }); - - assert.deepEqual(args, [undefined, 'b', { 'a': 1 }]); - }); - - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var object = { 'a': { 'b': 2, 'c': 3 } }, - actual = fp.updateWith(Object)('d.e')(_.constant(4))(object); - - assert.deepEqual(object, { 'a': { 'b': 2, 'c': 3 } }); - assert.deepEqual(actual, { 'a': { 'b': 2, 'c': 3 }, 'd': { 'e': 4 } }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.unset'); - - (function() { - QUnit.test('should not mutate values', function(assert) { - assert.expect(2); - - var object = { 'a': { 'b': 2, 'c': 3 } }, - actual = fp.unset('a.b')(object); - - assert.deepEqual(object, { 'a': { 'b': 2, 'c': 3 } }); - assert.deepEqual(actual, { 'a': { 'c': 3 } }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.xorBy'); - - (function() { - QUnit.test('should have an argument order of `iteratee`, `array`, then `other`', function(assert) { - assert.expect(1); - - var actual = fp.xorBy(Math.floor, [2.1, 1.2], [2.3, 3.4]); - assert.deepEqual(actual, [1.2, 3.4]); - }); - - QUnit.test('should provide the correct `iteratee` arguments', function(assert) { - assert.expect(1); - - var args; - - fp.xorBy(function() { - args || (args = slice.call(arguments)); - })([2.1, 1.2], [2.3, 3.4]); - - assert.deepEqual(args, [2.3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.xorWith'); - - (function() { - QUnit.test('should have an argument order of `comparator`, `array`, then `values`', function(assert) { - assert.expect(1); - - var actual = fp.xorWith(fp.eq)([2, 1])([2, 3]); - assert.deepEqual(actual, [1, 3]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('with methods'); - - _.each(['differenceWith', 'intersectionWith', 'xorWith'], function(methodName) { - var func = fp[methodName]; - - QUnit.test('`fp.' + methodName + '` should provide the correct `comparator` arguments', function(assert) { - assert.expect(1); - - var args; - - func(function() { - args || (args = slice.call(arguments)); - })([2, 1])([2, 3]); - - assert.deepEqual(args, [2, 2]); - }); - }); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.zip'); - - (function() { - QUnit.test('should zip together two arrays', function(assert) { - assert.expect(1); - - assert.deepEqual(fp.zip([1, 2])([3, 4]), [[1, 3], [2, 4]]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.zipAll'); - - (function() { - QUnit.test('should zip together an array of arrays', function(assert) { - assert.expect(1); - - assert.deepEqual(fp.zipAll([[1, 2], [3, 4], [5, 6]]), [[1, 3, 5], [2, 4, 6]]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.zipObject'); - - (function() { - QUnit.test('should zip together key/value arrays into an object', function(assert) { - assert.expect(1); - - assert.deepEqual(fp.zipObject(['a', 'b'])([1, 2]), { 'a': 1, 'b': 2 }); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.module('fp.zipWith'); - - (function() { - QUnit.test('should zip arrays combining grouped elements with `iteratee`', function(assert) { - assert.expect(1); - - var array1 = [1, 2, 3], - array2 = [4, 5, 6], - actual = fp.zipWith(add)(array1)(array2); - - assert.deepEqual(actual, [5, 7, 9]); - }); - }()); - - /*--------------------------------------------------------------------------*/ - - QUnit.config.asyncRetries = 10; - QUnit.config.hidepassed = true; - - if (!document) { - QUnit.config.noglobals = true; - QUnit.load(); - QUnit.start(); - } -}.call(this)); diff --git a/public/vendor/lodash/test/test.js b/public/vendor/lodash/test/test.js deleted file mode 100644 index decd47a0247..00000000000 --- a/public/vendor/lodash/test/test.js +++ /dev/null @@ -1,26556 +0,0 @@ -;(function() { - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used to detect when a function becomes hot. */ - var HOT_COUNT = 150; - - /** Used as the size to cover large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Used as the `TypeError` message for "Functions" methods. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used as references for various `Number` constants. */ - var MAX_SAFE_INTEGER = 9007199254740991, - MAX_INTEGER = 1.7976931348623157e+308; - - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295, - MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1; - - /** `Object#toString` result references. */ - var funcTag = '[object Function]', - numberTag = '[object Number]', - objectTag = '[object Object]'; - - /** Used as a reference to the global object. */ - var root = (typeof global == 'object' && global) || this; - - /** Used to store lodash to test for bad extensions/shims. */ - var lodashBizarro = root.lodashBizarro; - - /** Used for native method references. */ - var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.prototype, - numberProto = Number.prototype, - stringProto = String.prototype; - - /** Method and object shortcuts. */ - var phantom = root.phantom, - process = root.process, - amd = root.define && define.amd, - argv = process && process.argv, - defineProperty = Object.defineProperty, - document = !phantom && root.document, - body = root.document && root.document.body, - create = Object.create, - fnToString = funcProto.toString, - freeze = Object.freeze, - getSymbols = Object.getOwnPropertySymbols, - identity = function(value) { return value; }, - JSON = root.JSON, - noop = function() {}, - objToString = objectProto.toString, - params = argv, - push = arrayProto.push, - realm = {}, - slice = arrayProto.slice; - - var ArrayBuffer = root.ArrayBuffer, - Buffer = root.Buffer, - Promise = root.Promise, - Map = root.Map, - Set = root.Set, - Symbol = root.Symbol, - Uint8Array = root.Uint8Array, - WeakMap = root.WeakMap, - WeakSet = root.WeakSet; - - var arrayBuffer = ArrayBuffer ? new ArrayBuffer(2) : undefined, - map = Map ? new Map : undefined, - promise = Promise ? Promise.resolve(1) : undefined, - set = Set ? new Set : undefined, - symbol = Symbol ? Symbol('a') : undefined, - weakMap = WeakMap ? new WeakMap : undefined, - weakSet = WeakSet ? new WeakSet : undefined; - - /** Math helpers. */ - var add = function(x, y) { return x + y; }, - doubled = function(n) { return n * 2; }, - isEven = function(n) { return n % 2 == 0; }, - square = function(n) { return n * n; }; - - /** Stub functions. */ - var stubA = function() { return 'a'; }, - stubB = function() { return 'b'; }, - stubC = function() { return 'c'; }; - - var stubTrue = function() { return true; }, - stubFalse = function() { return false; }; - - var stubNaN = function() { return NaN; }, - stubNull = function() { return null; }; - - var stubZero = function() { return 0; }, - stubOne = function() { return 1; }, - stubTwo = function() { return 2; }, - stubThree = function() { return 3; }, - stubFour = function() { return 4; }; - - var stubArray = function() { return []; }, - stubObject = function() { return {}; }, - stubString = function() { return ''; }; - - - - /** List of Latin Unicode letters. */ - var burredLetters = [ - // Latin-1 Supplement letters. - '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', - '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', - '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', - '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', - // Latin Extended-A letters. - '\u0100', '\u0101', '\u0102', '\u0103', '\u0104', '\u0105', '\u0106', '\u0107', '\u0108', '\u0109', '\u010a', '\u010b', '\u010c', '\u010d', '\u010e', '\u010f', - '\u0110', '\u0111', '\u0112', '\u0113', '\u0114', '\u0115', '\u0116', '\u0117', '\u0118', '\u0119', '\u011a', '\u011b', '\u011c', '\u011d', '\u011e', '\u011f', - '\u0120', '\u0121', '\u0122', '\u0123', '\u0124', '\u0125', '\u0126', '\u0127', '\u0128', '\u0129', '\u012a', '\u012b', '\u012c', '\u012d', '\u012e', '\u012f', - '\u0130', '\u0131', '\u0132', '\u0133', '\u0134', '\u0135', '\u0136', '\u0137', '\u0138', '\u0139', '\u013a', '\u013b', '\u013c', '\u013d', '\u013e', '\u013f', - '\u0140', '\u0141', '\u0142', '\u0143', '\u0144', '\u0145', '\u0146', '\u0147', '\u0148', '\u0149', '\u014a', '\u014b', '\u014c', '\u014d', '\u014e', '\u014f', - '\u0150', '\u0151', '\u0152', '\u0153', '\u0154', '\u0155', '\u0156', '\u0157', '\u0158', '\u0159', '\u015a', '\u015b', '\u015c', '\u015d', '\u015e', '\u015f', - '\u0160', '\u0161', '\u0162', '\u0163', '\u0164', '\u0165', '\u0166', '\u0167', '\u0168', '\u0169', '\u016a', '\u016b', '\u016c', '\u016d', '\u016e', '\u016f', - '\u0170', '\u0171', '\u0172', '\u0173', '\u0174', '\u0175', '\u0176', '\u0177', '\u0178', '\u0179', '\u017a', '\u017b', '\u017c', '\u017d', '\u017e', '\u017f' - ]; - - /** List of combining diacritical marks. */ - var comboMarks = [ - '\u0300', '\u0301', '\u0302', '\u0303', '\u0304', '\u0305', '\u0306', '\u0307', '\u0308', '\u0309', '\u030a', '\u030b', '\u030c', '\u030d', '\u030e', '\u030f', - '\u0310', '\u0311', '\u0312', '\u0313', '\u0314', '\u0315', '\u0316', '\u0317', '\u0318', '\u0319', '\u031a', '\u031b', '\u031c', '\u031d', '\u031e', '\u031f', - '\u0320', '\u0321', '\u0322', '\u0323', '\u0324', '\u0325', '\u0326', '\u0327', '\u0328', '\u0329', '\u032a', '\u032b', '\u032c', '\u032d', '\u032e', '\u032f', - '\u0330', '\u0331', '\u0332', '\u0333', '\u0334', '\u0335', '\u0336', '\u0337', '\u0338', '\u0339', '\u033a', '\u033b', '\u033c', '\u033d', '\u033e', '\u033f', - '\u0340', '\u0341', '\u0342', '\u0343', '\u0344', '\u0345', '\u0346', '\u0347', '\u0348', '\u0349', '\u034a', '\u034b', '\u034c', '\u034d', '\u034e', '\u034f', - '\u0350', '\u0351', '\u0352', '\u0353', '\u0354', '\u0355', '\u0356', '\u0357', '\u0358', '\u0359', '\u035a', '\u035b', '\u035c', '\u035d', '\u035e', '\u035f', - '\u0360', '\u0361', '\u0362', '\u0363', '\u0364', '\u0365', '\u0366', '\u0367', '\u0368', '\u0369', '\u036a', '\u036b', '\u036c', '\u036d', '\u036e', '\u036f', - '\ufe20', '\ufe21', '\ufe22', '\ufe23' - ]; - - /** List of converted Latin Unicode letters. */ - var deburredLetters = [ - // Converted Latin-1 Supplement letters. - 'A', 'A', 'A', 'A', 'A', 'A', 'Ae', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', - 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 'Th', - 'ss', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', - 'i', 'd', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'th', 'y', - // Converted Latin Extended-A letters. - 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', - 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', - 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', - 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', - 'K', 'k', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', - 'N', 'n', 'N', 'n', 'N', 'n', "'n", 'N', 'n', - 'O', 'o', 'O', 'o', 'O', 'o', 'Oe', 'oe', - 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', - 'T', 't', 'T', 't', 'T', 't', - 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', - 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 'ss' - ]; - - /** Used to provide falsey values to methods. */ - var falsey = [, null, undefined, false, 0, NaN, '']; - - /** Used to specify the emoji style glyph variant of characters. */ - var emojiVar = '\ufe0f'; - - /** Used to provide empty values to methods. */ - var empties = [[], {}].concat(falsey.slice(1)); - - /** Used to test error objects. */ - var errors = [ - new Error, - new EvalError, - new RangeError, - new ReferenceError, - new SyntaxError, - new TypeError, - new URIError - ]; - - /** List of fitzpatrick modifiers. */ - var fitzModifiers = [ - '\ud83c\udffb', - '\ud83c\udffc', - '\ud83c\udffd', - '\ud83c\udffe', - '\ud83c\udfff' - ]; - - /** Used to provide primitive values to methods. */ - var primitives = [null, undefined, false, true, 1, NaN, 'a']; - - /** Used to check whether methods support typed arrays. */ - var typedArrays = [ - 'Float32Array', - 'Float64Array', - 'Int8Array', - 'Int16Array', - 'Int32Array', - 'Uint8Array', - 'Uint8ClampedArray', - 'Uint16Array', - 'Uint32Array' - ]; - - /** Used to check whether methods support array views. */ - var arrayViews = typedArrays.concat('DataView'); - - /** The file path of the lodash file to test. */ - var filePath = (function() { - var min = 2, - result = params || []; - - if (phantom) { - min = 0; - result = params = phantom.args || require('system').args; - } - var last = result[result.length - 1]; - result = (result.length > min && !/test(?:\.js)?$/.test(last)) ? last : '../lodash.js'; - - if (!amd) { - try { - result = require('fs').realpathSync(result); - } catch (e) {} - - try { - result = require.resolve(result); - } catch (e) {} - } - return result; - }()); - - /** The `ui` object. */ - var ui = root.ui || (root.ui = { - 'buildPath': filePath, - 'loaderPath': '', - 'isModularize': /\b(?:amd|commonjs|es|node|npm|(index|main)\.js)\b/.test(filePath), - 'isStrict': /\bes\b/.test(filePath) || 'default' in require(filePath), - 'urlParams': {} - }); - - /** The basename of the lodash file to test. */ - var basename = /[\w.-]+$/.exec(filePath)[0]; - - /** Used to indicate testing a modularized build. */ - var isModularize = ui.isModularize; - - /** Detect if testing `npm` modules. */ - var isNpm = isModularize && /\bnpm\b/.test([ui.buildPath, ui.urlParams.build]); - - /** Detect if running in PhantomJS. */ - var isPhantom = phantom || (typeof callPhantom == 'function'); - - /** Detect if lodash is in strict mode. */ - var isStrict = ui.isStrict; - - /*--------------------------------------------------------------------------*/ - - // Leak to avoid sporadic `noglobals` fails on Edge in Sauce Labs. - root.msWDfn = undefined; - - // Assign `setTimeout` to itself to avoid being flagged as a leak. - setProperty(root, 'setTimeout', setTimeout); - - // Exit early if going to run tests in a PhantomJS web page. - if (phantom && isModularize) { - var page = require('webpage').create(); - - page.onCallback = function(details) { - var coverage = details.coverage; - if (coverage) { - var fs = require('fs'), - cwd = fs.workingDirectory, - sep = fs.separator; - - fs.write([cwd, 'coverage', 'coverage.json'].join(sep), JSON.stringify(coverage)); - } - phantom.exit(details.failed ? 1 : 0); - }; - - page.onConsoleMessage = function(message) { - console.log(message); - }; - - page.onInitialized = function() { - page.evaluate(function() { - document.addEventListener('DOMContentLoaded', function() { - QUnit.done(function(details) { - details.coverage = window.__coverage__; - callPhantom(details); - }); - }); - }); - }; - - page.open(filePath, function(status) { - if (status != 'success') { - console.log('PhantomJS failed to load page: ' + filePath); - phantom.exit(1); - } - }); - - console.log('test.js invoked with arguments: ' + JSON.stringify(slice.call(params))); - return; - } - - /*--------------------------------------------------------------------------*/ - - /** Used to test Web Workers. */ - var Worker = !(ui.isForeign || ui.isSauceLabs || isModularize) && - (document && document.origin != 'null') && root.Worker; - - /** Used to test host objects in IE. */ - try { - var xml = new ActiveXObject('Microsoft.XMLDOM'); - } catch (e) {} - - /** Poison the free variable `root` in Node.js */ - try { - defineProperty(global.root, 'root', { - 'configurable': false, - 'enumerable': false, - 'get': function() { throw new ReferenceError; } - }); - } catch (e) {} - - /** Load QUnit and extras. */ - var QUnit = root.QUnit || require('qunit-extras'); - - /** Load stable Lodash. */ - var lodashStable = root.lodashStable; - if (!lodashStable) { - try { - lodashStable = interopRequire('../node_modules/lodash/lodash.js'); - } catch (e) { - console.log('Error: The stable lodash dev dependency should be at least a version behind master branch.'); - return; - } - lodashStable = lodashStable.noConflict(); - } - - /** The `lodash` function to test. */ - var _ = root._ || (root._ = interopRequire(filePath)); - - /** Used to test pseudo private map caches. */ - var mapCaches = (function() { - var MapCache = _.memoize.Cache; - var result = { - 'Hash': new MapCache().__data__.hash.constructor, - 'MapCache': MapCache - }; - _.isMatchWith({ 'a': 1 }, { 'a': 1 }, function() { - var stack = lodashStable.last(arguments); - result.ListCache = stack.__data__.constructor; - result.Stack = stack.constructor; - }); - return result; - }()); - - /** Used to detect instrumented istanbul code coverage runs. */ - var coverage = root.__coverage__ || root[lodashStable.find(lodashStable.keys(root), function(key) { - return /^(?:\$\$cov_\d+\$\$)$/.test(key); - })]; - - /** Used to test generator functions. */ - var generator = lodashStable.attempt(function() { - return Function('return function*(){}'); - }); - - /** Used to restore the `_` reference. */ - var oldDash = root._; - - /** - * Used to check for problems removing whitespace. For a whitespace reference, - * see [V8's unit test](https://code.google.com/p/v8/source/browse/branches/bleeding_edge/test/mjsunit/whitespaces.js). - */ - var whitespace = lodashStable.filter([ - // Basic whitespace characters. - ' ', '\t', '\x0b', '\f', '\xa0', '\ufeff', - - // Line terminators. - '\n', '\r', '\u2028', '\u2029', - - // Unicode category "Zs" space separators. - '\u1680', '\u180e', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', - '\u2006', '\u2007', '\u2008', '\u2009', '\u200a', '\u202f', '\u205f', '\u3000' - ], - function(chr) { return /\s/.exec(chr); }) - .join(''); - - /** - * Creates a custom error object. - * - * @private - * @constructor - * @param {string} message The error message. - */ - function CustomError(message) { - this.name = 'CustomError'; - this.message = message; - } - - CustomError.prototype = lodashStable.create(Error.prototype, { - 'constructor': CustomError - }); - - /** - * Removes all own enumerable string keyed properties from a given object. - * - * @private - * @param {Object} object The object to empty. - */ - function emptyObject(object) { - lodashStable.forOwn(object, function(value, key, object) { - delete object[key]; - }); - } - - /** - * Extracts the unwrapped value from its wrapper. - * - * @private - * @param {Object} wrapper The wrapper to unwrap. - * @returns {*} Returns the unwrapped value. - */ - function getUnwrappedValue(wrapper) { - var index = -1, - actions = wrapper.__actions__, - length = actions.length, - result = wrapper.__wrapped__; - - while (++index < length) { - var args = [result], - action = actions[index]; - - push.apply(args, action.args); - result = action.func.apply(action.thisArg, args); - } - return result; - } - - /** - * Loads the module of `id`. If the module has an `exports.default`, the - * exported default value is returned as the resolved module. - * - * @private - * @param {string} id The identifier of the module to resolve. - * @returns {*} Returns the resolved module. - */ - function interopRequire(id) { - var result = require(id); - return 'default' in result ? result['default'] : result; - } - - /** - * Sets a non-enumerable property value on `object`. - * - * Note: This function is used to avoid a bug in older versions of V8 where - * overwriting non-enumerable built-ins makes them enumerable. - * See https://code.google.com/p/v8/issues/detail?id=1623 - * - * @private - * @param {Object} object The object modify. - * @param {string} key The name of the property to set. - * @param {*} value The property value. - */ - function setProperty(object, key, value) { - try { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': false, - 'writable': true, - 'value': value - }); - } catch (e) { - object[key] = value; - } - return object; - } - - /** - * Skips a given number of tests with a passing result. - * - * @private - * @param {Object} assert The QUnit assert object. - * @param {number} [count=1] The number of tests to skip. - */ - function skipAssert(assert, count) { - count || (count = 1); - while (count--) { - assert.ok(true, 'test skipped'); - } - } - - /*--------------------------------------------------------------------------*/ - - // Add bizarro values. - (function() { - if (document || (typeof require != 'function')) { - return; - } - var nativeString = fnToString.call(toString), - reToString = /toString/g; - - function createToString(funcName) { - return lodashStable.constant(nativeString.replace(reToString, funcName)); - } - - // Allow bypassing native checks. - setProperty(funcProto, 'toString', function wrapper() { - setProperty(funcProto, 'toString', fnToString); - var result = lodashStable.has(this, 'toString') ? this.toString() : fnToString.call(this); - setProperty(funcProto, 'toString', wrapper); - return result; - }); - - // Add prototype extensions. - funcProto._method = noop; - - // Set bad shims. - setProperty(Object, 'create', (function() { - function object() {} - return function(prototype) { - if (lodashStable.isObject(prototype)) { - object.prototype = prototype; - var result = new object; - object.prototype = undefined; - } - return result || {}; - }; - }())); - - setProperty(Object, 'getOwnPropertySymbols', undefined); - - var _propertyIsEnumerable = objectProto.propertyIsEnumerable; - setProperty(objectProto, 'propertyIsEnumerable', function(key) { - return !(key == 'valueOf' && this && this.valueOf === 1) && _propertyIsEnumerable.call(this, key); - }); - - if (Buffer) { - defineProperty(root, 'Buffer', { - 'configurable': true, - 'enumerable': true, - 'get': function get() { - var caller = get.caller, - name = caller ? caller.name : ''; - - if (!(name == 'runInContext' || name.length == 1 || /\b_\.isBuffer\b/.test(caller))) { - return Buffer; - } - } - }); - } - if (Map) { - setProperty(root, 'Map', (function() { - var count = 0; - return function() { - if (count++) { - return new Map; - } - setProperty(root, 'Map', Map); - return {}; - }; - }())); - - setProperty(root.Map, 'toString', createToString('Map')); - } - setProperty(root, 'Promise', noop); - setProperty(root, 'Set', noop); - setProperty(root, 'Symbol', undefined); - setProperty(root, 'WeakMap', noop); - - // Fake `WinRTError`. - setProperty(root, 'WinRTError', Error); - - // Clear cache so lodash can be reloaded. - emptyObject(require.cache); - - // Load lodash and expose it to the bad extensions/shims. - lodashBizarro = interopRequire(filePath); - root._ = oldDash; - - // Restore built-in methods. - setProperty(Object, 'create', create); - setProperty(objectProto, 'propertyIsEnumerable', _propertyIsEnumerable); - setProperty(root, 'Buffer', Buffer); - - if (getSymbols) { - Object.getOwnPropertySymbols = getSymbols; - } else { - delete Object.getOwnPropertySymbols; - } - if (Map) { - setProperty(root, 'Map', Map); - } else { - delete root.Map; - } - if (Promise) { - setProperty(root, 'Promise', Promise); - } else { - delete root.Promise; - } - if (Set) { - setProperty(root, 'Set', Set); - } else { - delete root.Set; - } - if (Symbol) { - setProperty(root, 'Symbol', Symbol); - } else { - delete root.Symbol; - } - if (WeakMap) { - setProperty(root, 'WeakMap', WeakMap); - } else { - delete root.WeakMap; - } - delete root.WinRTError; - delete funcProto._method; - }()); - - // Add other realm values from the `vm` module. - lodashStable.attempt(function() { - lodashStable.assign(realm, require('vm').runInNewContext([ - '(function() {', - ' var noop = function() {},', - ' root = this;', - '', - ' var object = {', - " 'ArrayBuffer': root.ArrayBuffer,", - " 'arguments': (function() { return arguments; }(1, 2, 3)),", - " 'array': [1],", - " 'arrayBuffer': root.ArrayBuffer ? new root.ArrayBuffer : undefined,", - " 'boolean': Object(false),", - " 'date': new Date,", - " 'errors': [new Error, new EvalError, new RangeError, new ReferenceError, new SyntaxError, new TypeError, new URIError],", - " 'function': noop,", - " 'map': root.Map ? new root.Map : undefined,", - " 'nan': NaN,", - " 'null': null,", - " 'number': Object(0),", - " 'object': { 'a': 1 },", - " 'promise': root.Promise ? Promise.resolve(1) : undefined,", - " 'regexp': /x/,", - " 'set': root.Set ? new root.Set : undefined,", - " 'string': Object('a'),", - " 'symbol': root.Symbol ? root.Symbol() : undefined,", - " 'undefined': undefined,", - " 'weakMap': root.WeakMap ? new root.WeakMap : undefined,", - " 'weakSet': root.WeakSet ? new root.WeakSet : undefined", - ' };', - '', - " ['" + arrayViews.join("', '") + "'].forEach(function(type) {", - ' var Ctor = root[type]', - ' object[type] = Ctor;', - ' object[type.toLowerCase()] = Ctor ? new Ctor(new ArrayBuffer(24)) : undefined;', - ' });', - '', - ' return object;', - '}())' - ].join('\n'))); - }); - - // Add other realm values from an iframe. - lodashStable.attempt(function() { - _._realm = realm; - - var iframe = document.createElement('iframe'); - iframe.frameBorder = iframe.height = iframe.width = 0; - body.appendChild(iframe); - - var idoc = (idoc = iframe.contentDocument || iframe.contentWindow).document || idoc; - idoc.write([ - ' - - - - - - - - - - - diff --git a/public/vendor/lodash/vendor/backbone/LICENSE b/public/vendor/lodash/vendor/backbone/LICENSE deleted file mode 100644 index 02c89b26081..00000000000 --- a/public/vendor/lodash/vendor/backbone/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2010-2016 Jeremy Ashkenas, DocumentCloud - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/public/vendor/lodash/vendor/backbone/backbone.js b/public/vendor/lodash/vendor/backbone/backbone.js deleted file mode 100644 index 02722ac8110..00000000000 --- a/public/vendor/lodash/vendor/backbone/backbone.js +++ /dev/null @@ -1,1946 +0,0 @@ -// Backbone.js 1.3.3 - -// (c) 2010-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors -// Backbone may be freely distributed under the MIT license. -// For all details and documentation: -// http://backbonejs.org - -(function(factory) { - - // Establish the root object, `window` (`self`) in the browser, or `global` on the server. - // We use `self` instead of `window` for `WebWorker` support. - var root = (typeof self == 'object' && self.self === self && self) || - (typeof global == 'object' && global.global === global && global); - - // Set up Backbone appropriately for the environment. Start with AMD. - if (typeof define === 'function' && define.amd) { - define(['underscore', 'jquery', 'exports'], function(_, $, exports) { - // Export global even in AMD case in case this script is loaded with - // others that may still expect a global Backbone. - root.Backbone = factory(root, exports, _, $); - }); - - // Next for Node.js or CommonJS. jQuery may not be needed as a module. - } else if (typeof exports !== 'undefined') { - var _ = require('underscore'), $; - try { $ = require('jquery'); } catch (e) {} - factory(root, exports, _, $); - - // Finally, as a browser global. - } else { - root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); - } - -})(function(root, Backbone, _, $) { - - // Initial Setup - // ------------- - - // Save the previous value of the `Backbone` variable, so that it can be - // restored later on, if `noConflict` is used. - var previousBackbone = root.Backbone; - - // Create a local reference to a common array method we'll want to use later. - var slice = Array.prototype.slice; - - // Current version of the library. Keep in sync with `package.json`. - Backbone.VERSION = '1.3.3'; - - // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns - // the `$` variable. - Backbone.$ = $; - - // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable - // to its previous owner. Returns a reference to this Backbone object. - Backbone.noConflict = function() { - root.Backbone = previousBackbone; - return this; - }; - - // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option - // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and - // set a `X-Http-Method-Override` header. - Backbone.emulateHTTP = false; - - // Turn on `emulateJSON` to support legacy servers that can't deal with direct - // `application/json` requests ... this will encode the body as - // `application/x-www-form-urlencoded` instead and will send the model in a - // form param named `model`. - Backbone.emulateJSON = false; - - // Proxy Backbone class methods to Underscore functions, wrapping the model's - // `attributes` object or collection's `models` array behind the scenes. - // - // collection.filter(function(model) { return model.get('age') > 10 }); - // collection.each(this.addView); - // - // `Function#apply` can be slow so we use the method's arg count, if we know it. - var addMethod = function(length, method, attribute) { - switch (length) { - case 1: return function() { - return _[method](this[attribute]); - }; - case 2: return function(value) { - return _[method](this[attribute], value); - }; - case 3: return function(iteratee, context) { - return _[method](this[attribute], cb(iteratee, this), context); - }; - case 4: return function(iteratee, defaultVal, context) { - return _[method](this[attribute], cb(iteratee, this), defaultVal, context); - }; - default: return function() { - var args = slice.call(arguments); - args.unshift(this[attribute]); - return _[method].apply(_, args); - }; - } - }; - var addUnderscoreMethods = function(Class, methods, attribute) { - _.each(methods, function(length, method) { - if (_[method]) Class.prototype[method] = addMethod(length, method, attribute); - }); - }; - - // Support `collection.sortBy('attr')` and `collection.findWhere({id: 1})`. - var cb = function(iteratee, instance) { - if (_.isFunction(iteratee)) return iteratee; - if (_.isObject(iteratee) && !instance._isModel(iteratee)) return modelMatcher(iteratee); - if (_.isString(iteratee)) return function(model) { return model.get(iteratee); }; - return iteratee; - }; - var modelMatcher = function(attrs) { - var matcher = _.matches(attrs); - return function(model) { - return matcher(model.attributes); - }; - }; - - // Backbone.Events - // --------------- - - // A module that can be mixed in to *any object* in order to provide it with - // a custom event channel. You may bind a callback to an event with `on` or - // remove with `off`; `trigger`-ing an event fires all callbacks in - // succession. - // - // var object = {}; - // _.extend(object, Backbone.Events); - // object.on('expand', function(){ alert('expanded'); }); - // object.trigger('expand'); - // - var Events = Backbone.Events = {}; - - // Regular expression used to split event strings. - var eventSplitter = /\s+/; - - // Iterates over the standard `event, callback` (as well as the fancy multiple - // space-separated events `"change blur", callback` and jQuery-style event - // maps `{event: callback}`). - var eventsApi = function(iteratee, events, name, callback, opts) { - var i = 0, names; - if (name && typeof name === 'object') { - // Handle event maps. - if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback; - for (names = _.keys(name); i < names.length ; i++) { - events = eventsApi(iteratee, events, names[i], name[names[i]], opts); - } - } else if (name && eventSplitter.test(name)) { - // Handle space-separated event names by delegating them individually. - for (names = name.split(eventSplitter); i < names.length; i++) { - events = iteratee(events, names[i], callback, opts); - } - } else { - // Finally, standard events. - events = iteratee(events, name, callback, opts); - } - return events; - }; - - // Bind an event to a `callback` function. Passing `"all"` will bind - // the callback to all events fired. - Events.on = function(name, callback, context) { - return internalOn(this, name, callback, context); - }; - - // Guard the `listening` argument from the public API. - var internalOn = function(obj, name, callback, context, listening) { - obj._events = eventsApi(onApi, obj._events || {}, name, callback, { - context: context, - ctx: obj, - listening: listening - }); - - if (listening) { - var listeners = obj._listeners || (obj._listeners = {}); - listeners[listening.id] = listening; - } - - return obj; - }; - - // Inversion-of-control versions of `on`. Tell *this* object to listen to - // an event in another object... keeping track of what it's listening to - // for easier unbinding later. - Events.listenTo = function(obj, name, callback) { - if (!obj) return this; - var id = obj._listenId || (obj._listenId = _.uniqueId('l')); - var listeningTo = this._listeningTo || (this._listeningTo = {}); - var listening = listeningTo[id]; - - // This object is not listening to any other events on `obj` yet. - // Setup the necessary references to track the listening callbacks. - if (!listening) { - var thisId = this._listenId || (this._listenId = _.uniqueId('l')); - listening = listeningTo[id] = {obj: obj, objId: id, id: thisId, listeningTo: listeningTo, count: 0}; - } - - // Bind callbacks on obj, and keep track of them on listening. - internalOn(obj, name, callback, this, listening); - return this; - }; - - // The reducing API that adds a callback to the `events` object. - var onApi = function(events, name, callback, options) { - if (callback) { - var handlers = events[name] || (events[name] = []); - var context = options.context, ctx = options.ctx, listening = options.listening; - if (listening) listening.count++; - - handlers.push({callback: callback, context: context, ctx: context || ctx, listening: listening}); - } - return events; - }; - - // Remove one or many callbacks. If `context` is null, removes all - // callbacks with that function. If `callback` is null, removes all - // callbacks for the event. If `name` is null, removes all bound - // callbacks for all events. - Events.off = function(name, callback, context) { - if (!this._events) return this; - this._events = eventsApi(offApi, this._events, name, callback, { - context: context, - listeners: this._listeners - }); - return this; - }; - - // Tell this object to stop listening to either specific events ... or - // to every object it's currently listening to. - Events.stopListening = function(obj, name, callback) { - var listeningTo = this._listeningTo; - if (!listeningTo) return this; - - var ids = obj ? [obj._listenId] : _.keys(listeningTo); - - for (var i = 0; i < ids.length; i++) { - var listening = listeningTo[ids[i]]; - - // If listening doesn't exist, this object is not currently - // listening to obj. Break out early. - if (!listening) break; - - listening.obj.off(name, callback, this); - } - - return this; - }; - - // The reducing API that removes a callback from the `events` object. - var offApi = function(events, name, callback, options) { - if (!events) return; - - var i = 0, listening; - var context = options.context, listeners = options.listeners; - - // Delete all events listeners and "drop" events. - if (!name && !callback && !context) { - var ids = _.keys(listeners); - for (; i < ids.length; i++) { - listening = listeners[ids[i]]; - delete listeners[listening.id]; - delete listening.listeningTo[listening.objId]; - } - return; - } - - var names = name ? [name] : _.keys(events); - for (; i < names.length; i++) { - name = names[i]; - var handlers = events[name]; - - // Bail out if there are no events stored. - if (!handlers) break; - - // Replace events if there are any remaining. Otherwise, clean up. - var remaining = []; - for (var j = 0; j < handlers.length; j++) { - var handler = handlers[j]; - if ( - callback && callback !== handler.callback && - callback !== handler.callback._callback || - context && context !== handler.context - ) { - remaining.push(handler); - } else { - listening = handler.listening; - if (listening && --listening.count === 0) { - delete listeners[listening.id]; - delete listening.listeningTo[listening.objId]; - } - } - } - - // Update tail event if the list has any events. Otherwise, clean up. - if (remaining.length) { - events[name] = remaining; - } else { - delete events[name]; - } - } - return events; - }; - - // Bind an event to only be triggered a single time. After the first time - // the callback is invoked, its listener will be removed. If multiple events - // are passed in using the space-separated syntax, the handler will fire - // once for each event, not once for a combination of all events. - Events.once = function(name, callback, context) { - // Map the event into a `{event: once}` object. - var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this)); - if (typeof name === 'string' && context == null) callback = void 0; - return this.on(events, callback, context); - }; - - // Inversion-of-control versions of `once`. - Events.listenToOnce = function(obj, name, callback) { - // Map the event into a `{event: once}` object. - var events = eventsApi(onceMap, {}, name, callback, _.bind(this.stopListening, this, obj)); - return this.listenTo(obj, events); - }; - - // Reduces the event callbacks into a map of `{event: onceWrapper}`. - // `offer` unbinds the `onceWrapper` after it has been called. - var onceMap = function(map, name, callback, offer) { - if (callback) { - var once = map[name] = _.once(function() { - offer(name, once); - callback.apply(this, arguments); - }); - once._callback = callback; - } - return map; - }; - - // Trigger one or many events, firing all bound callbacks. Callbacks are - // passed the same arguments as `trigger` is, apart from the event name - // (unless you're listening on `"all"`, which will cause your callback to - // receive the true name of the event as the first argument). - Events.trigger = function(name) { - if (!this._events) return this; - - var length = Math.max(0, arguments.length - 1); - var args = Array(length); - for (var i = 0; i < length; i++) args[i] = arguments[i + 1]; - - eventsApi(triggerApi, this._events, name, void 0, args); - return this; - }; - - // Handles triggering the appropriate event callbacks. - var triggerApi = function(objEvents, name, callback, args) { - if (objEvents) { - var events = objEvents[name]; - var allEvents = objEvents.all; - if (events && allEvents) allEvents = allEvents.slice(); - if (events) triggerEvents(events, args); - if (allEvents) triggerEvents(allEvents, [name].concat(args)); - } - return objEvents; - }; - - // A difficult-to-believe, but optimized internal dispatch function for - // triggering events. Tries to keep the usual cases speedy (most internal - // Backbone events have 3 arguments). - var triggerEvents = function(events, args) { - var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; - switch (args.length) { - case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; - case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; - case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; - case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; - default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; - } - }; - - // Aliases for backwards compatibility. - Events.bind = Events.on; - Events.unbind = Events.off; - - // Allow the `Backbone` object to serve as a global event bus, for folks who - // want global "pubsub" in a convenient place. - _.extend(Backbone, Events); - - // Backbone.Model - // -------------- - - // Backbone **Models** are the basic data object in the framework -- - // frequently representing a row in a table in a database on your server. - // A discrete chunk of data and a bunch of useful, related methods for - // performing computations and transformations on that data. - - // Create a new model with the specified attributes. A client id (`cid`) - // is automatically generated and assigned for you. - var Model = Backbone.Model = function(attributes, options) { - var attrs = attributes || {}; - options || (options = {}); - this.preinitialize.apply(this, arguments); - this.cid = _.uniqueId(this.cidPrefix); - this.attributes = {}; - if (options.collection) this.collection = options.collection; - if (options.parse) attrs = this.parse(attrs, options) || {}; - var defaults = _.result(this, 'defaults'); - attrs = _.defaults(_.extend({}, defaults, attrs), defaults); - this.set(attrs, options); - this.changed = {}; - this.initialize.apply(this, arguments); - }; - - // Attach all inheritable methods to the Model prototype. - _.extend(Model.prototype, Events, { - - // A hash of attributes whose current and previous value differ. - changed: null, - - // The value returned during the last failed validation. - validationError: null, - - // The default name for the JSON `id` attribute is `"id"`. MongoDB and - // CouchDB users may want to set this to `"_id"`. - idAttribute: 'id', - - // The prefix is used to create the client id which is used to identify models locally. - // You may want to override this if you're experiencing name clashes with model ids. - cidPrefix: 'c', - - // preinitialize is an empty function by default. You can override it with a function - // or object. preinitialize will run before any instantiation logic is run in the Model. - preinitialize: function(){}, - - // Initialize is an empty function by default. Override it with your own - // initialization logic. - initialize: function(){}, - - // Return a copy of the model's `attributes` object. - toJSON: function(options) { - return _.clone(this.attributes); - }, - - // Proxy `Backbone.sync` by default -- but override this if you need - // custom syncing semantics for *this* particular model. - sync: function() { - return Backbone.sync.apply(this, arguments); - }, - - // Get the value of an attribute. - get: function(attr) { - return this.attributes[attr]; - }, - - // Get the HTML-escaped value of an attribute. - escape: function(attr) { - return _.escape(this.get(attr)); - }, - - // Returns `true` if the attribute contains a value that is not null - // or undefined. - has: function(attr) { - return this.get(attr) != null; - }, - - // Special-cased proxy to underscore's `_.matches` method. - matches: function(attrs) { - return !!_.iteratee(attrs, this)(this.attributes); - }, - - // Set a hash of model attributes on the object, firing `"change"`. This is - // the core primitive operation of a model, updating the data and notifying - // anyone who needs to know about the change in state. The heart of the beast. - set: function(key, val, options) { - if (key == null) return this; - - // Handle both `"key", value` and `{key: value}` -style arguments. - var attrs; - if (typeof key === 'object') { - attrs = key; - options = val; - } else { - (attrs = {})[key] = val; - } - - options || (options = {}); - - // Run validation. - if (!this._validate(attrs, options)) return false; - - // Extract attributes and options. - var unset = options.unset; - var silent = options.silent; - var changes = []; - var changing = this._changing; - this._changing = true; - - if (!changing) { - this._previousAttributes = _.clone(this.attributes); - this.changed = {}; - } - - var current = this.attributes; - var changed = this.changed; - var prev = this._previousAttributes; - - // For each `set` attribute, update or delete the current value. - for (var attr in attrs) { - val = attrs[attr]; - if (!_.isEqual(current[attr], val)) changes.push(attr); - if (!_.isEqual(prev[attr], val)) { - changed[attr] = val; - } else { - delete changed[attr]; - } - unset ? delete current[attr] : current[attr] = val; - } - - // Update the `id`. - if (this.idAttribute in attrs) this.id = this.get(this.idAttribute); - - // Trigger all relevant attribute changes. - if (!silent) { - if (changes.length) this._pending = options; - for (var i = 0; i < changes.length; i++) { - this.trigger('change:' + changes[i], this, current[changes[i]], options); - } - } - - // You might be wondering why there's a `while` loop here. Changes can - // be recursively nested within `"change"` events. - if (changing) return this; - if (!silent) { - while (this._pending) { - options = this._pending; - this._pending = false; - this.trigger('change', this, options); - } - } - this._pending = false; - this._changing = false; - return this; - }, - - // Remove an attribute from the model, firing `"change"`. `unset` is a noop - // if the attribute doesn't exist. - unset: function(attr, options) { - return this.set(attr, void 0, _.extend({}, options, {unset: true})); - }, - - // Clear all attributes on the model, firing `"change"`. - clear: function(options) { - var attrs = {}; - for (var key in this.attributes) attrs[key] = void 0; - return this.set(attrs, _.extend({}, options, {unset: true})); - }, - - // Determine if the model has changed since the last `"change"` event. - // If you specify an attribute name, determine if that attribute has changed. - hasChanged: function(attr) { - if (attr == null) return !_.isEmpty(this.changed); - return _.has(this.changed, attr); - }, - - // Return an object containing all the attributes that have changed, or - // false if there are no changed attributes. Useful for determining what - // parts of a view need to be updated and/or what attributes need to be - // persisted to the server. Unset attributes will be set to undefined. - // You can also pass an attributes object to diff against the model, - // determining if there *would be* a change. - changedAttributes: function(diff) { - if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; - var old = this._changing ? this._previousAttributes : this.attributes; - var changed = {}; - var hasChanged; - for (var attr in diff) { - var val = diff[attr]; - if (_.isEqual(old[attr], val)) continue; - changed[attr] = val; - hasChanged = true; - } - return hasChanged ? changed : false; - }, - - // Get the previous value of an attribute, recorded at the time the last - // `"change"` event was fired. - previous: function(attr) { - if (attr == null || !this._previousAttributes) return null; - return this._previousAttributes[attr]; - }, - - // Get all of the attributes of the model at the time of the previous - // `"change"` event. - previousAttributes: function() { - return _.clone(this._previousAttributes); - }, - - // Fetch the model from the server, merging the response with the model's - // local attributes. Any changed attributes will trigger a "change" event. - fetch: function(options) { - options = _.extend({parse: true}, options); - var model = this; - var success = options.success; - options.success = function(resp) { - var serverAttrs = options.parse ? model.parse(resp, options) : resp; - if (!model.set(serverAttrs, options)) return false; - if (success) success.call(options.context, model, resp, options); - model.trigger('sync', model, resp, options); - }; - wrapError(this, options); - return this.sync('read', this, options); - }, - - // Set a hash of model attributes, and sync the model to the server. - // If the server returns an attributes hash that differs, the model's - // state will be `set` again. - save: function(key, val, options) { - // Handle both `"key", value` and `{key: value}` -style arguments. - var attrs; - if (key == null || typeof key === 'object') { - attrs = key; - options = val; - } else { - (attrs = {})[key] = val; - } - - options = _.extend({validate: true, parse: true}, options); - var wait = options.wait; - - // If we're not waiting and attributes exist, save acts as - // `set(attr).save(null, opts)` with validation. Otherwise, check if - // the model will be valid when the attributes, if any, are set. - if (attrs && !wait) { - if (!this.set(attrs, options)) return false; - } else if (!this._validate(attrs, options)) { - return false; - } - - // After a successful server-side save, the client is (optionally) - // updated with the server-side state. - var model = this; - var success = options.success; - var attributes = this.attributes; - options.success = function(resp) { - // Ensure attributes are restored during synchronous saves. - model.attributes = attributes; - var serverAttrs = options.parse ? model.parse(resp, options) : resp; - if (wait) serverAttrs = _.extend({}, attrs, serverAttrs); - if (serverAttrs && !model.set(serverAttrs, options)) return false; - if (success) success.call(options.context, model, resp, options); - model.trigger('sync', model, resp, options); - }; - wrapError(this, options); - - // Set temporary attributes if `{wait: true}` to properly find new ids. - if (attrs && wait) this.attributes = _.extend({}, attributes, attrs); - - var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); - if (method === 'patch' && !options.attrs) options.attrs = attrs; - var xhr = this.sync(method, this, options); - - // Restore attributes. - this.attributes = attributes; - - return xhr; - }, - - // Destroy this model on the server if it was already persisted. - // Optimistically removes the model from its collection, if it has one. - // If `wait: true` is passed, waits for the server to respond before removal. - destroy: function(options) { - options = options ? _.clone(options) : {}; - var model = this; - var success = options.success; - var wait = options.wait; - - var destroy = function() { - model.stopListening(); - model.trigger('destroy', model, model.collection, options); - }; - - options.success = function(resp) { - if (wait) destroy(); - if (success) success.call(options.context, model, resp, options); - if (!model.isNew()) model.trigger('sync', model, resp, options); - }; - - var xhr = false; - if (this.isNew()) { - _.defer(options.success); - } else { - wrapError(this, options); - xhr = this.sync('delete', this, options); - } - if (!wait) destroy(); - return xhr; - }, - - // Default URL for the model's representation on the server -- if you're - // using Backbone's restful methods, override this to change the endpoint - // that will be called. - url: function() { - var base = - _.result(this, 'urlRoot') || - _.result(this.collection, 'url') || - urlError(); - if (this.isNew()) return base; - var id = this.get(this.idAttribute); - return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id); - }, - - // **parse** converts a response into the hash of attributes to be `set` on - // the model. The default implementation is just to pass the response along. - parse: function(resp, options) { - return resp; - }, - - // Create a new model with identical attributes to this one. - clone: function() { - return new this.constructor(this.attributes); - }, - - // A model is new if it has never been saved to the server, and lacks an id. - isNew: function() { - return !this.has(this.idAttribute); - }, - - // Check if the model is currently in a valid state. - isValid: function(options) { - return this._validate({}, _.extend({}, options, {validate: true})); - }, - - // Run validation against the next complete set of model attributes, - // returning `true` if all is well. Otherwise, fire an `"invalid"` event. - _validate: function(attrs, options) { - if (!options.validate || !this.validate) return true; - attrs = _.extend({}, this.attributes, attrs); - var error = this.validationError = this.validate(attrs, options) || null; - if (!error) return true; - this.trigger('invalid', this, error, _.extend(options, {validationError: error})); - return false; - } - - }); - - // Underscore methods that we want to implement on the Model, mapped to the - // number of arguments they take. - var modelMethods = {keys: 1, values: 1, pairs: 1, invert: 1, pick: 0, - omit: 0, chain: 1, isEmpty: 1}; - - // Mix in each Underscore method as a proxy to `Model#attributes`. - addUnderscoreMethods(Model, modelMethods, 'attributes'); - - // Backbone.Collection - // ------------------- - - // If models tend to represent a single row of data, a Backbone Collection is - // more analogous to a table full of data ... or a small slice or page of that - // table, or a collection of rows that belong together for a particular reason - // -- all of the messages in this particular folder, all of the documents - // belonging to this particular author, and so on. Collections maintain - // indexes of their models, both in order, and for lookup by `id`. - - // Create a new **Collection**, perhaps to contain a specific type of `model`. - // If a `comparator` is specified, the Collection will maintain - // its models in sort order, as they're added and removed. - var Collection = Backbone.Collection = function(models, options) { - options || (options = {}); - this.preinitialize.apply(this, arguments); - if (options.model) this.model = options.model; - if (options.comparator !== void 0) this.comparator = options.comparator; - this._reset(); - this.initialize.apply(this, arguments); - if (models) this.reset(models, _.extend({silent: true}, options)); - }; - - // Default options for `Collection#set`. - var setOptions = {add: true, remove: true, merge: true}; - var addOptions = {add: true, remove: false}; - - // Splices `insert` into `array` at index `at`. - var splice = function(array, insert, at) { - at = Math.min(Math.max(at, 0), array.length); - var tail = Array(array.length - at); - var length = insert.length; - var i; - for (i = 0; i < tail.length; i++) tail[i] = array[i + at]; - for (i = 0; i < length; i++) array[i + at] = insert[i]; - for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i]; - }; - - // Define the Collection's inheritable methods. - _.extend(Collection.prototype, Events, { - - // The default model for a collection is just a **Backbone.Model**. - // This should be overridden in most cases. - model: Model, - - - // preinitialize is an empty function by default. You can override it with a function - // or object. preinitialize will run before any instantiation logic is run in the Collection. - preinitialize: function(){}, - - // Initialize is an empty function by default. Override it with your own - // initialization logic. - initialize: function(){}, - - // The JSON representation of a Collection is an array of the - // models' attributes. - toJSON: function(options) { - return this.map(function(model) { return model.toJSON(options); }); - }, - - // Proxy `Backbone.sync` by default. - sync: function() { - return Backbone.sync.apply(this, arguments); - }, - - // Add a model, or list of models to the set. `models` may be Backbone - // Models or raw JavaScript objects to be converted to Models, or any - // combination of the two. - add: function(models, options) { - return this.set(models, _.extend({merge: false}, options, addOptions)); - }, - - // Remove a model, or a list of models from the set. - remove: function(models, options) { - options = _.extend({}, options); - var singular = !_.isArray(models); - models = singular ? [models] : models.slice(); - var removed = this._removeModels(models, options); - if (!options.silent && removed.length) { - options.changes = {added: [], merged: [], removed: removed}; - this.trigger('update', this, options); - } - return singular ? removed[0] : removed; - }, - - // Update a collection by `set`-ing a new list of models, adding new ones, - // removing models that are no longer present, and merging models that - // already exist in the collection, as necessary. Similar to **Model#set**, - // the core operation for updating the data contained by the collection. - set: function(models, options) { - if (models == null) return; - - options = _.extend({}, setOptions, options); - if (options.parse && !this._isModel(models)) { - models = this.parse(models, options) || []; - } - - var singular = !_.isArray(models); - models = singular ? [models] : models.slice(); - - var at = options.at; - if (at != null) at = +at; - if (at > this.length) at = this.length; - if (at < 0) at += this.length + 1; - - var set = []; - var toAdd = []; - var toMerge = []; - var toRemove = []; - var modelMap = {}; - - var add = options.add; - var merge = options.merge; - var remove = options.remove; - - var sort = false; - var sortable = this.comparator && at == null && options.sort !== false; - var sortAttr = _.isString(this.comparator) ? this.comparator : null; - - // Turn bare objects into model references, and prevent invalid models - // from being added. - var model, i; - for (i = 0; i < models.length; i++) { - model = models[i]; - - // If a duplicate is found, prevent it from being added and - // optionally merge it into the existing model. - var existing = this.get(model); - if (existing) { - if (merge && model !== existing) { - var attrs = this._isModel(model) ? model.attributes : model; - if (options.parse) attrs = existing.parse(attrs, options); - existing.set(attrs, options); - toMerge.push(existing); - if (sortable && !sort) sort = existing.hasChanged(sortAttr); - } - if (!modelMap[existing.cid]) { - modelMap[existing.cid] = true; - set.push(existing); - } - models[i] = existing; - - // If this is a new, valid model, push it to the `toAdd` list. - } else if (add) { - model = models[i] = this._prepareModel(model, options); - if (model) { - toAdd.push(model); - this._addReference(model, options); - modelMap[model.cid] = true; - set.push(model); - } - } - } - - // Remove stale models. - if (remove) { - for (i = 0; i < this.length; i++) { - model = this.models[i]; - if (!modelMap[model.cid]) toRemove.push(model); - } - if (toRemove.length) this._removeModels(toRemove, options); - } - - // See if sorting is needed, update `length` and splice in new models. - var orderChanged = false; - var replace = !sortable && add && remove; - if (set.length && replace) { - orderChanged = this.length !== set.length || _.some(this.models, function(m, index) { - return m !== set[index]; - }); - this.models.length = 0; - splice(this.models, set, 0); - this.length = this.models.length; - } else if (toAdd.length) { - if (sortable) sort = true; - splice(this.models, toAdd, at == null ? this.length : at); - this.length = this.models.length; - } - - // Silently sort the collection if appropriate. - if (sort) this.sort({silent: true}); - - // Unless silenced, it's time to fire all appropriate add/sort/update events. - if (!options.silent) { - for (i = 0; i < toAdd.length; i++) { - if (at != null) options.index = at + i; - model = toAdd[i]; - model.trigger('add', model, this, options); - } - if (sort || orderChanged) this.trigger('sort', this, options); - if (toAdd.length || toRemove.length || toMerge.length) { - options.changes = { - added: toAdd, - removed: toRemove, - merged: toMerge - }; - this.trigger('update', this, options); - } - } - - // Return the added (or merged) model (or models). - return singular ? models[0] : models; - }, - - // When you have more items than you want to add or remove individually, - // you can reset the entire set with a new list of models, without firing - // any granular `add` or `remove` events. Fires `reset` when finished. - // Useful for bulk operations and optimizations. - reset: function(models, options) { - options = options ? _.clone(options) : {}; - for (var i = 0; i < this.models.length; i++) { - this._removeReference(this.models[i], options); - } - options.previousModels = this.models; - this._reset(); - models = this.add(models, _.extend({silent: true}, options)); - if (!options.silent) this.trigger('reset', this, options); - return models; - }, - - // Add a model to the end of the collection. - push: function(model, options) { - return this.add(model, _.extend({at: this.length}, options)); - }, - - // Remove a model from the end of the collection. - pop: function(options) { - var model = this.at(this.length - 1); - return this.remove(model, options); - }, - - // Add a model to the beginning of the collection. - unshift: function(model, options) { - return this.add(model, _.extend({at: 0}, options)); - }, - - // Remove a model from the beginning of the collection. - shift: function(options) { - var model = this.at(0); - return this.remove(model, options); - }, - - // Slice out a sub-array of models from the collection. - slice: function() { - return slice.apply(this.models, arguments); - }, - - // Get a model from the set by id, cid, model object with id or cid - // properties, or an attributes object that is transformed through modelId. - get: function(obj) { - if (obj == null) return void 0; - return this._byId[obj] || - this._byId[this.modelId(obj.attributes || obj)] || - obj.cid && this._byId[obj.cid]; - }, - - // Returns `true` if the model is in the collection. - has: function(obj) { - return this.get(obj) != null; - }, - - // Get the model at the given index. - at: function(index) { - if (index < 0) index += this.length; - return this.models[index]; - }, - - // Return models with matching attributes. Useful for simple cases of - // `filter`. - where: function(attrs, first) { - return this[first ? 'find' : 'filter'](attrs); - }, - - // Return the first model with matching attributes. Useful for simple cases - // of `find`. - findWhere: function(attrs) { - return this.where(attrs, true); - }, - - // Force the collection to re-sort itself. You don't need to call this under - // normal circumstances, as the set will maintain sort order as each item - // is added. - sort: function(options) { - var comparator = this.comparator; - if (!comparator) throw new Error('Cannot sort a set without a comparator'); - options || (options = {}); - - var length = comparator.length; - if (_.isFunction(comparator)) comparator = _.bind(comparator, this); - - // Run sort based on type of `comparator`. - if (length === 1 || _.isString(comparator)) { - this.models = this.sortBy(comparator); - } else { - this.models.sort(comparator); - } - if (!options.silent) this.trigger('sort', this, options); - return this; - }, - - // Pluck an attribute from each model in the collection. - pluck: function(attr) { - return this.map(attr + ''); - }, - - // Fetch the default set of models for this collection, resetting the - // collection when they arrive. If `reset: true` is passed, the response - // data will be passed through the `reset` method instead of `set`. - fetch: function(options) { - options = _.extend({parse: true}, options); - var success = options.success; - var collection = this; - options.success = function(resp) { - var method = options.reset ? 'reset' : 'set'; - collection[method](resp, options); - if (success) success.call(options.context, collection, resp, options); - collection.trigger('sync', collection, resp, options); - }; - wrapError(this, options); - return this.sync('read', this, options); - }, - - // Create a new instance of a model in this collection. Add the model to the - // collection immediately, unless `wait: true` is passed, in which case we - // wait for the server to agree. - create: function(model, options) { - options = options ? _.clone(options) : {}; - var wait = options.wait; - model = this._prepareModel(model, options); - if (!model) return false; - if (!wait) this.add(model, options); - var collection = this; - var success = options.success; - options.success = function(m, resp, callbackOpts) { - if (wait) collection.add(m, callbackOpts); - if (success) success.call(callbackOpts.context, m, resp, callbackOpts); - }; - model.save(null, options); - return model; - }, - - // **parse** converts a response into a list of models to be added to the - // collection. The default implementation is just to pass it through. - parse: function(resp, options) { - return resp; - }, - - // Create a new collection with an identical list of models as this one. - clone: function() { - return new this.constructor(this.models, { - model: this.model, - comparator: this.comparator - }); - }, - - // Define how to uniquely identify models in the collection. - modelId: function(attrs) { - return attrs[this.model.prototype.idAttribute || 'id']; - }, - - // Private method to reset all internal state. Called when the collection - // is first initialized or reset. - _reset: function() { - this.length = 0; - this.models = []; - this._byId = {}; - }, - - // Prepare a hash of attributes (or other model) to be added to this - // collection. - _prepareModel: function(attrs, options) { - if (this._isModel(attrs)) { - if (!attrs.collection) attrs.collection = this; - return attrs; - } - options = options ? _.clone(options) : {}; - options.collection = this; - var model = new this.model(attrs, options); - if (!model.validationError) return model; - this.trigger('invalid', this, model.validationError, options); - return false; - }, - - // Internal method called by both remove and set. - _removeModels: function(models, options) { - var removed = []; - for (var i = 0; i < models.length; i++) { - var model = this.get(models[i]); - if (!model) continue; - - var index = this.indexOf(model); - this.models.splice(index, 1); - this.length--; - - // Remove references before triggering 'remove' event to prevent an - // infinite loop. #3693 - delete this._byId[model.cid]; - var id = this.modelId(model.attributes); - if (id != null) delete this._byId[id]; - - if (!options.silent) { - options.index = index; - model.trigger('remove', model, this, options); - } - - removed.push(model); - this._removeReference(model, options); - } - return removed; - }, - - // Method for checking whether an object should be considered a model for - // the purposes of adding to the collection. - _isModel: function(model) { - return model instanceof Model; - }, - - // Internal method to create a model's ties to a collection. - _addReference: function(model, options) { - this._byId[model.cid] = model; - var id = this.modelId(model.attributes); - if (id != null) this._byId[id] = model; - model.on('all', this._onModelEvent, this); - }, - - // Internal method to sever a model's ties to a collection. - _removeReference: function(model, options) { - delete this._byId[model.cid]; - var id = this.modelId(model.attributes); - if (id != null) delete this._byId[id]; - if (this === model.collection) delete model.collection; - model.off('all', this._onModelEvent, this); - }, - - // Internal method called every time a model in the set fires an event. - // Sets need to update their indexes when models change ids. All other - // events simply proxy through. "add" and "remove" events that originate - // in other collections are ignored. - _onModelEvent: function(event, model, collection, options) { - if (model) { - if ((event === 'add' || event === 'remove') && collection !== this) return; - if (event === 'destroy') this.remove(model, options); - if (event === 'change') { - var prevId = this.modelId(model.previousAttributes()); - var id = this.modelId(model.attributes); - if (prevId !== id) { - if (prevId != null) delete this._byId[prevId]; - if (id != null) this._byId[id] = model; - } - } - } - this.trigger.apply(this, arguments); - } - - }); - - // Underscore methods that we want to implement on the Collection. - // 90% of the core usefulness of Backbone Collections is actually implemented - // right here: - var collectionMethods = {forEach: 3, each: 3, map: 3, collect: 3, reduce: 0, - foldl: 0, inject: 0, reduceRight: 0, foldr: 0, find: 3, detect: 3, filter: 3, - select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 3, includes: 3, - contains: 3, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3, - head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3, - without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3, - isEmpty: 1, chain: 1, sample: 3, partition: 3, groupBy: 3, countBy: 3, - sortBy: 3, indexBy: 3, findIndex: 3, findLastIndex: 3}; - - // Mix in each Underscore method as a proxy to `Collection#models`. - addUnderscoreMethods(Collection, collectionMethods, 'models'); - - // Backbone.View - // ------------- - - // Backbone Views are almost more convention than they are actual code. A View - // is simply a JavaScript object that represents a logical chunk of UI in the - // DOM. This might be a single item, an entire list, a sidebar or panel, or - // even the surrounding frame which wraps your whole app. Defining a chunk of - // UI as a **View** allows you to define your DOM events declaratively, without - // having to worry about render order ... and makes it easy for the view to - // react to specific changes in the state of your models. - - // Creating a Backbone.View creates its initial element outside of the DOM, - // if an existing element is not provided... - var View = Backbone.View = function(options) { - this.cid = _.uniqueId('view'); - this.preinitialize.apply(this, arguments); - _.extend(this, _.pick(options, viewOptions)); - this._ensureElement(); - this.initialize.apply(this, arguments); - }; - - // Cached regex to split keys for `delegate`. - var delegateEventSplitter = /^(\S+)\s*(.*)$/; - - // List of view options to be set as properties. - var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; - - // Set up all inheritable **Backbone.View** properties and methods. - _.extend(View.prototype, Events, { - - // The default `tagName` of a View's element is `"div"`. - tagName: 'div', - - // jQuery delegate for element lookup, scoped to DOM elements within the - // current view. This should be preferred to global lookups where possible. - $: function(selector) { - return this.$el.find(selector); - }, - - // preinitialize is an empty function by default. You can override it with a function - // or object. preinitialize will run before any instantiation logic is run in the View - preinitialize: function(){}, - - // Initialize is an empty function by default. Override it with your own - // initialization logic. - initialize: function(){}, - - // **render** is the core function that your view should override, in order - // to populate its element (`this.el`), with the appropriate HTML. The - // convention is for **render** to always return `this`. - render: function() { - return this; - }, - - // Remove this view by taking the element out of the DOM, and removing any - // applicable Backbone.Events listeners. - remove: function() { - this._removeElement(); - this.stopListening(); - return this; - }, - - // Remove this view's element from the document and all event listeners - // attached to it. Exposed for subclasses using an alternative DOM - // manipulation API. - _removeElement: function() { - this.$el.remove(); - }, - - // Change the view's element (`this.el` property) and re-delegate the - // view's events on the new element. - setElement: function(element) { - this.undelegateEvents(); - this._setElement(element); - this.delegateEvents(); - return this; - }, - - // Creates the `this.el` and `this.$el` references for this view using the - // given `el`. `el` can be a CSS selector or an HTML string, a jQuery - // context or an element. Subclasses can override this to utilize an - // alternative DOM manipulation API and are only required to set the - // `this.el` property. - _setElement: function(el) { - this.$el = el instanceof Backbone.$ ? el : Backbone.$(el); - this.el = this.$el[0]; - }, - - // Set callbacks, where `this.events` is a hash of - // - // *{"event selector": "callback"}* - // - // { - // 'mousedown .title': 'edit', - // 'click .button': 'save', - // 'click .open': function(e) { ... } - // } - // - // pairs. Callbacks will be bound to the view, with `this` set properly. - // Uses event delegation for efficiency. - // Omitting the selector binds the event to `this.el`. - delegateEvents: function(events) { - events || (events = _.result(this, 'events')); - if (!events) return this; - this.undelegateEvents(); - for (var key in events) { - var method = events[key]; - if (!_.isFunction(method)) method = this[method]; - if (!method) continue; - var match = key.match(delegateEventSplitter); - this.delegate(match[1], match[2], _.bind(method, this)); - } - return this; - }, - - // Add a single event listener to the view's element (or a child element - // using `selector`). This only works for delegate-able events: not `focus`, - // `blur`, and not `change`, `submit`, and `reset` in Internet Explorer. - delegate: function(eventName, selector, listener) { - this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener); - return this; - }, - - // Clears all callbacks previously bound to the view by `delegateEvents`. - // You usually don't need to use this, but may wish to if you have multiple - // Backbone views attached to the same DOM element. - undelegateEvents: function() { - if (this.$el) this.$el.off('.delegateEvents' + this.cid); - return this; - }, - - // A finer-grained `undelegateEvents` for removing a single delegated event. - // `selector` and `listener` are both optional. - undelegate: function(eventName, selector, listener) { - this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener); - return this; - }, - - // Produces a DOM element to be assigned to your view. Exposed for - // subclasses using an alternative DOM manipulation API. - _createElement: function(tagName) { - return document.createElement(tagName); - }, - - // Ensure that the View has a DOM element to render into. - // If `this.el` is a string, pass it through `$()`, take the first - // matching element, and re-assign it to `el`. Otherwise, create - // an element from the `id`, `className` and `tagName` properties. - _ensureElement: function() { - if (!this.el) { - var attrs = _.extend({}, _.result(this, 'attributes')); - if (this.id) attrs.id = _.result(this, 'id'); - if (this.className) attrs['class'] = _.result(this, 'className'); - this.setElement(this._createElement(_.result(this, 'tagName'))); - this._setAttributes(attrs); - } else { - this.setElement(_.result(this, 'el')); - } - }, - - // Set attributes from a hash on this view's element. Exposed for - // subclasses using an alternative DOM manipulation API. - _setAttributes: function(attributes) { - this.$el.attr(attributes); - } - - }); - - // Backbone.sync - // ------------- - - // Override this function to change the manner in which Backbone persists - // models to the server. You will be passed the type of request, and the - // model in question. By default, makes a RESTful Ajax request - // to the model's `url()`. Some possible customizations could be: - // - // * Use `setTimeout` to batch rapid-fire updates into a single request. - // * Send up the models as XML instead of JSON. - // * Persist models via WebSockets instead of Ajax. - // - // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests - // as `POST`, with a `_method` parameter containing the true HTTP method, - // as well as all requests with the body as `application/x-www-form-urlencoded` - // instead of `application/json` with the model in a param named `model`. - // Useful when interfacing with server-side languages like **PHP** that make - // it difficult to read the body of `PUT` requests. - Backbone.sync = function(method, model, options) { - var type = methodMap[method]; - - // Default options, unless specified. - _.defaults(options || (options = {}), { - emulateHTTP: Backbone.emulateHTTP, - emulateJSON: Backbone.emulateJSON - }); - - // Default JSON-request options. - var params = {type: type, dataType: 'json'}; - - // Ensure that we have a URL. - if (!options.url) { - params.url = _.result(model, 'url') || urlError(); - } - - // Ensure that we have the appropriate request data. - if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { - params.contentType = 'application/json'; - params.data = JSON.stringify(options.attrs || model.toJSON(options)); - } - - // For older servers, emulate JSON by encoding the request into an HTML-form. - if (options.emulateJSON) { - params.contentType = 'application/x-www-form-urlencoded'; - params.data = params.data ? {model: params.data} : {}; - } - - // For older servers, emulate HTTP by mimicking the HTTP method with `_method` - // And an `X-HTTP-Method-Override` header. - if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { - params.type = 'POST'; - if (options.emulateJSON) params.data._method = type; - var beforeSend = options.beforeSend; - options.beforeSend = function(xhr) { - xhr.setRequestHeader('X-HTTP-Method-Override', type); - if (beforeSend) return beforeSend.apply(this, arguments); - }; - } - - // Don't process data on a non-GET request. - if (params.type !== 'GET' && !options.emulateJSON) { - params.processData = false; - } - - // Pass along `textStatus` and `errorThrown` from jQuery. - var error = options.error; - options.error = function(xhr, textStatus, errorThrown) { - options.textStatus = textStatus; - options.errorThrown = errorThrown; - if (error) error.call(options.context, xhr, textStatus, errorThrown); - }; - - // Make the request, allowing the user to override any Ajax options. - var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); - model.trigger('request', model, xhr, options); - return xhr; - }; - - // Map from CRUD to HTTP for our default `Backbone.sync` implementation. - var methodMap = { - 'create': 'POST', - 'update': 'PUT', - 'patch': 'PATCH', - 'delete': 'DELETE', - 'read': 'GET' - }; - - // Set the default implementation of `Backbone.ajax` to proxy through to `$`. - // Override this if you'd like to use a different library. - Backbone.ajax = function() { - return Backbone.$.ajax.apply(Backbone.$, arguments); - }; - - // Backbone.Router - // --------------- - - // Routers map faux-URLs to actions, and fire events when routes are - // matched. Creating a new one sets its `routes` hash, if not set statically. - var Router = Backbone.Router = function(options) { - options || (options = {}); - this.preinitialize.apply(this, arguments); - if (options.routes) this.routes = options.routes; - this._bindRoutes(); - this.initialize.apply(this, arguments); - }; - - // Cached regular expressions for matching named param parts and splatted - // parts of route strings. - var optionalParam = /\((.*?)\)/g; - var namedParam = /(\(\?)?:\w+/g; - var splatParam = /\*\w+/g; - var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; - - // Set up all inheritable **Backbone.Router** properties and methods. - _.extend(Router.prototype, Events, { - - // preinitialize is an empty function by default. You can override it with a function - // or object. preinitialize will run before any instantiation logic is run in the Router. - preinitialize: function(){}, - - // Initialize is an empty function by default. Override it with your own - // initialization logic. - initialize: function(){}, - - // Manually bind a single named route to a callback. For example: - // - // this.route('search/:query/p:num', 'search', function(query, num) { - // ... - // }); - // - route: function(route, name, callback) { - if (!_.isRegExp(route)) route = this._routeToRegExp(route); - if (_.isFunction(name)) { - callback = name; - name = ''; - } - if (!callback) callback = this[name]; - var router = this; - Backbone.history.route(route, function(fragment) { - var args = router._extractParameters(route, fragment); - if (router.execute(callback, args, name) !== false) { - router.trigger.apply(router, ['route:' + name].concat(args)); - router.trigger('route', name, args); - Backbone.history.trigger('route', router, name, args); - } - }); - return this; - }, - - // Execute a route handler with the provided parameters. This is an - // excellent place to do pre-route setup or post-route cleanup. - execute: function(callback, args, name) { - if (callback) callback.apply(this, args); - }, - - // Simple proxy to `Backbone.history` to save a fragment into the history. - navigate: function(fragment, options) { - Backbone.history.navigate(fragment, options); - return this; - }, - - // Bind all defined routes to `Backbone.history`. We have to reverse the - // order of the routes here to support behavior where the most general - // routes can be defined at the bottom of the route map. - _bindRoutes: function() { - if (!this.routes) return; - this.routes = _.result(this, 'routes'); - var route, routes = _.keys(this.routes); - while ((route = routes.pop()) != null) { - this.route(route, this.routes[route]); - } - }, - - // Convert a route string into a regular expression, suitable for matching - // against the current location hash. - _routeToRegExp: function(route) { - route = route.replace(escapeRegExp, '\\$&') - .replace(optionalParam, '(?:$1)?') - .replace(namedParam, function(match, optional) { - return optional ? match : '([^/?]+)'; - }) - .replace(splatParam, '([^?]*?)'); - return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'); - }, - - // Given a route, and a URL fragment that it matches, return the array of - // extracted decoded parameters. Empty or unmatched parameters will be - // treated as `null` to normalize cross-browser behavior. - _extractParameters: function(route, fragment) { - var params = route.exec(fragment).slice(1); - return _.map(params, function(param, i) { - // Don't decode the search params. - if (i === params.length - 1) return param || null; - return param ? decodeURIComponent(param) : null; - }); - } - - }); - - // Backbone.History - // ---------------- - - // Handles cross-browser history management, based on either - // [pushState](http://diveintohtml5.info/history.html) and real URLs, or - // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) - // and URL fragments. If the browser supports neither (old IE, natch), - // falls back to polling. - var History = Backbone.History = function() { - this.handlers = []; - this.checkUrl = _.bind(this.checkUrl, this); - - // Ensure that `History` can be used outside of the browser. - if (typeof window !== 'undefined') { - this.location = window.location; - this.history = window.history; - } - }; - - // Cached regex for stripping a leading hash/slash and trailing space. - var routeStripper = /^[#\/]|\s+$/g; - - // Cached regex for stripping leading and trailing slashes. - var rootStripper = /^\/+|\/+$/g; - - // Cached regex for stripping urls of hash. - var pathStripper = /#.*$/; - - // Has the history handling already been started? - History.started = false; - - // Set up all inheritable **Backbone.History** properties and methods. - _.extend(History.prototype, Events, { - - // The default interval to poll for hash changes, if necessary, is - // twenty times a second. - interval: 50, - - // Are we at the app root? - atRoot: function() { - var path = this.location.pathname.replace(/[^\/]$/, '$&/'); - return path === this.root && !this.getSearch(); - }, - - // Does the pathname match the root? - matchRoot: function() { - var path = this.decodeFragment(this.location.pathname); - var rootPath = path.slice(0, this.root.length - 1) + '/'; - return rootPath === this.root; - }, - - // Unicode characters in `location.pathname` are percent encoded so they're - // decoded for comparison. `%25` should not be decoded since it may be part - // of an encoded parameter. - decodeFragment: function(fragment) { - return decodeURI(fragment.replace(/%25/g, '%2525')); - }, - - // In IE6, the hash fragment and search params are incorrect if the - // fragment contains `?`. - getSearch: function() { - var match = this.location.href.replace(/#.*/, '').match(/\?.+/); - return match ? match[0] : ''; - }, - - // Gets the true hash value. Cannot use location.hash directly due to bug - // in Firefox where location.hash will always be decoded. - getHash: function(window) { - var match = (window || this).location.href.match(/#(.*)$/); - return match ? match[1] : ''; - }, - - // Get the pathname and search params, without the root. - getPath: function() { - var path = this.decodeFragment( - this.location.pathname + this.getSearch() - ).slice(this.root.length - 1); - return path.charAt(0) === '/' ? path.slice(1) : path; - }, - - // Get the cross-browser normalized URL fragment from the path or hash. - getFragment: function(fragment) { - if (fragment == null) { - if (this._usePushState || !this._wantsHashChange) { - fragment = this.getPath(); - } else { - fragment = this.getHash(); - } - } - return fragment.replace(routeStripper, ''); - }, - - // Start the hash change handling, returning `true` if the current URL matches - // an existing route, and `false` otherwise. - start: function(options) { - if (History.started) throw new Error('Backbone.history has already been started'); - History.started = true; - - // Figure out the initial configuration. Do we need an iframe? - // Is pushState desired ... is it available? - this.options = _.extend({root: '/'}, this.options, options); - this.root = this.options.root; - this._wantsHashChange = this.options.hashChange !== false; - this._hasHashChange = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7); - this._useHashChange = this._wantsHashChange && this._hasHashChange; - this._wantsPushState = !!this.options.pushState; - this._hasPushState = !!(this.history && this.history.pushState); - this._usePushState = this._wantsPushState && this._hasPushState; - this.fragment = this.getFragment(); - - // Normalize root to always include a leading and trailing slash. - this.root = ('/' + this.root + '/').replace(rootStripper, '/'); - - // Transition from hashChange to pushState or vice versa if both are - // requested. - if (this._wantsHashChange && this._wantsPushState) { - - // If we've started off with a route from a `pushState`-enabled - // browser, but we're currently in a browser that doesn't support it... - if (!this._hasPushState && !this.atRoot()) { - var rootPath = this.root.slice(0, -1) || '/'; - this.location.replace(rootPath + '#' + this.getPath()); - // Return immediately as browser will do redirect to new url - return true; - - // Or if we've started out with a hash-based route, but we're currently - // in a browser where it could be `pushState`-based instead... - } else if (this._hasPushState && this.atRoot()) { - this.navigate(this.getHash(), {replace: true}); - } - - } - - // Proxy an iframe to handle location events if the browser doesn't - // support the `hashchange` event, HTML5 history, or the user wants - // `hashChange` but not `pushState`. - if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) { - this.iframe = document.createElement('iframe'); - this.iframe.src = 'javascript:0'; - this.iframe.style.display = 'none'; - this.iframe.tabIndex = -1; - var body = document.body; - // Using `appendChild` will throw on IE < 9 if the document is not ready. - var iWindow = body.insertBefore(this.iframe, body.firstChild).contentWindow; - iWindow.document.open(); - iWindow.document.close(); - iWindow.location.hash = '#' + this.fragment; - } - - // Add a cross-platform `addEventListener` shim for older browsers. - var addEventListener = window.addEventListener || function(eventName, listener) { - return attachEvent('on' + eventName, listener); - }; - - // Depending on whether we're using pushState or hashes, and whether - // 'onhashchange' is supported, determine how we check the URL state. - if (this._usePushState) { - addEventListener('popstate', this.checkUrl, false); - } else if (this._useHashChange && !this.iframe) { - addEventListener('hashchange', this.checkUrl, false); - } else if (this._wantsHashChange) { - this._checkUrlInterval = setInterval(this.checkUrl, this.interval); - } - - if (!this.options.silent) return this.loadUrl(); - }, - - // Disable Backbone.history, perhaps temporarily. Not useful in a real app, - // but possibly useful for unit testing Routers. - stop: function() { - // Add a cross-platform `removeEventListener` shim for older browsers. - var removeEventListener = window.removeEventListener || function(eventName, listener) { - return detachEvent('on' + eventName, listener); - }; - - // Remove window listeners. - if (this._usePushState) { - removeEventListener('popstate', this.checkUrl, false); - } else if (this._useHashChange && !this.iframe) { - removeEventListener('hashchange', this.checkUrl, false); - } - - // Clean up the iframe if necessary. - if (this.iframe) { - document.body.removeChild(this.iframe); - this.iframe = null; - } - - // Some environments will throw when clearing an undefined interval. - if (this._checkUrlInterval) clearInterval(this._checkUrlInterval); - History.started = false; - }, - - // Add a route to be tested when the fragment changes. Routes added later - // may override previous routes. - route: function(route, callback) { - this.handlers.unshift({route: route, callback: callback}); - }, - - // Checks the current URL to see if it has changed, and if it has, - // calls `loadUrl`, normalizing across the hidden iframe. - checkUrl: function(e) { - var current = this.getFragment(); - - // If the user pressed the back button, the iframe's hash will have - // changed and we should use that for comparison. - if (current === this.fragment && this.iframe) { - current = this.getHash(this.iframe.contentWindow); - } - - if (current === this.fragment) return false; - if (this.iframe) this.navigate(current); - this.loadUrl(); - }, - - // Attempt to load the current URL fragment. If a route succeeds with a - // match, returns `true`. If no defined routes matches the fragment, - // returns `false`. - loadUrl: function(fragment) { - // If the root doesn't match, no routes can match either. - if (!this.matchRoot()) return false; - fragment = this.fragment = this.getFragment(fragment); - return _.some(this.handlers, function(handler) { - if (handler.route.test(fragment)) { - handler.callback(fragment); - return true; - } - }); - }, - - // Save a fragment into the hash history, or replace the URL state if the - // 'replace' option is passed. You are responsible for properly URL-encoding - // the fragment in advance. - // - // The options object can contain `trigger: true` if you wish to have the - // route callback be fired (not usually desirable), or `replace: true`, if - // you wish to modify the current URL without adding an entry to the history. - navigate: function(fragment, options) { - if (!History.started) return false; - if (!options || options === true) options = {trigger: !!options}; - - // Normalize the fragment. - fragment = this.getFragment(fragment || ''); - - // Don't include a trailing slash on the root. - var rootPath = this.root; - if (fragment === '' || fragment.charAt(0) === '?') { - rootPath = rootPath.slice(0, -1) || '/'; - } - var url = rootPath + fragment; - - // Strip the fragment of the query and hash for matching. - fragment = fragment.replace(pathStripper, ''); - - // Decode for matching. - var decodedFragment = this.decodeFragment(fragment); - - if (this.fragment === decodedFragment) return; - this.fragment = decodedFragment; - - // If pushState is available, we use it to set the fragment as a real URL. - if (this._usePushState) { - this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url); - - // If hash changes haven't been explicitly disabled, update the hash - // fragment to store history. - } else if (this._wantsHashChange) { - this._updateHash(this.location, fragment, options.replace); - if (this.iframe && fragment !== this.getHash(this.iframe.contentWindow)) { - var iWindow = this.iframe.contentWindow; - - // Opening and closing the iframe tricks IE7 and earlier to push a - // history entry on hash-tag change. When replace is true, we don't - // want this. - if (!options.replace) { - iWindow.document.open(); - iWindow.document.close(); - } - - this._updateHash(iWindow.location, fragment, options.replace); - } - - // If you've told us that you explicitly don't want fallback hashchange- - // based history, then `navigate` becomes a page refresh. - } else { - return this.location.assign(url); - } - if (options.trigger) return this.loadUrl(fragment); - }, - - // Update the hash location, either replacing the current entry, or adding - // a new one to the browser history. - _updateHash: function(location, fragment, replace) { - if (replace) { - var href = location.href.replace(/(javascript:|#).*$/, ''); - location.replace(href + '#' + fragment); - } else { - // Some browsers require that `hash` contains a leading #. - location.hash = '#' + fragment; - } - } - - }); - - // Create the default Backbone.history. - Backbone.history = new History; - - // Helpers - // ------- - - // Helper function to correctly set up the prototype chain for subclasses. - // Similar to `goog.inherits`, but uses a hash of prototype properties and - // class properties to be extended. - var extend = function(protoProps, staticProps) { - var parent = this; - var child; - - // The constructor function for the new subclass is either defined by you - // (the "constructor" property in your `extend` definition), or defaulted - // by us to simply call the parent constructor. - if (protoProps && _.has(protoProps, 'constructor')) { - child = protoProps.constructor; - } else { - child = function(){ return parent.apply(this, arguments); }; - } - - // Add static properties to the constructor function, if supplied. - _.extend(child, parent, staticProps); - - // Set the prototype chain to inherit from `parent`, without calling - // `parent`'s constructor function and add the prototype properties. - child.prototype = _.create(parent.prototype, protoProps); - child.prototype.constructor = child; - - // Set a convenience property in case the parent's prototype is needed - // later. - child.__super__ = parent.prototype; - - return child; - }; - - // Set up inheritance for the model, collection, router, view and history. - Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend; - - // Throw an error when a URL is needed, and none is supplied. - var urlError = function() { - throw new Error('A "url" property or function must be specified'); - }; - - // Wrap an optional error callback with a fallback error event. - var wrapError = function(model, options) { - var error = options.error; - options.error = function(resp) { - if (error) error.call(options.context, model, resp, options); - model.trigger('error', model, resp, options); - }; - }; - - return Backbone; -}); diff --git a/public/vendor/lodash/vendor/backbone/test/collection.js b/public/vendor/lodash/vendor/backbone/test/collection.js deleted file mode 100644 index 4d1dd44832a..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/collection.js +++ /dev/null @@ -1,2023 +0,0 @@ -(function(QUnit) { - - var a, b, c, d, e, col, otherCol; - - QUnit.module('Backbone.Collection', { - - beforeEach: function(assert) { - a = new Backbone.Model({id: 3, label: 'a'}); - b = new Backbone.Model({id: 2, label: 'b'}); - c = new Backbone.Model({id: 1, label: 'c'}); - d = new Backbone.Model({id: 0, label: 'd'}); - e = null; - col = new Backbone.Collection([a, b, c, d]); - otherCol = new Backbone.Collection(); - } - - }); - - QUnit.test('new and sort', function(assert) { - assert.expect(6); - var counter = 0; - col.on('sort', function(){ counter++; }); - assert.deepEqual(col.pluck('label'), ['a', 'b', 'c', 'd']); - col.comparator = function(m1, m2) { - return m1.id > m2.id ? -1 : 1; - }; - col.sort(); - assert.equal(counter, 1); - assert.deepEqual(col.pluck('label'), ['a', 'b', 'c', 'd']); - col.comparator = function(model) { return model.id; }; - col.sort(); - assert.equal(counter, 2); - assert.deepEqual(col.pluck('label'), ['d', 'c', 'b', 'a']); - assert.equal(col.length, 4); - }); - - QUnit.test('String comparator.', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([ - {id: 3}, - {id: 1}, - {id: 2} - ], {comparator: 'id'}); - assert.deepEqual(collection.pluck('id'), [1, 2, 3]); - }); - - QUnit.test('new and parse', function(assert) { - assert.expect(3); - var Collection = Backbone.Collection.extend({ - parse: function(data) { - return _.filter(data, function(datum) { - return datum.a % 2 === 0; - }); - } - }); - var models = [{a: 1}, {a: 2}, {a: 3}, {a: 4}]; - var collection = new Collection(models, {parse: true}); - assert.strictEqual(collection.length, 2); - assert.strictEqual(collection.first().get('a'), 2); - assert.strictEqual(collection.last().get('a'), 4); - }); - - QUnit.test('clone preserves model and comparator', function(assert) { - assert.expect(3); - var Model = Backbone.Model.extend(); - var comparator = function(model){ return model.id; }; - - var collection = new Backbone.Collection([{id: 1}], { - model: Model, - comparator: comparator - }).clone(); - collection.add({id: 2}); - assert.ok(collection.at(0) instanceof Model); - assert.ok(collection.at(1) instanceof Model); - assert.strictEqual(collection.comparator, comparator); - }); - - QUnit.test('get', function(assert) { - assert.expect(6); - assert.equal(col.get(0), d); - assert.equal(col.get(d.clone()), d); - assert.equal(col.get(2), b); - assert.equal(col.get({id: 1}), c); - assert.equal(col.get(c.clone()), c); - assert.equal(col.get(col.first().cid), col.first()); - }); - - QUnit.test('get with non-default ids', function(assert) { - assert.expect(5); - var MongoModel = Backbone.Model.extend({idAttribute: '_id'}); - var model = new MongoModel({_id: 100}); - var collection = new Backbone.Collection([model], {model: MongoModel}); - assert.equal(collection.get(100), model); - assert.equal(collection.get(model.cid), model); - assert.equal(collection.get(model), model); - assert.equal(collection.get(101), void 0); - - var collection2 = new Backbone.Collection(); - collection2.model = MongoModel; - collection2.add(model.attributes); - assert.equal(collection2.get(model.clone()), collection2.first()); - }); - - QUnit.test('has', function(assert) { - assert.expect(15); - assert.ok(col.has(a)); - assert.ok(col.has(b)); - assert.ok(col.has(c)); - assert.ok(col.has(d)); - assert.ok(col.has(a.id)); - assert.ok(col.has(b.id)); - assert.ok(col.has(c.id)); - assert.ok(col.has(d.id)); - assert.ok(col.has(a.cid)); - assert.ok(col.has(b.cid)); - assert.ok(col.has(c.cid)); - assert.ok(col.has(d.cid)); - var outsider = new Backbone.Model({id: 4}); - assert.notOk(col.has(outsider)); - assert.notOk(col.has(outsider.id)); - assert.notOk(col.has(outsider.cid)); - }); - - QUnit.test('update index when id changes', function(assert) { - assert.expect(4); - var collection = new Backbone.Collection(); - collection.add([ - {id: 0, name: 'one'}, - {id: 1, name: 'two'} - ]); - var one = collection.get(0); - assert.equal(one.get('name'), 'one'); - collection.on('change:name', function(model) { assert.ok(this.get(model)); }); - one.set({name: 'dalmatians', id: 101}); - assert.equal(collection.get(0), null); - assert.equal(collection.get(101).get('name'), 'dalmatians'); - }); - - QUnit.test('at', function(assert) { - assert.expect(2); - assert.equal(col.at(2), c); - assert.equal(col.at(-2), c); - }); - - QUnit.test('pluck', function(assert) { - assert.expect(1); - assert.equal(col.pluck('label').join(' '), 'a b c d'); - }); - - QUnit.test('add', function(assert) { - assert.expect(14); - var added, opts, secondAdded; - added = opts = secondAdded = null; - e = new Backbone.Model({id: 10, label: 'e'}); - otherCol.add(e); - otherCol.on('add', function() { - secondAdded = true; - }); - col.on('add', function(model, collection, options){ - added = model.get('label'); - opts = options; - }); - col.add(e, {amazing: true}); - assert.equal(added, 'e'); - assert.equal(col.length, 5); - assert.equal(col.last(), e); - assert.equal(otherCol.length, 1); - assert.equal(secondAdded, null); - assert.ok(opts.amazing); - - var f = new Backbone.Model({id: 20, label: 'f'}); - var g = new Backbone.Model({id: 21, label: 'g'}); - var h = new Backbone.Model({id: 22, label: 'h'}); - var atCol = new Backbone.Collection([f, g, h]); - assert.equal(atCol.length, 3); - atCol.add(e, {at: 1}); - assert.equal(atCol.length, 4); - assert.equal(atCol.at(1), e); - assert.equal(atCol.last(), h); - - var coll = new Backbone.Collection(new Array(2)); - var addCount = 0; - coll.on('add', function(){ - addCount += 1; - }); - coll.add([undefined, f, g]); - assert.equal(coll.length, 5); - assert.equal(addCount, 3); - coll.add(new Array(4)); - assert.equal(coll.length, 9); - assert.equal(addCount, 7); - }); - - QUnit.test('add multiple models', function(assert) { - assert.expect(6); - var collection = new Backbone.Collection([{at: 0}, {at: 1}, {at: 9}]); - collection.add([{at: 2}, {at: 3}, {at: 4}, {at: 5}, {at: 6}, {at: 7}, {at: 8}], {at: 2}); - for (var i = 0; i <= 5; i++) { - assert.equal(collection.at(i).get('at'), i); - } - }); - - QUnit.test('add; at should have preference over comparator', function(assert) { - assert.expect(1); - var Col = Backbone.Collection.extend({ - comparator: function(m1, m2) { - return m1.id > m2.id ? -1 : 1; - } - }); - - var collection = new Col([{id: 2}, {id: 3}]); - collection.add(new Backbone.Model({id: 1}), {at: 1}); - - assert.equal(collection.pluck('id').join(' '), '3 1 2'); - }); - - QUnit.test('add; at should add to the end if the index is out of bounds', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([{id: 2}, {id: 3}]); - collection.add(new Backbone.Model({id: 1}), {at: 5}); - - assert.equal(collection.pluck('id').join(' '), '2 3 1'); - }); - - QUnit.test("can't add model to collection twice", function(assert) { - var collection = new Backbone.Collection([{id: 1}, {id: 2}, {id: 1}, {id: 2}, {id: 3}]); - assert.equal(collection.pluck('id').join(' '), '1 2 3'); - }); - - QUnit.test("can't add different model with same id to collection twice", function(assert) { - assert.expect(1); - var collection = new Backbone.Collection; - collection.unshift({id: 101}); - collection.add({id: 101}); - assert.equal(collection.length, 1); - }); - - QUnit.test('merge in duplicate models with {merge: true}', function(assert) { - assert.expect(3); - var collection = new Backbone.Collection; - collection.add([{id: 1, name: 'Moe'}, {id: 2, name: 'Curly'}, {id: 3, name: 'Larry'}]); - collection.add({id: 1, name: 'Moses'}); - assert.equal(collection.first().get('name'), 'Moe'); - collection.add({id: 1, name: 'Moses'}, {merge: true}); - assert.equal(collection.first().get('name'), 'Moses'); - collection.add({id: 1, name: 'Tim'}, {merge: true, silent: true}); - assert.equal(collection.first().get('name'), 'Tim'); - }); - - QUnit.test('add model to multiple collections', function(assert) { - assert.expect(10); - var counter = 0; - var m = new Backbone.Model({id: 10, label: 'm'}); - m.on('add', function(model, collection) { - counter++; - assert.equal(m, model); - if (counter > 1) { - assert.equal(collection, col2); - } else { - assert.equal(collection, col1); - } - }); - var col1 = new Backbone.Collection([]); - col1.on('add', function(model, collection) { - assert.equal(m, model); - assert.equal(col1, collection); - }); - var col2 = new Backbone.Collection([]); - col2.on('add', function(model, collection) { - assert.equal(m, model); - assert.equal(col2, collection); - }); - col1.add(m); - assert.equal(m.collection, col1); - col2.add(m); - assert.equal(m.collection, col1); - }); - - QUnit.test('add model with parse', function(assert) { - assert.expect(1); - var Model = Backbone.Model.extend({ - parse: function(obj) { - obj.value += 1; - return obj; - } - }); - - var Col = Backbone.Collection.extend({model: Model}); - var collection = new Col; - collection.add({value: 1}, {parse: true}); - assert.equal(collection.at(0).get('value'), 2); - }); - - QUnit.test('add with parse and merge', function(assert) { - var collection = new Backbone.Collection(); - collection.parse = function(attrs) { - return _.map(attrs, function(model) { - if (model.model) return model.model; - return model; - }); - }; - collection.add({id: 1}); - collection.add({model: {id: 1, name: 'Alf'}}, {parse: true, merge: true}); - assert.equal(collection.first().get('name'), 'Alf'); - }); - - QUnit.test('add model to collection with sort()-style comparator', function(assert) { - assert.expect(3); - var collection = new Backbone.Collection; - collection.comparator = function(m1, m2) { - return m1.get('name') < m2.get('name') ? -1 : 1; - }; - var tom = new Backbone.Model({name: 'Tom'}); - var rob = new Backbone.Model({name: 'Rob'}); - var tim = new Backbone.Model({name: 'Tim'}); - collection.add(tom); - collection.add(rob); - collection.add(tim); - assert.equal(collection.indexOf(rob), 0); - assert.equal(collection.indexOf(tim), 1); - assert.equal(collection.indexOf(tom), 2); - }); - - QUnit.test('comparator that depends on `this`', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection; - collection.negative = function(num) { - return -num; - }; - collection.comparator = function(model) { - return this.negative(model.id); - }; - collection.add([{id: 1}, {id: 2}, {id: 3}]); - assert.deepEqual(collection.pluck('id'), [3, 2, 1]); - collection.comparator = function(m1, m2) { - return this.negative(m2.id) - this.negative(m1.id); - }; - collection.sort(); - assert.deepEqual(collection.pluck('id'), [1, 2, 3]); - }); - - QUnit.test('remove', function(assert) { - assert.expect(12); - var removed = null; - var result = null; - col.on('remove', function(model, collection, options) { - removed = model.get('label'); - assert.equal(options.index, 3); - assert.equal(collection.get(model), undefined, '#3693: model cannot be fetched from collection'); - }); - result = col.remove(d); - assert.equal(removed, 'd'); - assert.strictEqual(result, d); - //if we try to remove d again, it's not going to actually get removed - result = col.remove(d); - assert.strictEqual(result, undefined); - assert.equal(col.length, 3); - assert.equal(col.first(), a); - col.off(); - result = col.remove([c, d]); - assert.equal(result.length, 1, 'only returns removed models'); - assert.equal(result[0], c, 'only returns removed models'); - result = col.remove([c, b]); - assert.equal(result.length, 1, 'only returns removed models'); - assert.equal(result[0], b, 'only returns removed models'); - result = col.remove([]); - assert.deepEqual(result, [], 'returns empty array when nothing removed'); - }); - - QUnit.test('add and remove return values', function(assert) { - assert.expect(13); - var Even = Backbone.Model.extend({ - validate: function(attrs) { - if (attrs.id % 2 !== 0) return 'odd'; - } - }); - var collection = new Backbone.Collection; - collection.model = Even; - - var list = collection.add([{id: 2}, {id: 4}], {validate: true}); - assert.equal(list.length, 2); - assert.ok(list[0] instanceof Backbone.Model); - assert.equal(list[1], collection.last()); - assert.equal(list[1].get('id'), 4); - - list = collection.add([{id: 3}, {id: 6}], {validate: true}); - assert.equal(collection.length, 3); - assert.equal(list[0], false); - assert.equal(list[1].get('id'), 6); - - var result = collection.add({id: 6}); - assert.equal(result.cid, list[1].cid); - - result = collection.remove({id: 6}); - assert.equal(collection.length, 2); - assert.equal(result.id, 6); - - list = collection.remove([{id: 2}, {id: 8}]); - assert.equal(collection.length, 1); - assert.equal(list[0].get('id'), 2); - assert.equal(list[1], null); - }); - - QUnit.test('shift and pop', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection([{a: 'a'}, {b: 'b'}, {c: 'c'}]); - assert.equal(collection.shift().get('a'), 'a'); - assert.equal(collection.pop().get('c'), 'c'); - }); - - QUnit.test('slice', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection([{a: 'a'}, {b: 'b'}, {c: 'c'}]); - var array = collection.slice(1, 3); - assert.equal(array.length, 2); - assert.equal(array[0].get('b'), 'b'); - }); - - QUnit.test('events are unbound on remove', function(assert) { - assert.expect(3); - var counter = 0; - var dj = new Backbone.Model(); - var emcees = new Backbone.Collection([dj]); - emcees.on('change', function(){ counter++; }); - dj.set({name: 'Kool'}); - assert.equal(counter, 1); - emcees.reset([]); - assert.equal(dj.collection, undefined); - dj.set({name: 'Shadow'}); - assert.equal(counter, 1); - }); - - QUnit.test('remove in multiple collections', function(assert) { - assert.expect(7); - var modelData = { - id: 5, - title: 'Othello' - }; - var passed = false; - var m1 = new Backbone.Model(modelData); - var m2 = new Backbone.Model(modelData); - m2.on('remove', function() { - passed = true; - }); - var col1 = new Backbone.Collection([m1]); - var col2 = new Backbone.Collection([m2]); - assert.notEqual(m1, m2); - assert.ok(col1.length === 1); - assert.ok(col2.length === 1); - col1.remove(m1); - assert.equal(passed, false); - assert.ok(col1.length === 0); - col2.remove(m1); - assert.ok(col2.length === 0); - assert.equal(passed, true); - }); - - QUnit.test('remove same model in multiple collection', function(assert) { - assert.expect(16); - var counter = 0; - var m = new Backbone.Model({id: 5, title: 'Othello'}); - m.on('remove', function(model, collection) { - counter++; - assert.equal(m, model); - if (counter > 1) { - assert.equal(collection, col1); - } else { - assert.equal(collection, col2); - } - }); - var col1 = new Backbone.Collection([m]); - col1.on('remove', function(model, collection) { - assert.equal(m, model); - assert.equal(col1, collection); - }); - var col2 = new Backbone.Collection([m]); - col2.on('remove', function(model, collection) { - assert.equal(m, model); - assert.equal(col2, collection); - }); - assert.equal(col1, m.collection); - col2.remove(m); - assert.ok(col2.length === 0); - assert.ok(col1.length === 1); - assert.equal(counter, 1); - assert.equal(col1, m.collection); - col1.remove(m); - assert.equal(null, m.collection); - assert.ok(col1.length === 0); - assert.equal(counter, 2); - }); - - QUnit.test('model destroy removes from all collections', function(assert) { - assert.expect(3); - var m = new Backbone.Model({id: 5, title: 'Othello'}); - m.sync = function(method, model, options) { options.success(); }; - var col1 = new Backbone.Collection([m]); - var col2 = new Backbone.Collection([m]); - m.destroy(); - assert.ok(col1.length === 0); - assert.ok(col2.length === 0); - assert.equal(undefined, m.collection); - }); - - QUnit.test('Collection: non-persisted model destroy removes from all collections', function(assert) { - assert.expect(3); - var m = new Backbone.Model({title: 'Othello'}); - m.sync = function(method, model, options) { throw 'should not be called'; }; - var col1 = new Backbone.Collection([m]); - var col2 = new Backbone.Collection([m]); - m.destroy(); - assert.ok(col1.length === 0); - assert.ok(col2.length === 0); - assert.equal(undefined, m.collection); - }); - - QUnit.test('fetch', function(assert) { - assert.expect(4); - var collection = new Backbone.Collection; - collection.url = '/test'; - collection.fetch(); - assert.equal(this.syncArgs.method, 'read'); - assert.equal(this.syncArgs.model, collection); - assert.equal(this.syncArgs.options.parse, true); - - collection.fetch({parse: false}); - assert.equal(this.syncArgs.options.parse, false); - }); - - QUnit.test('fetch with an error response triggers an error event', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection(); - collection.on('error', function() { - assert.ok(true); - }); - collection.sync = function(method, model, options) { options.error(); }; - collection.fetch(); - }); - - QUnit.test('#3283 - fetch with an error response calls error with context', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection(); - var obj = {}; - var options = { - context: obj, - error: function() { - assert.equal(this, obj); - } - }; - collection.sync = function(method, model, opts) { - opts.error.call(opts.context); - }; - collection.fetch(options); - }); - - QUnit.test('ensure fetch only parses once', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection; - var counter = 0; - collection.parse = function(models) { - counter++; - return models; - }; - collection.url = '/test'; - collection.fetch(); - this.syncArgs.options.success([]); - assert.equal(counter, 1); - }); - - QUnit.test('create', function(assert) { - assert.expect(4); - var collection = new Backbone.Collection; - collection.url = '/test'; - var model = collection.create({label: 'f'}, {wait: true}); - assert.equal(this.syncArgs.method, 'create'); - assert.equal(this.syncArgs.model, model); - assert.equal(model.get('label'), 'f'); - assert.equal(model.collection, collection); - }); - - QUnit.test('create with validate:true enforces validation', function(assert) { - assert.expect(3); - var ValidatingModel = Backbone.Model.extend({ - validate: function(attrs) { - return 'fail'; - } - }); - var ValidatingCollection = Backbone.Collection.extend({ - model: ValidatingModel - }); - var collection = new ValidatingCollection(); - collection.on('invalid', function(coll, error, options) { - assert.equal(error, 'fail'); - assert.equal(options.validationError, 'fail'); - }); - assert.equal(collection.create({foo: 'bar'}, {validate: true}), false); - }); - - QUnit.test('create will pass extra options to success callback', function(assert) { - assert.expect(1); - var Model = Backbone.Model.extend({ - sync: function(method, model, options) { - _.extend(options, {specialSync: true}); - return Backbone.Model.prototype.sync.call(this, method, model, options); - } - }); - - var Collection = Backbone.Collection.extend({ - model: Model, - url: '/test' - }); - - var collection = new Collection; - - var success = function(model, response, options) { - assert.ok(options.specialSync, 'Options were passed correctly to callback'); - }; - - collection.create({}, {success: success}); - this.ajaxSettings.success(); - }); - - QUnit.test('create with wait:true should not call collection.parse', function(assert) { - assert.expect(0); - var Collection = Backbone.Collection.extend({ - url: '/test', - parse: function() { - assert.ok(false); - } - }); - - var collection = new Collection; - - collection.create({}, {wait: true}); - this.ajaxSettings.success(); - }); - - QUnit.test('a failing create returns model with errors', function(assert) { - var ValidatingModel = Backbone.Model.extend({ - validate: function(attrs) { - return 'fail'; - } - }); - var ValidatingCollection = Backbone.Collection.extend({ - model: ValidatingModel - }); - var collection = new ValidatingCollection(); - var m = collection.create({foo: 'bar'}); - assert.equal(m.validationError, 'fail'); - assert.equal(collection.length, 1); - }); - - QUnit.test('initialize', function(assert) { - assert.expect(1); - var Collection = Backbone.Collection.extend({ - initialize: function() { - this.one = 1; - } - }); - var coll = new Collection; - assert.equal(coll.one, 1); - }); - - QUnit.test('preinitialize', function(assert) { - assert.expect(1); - var Collection = Backbone.Collection.extend({ - preinitialize: function() { - this.one = 1; - } - }); - var coll = new Collection; - assert.equal(coll.one, 1); - }); - - QUnit.test('preinitialize occurs before the collection is set up', function(assert) { - assert.expect(2); - var Collection = Backbone.Collection.extend({ - preinitialize: function() { - assert.notEqual(this.model, FooModel); - } - }); - var FooModel = Backbone.Model.extend({id: 'foo'}); - var coll = new Collection({}, { - model: FooModel - }); - assert.equal(coll.model, FooModel); - }); - - QUnit.test('toJSON', function(assert) { - assert.expect(1); - assert.equal(JSON.stringify(col), '[{"id":3,"label":"a"},{"id":2,"label":"b"},{"id":1,"label":"c"},{"id":0,"label":"d"}]'); - }); - - QUnit.test('where and findWhere', function(assert) { - assert.expect(8); - var model = new Backbone.Model({a: 1}); - var coll = new Backbone.Collection([ - model, - {a: 1}, - {a: 1, b: 2}, - {a: 2, b: 2}, - {a: 3} - ]); - assert.equal(coll.where({a: 1}).length, 3); - assert.equal(coll.where({a: 2}).length, 1); - assert.equal(coll.where({a: 3}).length, 1); - assert.equal(coll.where({b: 1}).length, 0); - assert.equal(coll.where({b: 2}).length, 2); - assert.equal(coll.where({a: 1, b: 2}).length, 1); - assert.equal(coll.findWhere({a: 1}), model); - assert.equal(coll.findWhere({a: 4}), void 0); - }); - - QUnit.test('Underscore methods', function(assert) { - assert.expect(21); - assert.equal(col.map(function(model){ return model.get('label'); }).join(' '), 'a b c d'); - assert.equal(col.some(function(model){ return model.id === 100; }), false); - assert.equal(col.some(function(model){ return model.id === 0; }), true); - assert.equal(col.reduce(function(m1, m2) {return m1.id > m2.id ? m1 : m2;}).id, 3); - assert.equal(col.reduceRight(function(m1, m2) {return m1.id > m2.id ? m1 : m2;}).id, 3); - assert.equal(col.indexOf(b), 1); - assert.equal(col.size(), 4); - assert.equal(col.rest().length, 3); - assert.ok(!_.includes(col.rest(), a)); - assert.ok(_.includes(col.rest(), d)); - assert.ok(!col.isEmpty()); - assert.ok(!_.includes(col.without(d), d)); - - var wrapped = col.chain(); - assert.equal(wrapped.map('id').max().value(), 3); - assert.equal(wrapped.map('id').min().value(), 0); - assert.deepEqual(wrapped - .filter(function(o){ return o.id % 2 === 0; }) - .map(function(o){ return o.id * 2; }) - .value(), - [4, 0]); - assert.deepEqual(col.difference([c, d]), [a, b]); - assert.ok(col.includes(col.sample())); - - var first = col.first(); - assert.deepEqual(col.groupBy(function(model){ return model.id; })[first.id], [first]); - assert.deepEqual(col.countBy(function(model){ return model.id; }), {0: 1, 1: 1, 2: 1, 3: 1}); - assert.deepEqual(col.sortBy(function(model){ return model.id; })[0], col.at(3)); - assert.ok(col.indexBy('id')[first.id] === first); - }); - - QUnit.test('Underscore methods with object-style and property-style iteratee', function(assert) { - assert.expect(26); - var model = new Backbone.Model({a: 4, b: 1, e: 3}); - var coll = new Backbone.Collection([ - {a: 1, b: 1}, - {a: 2, b: 1, c: 1}, - {a: 3, b: 1}, - model - ]); - assert.equal(coll.find({a: 0}), undefined); - assert.deepEqual(coll.find({a: 4}), model); - assert.equal(coll.find('d'), undefined); - assert.deepEqual(coll.find('e'), model); - assert.equal(coll.filter({a: 0}), false); - assert.deepEqual(coll.filter({a: 4}), [model]); - assert.equal(coll.some({a: 0}), false); - assert.equal(coll.some({a: 1}), true); - assert.equal(coll.reject({a: 0}).length, 4); - assert.deepEqual(coll.reject({a: 4}), _.without(coll.models, model)); - assert.equal(coll.every({a: 0}), false); - assert.equal(coll.every({b: 1}), true); - assert.deepEqual(coll.partition({a: 0})[0], []); - assert.deepEqual(coll.partition({a: 0})[1], coll.models); - assert.deepEqual(coll.partition({a: 4})[0], [model]); - assert.deepEqual(coll.partition({a: 4})[1], _.without(coll.models, model)); - assert.deepEqual(coll.map({a: 2}), [false, true, false, false]); - assert.deepEqual(coll.map('a'), [1, 2, 3, 4]); - assert.deepEqual(coll.sortBy('a')[3], model); - assert.deepEqual(coll.sortBy('e')[0], model); - assert.deepEqual(coll.countBy({a: 4}), {'false': 3, 'true': 1}); - assert.deepEqual(coll.countBy('d'), {'undefined': 4}); - assert.equal(coll.findIndex({b: 1}), 0); - assert.equal(coll.findIndex({b: 9}), -1); - assert.equal(coll.findLastIndex({b: 1}), 3); - assert.equal(coll.findLastIndex({b: 9}), -1); - }); - - QUnit.test('reset', function(assert) { - assert.expect(16); - - var resetCount = 0; - var models = col.models; - col.on('reset', function() { resetCount += 1; }); - col.reset([]); - assert.equal(resetCount, 1); - assert.equal(col.length, 0); - assert.equal(col.last(), null); - col.reset(models); - assert.equal(resetCount, 2); - assert.equal(col.length, 4); - assert.equal(col.last(), d); - col.reset(_.map(models, function(m){ return m.attributes; })); - assert.equal(resetCount, 3); - assert.equal(col.length, 4); - assert.ok(col.last() !== d); - assert.ok(_.isEqual(col.last().attributes, d.attributes)); - col.reset(); - assert.equal(col.length, 0); - assert.equal(resetCount, 4); - - var f = new Backbone.Model({id: 20, label: 'f'}); - col.reset([undefined, f]); - assert.equal(col.length, 2); - assert.equal(resetCount, 5); - - col.reset(new Array(4)); - assert.equal(col.length, 4); - assert.equal(resetCount, 6); - }); - - QUnit.test('reset with different values', function(assert) { - var collection = new Backbone.Collection({id: 1}); - collection.reset({id: 1, a: 1}); - assert.equal(collection.get(1).get('a'), 1); - }); - - QUnit.test('same references in reset', function(assert) { - var model = new Backbone.Model({id: 1}); - var collection = new Backbone.Collection({id: 1}); - collection.reset(model); - assert.equal(collection.get(1), model); - }); - - QUnit.test('reset passes caller options', function(assert) { - assert.expect(3); - var Model = Backbone.Model.extend({ - initialize: function(attrs, options) { - this.modelParameter = options.modelParameter; - } - }); - var collection = new (Backbone.Collection.extend({model: Model}))(); - collection.reset([{astring: 'green', anumber: 1}, {astring: 'blue', anumber: 2}], {modelParameter: 'model parameter'}); - assert.equal(collection.length, 2); - collection.each(function(model) { - assert.equal(model.modelParameter, 'model parameter'); - }); - }); - - QUnit.test('reset does not alter options by reference', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection([{id: 1}]); - var origOpts = {}; - collection.on('reset', function(coll, opts){ - assert.equal(origOpts.previousModels, undefined); - assert.equal(opts.previousModels[0].id, 1); - }); - collection.reset([], origOpts); - }); - - QUnit.test('trigger custom events on models', function(assert) { - assert.expect(1); - var fired = null; - a.on('custom', function() { fired = true; }); - a.trigger('custom'); - assert.equal(fired, true); - }); - - QUnit.test('add does not alter arguments', function(assert) { - assert.expect(2); - var attrs = {}; - var models = [attrs]; - new Backbone.Collection().add(models); - assert.equal(models.length, 1); - assert.ok(attrs === models[0]); - }); - - QUnit.test('#714: access `model.collection` in a brand new model.', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection; - collection.url = '/test'; - var Model = Backbone.Model.extend({ - set: function(attrs) { - assert.equal(attrs.prop, 'value'); - assert.equal(this.collection, collection); - return this; - } - }); - collection.model = Model; - collection.create({prop: 'value'}); - }); - - QUnit.test('#574, remove its own reference to the .models array.', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection([ - {id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6} - ]); - assert.equal(collection.length, 6); - collection.remove(collection.models); - assert.equal(collection.length, 0); - }); - - QUnit.test('#861, adding models to a collection which do not pass validation, with validate:true', function(assert) { - assert.expect(2); - var Model = Backbone.Model.extend({ - validate: function(attrs) { - if (attrs.id === 3) return "id can't be 3"; - } - }); - - var Collection = Backbone.Collection.extend({ - model: Model - }); - - var collection = new Collection; - collection.on('invalid', function() { assert.ok(true); }); - - collection.add([{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}], {validate: true}); - assert.deepEqual(collection.pluck('id'), [1, 2, 4, 5, 6]); - }); - - QUnit.test('Invalid models are discarded with validate:true.', function(assert) { - assert.expect(5); - var collection = new Backbone.Collection; - collection.on('test', function() { assert.ok(true); }); - collection.model = Backbone.Model.extend({ - validate: function(attrs){ if (!attrs.valid) return 'invalid'; } - }); - var model = new collection.model({id: 1, valid: true}); - collection.add([model, {id: 2}], {validate: true}); - model.trigger('test'); - assert.ok(collection.get(model.cid)); - assert.ok(collection.get(1)); - assert.ok(!collection.get(2)); - assert.equal(collection.length, 1); - }); - - QUnit.test('multiple copies of the same model', function(assert) { - assert.expect(3); - var collection = new Backbone.Collection(); - var model = new Backbone.Model(); - collection.add([model, model]); - assert.equal(collection.length, 1); - collection.add([{id: 1}, {id: 1}]); - assert.equal(collection.length, 2); - assert.equal(collection.last().id, 1); - }); - - QUnit.test('#964 - collection.get return inconsistent', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection(); - assert.ok(collection.get(null) === undefined); - assert.ok(collection.get() === undefined); - }); - - QUnit.test('#1112 - passing options.model sets collection.model', function(assert) { - assert.expect(2); - var Model = Backbone.Model.extend({}); - var collection = new Backbone.Collection([{id: 1}], {model: Model}); - assert.ok(collection.model === Model); - assert.ok(collection.at(0) instanceof Model); - }); - - QUnit.test('null and undefined are invalid ids.', function(assert) { - assert.expect(2); - var model = new Backbone.Model({id: 1}); - var collection = new Backbone.Collection([model]); - model.set({id: null}); - assert.ok(!collection.get('null')); - model.set({id: 1}); - model.set({id: undefined}); - assert.ok(!collection.get('undefined')); - }); - - QUnit.test('falsy comparator', function(assert) { - assert.expect(4); - var Col = Backbone.Collection.extend({ - comparator: function(model){ return model.id; } - }); - var collection = new Col(); - var colFalse = new Col(null, {comparator: false}); - var colNull = new Col(null, {comparator: null}); - var colUndefined = new Col(null, {comparator: undefined}); - assert.ok(collection.comparator); - assert.ok(!colFalse.comparator); - assert.ok(!colNull.comparator); - assert.ok(colUndefined.comparator); - }); - - QUnit.test('#1355 - `options` is passed to success callbacks', function(assert) { - assert.expect(2); - var m = new Backbone.Model({x: 1}); - var collection = new Backbone.Collection(); - var opts = { - opts: true, - success: function(coll, resp, options) { - assert.ok(options.opts); - } - }; - collection.sync = m.sync = function( method, coll, options ){ - options.success({}); - }; - collection.fetch(opts); - collection.create(m, opts); - }); - - QUnit.test("#1412 - Trigger 'request' and 'sync' events.", function(assert) { - assert.expect(4); - var collection = new Backbone.Collection; - collection.url = '/test'; - Backbone.ajax = function(settings){ settings.success(); }; - - collection.on('request', function(obj, xhr, options) { - assert.ok(obj === collection, "collection has correct 'request' event after fetching"); - }); - collection.on('sync', function(obj, response, options) { - assert.ok(obj === collection, "collection has correct 'sync' event after fetching"); - }); - collection.fetch(); - collection.off(); - - collection.on('request', function(obj, xhr, options) { - assert.ok(obj === collection.get(1), "collection has correct 'request' event after one of its models save"); - }); - collection.on('sync', function(obj, response, options) { - assert.ok(obj === collection.get(1), "collection has correct 'sync' event after one of its models save"); - }); - collection.create({id: 1}); - collection.off(); - }); - - QUnit.test('#3283 - fetch, create calls success with context', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection; - collection.url = '/test'; - Backbone.ajax = function(settings) { - settings.success.call(settings.context); - }; - var obj = {}; - var options = { - context: obj, - success: function() { - assert.equal(this, obj); - } - }; - - collection.fetch(options); - collection.create({id: 1}, options); - }); - - QUnit.test('#1447 - create with wait adds model.', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection; - var model = new Backbone.Model; - model.sync = function(method, m, options){ options.success(); }; - collection.on('add', function(){ assert.ok(true); }); - collection.create(model, {wait: true}); - }); - - QUnit.test('#1448 - add sorts collection after merge.', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([ - {id: 1, x: 1}, - {id: 2, x: 2} - ]); - collection.comparator = function(model){ return model.get('x'); }; - collection.add({id: 1, x: 3}, {merge: true}); - assert.deepEqual(collection.pluck('id'), [2, 1]); - }); - - QUnit.test('#1655 - groupBy can be used with a string argument.', function(assert) { - assert.expect(3); - var collection = new Backbone.Collection([{x: 1}, {x: 2}]); - var grouped = collection.groupBy('x'); - assert.strictEqual(_.keys(grouped).length, 2); - assert.strictEqual(grouped[1][0].get('x'), 1); - assert.strictEqual(grouped[2][0].get('x'), 2); - }); - - QUnit.test('#1655 - sortBy can be used with a string argument.', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([{x: 3}, {x: 1}, {x: 2}]); - var values = _.map(collection.sortBy('x'), function(model) { - return model.get('x'); - }); - assert.deepEqual(values, [1, 2, 3]); - }); - - QUnit.test('#1604 - Removal during iteration.', function(assert) { - assert.expect(0); - var collection = new Backbone.Collection([{}, {}]); - collection.on('add', function() { - collection.at(0).destroy(); - }); - collection.add({}, {at: 0}); - }); - - QUnit.test('#1638 - `sort` during `add` triggers correctly.', function(assert) { - var collection = new Backbone.Collection; - collection.comparator = function(model) { return model.get('x'); }; - var added = []; - collection.on('add', function(model) { - model.set({x: 3}); - collection.sort(); - added.push(model.id); - }); - collection.add([{id: 1, x: 1}, {id: 2, x: 2}]); - assert.deepEqual(added, [1, 2]); - }); - - QUnit.test('fetch parses models by default', function(assert) { - assert.expect(1); - var model = {}; - var Collection = Backbone.Collection.extend({ - url: 'test', - model: Backbone.Model.extend({ - parse: function(resp) { - assert.strictEqual(resp, model); - } - }) - }); - new Collection().fetch(); - this.ajaxSettings.success([model]); - }); - - QUnit.test("`sort` shouldn't always fire on `add`", function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([{id: 1}, {id: 2}, {id: 3}], { - comparator: 'id' - }); - collection.sort = function(){ assert.ok(true); }; - collection.add([]); - collection.add({id: 1}); - collection.add([{id: 2}, {id: 3}]); - collection.add({id: 4}); - }); - - QUnit.test('#1407 parse option on constructor parses collection and models', function(assert) { - assert.expect(2); - var model = { - namespace: [{id: 1}, {id: 2}] - }; - var Collection = Backbone.Collection.extend({ - model: Backbone.Model.extend({ - parse: function(m) { - m.name = 'test'; - return m; - } - }), - parse: function(m) { - return m.namespace; - } - }); - var collection = new Collection(model, {parse: true}); - - assert.equal(collection.length, 2); - assert.equal(collection.at(0).get('name'), 'test'); - }); - - QUnit.test('#1407 parse option on reset parses collection and models', function(assert) { - assert.expect(2); - var model = { - namespace: [{id: 1}, {id: 2}] - }; - var Collection = Backbone.Collection.extend({ - model: Backbone.Model.extend({ - parse: function(m) { - m.name = 'test'; - return m; - } - }), - parse: function(m) { - return m.namespace; - } - }); - var collection = new Collection(); - collection.reset(model, {parse: true}); - - assert.equal(collection.length, 2); - assert.equal(collection.at(0).get('name'), 'test'); - }); - - - QUnit.test('Reset includes previous models in triggered event.', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - var collection = new Backbone.Collection([model]); - collection.on('reset', function(coll, options) { - assert.deepEqual(options.previousModels, [model]); - }); - collection.reset([]); - }); - - QUnit.test('set', function(assert) { - var m1 = new Backbone.Model(); - var m2 = new Backbone.Model({id: 2}); - var m3 = new Backbone.Model(); - var collection = new Backbone.Collection([m1, m2]); - - // Test add/change/remove events - collection.on('add', function(model) { - assert.strictEqual(model, m3); - }); - collection.on('change', function(model) { - assert.strictEqual(model, m2); - }); - collection.on('remove', function(model) { - assert.strictEqual(model, m1); - }); - - // remove: false doesn't remove any models - collection.set([], {remove: false}); - assert.strictEqual(collection.length, 2); - - // add: false doesn't add any models - collection.set([m1, m2, m3], {add: false}); - assert.strictEqual(collection.length, 2); - - // merge: false doesn't change any models - collection.set([m1, {id: 2, a: 1}], {merge: false}); - assert.strictEqual(m2.get('a'), void 0); - - // add: false, remove: false only merges existing models - collection.set([m1, {id: 2, a: 0}, m3, {id: 4}], {add: false, remove: false}); - assert.strictEqual(collection.length, 2); - assert.strictEqual(m2.get('a'), 0); - - // default options add/remove/merge as appropriate - collection.set([{id: 2, a: 1}, m3]); - assert.strictEqual(collection.length, 2); - assert.strictEqual(m2.get('a'), 1); - - // Test removing models not passing an argument - collection.off('remove').on('remove', function(model) { - assert.ok(model === m2 || model === m3); - }); - collection.set([]); - assert.strictEqual(collection.length, 0); - - // Test null models on set doesn't clear collection - collection.off(); - collection.set([{id: 1}]); - collection.set(); - assert.strictEqual(collection.length, 1); - }); - - QUnit.test('set with only cids', function(assert) { - assert.expect(3); - var m1 = new Backbone.Model; - var m2 = new Backbone.Model; - var collection = new Backbone.Collection; - collection.set([m1, m2]); - assert.equal(collection.length, 2); - collection.set([m1]); - assert.equal(collection.length, 1); - collection.set([m1, m1, m1, m2, m2], {remove: false}); - assert.equal(collection.length, 2); - }); - - QUnit.test('set with only idAttribute', function(assert) { - assert.expect(3); - var m1 = {_id: 1}; - var m2 = {_id: 2}; - var Col = Backbone.Collection.extend({ - model: Backbone.Model.extend({ - idAttribute: '_id' - }) - }); - var collection = new Col; - collection.set([m1, m2]); - assert.equal(collection.length, 2); - collection.set([m1]); - assert.equal(collection.length, 1); - collection.set([m1, m1, m1, m2, m2], {remove: false}); - assert.equal(collection.length, 2); - }); - - QUnit.test('set + merge with default values defined', function(assert) { - var Model = Backbone.Model.extend({ - defaults: { - key: 'value' - } - }); - var m = new Model({id: 1}); - var collection = new Backbone.Collection([m], {model: Model}); - assert.equal(collection.first().get('key'), 'value'); - - collection.set({id: 1, key: 'other'}); - assert.equal(collection.first().get('key'), 'other'); - - collection.set({id: 1, other: 'value'}); - assert.equal(collection.first().get('key'), 'other'); - assert.equal(collection.length, 1); - }); - - QUnit.test('merge without mutation', function(assert) { - var Model = Backbone.Model.extend({ - initialize: function(attrs, options) { - if (attrs.child) { - this.set('child', new Model(attrs.child, options), options); - } - } - }); - var Collection = Backbone.Collection.extend({model: Model}); - var data = [{id: 1, child: {id: 2}}]; - var collection = new Collection(data); - assert.equal(collection.first().id, 1); - collection.set(data); - assert.equal(collection.first().id, 1); - collection.set([{id: 2, child: {id: 2}}].concat(data)); - assert.deepEqual(collection.pluck('id'), [2, 1]); - }); - - QUnit.test('`set` and model level `parse`', function(assert) { - var Model = Backbone.Model.extend({}); - var Collection = Backbone.Collection.extend({ - model: Model, - parse: function(res) { return _.map(res.models, 'model'); } - }); - var model = new Model({id: 1}); - var collection = new Collection(model); - collection.set({models: [ - {model: {id: 1}}, - {model: {id: 2}} - ]}, {parse: true}); - assert.equal(collection.first(), model); - }); - - QUnit.test('`set` data is only parsed once', function(assert) { - var collection = new Backbone.Collection(); - collection.model = Backbone.Model.extend({ - parse: function(data) { - assert.equal(data.parsed, void 0); - data.parsed = true; - return data; - } - }); - collection.set({}, {parse: true}); - }); - - QUnit.test('`set` matches input order in the absence of a comparator', function(assert) { - var one = new Backbone.Model({id: 1}); - var two = new Backbone.Model({id: 2}); - var three = new Backbone.Model({id: 3}); - var collection = new Backbone.Collection([one, two, three]); - collection.set([{id: 3}, {id: 2}, {id: 1}]); - assert.deepEqual(collection.models, [three, two, one]); - collection.set([{id: 1}, {id: 2}]); - assert.deepEqual(collection.models, [one, two]); - collection.set([two, three, one]); - assert.deepEqual(collection.models, [two, three, one]); - collection.set([{id: 1}, {id: 2}], {remove: false}); - assert.deepEqual(collection.models, [two, three, one]); - collection.set([{id: 1}, {id: 2}, {id: 3}], {merge: false}); - assert.deepEqual(collection.models, [one, two, three]); - collection.set([three, two, one, {id: 4}], {add: false}); - assert.deepEqual(collection.models, [one, two, three]); - }); - - QUnit.test('#1894 - Push should not trigger a sort', function(assert) { - assert.expect(0); - var Collection = Backbone.Collection.extend({ - comparator: 'id', - sort: function() { assert.ok(false); } - }); - new Collection().push({id: 1}); - }); - - QUnit.test('#2428 - push duplicate models, return the correct one', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection; - var model1 = collection.push({id: 101}); - var model2 = collection.push({id: 101}); - assert.ok(model2.cid === model1.cid); - }); - - QUnit.test('`set` with non-normal id', function(assert) { - var Collection = Backbone.Collection.extend({ - model: Backbone.Model.extend({idAttribute: '_id'}) - }); - var collection = new Collection({_id: 1}); - collection.set([{_id: 1, a: 1}], {add: false}); - assert.equal(collection.first().get('a'), 1); - }); - - QUnit.test('#1894 - `sort` can optionally be turned off', function(assert) { - assert.expect(0); - var Collection = Backbone.Collection.extend({ - comparator: 'id', - sort: function() { assert.ok(false); } - }); - new Collection().add({id: 1}, {sort: false}); - }); - - QUnit.test('#1915 - `parse` data in the right order in `set`', function(assert) { - var collection = new (Backbone.Collection.extend({ - parse: function(data) { - assert.strictEqual(data.status, 'ok'); - return data.data; - } - })); - var res = {status: 'ok', data: [{id: 1}]}; - collection.set(res, {parse: true}); - }); - - QUnit.test('#1939 - `parse` is passed `options`', function(assert) { - var done = assert.async(); - assert.expect(1); - var collection = new (Backbone.Collection.extend({ - url: '/', - parse: function(data, options) { - assert.strictEqual(options.xhr.someHeader, 'headerValue'); - return data; - } - })); - var ajax = Backbone.ajax; - Backbone.ajax = function(params) { - _.defer(params.success, []); - return {someHeader: 'headerValue'}; - }; - collection.fetch({ - success: function() { done(); } - }); - Backbone.ajax = ajax; - }); - - QUnit.test('fetch will pass extra options to success callback', function(assert) { - assert.expect(1); - var SpecialSyncCollection = Backbone.Collection.extend({ - url: '/test', - sync: function(method, collection, options) { - _.extend(options, {specialSync: true}); - return Backbone.Collection.prototype.sync.call(this, method, collection, options); - } - }); - - var collection = new SpecialSyncCollection(); - - var onSuccess = function(coll, resp, options) { - assert.ok(options.specialSync, 'Options were passed correctly to callback'); - }; - - collection.fetch({success: onSuccess}); - this.ajaxSettings.success(); - }); - - QUnit.test('`add` only `sort`s when necessary', function(assert) { - assert.expect(2); - var collection = new (Backbone.Collection.extend({ - comparator: 'a' - }))([{id: 1}, {id: 2}, {id: 3}]); - collection.on('sort', function() { assert.ok(true); }); - collection.add({id: 4}); // do sort, new model - collection.add({id: 1, a: 1}, {merge: true}); // do sort, comparator change - collection.add({id: 1, b: 1}, {merge: true}); // don't sort, no comparator change - collection.add({id: 1, a: 1}, {merge: true}); // don't sort, no comparator change - collection.add(collection.models); // don't sort, nothing new - collection.add(collection.models, {merge: true}); // don't sort - }); - - QUnit.test('`add` only `sort`s when necessary with comparator function', function(assert) { - assert.expect(3); - var collection = new (Backbone.Collection.extend({ - comparator: function(m1, m2) { - return m1.get('a') > m2.get('a') ? 1 : (m1.get('a') < m2.get('a') ? -1 : 0); - } - }))([{id: 1}, {id: 2}, {id: 3}]); - collection.on('sort', function() { assert.ok(true); }); - collection.add({id: 4}); // do sort, new model - collection.add({id: 1, a: 1}, {merge: true}); // do sort, model change - collection.add({id: 1, b: 1}, {merge: true}); // do sort, model change - collection.add({id: 1, a: 1}, {merge: true}); // don't sort, no model change - collection.add(collection.models); // don't sort, nothing new - collection.add(collection.models, {merge: true}); // don't sort - }); - - QUnit.test('Attach options to collection.', function(assert) { - assert.expect(2); - var Model = Backbone.Model; - var comparator = function(){}; - - var collection = new Backbone.Collection([], { - model: Model, - comparator: comparator - }); - - assert.ok(collection.model === Model); - assert.ok(collection.comparator === comparator); - }); - - QUnit.test('Pass falsey for `models` for empty Col with `options`', function(assert) { - assert.expect(9); - var opts = {a: 1, b: 2}; - _.forEach([undefined, null, false], function(falsey) { - var Collection = Backbone.Collection.extend({ - initialize: function(models, options) { - assert.strictEqual(models, falsey); - assert.strictEqual(options, opts); - } - }); - - var collection = new Collection(falsey, opts); - assert.strictEqual(collection.length, 0); - }); - }); - - QUnit.test('`add` overrides `set` flags', function(assert) { - var collection = new Backbone.Collection(); - collection.once('add', function(model, coll, options) { - coll.add({id: 2}, options); - }); - collection.set({id: 1}); - assert.equal(collection.length, 2); - }); - - QUnit.test('#2606 - Collection#create, success arguments', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection; - collection.url = 'test'; - collection.create({}, { - success: function(model, resp, options) { - assert.strictEqual(resp, 'response'); - } - }); - this.ajaxSettings.success('response'); - }); - - QUnit.test('#2612 - nested `parse` works with `Collection#set`', function(assert) { - - var Job = Backbone.Model.extend({ - constructor: function() { - this.items = new Items(); - Backbone.Model.apply(this, arguments); - }, - parse: function(attrs) { - this.items.set(attrs.items, {parse: true}); - return _.omit(attrs, 'items'); - } - }); - - var Item = Backbone.Model.extend({ - constructor: function() { - this.subItems = new Backbone.Collection(); - Backbone.Model.apply(this, arguments); - }, - parse: function(attrs) { - this.subItems.set(attrs.subItems, {parse: true}); - return _.omit(attrs, 'subItems'); - } - }); - - var Items = Backbone.Collection.extend({ - model: Item - }); - - var data = { - name: 'JobName', - id: 1, - items: [{ - id: 1, - name: 'Sub1', - subItems: [ - {id: 1, subName: 'One'}, - {id: 2, subName: 'Two'} - ] - }, { - id: 2, - name: 'Sub2', - subItems: [ - {id: 3, subName: 'Three'}, - {id: 4, subName: 'Four'} - ] - }] - }; - - var newData = { - name: 'NewJobName', - id: 1, - items: [{ - id: 1, - name: 'NewSub1', - subItems: [ - {id: 1, subName: 'NewOne'}, - {id: 2, subName: 'NewTwo'} - ] - }, { - id: 2, - name: 'NewSub2', - subItems: [ - {id: 3, subName: 'NewThree'}, - {id: 4, subName: 'NewFour'} - ] - }] - }; - - var job = new Job(data, {parse: true}); - assert.equal(job.get('name'), 'JobName'); - assert.equal(job.items.at(0).get('name'), 'Sub1'); - assert.equal(job.items.length, 2); - assert.equal(job.items.get(1).subItems.get(1).get('subName'), 'One'); - assert.equal(job.items.get(2).subItems.get(3).get('subName'), 'Three'); - job.set(job.parse(newData, {parse: true})); - assert.equal(job.get('name'), 'NewJobName'); - assert.equal(job.items.at(0).get('name'), 'NewSub1'); - assert.equal(job.items.length, 2); - assert.equal(job.items.get(1).subItems.get(1).get('subName'), 'NewOne'); - assert.equal(job.items.get(2).subItems.get(3).get('subName'), 'NewThree'); - }); - - QUnit.test('_addReference binds all collection events & adds to the lookup hashes', function(assert) { - assert.expect(8); - - var calls = {add: 0, remove: 0}; - - var Collection = Backbone.Collection.extend({ - - _addReference: function(model) { - Backbone.Collection.prototype._addReference.apply(this, arguments); - calls.add++; - assert.equal(model, this._byId[model.id]); - assert.equal(model, this._byId[model.cid]); - assert.equal(model._events.all.length, 1); - }, - - _removeReference: function(model) { - Backbone.Collection.prototype._removeReference.apply(this, arguments); - calls.remove++; - assert.equal(this._byId[model.id], void 0); - assert.equal(this._byId[model.cid], void 0); - assert.equal(model.collection, void 0); - } - - }); - - var collection = new Collection(); - var model = collection.add({id: 1}); - collection.remove(model); - - assert.equal(calls.add, 1); - assert.equal(calls.remove, 1); - }); - - QUnit.test('Do not allow duplicate models to be `add`ed or `set`', function(assert) { - var collection = new Backbone.Collection(); - - collection.add([{id: 1}, {id: 1}]); - assert.equal(collection.length, 1); - assert.equal(collection.models.length, 1); - - collection.set([{id: 1}, {id: 1}]); - assert.equal(collection.length, 1); - assert.equal(collection.models.length, 1); - }); - - QUnit.test('#3020: #set with {add: false} should not throw.', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection; - collection.set([{id: 1}], {add: false}); - assert.strictEqual(collection.length, 0); - assert.strictEqual(collection.models.length, 0); - }); - - QUnit.test('create with wait, model instance, #3028', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection(); - var model = new Backbone.Model({id: 1}); - model.sync = function(){ - assert.equal(this.collection, collection); - }; - collection.create(model, {wait: true}); - }); - - QUnit.test('modelId', function(assert) { - var Stooge = Backbone.Model.extend(); - var StoogeCollection = Backbone.Collection.extend({model: Stooge}); - - // Default to using `Collection::model::idAttribute`. - assert.equal(StoogeCollection.prototype.modelId({id: 1}), 1); - Stooge.prototype.idAttribute = '_id'; - assert.equal(StoogeCollection.prototype.modelId({_id: 1}), 1); - }); - - QUnit.test('Polymorphic models work with "simple" constructors', function(assert) { - var A = Backbone.Model.extend(); - var B = Backbone.Model.extend(); - var C = Backbone.Collection.extend({ - model: function(attrs) { - return attrs.type === 'a' ? new A(attrs) : new B(attrs); - } - }); - var collection = new C([{id: 1, type: 'a'}, {id: 2, type: 'b'}]); - assert.equal(collection.length, 2); - assert.ok(collection.at(0) instanceof A); - assert.equal(collection.at(0).id, 1); - assert.ok(collection.at(1) instanceof B); - assert.equal(collection.at(1).id, 2); - }); - - QUnit.test('Polymorphic models work with "advanced" constructors', function(assert) { - var A = Backbone.Model.extend({idAttribute: '_id'}); - var B = Backbone.Model.extend({idAttribute: '_id'}); - var C = Backbone.Collection.extend({ - model: Backbone.Model.extend({ - constructor: function(attrs) { - return attrs.type === 'a' ? new A(attrs) : new B(attrs); - }, - - idAttribute: '_id' - }) - }); - var collection = new C([{_id: 1, type: 'a'}, {_id: 2, type: 'b'}]); - assert.equal(collection.length, 2); - assert.ok(collection.at(0) instanceof A); - assert.equal(collection.at(0), collection.get(1)); - assert.ok(collection.at(1) instanceof B); - assert.equal(collection.at(1), collection.get(2)); - - C = Backbone.Collection.extend({ - model: function(attrs) { - return attrs.type === 'a' ? new A(attrs) : new B(attrs); - }, - - modelId: function(attrs) { - return attrs.type + '-' + attrs.id; - } - }); - collection = new C([{id: 1, type: 'a'}, {id: 1, type: 'b'}]); - assert.equal(collection.length, 2); - assert.ok(collection.at(0) instanceof A); - assert.equal(collection.at(0), collection.get('a-1')); - assert.ok(collection.at(1) instanceof B); - assert.equal(collection.at(1), collection.get('b-1')); - }); - - QUnit.test('Collection with polymorphic models receives default id from modelId', function(assert) { - assert.expect(6); - // When the polymorphic models use 'id' for the idAttribute, all is fine. - var C1 = Backbone.Collection.extend({ - model: function(attrs) { - return new Backbone.Model(attrs); - } - }); - var c1 = new C1({id: 1}); - assert.equal(c1.get(1).id, 1); - assert.equal(c1.modelId({id: 1}), 1); - - // If the polymorphic models define their own idAttribute, - // the modelId method should be overridden, for the reason below. - var M = Backbone.Model.extend({ - idAttribute: '_id' - }); - var C2 = Backbone.Collection.extend({ - model: function(attrs) { - return new M(attrs); - } - }); - var c2 = new C2({_id: 1}); - assert.equal(c2.get(1), void 0); - assert.equal(c2.modelId(c2.at(0).attributes), void 0); - var m = new M({_id: 2}); - c2.add(m); - assert.equal(c2.get(2), void 0); - assert.equal(c2.modelId(m.attributes), void 0); - }); - - QUnit.test('#3039 #3951: adding at index fires with correct at', function(assert) { - assert.expect(4); - var collection = new Backbone.Collection([{val: 0}, {val: 4}]); - collection.on('add', function(model, coll, options) { - assert.equal(model.get('val'), options.index); - }); - collection.add([{val: 1}, {val: 2}, {val: 3}], {at: 1}); - collection.add({val: 5}, {at: 10}); - }); - - QUnit.test('#3039: index is not sent when at is not specified', function(assert) { - assert.expect(2); - var collection = new Backbone.Collection([{at: 0}]); - collection.on('add', function(model, coll, options) { - assert.equal(undefined, options.index); - }); - collection.add([{at: 1}, {at: 2}]); - }); - - QUnit.test('#3199 - Order changing should trigger a sort', function(assert) { - assert.expect(1); - var one = new Backbone.Model({id: 1}); - var two = new Backbone.Model({id: 2}); - var three = new Backbone.Model({id: 3}); - var collection = new Backbone.Collection([one, two, three]); - collection.on('sort', function() { - assert.ok(true); - }); - collection.set([{id: 3}, {id: 2}, {id: 1}]); - }); - - QUnit.test('#3199 - Adding a model should trigger a sort', function(assert) { - assert.expect(1); - var one = new Backbone.Model({id: 1}); - var two = new Backbone.Model({id: 2}); - var three = new Backbone.Model({id: 3}); - var collection = new Backbone.Collection([one, two, three]); - collection.on('sort', function() { - assert.ok(true); - }); - collection.set([{id: 1}, {id: 2}, {id: 3}, {id: 0}]); - }); - - QUnit.test('#3199 - Order not changing should not trigger a sort', function(assert) { - assert.expect(0); - var one = new Backbone.Model({id: 1}); - var two = new Backbone.Model({id: 2}); - var three = new Backbone.Model({id: 3}); - var collection = new Backbone.Collection([one, two, three]); - collection.on('sort', function() { - assert.ok(false); - }); - collection.set([{id: 1}, {id: 2}, {id: 3}]); - }); - - QUnit.test('add supports negative indexes', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([{id: 1}]); - collection.add([{id: 2}, {id: 3}], {at: -1}); - collection.add([{id: 2.5}], {at: -2}); - collection.add([{id: 0.5}], {at: -6}); - assert.equal(collection.pluck('id').join(','), '0.5,1,2,2.5,3'); - }); - - QUnit.test('#set accepts options.at as a string', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([{id: 1}, {id: 2}]); - collection.add([{id: 3}], {at: '1'}); - assert.deepEqual(collection.pluck('id'), [1, 3, 2]); - }); - - QUnit.test('adding multiple models triggers `update` event once', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection; - collection.on('update', function() { assert.ok(true); }); - collection.add([{id: 1}, {id: 2}, {id: 3}]); - }); - - QUnit.test('removing models triggers `update` event once', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([{id: 1}, {id: 2}, {id: 3}]); - collection.on('update', function() { assert.ok(true); }); - collection.remove([{id: 1}, {id: 2}]); - }); - - QUnit.test('remove does not trigger `update` when nothing removed', function(assert) { - assert.expect(0); - var collection = new Backbone.Collection([{id: 1}, {id: 2}]); - collection.on('update', function() { assert.ok(false); }); - collection.remove([{id: 3}]); - }); - - QUnit.test('set triggers `set` event once', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([{id: 1}, {id: 2}]); - collection.on('update', function() { assert.ok(true); }); - collection.set([{id: 1}, {id: 3}]); - }); - - QUnit.test('set does not trigger `update` event when nothing added nor removed', function(assert) { - var collection = new Backbone.Collection([{id: 1}, {id: 2}]); - collection.on('update', function(coll, options) { - assert.equal(options.changes.added.length, 0); - assert.equal(options.changes.removed.length, 0); - assert.equal(options.changes.merged.length, 2); - }); - collection.set([{id: 1}, {id: 2}]); - }); - - QUnit.test('#3610 - invoke collects arguments', function(assert) { - assert.expect(3); - var Model = Backbone.Model.extend({ - method: function(x, y, z) { - assert.equal(x, 1); - assert.equal(y, 2); - assert.equal(z, 3); - } - }); - var Collection = Backbone.Collection.extend({ - model: Model - }); - var collection = new Collection([{id: 1}]); - collection.invoke('method', 1, 2, 3); - }); - - QUnit.test('#3662 - triggering change without model will not error', function(assert) { - assert.expect(1); - var collection = new Backbone.Collection([{id: 1}]); - var model = collection.first(); - collection.on('change', function(m) { - assert.equal(m, undefined); - }); - model.trigger('change'); - }); - - QUnit.test('#3871 - falsy parse result creates empty collection', function(assert) { - var collection = new (Backbone.Collection.extend({ - parse: function(data, options) {} - })); - collection.set('', {parse: true}); - assert.equal(collection.length, 0); - }); - - QUnit.test("#3711 - remove's `update` event returns one removed model", function(assert) { - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var collection = new Backbone.Collection([model]); - collection.on('update', function(context, options) { - var changed = options.changes; - assert.deepEqual(changed.added, []); - assert.deepEqual(changed.merged, []); - assert.strictEqual(changed.removed[0], model); - }); - collection.remove(model); - }); - - QUnit.test("#3711 - remove's `update` event returns multiple removed models", function(assert) { - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var model2 = new Backbone.Model({id: 2, title: 'Second Post'}); - var collection = new Backbone.Collection([model, model2]); - collection.on('update', function(context, options) { - var changed = options.changes; - assert.deepEqual(changed.added, []); - assert.deepEqual(changed.merged, []); - assert.ok(changed.removed.length === 2); - - assert.ok(_.indexOf(changed.removed, model) > -1 && _.indexOf(changed.removed, model2) > -1); - }); - collection.remove([model, model2]); - }); - - QUnit.test("#3711 - set's `update` event returns one added model", function(assert) { - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var collection = new Backbone.Collection(); - collection.on('update', function(context, options) { - var addedModels = options.changes.added; - assert.ok(addedModels.length === 1); - assert.strictEqual(addedModels[0], model); - }); - collection.set(model); - }); - - QUnit.test("#3711 - set's `update` event returns multiple added models", function(assert) { - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var model2 = new Backbone.Model({id: 2, title: 'Second Post'}); - var collection = new Backbone.Collection(); - collection.on('update', function(context, options) { - var addedModels = options.changes.added; - assert.ok(addedModels.length === 2); - assert.strictEqual(addedModels[0], model); - assert.strictEqual(addedModels[1], model2); - }); - collection.set([model, model2]); - }); - - QUnit.test("#3711 - set's `update` event returns one removed model", function(assert) { - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var model2 = new Backbone.Model({id: 2, title: 'Second Post'}); - var model3 = new Backbone.Model({id: 3, title: 'My Last Post'}); - var collection = new Backbone.Collection([model]); - collection.on('update', function(context, options) { - var changed = options.changes; - assert.equal(changed.added.length, 2); - assert.equal(changed.merged.length, 0); - assert.ok(changed.removed.length === 1); - assert.strictEqual(changed.removed[0], model); - }); - collection.set([model2, model3]); - }); - - QUnit.test("#3711 - set's `update` event returns multiple removed models", function(assert) { - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var model2 = new Backbone.Model({id: 2, title: 'Second Post'}); - var model3 = new Backbone.Model({id: 3, title: 'My Last Post'}); - var collection = new Backbone.Collection([model, model2]); - collection.on('update', function(context, options) { - var removedModels = options.changes.removed; - assert.ok(removedModels.length === 2); - assert.strictEqual(removedModels[0], model); - assert.strictEqual(removedModels[1], model2); - }); - collection.set([model3]); - }); - - QUnit.test("#3711 - set's `update` event returns one merged model", function(assert) { - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var model2 = new Backbone.Model({id: 2, title: 'Second Post'}); - var model2Update = new Backbone.Model({id: 2, title: 'Second Post V2'}); - var collection = new Backbone.Collection([model, model2]); - collection.on('update', function(context, options) { - var mergedModels = options.changes.merged; - assert.ok(mergedModels.length === 1); - assert.strictEqual(mergedModels[0].get('title'), model2Update.get('title')); - }); - collection.set([model2Update]); - }); - - QUnit.test("#3711 - set's `update` event returns multiple merged models", function(assert) { - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var modelUpdate = new Backbone.Model({id: 1, title: 'First Post V2'}); - var model2 = new Backbone.Model({id: 2, title: 'Second Post'}); - var model2Update = new Backbone.Model({id: 2, title: 'Second Post V2'}); - var collection = new Backbone.Collection([model, model2]); - collection.on('update', function(context, options) { - var mergedModels = options.changes.merged; - assert.ok(mergedModels.length === 2); - assert.strictEqual(mergedModels[0].get('title'), model2Update.get('title')); - assert.strictEqual(mergedModels[1].get('title'), modelUpdate.get('title')); - }); - collection.set([model2Update, modelUpdate]); - }); - - QUnit.test("#3711 - set's `update` event should not be triggered adding a model which already exists exactly alike", function(assert) { - var fired = false; - var model = new Backbone.Model({id: 1, title: 'First Post'}); - var collection = new Backbone.Collection([model]); - collection.on('update', function(context, options) { - fired = true; - }); - collection.set([model]); - assert.equal(fired, false); - }); - -})(QUnit); diff --git a/public/vendor/lodash/vendor/backbone/test/events.js b/public/vendor/lodash/vendor/backbone/test/events.js deleted file mode 100644 index ec1e5474fa5..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/events.js +++ /dev/null @@ -1,706 +0,0 @@ -(function(QUnit) { - - QUnit.module('Backbone.Events'); - - QUnit.test('on and trigger', function(assert) { - assert.expect(2); - var obj = {counter: 0}; - _.extend(obj, Backbone.Events); - obj.on('event', function() { obj.counter += 1; }); - obj.trigger('event'); - assert.equal(obj.counter, 1, 'counter should be incremented.'); - obj.trigger('event'); - obj.trigger('event'); - obj.trigger('event'); - obj.trigger('event'); - assert.equal(obj.counter, 5, 'counter should be incremented five times.'); - }); - - QUnit.test('binding and triggering multiple events', function(assert) { - assert.expect(4); - var obj = {counter: 0}; - _.extend(obj, Backbone.Events); - - obj.on('a b c', function() { obj.counter += 1; }); - - obj.trigger('a'); - assert.equal(obj.counter, 1); - - obj.trigger('a b'); - assert.equal(obj.counter, 3); - - obj.trigger('c'); - assert.equal(obj.counter, 4); - - obj.off('a c'); - obj.trigger('a b c'); - assert.equal(obj.counter, 5); - }); - - QUnit.test('binding and triggering with event maps', function(assert) { - var obj = {counter: 0}; - _.extend(obj, Backbone.Events); - - var increment = function() { - this.counter += 1; - }; - - obj.on({ - a: increment, - b: increment, - c: increment - }, obj); - - obj.trigger('a'); - assert.equal(obj.counter, 1); - - obj.trigger('a b'); - assert.equal(obj.counter, 3); - - obj.trigger('c'); - assert.equal(obj.counter, 4); - - obj.off({ - a: increment, - c: increment - }, obj); - obj.trigger('a b c'); - assert.equal(obj.counter, 5); - }); - - QUnit.test('binding and triggering multiple event names with event maps', function(assert) { - var obj = {counter: 0}; - _.extend(obj, Backbone.Events); - - var increment = function() { - this.counter += 1; - }; - - obj.on({ - 'a b c': increment - }); - - obj.trigger('a'); - assert.equal(obj.counter, 1); - - obj.trigger('a b'); - assert.equal(obj.counter, 3); - - obj.trigger('c'); - assert.equal(obj.counter, 4); - - obj.off({ - 'a c': increment - }); - obj.trigger('a b c'); - assert.equal(obj.counter, 5); - }); - - QUnit.test('binding and trigger with event maps context', function(assert) { - assert.expect(2); - var obj = {counter: 0}; - var context = {}; - _.extend(obj, Backbone.Events); - - obj.on({ - a: function() { - assert.strictEqual(this, context, 'defaults `context` to `callback` param'); - } - }, context).trigger('a'); - - obj.off().on({ - a: function() { - assert.strictEqual(this, context, 'will not override explicit `context` param'); - } - }, this, context).trigger('a'); - }); - - QUnit.test('listenTo and stopListening', function(assert) { - assert.expect(1); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - a.listenTo(b, 'all', function(){ assert.ok(true); }); - b.trigger('anything'); - a.listenTo(b, 'all', function(){ assert.ok(false); }); - a.stopListening(); - b.trigger('anything'); - }); - - QUnit.test('listenTo and stopListening with event maps', function(assert) { - assert.expect(4); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - var cb = function(){ assert.ok(true); }; - a.listenTo(b, {event: cb}); - b.trigger('event'); - a.listenTo(b, {event2: cb}); - b.on('event2', cb); - a.stopListening(b, {event2: cb}); - b.trigger('event event2'); - a.stopListening(); - b.trigger('event event2'); - }); - - QUnit.test('stopListening with omitted args', function(assert) { - assert.expect(2); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - var cb = function() { assert.ok(true); }; - a.listenTo(b, 'event', cb); - b.on('event', cb); - a.listenTo(b, 'event2', cb); - a.stopListening(null, {event: cb}); - b.trigger('event event2'); - b.off(); - a.listenTo(b, 'event event2', cb); - a.stopListening(null, 'event'); - a.stopListening(); - b.trigger('event2'); - }); - - QUnit.test('listenToOnce', function(assert) { - assert.expect(2); - // Same as the previous test, but we use once rather than having to explicitly unbind - var obj = {counterA: 0, counterB: 0}; - _.extend(obj, Backbone.Events); - var incrA = function(){ obj.counterA += 1; obj.trigger('event'); }; - var incrB = function(){ obj.counterB += 1; }; - obj.listenToOnce(obj, 'event', incrA); - obj.listenToOnce(obj, 'event', incrB); - obj.trigger('event'); - assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.'); - assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.'); - }); - - QUnit.test('listenToOnce and stopListening', function(assert) { - assert.expect(1); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - a.listenToOnce(b, 'all', function() { assert.ok(true); }); - b.trigger('anything'); - b.trigger('anything'); - a.listenToOnce(b, 'all', function() { assert.ok(false); }); - a.stopListening(); - b.trigger('anything'); - }); - - QUnit.test('listenTo, listenToOnce and stopListening', function(assert) { - assert.expect(1); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - a.listenToOnce(b, 'all', function() { assert.ok(true); }); - b.trigger('anything'); - b.trigger('anything'); - a.listenTo(b, 'all', function() { assert.ok(false); }); - a.stopListening(); - b.trigger('anything'); - }); - - QUnit.test('listenTo and stopListening with event maps', function(assert) { - assert.expect(1); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - a.listenTo(b, {change: function(){ assert.ok(true); }}); - b.trigger('change'); - a.listenTo(b, {change: function(){ assert.ok(false); }}); - a.stopListening(); - b.trigger('change'); - }); - - QUnit.test('listenTo yourself', function(assert) { - assert.expect(1); - var e = _.extend({}, Backbone.Events); - e.listenTo(e, 'foo', function(){ assert.ok(true); }); - e.trigger('foo'); - }); - - QUnit.test('listenTo yourself cleans yourself up with stopListening', function(assert) { - assert.expect(1); - var e = _.extend({}, Backbone.Events); - e.listenTo(e, 'foo', function(){ assert.ok(true); }); - e.trigger('foo'); - e.stopListening(); - e.trigger('foo'); - }); - - QUnit.test('stopListening cleans up references', function(assert) { - assert.expect(12); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - var fn = function() {}; - b.on('event', fn); - a.listenTo(b, 'event', fn).stopListening(); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._events.event), 1); - assert.equal(_.size(b._listeners), 0); - a.listenTo(b, 'event', fn).stopListening(b); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._events.event), 1); - assert.equal(_.size(b._listeners), 0); - a.listenTo(b, 'event', fn).stopListening(b, 'event'); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._events.event), 1); - assert.equal(_.size(b._listeners), 0); - a.listenTo(b, 'event', fn).stopListening(b, 'event', fn); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._events.event), 1); - assert.equal(_.size(b._listeners), 0); - }); - - QUnit.test('stopListening cleans up references from listenToOnce', function(assert) { - assert.expect(12); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - var fn = function() {}; - b.on('event', fn); - a.listenToOnce(b, 'event', fn).stopListening(); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._events.event), 1); - assert.equal(_.size(b._listeners), 0); - a.listenToOnce(b, 'event', fn).stopListening(b); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._events.event), 1); - assert.equal(_.size(b._listeners), 0); - a.listenToOnce(b, 'event', fn).stopListening(b, 'event'); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._events.event), 1); - assert.equal(_.size(b._listeners), 0); - a.listenToOnce(b, 'event', fn).stopListening(b, 'event', fn); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._events.event), 1); - assert.equal(_.size(b._listeners), 0); - }); - - QUnit.test('listenTo and off cleaning up references', function(assert) { - assert.expect(8); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - var fn = function() {}; - a.listenTo(b, 'event', fn); - b.off(); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._listeners), 0); - a.listenTo(b, 'event', fn); - b.off('event'); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._listeners), 0); - a.listenTo(b, 'event', fn); - b.off(null, fn); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._listeners), 0); - a.listenTo(b, 'event', fn); - b.off(null, null, a); - assert.equal(_.size(a._listeningTo), 0); - assert.equal(_.size(b._listeners), 0); - }); - - QUnit.test('listenTo and stopListening cleaning up references', function(assert) { - assert.expect(2); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - a.listenTo(b, 'all', function(){ assert.ok(true); }); - b.trigger('anything'); - a.listenTo(b, 'other', function(){ assert.ok(false); }); - a.stopListening(b, 'other'); - a.stopListening(b, 'all'); - assert.equal(_.size(a._listeningTo), 0); - }); - - QUnit.test('listenToOnce without context cleans up references after the event has fired', function(assert) { - assert.expect(2); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - a.listenToOnce(b, 'all', function(){ assert.ok(true); }); - b.trigger('anything'); - assert.equal(_.size(a._listeningTo), 0); - }); - - QUnit.test('listenToOnce with event maps cleans up references', function(assert) { - assert.expect(2); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - a.listenToOnce(b, { - one: function() { assert.ok(true); }, - two: function() { assert.ok(false); } - }); - b.trigger('one'); - assert.equal(_.size(a._listeningTo), 1); - }); - - QUnit.test('listenToOnce with event maps binds the correct `this`', function(assert) { - assert.expect(1); - var a = _.extend({}, Backbone.Events); - var b = _.extend({}, Backbone.Events); - a.listenToOnce(b, { - one: function() { assert.ok(this === a); }, - two: function() { assert.ok(false); } - }); - b.trigger('one'); - }); - - QUnit.test("listenTo with empty callback doesn't throw an error", function(assert) { - assert.expect(1); - var e = _.extend({}, Backbone.Events); - e.listenTo(e, 'foo', null); - e.trigger('foo'); - assert.ok(true); - }); - - QUnit.test('trigger all for each event', function(assert) { - assert.expect(3); - var a, b, obj = {counter: 0}; - _.extend(obj, Backbone.Events); - obj.on('all', function(event) { - obj.counter++; - if (event === 'a') a = true; - if (event === 'b') b = true; - }) - .trigger('a b'); - assert.ok(a); - assert.ok(b); - assert.equal(obj.counter, 2); - }); - - QUnit.test('on, then unbind all functions', function(assert) { - assert.expect(1); - var obj = {counter: 0}; - _.extend(obj, Backbone.Events); - var callback = function() { obj.counter += 1; }; - obj.on('event', callback); - obj.trigger('event'); - obj.off('event'); - obj.trigger('event'); - assert.equal(obj.counter, 1, 'counter should have only been incremented once.'); - }); - - QUnit.test('bind two callbacks, unbind only one', function(assert) { - assert.expect(2); - var obj = {counterA: 0, counterB: 0}; - _.extend(obj, Backbone.Events); - var callback = function() { obj.counterA += 1; }; - obj.on('event', callback); - obj.on('event', function() { obj.counterB += 1; }); - obj.trigger('event'); - obj.off('event', callback); - obj.trigger('event'); - assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.'); - assert.equal(obj.counterB, 2, 'counterB should have been incremented twice.'); - }); - - QUnit.test('unbind a callback in the midst of it firing', function(assert) { - assert.expect(1); - var obj = {counter: 0}; - _.extend(obj, Backbone.Events); - var callback = function() { - obj.counter += 1; - obj.off('event', callback); - }; - obj.on('event', callback); - obj.trigger('event'); - obj.trigger('event'); - obj.trigger('event'); - assert.equal(obj.counter, 1, 'the callback should have been unbound.'); - }); - - QUnit.test('two binds that unbind themeselves', function(assert) { - assert.expect(2); - var obj = {counterA: 0, counterB: 0}; - _.extend(obj, Backbone.Events); - var incrA = function(){ obj.counterA += 1; obj.off('event', incrA); }; - var incrB = function(){ obj.counterB += 1; obj.off('event', incrB); }; - obj.on('event', incrA); - obj.on('event', incrB); - obj.trigger('event'); - obj.trigger('event'); - obj.trigger('event'); - assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.'); - assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.'); - }); - - QUnit.test('bind a callback with a default context when none supplied', function(assert) { - assert.expect(1); - var obj = _.extend({ - assertTrue: function() { - assert.equal(this, obj, '`this` was bound to the callback'); - } - }, Backbone.Events); - - obj.once('event', obj.assertTrue); - obj.trigger('event'); - }); - - QUnit.test('bind a callback with a supplied context', function(assert) { - assert.expect(1); - var TestClass = function() { - return this; - }; - TestClass.prototype.assertTrue = function() { - assert.ok(true, '`this` was bound to the callback'); - }; - - var obj = _.extend({}, Backbone.Events); - obj.on('event', function() { this.assertTrue(); }, new TestClass); - obj.trigger('event'); - }); - - QUnit.test('nested trigger with unbind', function(assert) { - assert.expect(1); - var obj = {counter: 0}; - _.extend(obj, Backbone.Events); - var incr1 = function(){ obj.counter += 1; obj.off('event', incr1); obj.trigger('event'); }; - var incr2 = function(){ obj.counter += 1; }; - obj.on('event', incr1); - obj.on('event', incr2); - obj.trigger('event'); - assert.equal(obj.counter, 3, 'counter should have been incremented three times'); - }); - - QUnit.test('callback list is not altered during trigger', function(assert) { - assert.expect(2); - var counter = 0, obj = _.extend({}, Backbone.Events); - var incr = function(){ counter++; }; - var incrOn = function(){ obj.on('event all', incr); }; - var incrOff = function(){ obj.off('event all', incr); }; - - obj.on('event all', incrOn).trigger('event'); - assert.equal(counter, 0, 'on does not alter callback list'); - - obj.off().on('event', incrOff).on('event all', incr).trigger('event'); - assert.equal(counter, 2, 'off does not alter callback list'); - }); - - QUnit.test("#1282 - 'all' callback list is retrieved after each event.", function(assert) { - assert.expect(1); - var counter = 0; - var obj = _.extend({}, Backbone.Events); - var incr = function(){ counter++; }; - obj.on('x', function() { - obj.on('y', incr).on('all', incr); - }) - .trigger('x y'); - assert.strictEqual(counter, 2); - }); - - QUnit.test('if no callback is provided, `on` is a noop', function(assert) { - assert.expect(0); - _.extend({}, Backbone.Events).on('test').trigger('test'); - }); - - QUnit.test('if callback is truthy but not a function, `on` should throw an error just like jQuery', function(assert) { - assert.expect(1); - var view = _.extend({}, Backbone.Events).on('test', 'noop'); - assert.raises(function() { - view.trigger('test'); - }); - }); - - QUnit.test('remove all events for a specific context', function(assert) { - assert.expect(4); - var obj = _.extend({}, Backbone.Events); - obj.on('x y all', function() { assert.ok(true); }); - obj.on('x y all', function() { assert.ok(false); }, obj); - obj.off(null, null, obj); - obj.trigger('x y'); - }); - - QUnit.test('remove all events for a specific callback', function(assert) { - assert.expect(4); - var obj = _.extend({}, Backbone.Events); - var success = function() { assert.ok(true); }; - var fail = function() { assert.ok(false); }; - obj.on('x y all', success); - obj.on('x y all', fail); - obj.off(null, fail); - obj.trigger('x y'); - }); - - QUnit.test('#1310 - off does not skip consecutive events', function(assert) { - assert.expect(0); - var obj = _.extend({}, Backbone.Events); - obj.on('event', function() { assert.ok(false); }, obj); - obj.on('event', function() { assert.ok(false); }, obj); - obj.off(null, null, obj); - obj.trigger('event'); - }); - - QUnit.test('once', function(assert) { - assert.expect(2); - // Same as the previous test, but we use once rather than having to explicitly unbind - var obj = {counterA: 0, counterB: 0}; - _.extend(obj, Backbone.Events); - var incrA = function(){ obj.counterA += 1; obj.trigger('event'); }; - var incrB = function(){ obj.counterB += 1; }; - obj.once('event', incrA); - obj.once('event', incrB); - obj.trigger('event'); - assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.'); - assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.'); - }); - - QUnit.test('once variant one', function(assert) { - assert.expect(3); - var f = function(){ assert.ok(true); }; - - var a = _.extend({}, Backbone.Events).once('event', f); - var b = _.extend({}, Backbone.Events).on('event', f); - - a.trigger('event'); - - b.trigger('event'); - b.trigger('event'); - }); - - QUnit.test('once variant two', function(assert) { - assert.expect(3); - var f = function(){ assert.ok(true); }; - var obj = _.extend({}, Backbone.Events); - - obj - .once('event', f) - .on('event', f) - .trigger('event') - .trigger('event'); - }); - - QUnit.test('once with off', function(assert) { - assert.expect(0); - var f = function(){ assert.ok(true); }; - var obj = _.extend({}, Backbone.Events); - - obj.once('event', f); - obj.off('event', f); - obj.trigger('event'); - }); - - QUnit.test('once with event maps', function(assert) { - var obj = {counter: 0}; - _.extend(obj, Backbone.Events); - - var increment = function() { - this.counter += 1; - }; - - obj.once({ - a: increment, - b: increment, - c: increment - }, obj); - - obj.trigger('a'); - assert.equal(obj.counter, 1); - - obj.trigger('a b'); - assert.equal(obj.counter, 2); - - obj.trigger('c'); - assert.equal(obj.counter, 3); - - obj.trigger('a b c'); - assert.equal(obj.counter, 3); - }); - - QUnit.test('bind a callback with a supplied context using once with object notation', function(assert) { - assert.expect(1); - var obj = {counter: 0}; - var context = {}; - _.extend(obj, Backbone.Events); - - obj.once({ - a: function() { - assert.strictEqual(this, context, 'defaults `context` to `callback` param'); - } - }, context).trigger('a'); - }); - - QUnit.test('once with off only by context', function(assert) { - assert.expect(0); - var context = {}; - var obj = _.extend({}, Backbone.Events); - obj.once('event', function(){ assert.ok(false); }, context); - obj.off(null, null, context); - obj.trigger('event'); - }); - - QUnit.test('Backbone object inherits Events', function(assert) { - assert.ok(Backbone.on === Backbone.Events.on); - }); - - QUnit.test('once with asynchronous events', function(assert) { - var done = assert.async(); - assert.expect(1); - var func = _.debounce(function() { assert.ok(true); done(); }, 50); - var obj = _.extend({}, Backbone.Events).once('async', func); - - obj.trigger('async'); - obj.trigger('async'); - }); - - QUnit.test('once with multiple events.', function(assert) { - assert.expect(2); - var obj = _.extend({}, Backbone.Events); - obj.once('x y', function() { assert.ok(true); }); - obj.trigger('x y'); - }); - - QUnit.test('Off during iteration with once.', function(assert) { - assert.expect(2); - var obj = _.extend({}, Backbone.Events); - var f = function(){ this.off('event', f); }; - obj.on('event', f); - obj.once('event', function(){}); - obj.on('event', function(){ assert.ok(true); }); - - obj.trigger('event'); - obj.trigger('event'); - }); - - QUnit.test('`once` on `all` should work as expected', function(assert) { - assert.expect(1); - Backbone.once('all', function() { - assert.ok(true); - Backbone.trigger('all'); - }); - Backbone.trigger('all'); - }); - - QUnit.test('once without a callback is a noop', function(assert) { - assert.expect(0); - _.extend({}, Backbone.Events).once('event').trigger('event'); - }); - - QUnit.test('listenToOnce without a callback is a noop', function(assert) { - assert.expect(0); - var obj = _.extend({}, Backbone.Events); - obj.listenToOnce(obj, 'event').trigger('event'); - }); - - QUnit.test('event functions are chainable', function(assert) { - var obj = _.extend({}, Backbone.Events); - var obj2 = _.extend({}, Backbone.Events); - var fn = function() {}; - assert.equal(obj, obj.trigger('noeventssetyet')); - assert.equal(obj, obj.off('noeventssetyet')); - assert.equal(obj, obj.stopListening('noeventssetyet')); - assert.equal(obj, obj.on('a', fn)); - assert.equal(obj, obj.once('c', fn)); - assert.equal(obj, obj.trigger('a')); - assert.equal(obj, obj.listenTo(obj2, 'a', fn)); - assert.equal(obj, obj.listenToOnce(obj2, 'b', fn)); - assert.equal(obj, obj.off('a c')); - assert.equal(obj, obj.stopListening(obj2, 'a')); - assert.equal(obj, obj.stopListening()); - }); - - QUnit.test('#3448 - listenToOnce with space-separated events', function(assert) { - assert.expect(2); - var one = _.extend({}, Backbone.Events); - var two = _.extend({}, Backbone.Events); - var count = 1; - one.listenToOnce(two, 'x y', function(n) { assert.ok(n === count++); }); - two.trigger('x', 1); - two.trigger('x', 1); - two.trigger('y', 2); - two.trigger('y', 2); - }); - -})(QUnit); diff --git a/public/vendor/lodash/vendor/backbone/test/model.js b/public/vendor/lodash/vendor/backbone/test/model.js deleted file mode 100644 index 440047fef65..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/model.js +++ /dev/null @@ -1,1448 +0,0 @@ -(function(QUnit) { - - var ProxyModel = Backbone.Model.extend(); - var Klass = Backbone.Collection.extend({ - url: function() { return '/collection'; } - }); - var doc, collection; - - QUnit.module('Backbone.Model', { - - beforeEach: function(assert) { - doc = new ProxyModel({ - id: '1-the-tempest', - title: 'The Tempest', - author: 'Bill Shakespeare', - length: 123 - }); - collection = new Klass(); - collection.add(doc); - } - - }); - - QUnit.test('initialize', function(assert) { - assert.expect(3); - var Model = Backbone.Model.extend({ - initialize: function() { - this.one = 1; - assert.equal(this.collection, collection); - } - }); - var model = new Model({}, {collection: collection}); - assert.equal(model.one, 1); - assert.equal(model.collection, collection); - }); - - QUnit.test('Object.prototype properties are overridden by attributes', function(assert) { - assert.expect(1); - var model = new Backbone.Model({hasOwnProperty: true}); - assert.equal(model.get('hasOwnProperty'), true); - }); - - QUnit.test('initialize with attributes and options', function(assert) { - assert.expect(1); - var Model = Backbone.Model.extend({ - initialize: function(attributes, options) { - this.one = options.one; - } - }); - var model = new Model({}, {one: 1}); - assert.equal(model.one, 1); - }); - - QUnit.test('initialize with parsed attributes', function(assert) { - assert.expect(1); - var Model = Backbone.Model.extend({ - parse: function(attrs) { - attrs.value += 1; - return attrs; - } - }); - var model = new Model({value: 1}, {parse: true}); - assert.equal(model.get('value'), 2); - }); - - - QUnit.test('preinitialize', function(assert) { - assert.expect(2); - var Model = Backbone.Model.extend({ - - preinitialize: function() { - this.one = 1; - } - }); - var model = new Model({}, {collection: collection}); - assert.equal(model.one, 1); - assert.equal(model.collection, collection); - }); - - QUnit.test('preinitialize occurs before the model is set up', function(assert) { - assert.expect(6); - var Model = Backbone.Model.extend({ - - preinitialize: function() { - assert.equal(this.collection, undefined); - assert.equal(this.cid, undefined); - assert.equal(this.id, undefined); - } - }); - var model = new Model({id: 'foo'}, {collection: collection}); - assert.equal(model.collection, collection); - assert.equal(model.id, 'foo'); - assert.notEqual(model.cid, undefined); - }); - - QUnit.test('parse can return null', function(assert) { - assert.expect(1); - var Model = Backbone.Model.extend({ - parse: function(attrs) { - attrs.value += 1; - return null; - } - }); - var model = new Model({value: 1}, {parse: true}); - assert.equal(JSON.stringify(model.toJSON()), '{}'); - }); - - QUnit.test('url', function(assert) { - assert.expect(3); - doc.urlRoot = null; - assert.equal(doc.url(), '/collection/1-the-tempest'); - doc.collection.url = '/collection/'; - assert.equal(doc.url(), '/collection/1-the-tempest'); - doc.collection = null; - assert.raises(function() { doc.url(); }); - doc.collection = collection; - }); - - QUnit.test('url when using urlRoot, and uri encoding', function(assert) { - assert.expect(2); - var Model = Backbone.Model.extend({ - urlRoot: '/collection' - }); - var model = new Model(); - assert.equal(model.url(), '/collection'); - model.set({id: '+1+'}); - assert.equal(model.url(), '/collection/%2B1%2B'); - }); - - QUnit.test('url when using urlRoot as a function to determine urlRoot at runtime', function(assert) { - assert.expect(2); - var Model = Backbone.Model.extend({ - urlRoot: function() { - return '/nested/' + this.get('parentId') + '/collection'; - } - }); - - var model = new Model({parentId: 1}); - assert.equal(model.url(), '/nested/1/collection'); - model.set({id: 2}); - assert.equal(model.url(), '/nested/1/collection/2'); - }); - - QUnit.test('underscore methods', function(assert) { - assert.expect(5); - var model = new Backbone.Model({foo: 'a', bar: 'b', baz: 'c'}); - var model2 = model.clone(); - assert.deepEqual(model.keys(), ['foo', 'bar', 'baz']); - assert.deepEqual(model.values(), ['a', 'b', 'c']); - assert.deepEqual(model.invert(), {a: 'foo', b: 'bar', c: 'baz'}); - assert.deepEqual(model.pick('foo', 'baz'), {foo: 'a', baz: 'c'}); - assert.deepEqual(model.omit('foo', 'bar'), {baz: 'c'}); - }); - - QUnit.test('chain', function(assert) { - var model = new Backbone.Model({a: 0, b: 1, c: 2}); - assert.deepEqual(model.chain().pick('a', 'b', 'c').values().compact().value(), [1, 2]); - }); - - QUnit.test('clone', function(assert) { - assert.expect(10); - var a = new Backbone.Model({foo: 1, bar: 2, baz: 3}); - var b = a.clone(); - assert.equal(a.get('foo'), 1); - assert.equal(a.get('bar'), 2); - assert.equal(a.get('baz'), 3); - assert.equal(b.get('foo'), a.get('foo'), 'Foo should be the same on the clone.'); - assert.equal(b.get('bar'), a.get('bar'), 'Bar should be the same on the clone.'); - assert.equal(b.get('baz'), a.get('baz'), 'Baz should be the same on the clone.'); - a.set({foo: 100}); - assert.equal(a.get('foo'), 100); - assert.equal(b.get('foo'), 1, 'Changing a parent attribute does not change the clone.'); - - var foo = new Backbone.Model({p: 1}); - var bar = new Backbone.Model({p: 2}); - bar.set(foo.clone().attributes, {unset: true}); - assert.equal(foo.get('p'), 1); - assert.equal(bar.get('p'), undefined); - }); - - QUnit.test('isNew', function(assert) { - assert.expect(6); - var a = new Backbone.Model({foo: 1, bar: 2, baz: 3}); - assert.ok(a.isNew(), 'it should be new'); - a = new Backbone.Model({foo: 1, bar: 2, baz: 3, id: -5}); - assert.ok(!a.isNew(), 'any defined ID is legal, negative or positive'); - a = new Backbone.Model({foo: 1, bar: 2, baz: 3, id: 0}); - assert.ok(!a.isNew(), 'any defined ID is legal, including zero'); - assert.ok(new Backbone.Model().isNew(), 'is true when there is no id'); - assert.ok(!new Backbone.Model({id: 2}).isNew(), 'is false for a positive integer'); - assert.ok(!new Backbone.Model({id: -5}).isNew(), 'is false for a negative integer'); - }); - - QUnit.test('get', function(assert) { - assert.expect(2); - assert.equal(doc.get('title'), 'The Tempest'); - assert.equal(doc.get('author'), 'Bill Shakespeare'); - }); - - QUnit.test('escape', function(assert) { - assert.expect(5); - assert.equal(doc.escape('title'), 'The Tempest'); - doc.set({audience: 'Bill & Bob'}); - assert.equal(doc.escape('audience'), 'Bill & Bob'); - doc.set({audience: 'Tim > Joan'}); - assert.equal(doc.escape('audience'), 'Tim > Joan'); - doc.set({audience: 10101}); - assert.equal(doc.escape('audience'), '10101'); - doc.unset('audience'); - assert.equal(doc.escape('audience'), ''); - }); - - QUnit.test('has', function(assert) { - assert.expect(10); - var model = new Backbone.Model(); - - assert.strictEqual(model.has('name'), false); - - model.set({ - '0': 0, - '1': 1, - 'true': true, - 'false': false, - 'empty': '', - 'name': 'name', - 'null': null, - 'undefined': undefined - }); - - assert.strictEqual(model.has('0'), true); - assert.strictEqual(model.has('1'), true); - assert.strictEqual(model.has('true'), true); - assert.strictEqual(model.has('false'), true); - assert.strictEqual(model.has('empty'), true); - assert.strictEqual(model.has('name'), true); - - model.unset('name'); - - assert.strictEqual(model.has('name'), false); - assert.strictEqual(model.has('null'), false); - assert.strictEqual(model.has('undefined'), false); - }); - - QUnit.test('matches', function(assert) { - assert.expect(4); - var model = new Backbone.Model(); - - assert.strictEqual(model.matches({name: 'Jonas', cool: true}), false); - - model.set({name: 'Jonas', cool: true}); - - assert.strictEqual(model.matches({name: 'Jonas'}), true); - assert.strictEqual(model.matches({name: 'Jonas', cool: true}), true); - assert.strictEqual(model.matches({name: 'Jonas', cool: false}), false); - }); - - QUnit.test('matches with predicate', function(assert) { - var model = new Backbone.Model({a: 0}); - - assert.strictEqual(model.matches(function(attr) { - return attr.a > 1 && attr.b != null; - }), false); - - model.set({a: 3, b: true}); - - assert.strictEqual(model.matches(function(attr) { - return attr.a > 1 && attr.b != null; - }), true); - }); - - QUnit.test('set and unset', function(assert) { - assert.expect(8); - var a = new Backbone.Model({id: 'id', foo: 1, bar: 2, baz: 3}); - var changeCount = 0; - a.on('change:foo', function() { changeCount += 1; }); - a.set({foo: 2}); - assert.equal(a.get('foo'), 2, 'Foo should have changed.'); - assert.equal(changeCount, 1, 'Change count should have incremented.'); - // set with value that is not new shouldn't fire change event - a.set({foo: 2}); - assert.equal(a.get('foo'), 2, 'Foo should NOT have changed, still 2'); - assert.equal(changeCount, 1, 'Change count should NOT have incremented.'); - - a.validate = function(attrs) { - assert.equal(attrs.foo, void 0, 'validate:true passed while unsetting'); - }; - a.unset('foo', {validate: true}); - assert.equal(a.get('foo'), void 0, 'Foo should have changed'); - delete a.validate; - assert.equal(changeCount, 2, 'Change count should have incremented for unset.'); - - a.unset('id'); - assert.equal(a.id, undefined, 'Unsetting the id should remove the id property.'); - }); - - QUnit.test('#2030 - set with failed validate, followed by another set triggers change', function(assert) { - var attr = 0, main = 0, error = 0; - var Model = Backbone.Model.extend({ - validate: function(attrs) { - if (attrs.x > 1) { - error++; - return 'this is an error'; - } - } - }); - var model = new Model({x: 0}); - model.on('change:x', function() { attr++; }); - model.on('change', function() { main++; }); - model.set({x: 2}, {validate: true}); - model.set({x: 1}, {validate: true}); - assert.deepEqual([attr, main, error], [1, 1, 1]); - }); - - QUnit.test('set triggers changes in the correct order', function(assert) { - var value = null; - var model = new Backbone.Model; - model.on('last', function(){ value = 'last'; }); - model.on('first', function(){ value = 'first'; }); - model.trigger('first'); - model.trigger('last'); - assert.equal(value, 'last'); - }); - - QUnit.test('set falsy values in the correct order', function(assert) { - assert.expect(2); - var model = new Backbone.Model({result: 'result'}); - model.on('change', function() { - assert.equal(model.changed.result, void 0); - assert.equal(model.previous('result'), false); - }); - model.set({result: void 0}, {silent: true}); - model.set({result: null}, {silent: true}); - model.set({result: false}, {silent: true}); - model.set({result: void 0}); - }); - - QUnit.test('nested set triggers with the correct options', function(assert) { - var model = new Backbone.Model(); - var o1 = {}; - var o2 = {}; - var o3 = {}; - model.on('change', function(__, options) { - switch (model.get('a')) { - case 1: - assert.equal(options, o1); - return model.set('a', 2, o2); - case 2: - assert.equal(options, o2); - return model.set('a', 3, o3); - case 3: - assert.equal(options, o3); - } - }); - model.set('a', 1, o1); - }); - - QUnit.test('multiple unsets', function(assert) { - assert.expect(1); - var i = 0; - var counter = function(){ i++; }; - var model = new Backbone.Model({a: 1}); - model.on('change:a', counter); - model.set({a: 2}); - model.unset('a'); - model.unset('a'); - assert.equal(i, 2, 'Unset does not fire an event for missing attributes.'); - }); - - QUnit.test('unset and changedAttributes', function(assert) { - assert.expect(1); - var model = new Backbone.Model({a: 1}); - model.on('change', function() { - assert.ok('a' in model.changedAttributes(), 'changedAttributes should contain unset properties'); - }); - model.unset('a'); - }); - - QUnit.test('using a non-default id attribute.', function(assert) { - assert.expect(5); - var MongoModel = Backbone.Model.extend({idAttribute: '_id'}); - var model = new MongoModel({id: 'eye-dee', _id: 25, title: 'Model'}); - assert.equal(model.get('id'), 'eye-dee'); - assert.equal(model.id, 25); - assert.equal(model.isNew(), false); - model.unset('_id'); - assert.equal(model.id, undefined); - assert.equal(model.isNew(), true); - }); - - QUnit.test('setting an alternative cid prefix', function(assert) { - assert.expect(4); - var Model = Backbone.Model.extend({ - cidPrefix: 'm' - }); - var model = new Model(); - - assert.equal(model.cid.charAt(0), 'm'); - - model = new Backbone.Model(); - assert.equal(model.cid.charAt(0), 'c'); - - var Collection = Backbone.Collection.extend({ - model: Model - }); - var col = new Collection([{id: 'c5'}, {id: 'c6'}, {id: 'c7'}]); - - assert.equal(col.get('c6').cid.charAt(0), 'm'); - col.set([{id: 'c6', value: 'test'}], { - merge: true, - add: true, - remove: false - }); - assert.ok(col.get('c6').has('value')); - }); - - QUnit.test('set an empty string', function(assert) { - assert.expect(1); - var model = new Backbone.Model({name: 'Model'}); - model.set({name: ''}); - assert.equal(model.get('name'), ''); - }); - - QUnit.test('setting an object', function(assert) { - assert.expect(1); - var model = new Backbone.Model({ - custom: {foo: 1} - }); - model.on('change', function() { - assert.ok(1); - }); - model.set({ - custom: {foo: 1} // no change should be fired - }); - model.set({ - custom: {foo: 2} // change event should be fired - }); - }); - - QUnit.test('clear', function(assert) { - assert.expect(3); - var changed; - var model = new Backbone.Model({id: 1, name: 'Model'}); - model.on('change:name', function(){ changed = true; }); - model.on('change', function() { - var changedAttrs = model.changedAttributes(); - assert.ok('name' in changedAttrs); - }); - model.clear(); - assert.equal(changed, true); - assert.equal(model.get('name'), undefined); - }); - - QUnit.test('defaults', function(assert) { - assert.expect(9); - var Defaulted = Backbone.Model.extend({ - defaults: { - one: 1, - two: 2 - } - }); - var model = new Defaulted({two: undefined}); - assert.equal(model.get('one'), 1); - assert.equal(model.get('two'), 2); - model = new Defaulted({two: 3}); - assert.equal(model.get('one'), 1); - assert.equal(model.get('two'), 3); - Defaulted = Backbone.Model.extend({ - defaults: function() { - return { - one: 3, - two: 4 - }; - } - }); - model = new Defaulted({two: undefined}); - assert.equal(model.get('one'), 3); - assert.equal(model.get('two'), 4); - Defaulted = Backbone.Model.extend({ - defaults: {hasOwnProperty: true} - }); - model = new Defaulted(); - assert.equal(model.get('hasOwnProperty'), true); - model = new Defaulted({hasOwnProperty: undefined}); - assert.equal(model.get('hasOwnProperty'), true); - model = new Defaulted({hasOwnProperty: false}); - assert.equal(model.get('hasOwnProperty'), false); - }); - - QUnit.test('change, hasChanged, changedAttributes, previous, previousAttributes', function(assert) { - assert.expect(9); - var model = new Backbone.Model({name: 'Tim', age: 10}); - assert.deepEqual(model.changedAttributes(), false); - model.on('change', function() { - assert.ok(model.hasChanged('name'), 'name changed'); - assert.ok(!model.hasChanged('age'), 'age did not'); - assert.ok(_.isEqual(model.changedAttributes(), {name: 'Rob'}), 'changedAttributes returns the changed attrs'); - assert.equal(model.previous('name'), 'Tim'); - assert.ok(_.isEqual(model.previousAttributes(), {name: 'Tim', age: 10}), 'previousAttributes is correct'); - }); - assert.equal(model.hasChanged(), false); - assert.equal(model.hasChanged(undefined), false); - model.set({name: 'Rob'}); - assert.equal(model.get('name'), 'Rob'); - }); - - QUnit.test('changedAttributes', function(assert) { - assert.expect(3); - var model = new Backbone.Model({a: 'a', b: 'b'}); - assert.deepEqual(model.changedAttributes(), false); - assert.equal(model.changedAttributes({a: 'a'}), false); - assert.equal(model.changedAttributes({a: 'b'}).a, 'b'); - }); - - QUnit.test('change with options', function(assert) { - assert.expect(2); - var value; - var model = new Backbone.Model({name: 'Rob'}); - model.on('change', function(m, options) { - value = options.prefix + m.get('name'); - }); - model.set({name: 'Bob'}, {prefix: 'Mr. '}); - assert.equal(value, 'Mr. Bob'); - model.set({name: 'Sue'}, {prefix: 'Ms. '}); - assert.equal(value, 'Ms. Sue'); - }); - - QUnit.test('change after initialize', function(assert) { - assert.expect(1); - var changed = 0; - var attrs = {id: 1, label: 'c'}; - var obj = new Backbone.Model(attrs); - obj.on('change', function() { changed += 1; }); - obj.set(attrs); - assert.equal(changed, 0); - }); - - QUnit.test('save within change event', function(assert) { - assert.expect(1); - var env = this; - var model = new Backbone.Model({firstName: 'Taylor', lastName: 'Swift'}); - model.url = '/test'; - model.on('change', function() { - model.save(); - assert.ok(_.isEqual(env.syncArgs.model, model)); - }); - model.set({lastName: 'Hicks'}); - }); - - QUnit.test('validate after save', function(assert) { - assert.expect(2); - var lastError, model = new Backbone.Model(); - model.validate = function(attrs) { - if (attrs.admin) return "Can't change admin status."; - }; - model.sync = function(method, m, options) { - options.success.call(this, {admin: true}); - }; - model.on('invalid', function(m, error) { - lastError = error; - }); - model.save(null); - - assert.equal(lastError, "Can't change admin status."); - assert.equal(model.validationError, "Can't change admin status."); - }); - - QUnit.test('save', function(assert) { - assert.expect(2); - doc.save({title: 'Henry V'}); - assert.equal(this.syncArgs.method, 'update'); - assert.ok(_.isEqual(this.syncArgs.model, doc)); - }); - - QUnit.test('save, fetch, destroy triggers error event when an error occurs', function(assert) { - assert.expect(3); - var model = new Backbone.Model(); - model.on('error', function() { - assert.ok(true); - }); - model.sync = function(method, m, options) { - options.error(); - }; - model.save({data: 2, id: 1}); - model.fetch(); - model.destroy(); - }); - - QUnit.test('#3283 - save, fetch, destroy calls success with context', function(assert) { - assert.expect(3); - var model = new Backbone.Model(); - var obj = {}; - var options = { - context: obj, - success: function() { - assert.equal(this, obj); - } - }; - model.sync = function(method, m, opts) { - opts.success.call(opts.context); - }; - model.save({data: 2, id: 1}, options); - model.fetch(options); - model.destroy(options); - }); - - QUnit.test('#3283 - save, fetch, destroy calls error with context', function(assert) { - assert.expect(3); - var model = new Backbone.Model(); - var obj = {}; - var options = { - context: obj, - error: function() { - assert.equal(this, obj); - } - }; - model.sync = function(method, m, opts) { - opts.error.call(opts.context); - }; - model.save({data: 2, id: 1}, options); - model.fetch(options); - model.destroy(options); - }); - - QUnit.test('#3470 - save and fetch with parse false', function(assert) { - assert.expect(2); - var i = 0; - var model = new Backbone.Model(); - model.parse = function() { - assert.ok(false); - }; - model.sync = function(method, m, options) { - options.success({i: ++i}); - }; - model.fetch({parse: false}); - assert.equal(model.get('i'), i); - model.save(null, {parse: false}); - assert.equal(model.get('i'), i); - }); - - QUnit.test('save with PATCH', function(assert) { - doc.clear().set({id: 1, a: 1, b: 2, c: 3, d: 4}); - doc.save(); - assert.equal(this.syncArgs.method, 'update'); - assert.equal(this.syncArgs.options.attrs, undefined); - - doc.save({b: 2, d: 4}, {patch: true}); - assert.equal(this.syncArgs.method, 'patch'); - assert.equal(_.size(this.syncArgs.options.attrs), 2); - assert.equal(this.syncArgs.options.attrs.d, 4); - assert.equal(this.syncArgs.options.attrs.a, undefined); - assert.equal(this.ajaxSettings.data, '{"b":2,"d":4}'); - }); - - QUnit.test('save with PATCH and different attrs', function(assert) { - doc.clear().save({b: 2, d: 4}, {patch: true, attrs: {B: 1, D: 3}}); - assert.equal(this.syncArgs.options.attrs.D, 3); - assert.equal(this.syncArgs.options.attrs.d, undefined); - assert.equal(this.ajaxSettings.data, '{"B":1,"D":3}'); - assert.deepEqual(doc.attributes, {b: 2, d: 4}); - }); - - QUnit.test('save in positional style', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.sync = function(method, m, options) { - options.success(); - }; - model.save('title', 'Twelfth Night'); - assert.equal(model.get('title'), 'Twelfth Night'); - }); - - QUnit.test('save with non-object success response', function(assert) { - assert.expect(2); - var model = new Backbone.Model(); - model.sync = function(method, m, options) { - options.success('', options); - options.success(null, options); - }; - model.save({testing: 'empty'}, { - success: function(m) { - assert.deepEqual(m.attributes, {testing: 'empty'}); - } - }); - }); - - QUnit.test('save with wait and supplied id', function(assert) { - var Model = Backbone.Model.extend({ - urlRoot: '/collection' - }); - var model = new Model(); - model.save({id: 42}, {wait: true}); - assert.equal(this.ajaxSettings.url, '/collection/42'); - }); - - QUnit.test('save will pass extra options to success callback', function(assert) { - assert.expect(1); - var SpecialSyncModel = Backbone.Model.extend({ - sync: function(method, m, options) { - _.extend(options, {specialSync: true}); - return Backbone.Model.prototype.sync.call(this, method, m, options); - }, - urlRoot: '/test' - }); - - var model = new SpecialSyncModel(); - - var onSuccess = function(m, response, options) { - assert.ok(options.specialSync, 'Options were passed correctly to callback'); - }; - - model.save(null, {success: onSuccess}); - this.ajaxSettings.success(); - }); - - QUnit.test('fetch', function(assert) { - assert.expect(2); - doc.fetch(); - assert.equal(this.syncArgs.method, 'read'); - assert.ok(_.isEqual(this.syncArgs.model, doc)); - }); - - QUnit.test('fetch will pass extra options to success callback', function(assert) { - assert.expect(1); - var SpecialSyncModel = Backbone.Model.extend({ - sync: function(method, m, options) { - _.extend(options, {specialSync: true}); - return Backbone.Model.prototype.sync.call(this, method, m, options); - }, - urlRoot: '/test' - }); - - var model = new SpecialSyncModel(); - - var onSuccess = function(m, response, options) { - assert.ok(options.specialSync, 'Options were passed correctly to callback'); - }; - - model.fetch({success: onSuccess}); - this.ajaxSettings.success(); - }); - - QUnit.test('destroy', function(assert) { - assert.expect(3); - doc.destroy(); - assert.equal(this.syncArgs.method, 'delete'); - assert.ok(_.isEqual(this.syncArgs.model, doc)); - - var newModel = new Backbone.Model; - assert.equal(newModel.destroy(), false); - }); - - QUnit.test('destroy will pass extra options to success callback', function(assert) { - assert.expect(1); - var SpecialSyncModel = Backbone.Model.extend({ - sync: function(method, m, options) { - _.extend(options, {specialSync: true}); - return Backbone.Model.prototype.sync.call(this, method, m, options); - }, - urlRoot: '/test' - }); - - var model = new SpecialSyncModel({id: 'id'}); - - var onSuccess = function(m, response, options) { - assert.ok(options.specialSync, 'Options were passed correctly to callback'); - }; - - model.destroy({success: onSuccess}); - this.ajaxSettings.success(); - }); - - QUnit.test('non-persisted destroy', function(assert) { - assert.expect(1); - var a = new Backbone.Model({foo: 1, bar: 2, baz: 3}); - a.sync = function() { throw 'should not be called'; }; - a.destroy(); - assert.ok(true, 'non-persisted model should not call sync'); - }); - - QUnit.test('validate', function(assert) { - var lastError; - var model = new Backbone.Model(); - model.validate = function(attrs) { - if (attrs.admin !== this.get('admin')) return "Can't change admin status."; - }; - model.on('invalid', function(m, error) { - lastError = error; - }); - var result = model.set({a: 100}); - assert.equal(result, model); - assert.equal(model.get('a'), 100); - assert.equal(lastError, undefined); - result = model.set({admin: true}); - assert.equal(model.get('admin'), true); - result = model.set({a: 200, admin: false}, {validate: true}); - assert.equal(lastError, "Can't change admin status."); - assert.equal(result, false); - assert.equal(model.get('a'), 100); - }); - - QUnit.test('validate on unset and clear', function(assert) { - assert.expect(6); - var error; - var model = new Backbone.Model({name: 'One'}); - model.validate = function(attrs) { - if (!attrs.name) { - error = true; - return 'No thanks.'; - } - }; - model.set({name: 'Two'}); - assert.equal(model.get('name'), 'Two'); - assert.equal(error, undefined); - model.unset('name', {validate: true}); - assert.equal(error, true); - assert.equal(model.get('name'), 'Two'); - model.clear({validate: true}); - assert.equal(model.get('name'), 'Two'); - delete model.validate; - model.clear(); - assert.equal(model.get('name'), undefined); - }); - - QUnit.test('validate with error callback', function(assert) { - assert.expect(8); - var lastError, boundError; - var model = new Backbone.Model(); - model.validate = function(attrs) { - if (attrs.admin) return "Can't change admin status."; - }; - model.on('invalid', function(m, error) { - boundError = true; - }); - var result = model.set({a: 100}, {validate: true}); - assert.equal(result, model); - assert.equal(model.get('a'), 100); - assert.equal(model.validationError, null); - assert.equal(boundError, undefined); - result = model.set({a: 200, admin: true}, {validate: true}); - assert.equal(result, false); - assert.equal(model.get('a'), 100); - assert.equal(model.validationError, "Can't change admin status."); - assert.equal(boundError, true); - }); - - QUnit.test('defaults always extend attrs (#459)', function(assert) { - assert.expect(2); - var Defaulted = Backbone.Model.extend({ - defaults: {one: 1}, - initialize: function(attrs, opts) { - assert.equal(this.attributes.one, 1); - } - }); - var providedattrs = new Defaulted({}); - var emptyattrs = new Defaulted(); - }); - - QUnit.test('Inherit class properties', function(assert) { - assert.expect(6); - var Parent = Backbone.Model.extend({ - instancePropSame: function() {}, - instancePropDiff: function() {} - }, { - classProp: function() {} - }); - var Child = Parent.extend({ - instancePropDiff: function() {} - }); - - var adult = new Parent; - var kid = new Child; - - assert.equal(Child.classProp, Parent.classProp); - assert.notEqual(Child.classProp, undefined); - - assert.equal(kid.instancePropSame, adult.instancePropSame); - assert.notEqual(kid.instancePropSame, undefined); - - assert.notEqual(Child.prototype.instancePropDiff, Parent.prototype.instancePropDiff); - assert.notEqual(Child.prototype.instancePropDiff, undefined); - }); - - QUnit.test("Nested change events don't clobber previous attributes", function(assert) { - assert.expect(4); - new Backbone.Model() - .on('change:state', function(m, newState) { - assert.equal(m.previous('state'), undefined); - assert.equal(newState, 'hello'); - // Fire a nested change event. - m.set({other: 'whatever'}); - }) - .on('change:state', function(m, newState) { - assert.equal(m.previous('state'), undefined); - assert.equal(newState, 'hello'); - }) - .set({state: 'hello'}); - }); - - QUnit.test('hasChanged/set should use same comparison', function(assert) { - assert.expect(2); - var changed = 0, model = new Backbone.Model({a: null}); - model.on('change', function() { - assert.ok(this.hasChanged('a')); - }) - .on('change:a', function() { - changed++; - }) - .set({a: undefined}); - assert.equal(changed, 1); - }); - - QUnit.test('#582, #425, change:attribute callbacks should fire after all changes have occurred', function(assert) { - assert.expect(9); - var model = new Backbone.Model; - - var assertion = function() { - assert.equal(model.get('a'), 'a'); - assert.equal(model.get('b'), 'b'); - assert.equal(model.get('c'), 'c'); - }; - - model.on('change:a', assertion); - model.on('change:b', assertion); - model.on('change:c', assertion); - - model.set({a: 'a', b: 'b', c: 'c'}); - }); - - QUnit.test('#871, set with attributes property', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.set({attributes: true}); - assert.ok(model.has('attributes')); - }); - - QUnit.test('set value regardless of equality/change', function(assert) { - assert.expect(1); - var model = new Backbone.Model({x: []}); - var a = []; - model.set({x: a}); - assert.ok(model.get('x') === a); - }); - - QUnit.test('set same value does not trigger change', function(assert) { - assert.expect(0); - var model = new Backbone.Model({x: 1}); - model.on('change change:x', function() { assert.ok(false); }); - model.set({x: 1}); - model.set({x: 1}); - }); - - QUnit.test('unset does not fire a change for undefined attributes', function(assert) { - assert.expect(0); - var model = new Backbone.Model({x: undefined}); - model.on('change:x', function(){ assert.ok(false); }); - model.unset('x'); - }); - - QUnit.test('set: undefined values', function(assert) { - assert.expect(1); - var model = new Backbone.Model({x: undefined}); - assert.ok('x' in model.attributes); - }); - - QUnit.test('hasChanged works outside of change events, and true within', function(assert) { - assert.expect(6); - var model = new Backbone.Model({x: 1}); - model.on('change:x', function() { - assert.ok(model.hasChanged('x')); - assert.equal(model.get('x'), 1); - }); - model.set({x: 2}, {silent: true}); - assert.ok(model.hasChanged()); - assert.equal(model.hasChanged('x'), true); - model.set({x: 1}); - assert.ok(model.hasChanged()); - assert.equal(model.hasChanged('x'), true); - }); - - QUnit.test('hasChanged gets cleared on the following set', function(assert) { - assert.expect(4); - var model = new Backbone.Model; - model.set({x: 1}); - assert.ok(model.hasChanged()); - model.set({x: 1}); - assert.ok(!model.hasChanged()); - model.set({x: 2}); - assert.ok(model.hasChanged()); - model.set({}); - assert.ok(!model.hasChanged()); - }); - - QUnit.test('save with `wait` succeeds without `validate`', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.url = '/test'; - model.save({x: 1}, {wait: true}); - assert.ok(this.syncArgs.model === model); - }); - - QUnit.test("save without `wait` doesn't set invalid attributes", function(assert) { - var model = new Backbone.Model(); - model.validate = function() { return 1; }; - model.save({a: 1}); - assert.equal(model.get('a'), void 0); - }); - - QUnit.test("save doesn't validate twice", function(assert) { - var model = new Backbone.Model(); - var times = 0; - model.sync = function() {}; - model.validate = function() { ++times; }; - model.save({}); - assert.equal(times, 1); - }); - - QUnit.test('`hasChanged` for falsey keys', function(assert) { - assert.expect(2); - var model = new Backbone.Model(); - model.set({x: true}, {silent: true}); - assert.ok(!model.hasChanged(0)); - assert.ok(!model.hasChanged('')); - }); - - QUnit.test('`previous` for falsey keys', function(assert) { - assert.expect(2); - var model = new Backbone.Model({'0': true, '': true}); - model.set({'0': false, '': false}, {silent: true}); - assert.equal(model.previous(0), true); - assert.equal(model.previous(''), true); - }); - - QUnit.test('`save` with `wait` sends correct attributes', function(assert) { - assert.expect(5); - var changed = 0; - var model = new Backbone.Model({x: 1, y: 2}); - model.url = '/test'; - model.on('change:x', function() { changed++; }); - model.save({x: 3}, {wait: true}); - assert.deepEqual(JSON.parse(this.ajaxSettings.data), {x: 3, y: 2}); - assert.equal(model.get('x'), 1); - assert.equal(changed, 0); - this.syncArgs.options.success({}); - assert.equal(model.get('x'), 3); - assert.equal(changed, 1); - }); - - QUnit.test("a failed `save` with `wait` doesn't leave attributes behind", function(assert) { - assert.expect(1); - var model = new Backbone.Model; - model.url = '/test'; - model.save({x: 1}, {wait: true}); - assert.equal(model.get('x'), void 0); - }); - - QUnit.test('#1030 - `save` with `wait` results in correct attributes if success is called during sync', function(assert) { - assert.expect(2); - var model = new Backbone.Model({x: 1, y: 2}); - model.sync = function(method, m, options) { - options.success(); - }; - model.on('change:x', function() { assert.ok(true); }); - model.save({x: 3}, {wait: true}); - assert.equal(model.get('x'), 3); - }); - - QUnit.test('save with wait validates attributes', function(assert) { - var model = new Backbone.Model(); - model.url = '/test'; - model.validate = function() { assert.ok(true); }; - model.save({x: 1}, {wait: true}); - }); - - QUnit.test('save turns on parse flag', function(assert) { - var Model = Backbone.Model.extend({ - sync: function(method, m, options) { assert.ok(options.parse); } - }); - new Model().save(); - }); - - QUnit.test("nested `set` during `'change:attr'`", function(assert) { - assert.expect(2); - var events = []; - var model = new Backbone.Model(); - model.on('all', function(event) { events.push(event); }); - model.on('change', function() { - model.set({z: true}, {silent: true}); - }); - model.on('change:x', function() { - model.set({y: true}); - }); - model.set({x: true}); - assert.deepEqual(events, ['change:y', 'change:x', 'change']); - events = []; - model.set({z: true}); - assert.deepEqual(events, []); - }); - - QUnit.test('nested `change` only fires once', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.on('change', function() { - assert.ok(true); - model.set({x: true}); - }); - model.set({x: true}); - }); - - QUnit.test("nested `set` during `'change'`", function(assert) { - assert.expect(6); - var count = 0; - var model = new Backbone.Model(); - model.on('change', function() { - switch (count++) { - case 0: - assert.deepEqual(this.changedAttributes(), {x: true}); - assert.equal(model.previous('x'), undefined); - model.set({y: true}); - break; - case 1: - assert.deepEqual(this.changedAttributes(), {x: true, y: true}); - assert.equal(model.previous('x'), undefined); - model.set({z: true}); - break; - case 2: - assert.deepEqual(this.changedAttributes(), {x: true, y: true, z: true}); - assert.equal(model.previous('y'), undefined); - break; - default: - assert.ok(false); - } - }); - model.set({x: true}); - }); - - QUnit.test('nested `change` with silent', function(assert) { - assert.expect(3); - var count = 0; - var model = new Backbone.Model(); - model.on('change:y', function() { assert.ok(false); }); - model.on('change', function() { - switch (count++) { - case 0: - assert.deepEqual(this.changedAttributes(), {x: true}); - model.set({y: true}, {silent: true}); - model.set({z: true}); - break; - case 1: - assert.deepEqual(this.changedAttributes(), {x: true, y: true, z: true}); - break; - case 2: - assert.deepEqual(this.changedAttributes(), {z: false}); - break; - default: - assert.ok(false); - } - }); - model.set({x: true}); - model.set({z: false}); - }); - - QUnit.test('nested `change:attr` with silent', function(assert) { - assert.expect(0); - var model = new Backbone.Model(); - model.on('change:y', function(){ assert.ok(false); }); - model.on('change', function() { - model.set({y: true}, {silent: true}); - model.set({z: true}); - }); - model.set({x: true}); - }); - - QUnit.test('multiple nested changes with silent', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.on('change:x', function() { - model.set({y: 1}, {silent: true}); - model.set({y: 2}); - }); - model.on('change:y', function(m, val) { - assert.equal(val, 2); - }); - model.set({x: true}); - }); - - QUnit.test('multiple nested changes with silent', function(assert) { - assert.expect(1); - var changes = []; - var model = new Backbone.Model(); - model.on('change:b', function(m, val) { changes.push(val); }); - model.on('change', function() { - model.set({b: 1}); - }); - model.set({b: 0}); - assert.deepEqual(changes, [0, 1]); - }); - - QUnit.test('basic silent change semantics', function(assert) { - assert.expect(1); - var model = new Backbone.Model; - model.set({x: 1}); - model.on('change', function(){ assert.ok(true); }); - model.set({x: 2}, {silent: true}); - model.set({x: 1}); - }); - - QUnit.test('nested set multiple times', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.on('change:b', function() { - assert.ok(true); - }); - model.on('change:a', function() { - model.set({b: true}); - model.set({b: true}); - }); - model.set({a: true}); - }); - - QUnit.test('#1122 - clear does not alter options.', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - var options = {}; - model.clear(options); - assert.ok(!options.unset); - }); - - QUnit.test('#1122 - unset does not alter options.', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - var options = {}; - model.unset('x', options); - assert.ok(!options.unset); - }); - - QUnit.test('#1355 - `options` is passed to success callbacks', function(assert) { - assert.expect(3); - var model = new Backbone.Model(); - var opts = { - success: function( m, resp, options ) { - assert.ok(options); - } - }; - model.sync = function(method, m, options) { - options.success(); - }; - model.save({id: 1}, opts); - model.fetch(opts); - model.destroy(opts); - }); - - QUnit.test("#1412 - Trigger 'sync' event.", function(assert) { - assert.expect(3); - var model = new Backbone.Model({id: 1}); - model.sync = function(method, m, options) { options.success(); }; - model.on('sync', function(){ assert.ok(true); }); - model.fetch(); - model.save(); - model.destroy(); - }); - - QUnit.test('#1365 - Destroy: New models execute success callback.', function(assert) { - var done = assert.async(); - assert.expect(2); - new Backbone.Model() - .on('sync', function() { assert.ok(false); }) - .on('destroy', function(){ assert.ok(true); }) - .destroy({success: function(){ - assert.ok(true); - done(); - }}); - }); - - QUnit.test('#1433 - Save: An invalid model cannot be persisted.', function(assert) { - assert.expect(1); - var model = new Backbone.Model; - model.validate = function(){ return 'invalid'; }; - model.sync = function(){ assert.ok(false); }; - assert.strictEqual(model.save(), false); - }); - - QUnit.test("#1377 - Save without attrs triggers 'error'.", function(assert) { - assert.expect(1); - var Model = Backbone.Model.extend({ - url: '/test/', - sync: function(method, m, options){ options.success(); }, - validate: function(){ return 'invalid'; } - }); - var model = new Model({id: 1}); - model.on('invalid', function(){ assert.ok(true); }); - model.save(); - }); - - QUnit.test('#1545 - `undefined` can be passed to a model constructor without coersion', function(assert) { - var Model = Backbone.Model.extend({ - defaults: {one: 1}, - initialize: function(attrs, opts) { - assert.equal(attrs, undefined); - } - }); - var emptyattrs = new Model(); - var undefinedattrs = new Model(undefined); - }); - - QUnit.test('#1478 - Model `save` does not trigger change on unchanged attributes', function(assert) { - var done = assert.async(); - assert.expect(0); - var Model = Backbone.Model.extend({ - sync: function(method, m, options) { - setTimeout(function(){ - options.success(); - done(); - }, 0); - } - }); - new Model({x: true}) - .on('change:x', function(){ assert.ok(false); }) - .save(null, {wait: true}); - }); - - QUnit.test('#1664 - Changing from one value, silently to another, back to original triggers a change.', function(assert) { - assert.expect(1); - var model = new Backbone.Model({x: 1}); - model.on('change:x', function() { assert.ok(true); }); - model.set({x: 2}, {silent: true}); - model.set({x: 3}, {silent: true}); - model.set({x: 1}); - }); - - QUnit.test('#1664 - multiple silent changes nested inside a change event', function(assert) { - assert.expect(2); - var changes = []; - var model = new Backbone.Model(); - model.on('change', function() { - model.set({a: 'c'}, {silent: true}); - model.set({b: 2}, {silent: true}); - model.unset('c', {silent: true}); - }); - model.on('change:a change:b change:c', function(m, val) { changes.push(val); }); - model.set({a: 'a', b: 1, c: 'item'}); - assert.deepEqual(changes, ['a', 1, 'item']); - assert.deepEqual(model.attributes, {a: 'c', b: 2}); - }); - - QUnit.test('#1791 - `attributes` is available for `parse`', function(assert) { - var Model = Backbone.Model.extend({ - parse: function() { this.has('a'); } // shouldn't throw an error - }); - var model = new Model(null, {parse: true}); - assert.expect(0); - }); - - QUnit.test('silent changes in last `change` event back to original triggers change', function(assert) { - assert.expect(2); - var changes = []; - var model = new Backbone.Model(); - model.on('change:a change:b change:c', function(m, val) { changes.push(val); }); - model.on('change', function() { - model.set({a: 'c'}, {silent: true}); - }); - model.set({a: 'a'}); - assert.deepEqual(changes, ['a']); - model.set({a: 'a'}); - assert.deepEqual(changes, ['a', 'a']); - }); - - QUnit.test('#1943 change calculations should use _.isEqual', function(assert) { - var model = new Backbone.Model({a: {key: 'value'}}); - model.set('a', {key: 'value'}, {silent: true}); - assert.equal(model.changedAttributes(), false); - }); - - QUnit.test('#1964 - final `change` event is always fired, regardless of interim changes', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.on('change:property', function() { - model.set('property', 'bar'); - }); - model.on('change', function() { - assert.ok(true); - }); - model.set('property', 'foo'); - }); - - QUnit.test('isValid', function(assert) { - var model = new Backbone.Model({valid: true}); - model.validate = function(attrs) { - if (!attrs.valid) return 'invalid'; - }; - assert.equal(model.isValid(), true); - assert.equal(model.set({valid: false}, {validate: true}), false); - assert.equal(model.isValid(), true); - model.set({valid: false}); - assert.equal(model.isValid(), false); - assert.ok(!model.set('valid', false, {validate: true})); - }); - - QUnit.test('#1179 - isValid returns true in the absence of validate.', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.validate = null; - assert.ok(model.isValid()); - }); - - QUnit.test('#1961 - Creating a model with {validate:true} will call validate and use the error callback', function(assert) { - var Model = Backbone.Model.extend({ - validate: function(attrs) { - if (attrs.id === 1) return "This shouldn't happen"; - } - }); - var model = new Model({id: 1}, {validate: true}); - assert.equal(model.validationError, "This shouldn't happen"); - }); - - QUnit.test('toJSON receives attrs during save(..., {wait: true})', function(assert) { - assert.expect(1); - var Model = Backbone.Model.extend({ - url: '/test', - toJSON: function() { - assert.strictEqual(this.attributes.x, 1); - return _.clone(this.attributes); - } - }); - var model = new Model; - model.save({x: 1}, {wait: true}); - }); - - QUnit.test('#2034 - nested set with silent only triggers one change', function(assert) { - assert.expect(1); - var model = new Backbone.Model(); - model.on('change', function() { - model.set({b: true}, {silent: true}); - assert.ok(true); - }); - model.set({a: true}); - }); - - QUnit.test('#3778 - id will only be updated if it is set', function(assert) { - assert.expect(2); - var model = new Backbone.Model({id: 1}); - model.id = 2; - model.set({foo: 'bar'}); - assert.equal(model.id, 2); - model.set({id: 3}); - assert.equal(model.id, 3); - }); - -})(QUnit); diff --git a/public/vendor/lodash/vendor/backbone/test/noconflict.js b/public/vendor/lodash/vendor/backbone/test/noconflict.js deleted file mode 100644 index ab5d05f1652..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/noconflict.js +++ /dev/null @@ -1,13 +0,0 @@ -(function(QUnit) { - - QUnit.module('Backbone.noConflict'); - - QUnit.test('noConflict', function(assert) { - assert.expect(2); - var noconflictBackbone = Backbone.noConflict(); - assert.equal(window.Backbone, undefined, 'Returned window.Backbone'); - window.Backbone = noconflictBackbone; - assert.equal(window.Backbone, noconflictBackbone, 'Backbone is still pointing to the original Backbone'); - }); - -})(QUnit); diff --git a/public/vendor/lodash/vendor/backbone/test/router.js b/public/vendor/lodash/vendor/backbone/test/router.js deleted file mode 100644 index 5bcd7677d70..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/router.js +++ /dev/null @@ -1,1081 +0,0 @@ -(function(QUnit) { - - var router = null; - var location = null; - var lastRoute = null; - var lastArgs = []; - - var onRoute = function(routerParam, route, args) { - lastRoute = route; - lastArgs = args; - }; - - var Location = function(href) { - this.replace(href); - }; - - _.extend(Location.prototype, { - - parser: document.createElement('a'), - - replace: function(href) { - this.parser.href = href; - _.extend(this, _.pick(this.parser, - 'href', - 'hash', - 'host', - 'search', - 'fragment', - 'pathname', - 'protocol' - )); - - // In IE, anchor.pathname does not contain a leading slash though - // window.location.pathname does. - if (!/^\//.test(this.pathname)) this.pathname = '/' + this.pathname; - }, - - toString: function() { - return this.href; - } - - }); - - QUnit.module('Backbone.Router', { - - beforeEach: function() { - location = new Location('http://example.com'); - Backbone.history = _.extend(new Backbone.History, {location: location}); - router = new Router({testing: 101}); - Backbone.history.interval = 9; - Backbone.history.start({pushState: false}); - lastRoute = null; - lastArgs = []; - Backbone.history.on('route', onRoute); - }, - - afterEach: function() { - Backbone.history.stop(); - Backbone.history.off('route', onRoute); - } - - }); - - var ExternalObject = { - value: 'unset', - - routingFunction: function(value) { - this.value = value; - } - }; - ExternalObject.routingFunction = _.bind(ExternalObject.routingFunction, ExternalObject); - - var Router = Backbone.Router.extend({ - - count: 0, - - routes: { - 'noCallback': 'noCallback', - 'counter': 'counter', - 'search/:query': 'search', - 'search/:query/p:page': 'search', - 'charñ': 'charUTF', - 'char%C3%B1': 'charEscaped', - 'contacts': 'contacts', - 'contacts/new': 'newContact', - 'contacts/:id': 'loadContact', - 'route-event/:arg': 'routeEvent', - 'optional(/:item)': 'optionalItem', - 'named/optional/(y:z)': 'namedOptional', - 'splat/*args/end': 'splat', - ':repo/compare/*from...*to': 'github', - 'decode/:named/*splat': 'decode', - '*first/complex-*part/*rest': 'complex', - 'query/:entity': 'query', - 'function/:value': ExternalObject.routingFunction, - '*anything': 'anything' - }, - - preinitialize: function(options) { - this.testpreinit = 'foo'; - }, - - initialize: function(options) { - this.testing = options.testing; - this.route('implicit', 'implicit'); - }, - - counter: function() { - this.count++; - }, - - implicit: function() { - this.count++; - }, - - search: function(query, page) { - this.query = query; - this.page = page; - }, - - charUTF: function() { - this.charType = 'UTF'; - }, - - charEscaped: function() { - this.charType = 'escaped'; - }, - - contacts: function() { - this.contact = 'index'; - }, - - newContact: function() { - this.contact = 'new'; - }, - - loadContact: function() { - this.contact = 'load'; - }, - - optionalItem: function(arg) { - this.arg = arg !== void 0 ? arg : null; - }, - - splat: function(args) { - this.args = args; - }, - - github: function(repo, from, to) { - this.repo = repo; - this.from = from; - this.to = to; - }, - - complex: function(first, part, rest) { - this.first = first; - this.part = part; - this.rest = rest; - }, - - query: function(entity, args) { - this.entity = entity; - this.queryArgs = args; - }, - - anything: function(whatever) { - this.anything = whatever; - }, - - namedOptional: function(z) { - this.z = z; - }, - - decode: function(named, path) { - this.named = named; - this.path = path; - }, - - routeEvent: function(arg) { - } - - }); - - QUnit.test('initialize', function(assert) { - assert.expect(1); - assert.equal(router.testing, 101); - }); - - QUnit.test('preinitialize', function(assert) { - assert.expect(1); - assert.equal(router.testpreinit, 'foo'); - }); - - QUnit.test('routes (simple)', function(assert) { - assert.expect(4); - location.replace('http://example.com#search/news'); - Backbone.history.checkUrl(); - assert.equal(router.query, 'news'); - assert.equal(router.page, void 0); - assert.equal(lastRoute, 'search'); - assert.equal(lastArgs[0], 'news'); - }); - - QUnit.test('routes (simple, but unicode)', function(assert) { - assert.expect(4); - location.replace('http://example.com#search/тест'); - Backbone.history.checkUrl(); - assert.equal(router.query, 'тест'); - assert.equal(router.page, void 0); - assert.equal(lastRoute, 'search'); - assert.equal(lastArgs[0], 'тест'); - }); - - QUnit.test('routes (two part)', function(assert) { - assert.expect(2); - location.replace('http://example.com#search/nyc/p10'); - Backbone.history.checkUrl(); - assert.equal(router.query, 'nyc'); - assert.equal(router.page, '10'); - }); - - QUnit.test('routes via navigate', function(assert) { - assert.expect(2); - Backbone.history.navigate('search/manhattan/p20', {trigger: true}); - assert.equal(router.query, 'manhattan'); - assert.equal(router.page, '20'); - }); - - QUnit.test('routes via navigate with params', function(assert) { - assert.expect(1); - Backbone.history.navigate('query/test?a=b', {trigger: true}); - assert.equal(router.queryArgs, 'a=b'); - }); - - QUnit.test('routes via navigate for backwards-compatibility', function(assert) { - assert.expect(2); - Backbone.history.navigate('search/manhattan/p20', true); - assert.equal(router.query, 'manhattan'); - assert.equal(router.page, '20'); - }); - - QUnit.test('reports matched route via nagivate', function(assert) { - assert.expect(1); - assert.ok(Backbone.history.navigate('search/manhattan/p20', true)); - }); - - QUnit.test('route precedence via navigate', function(assert) { - assert.expect(6); - - // Check both 0.9.x and backwards-compatibility options - _.each([{trigger: true}, true], function(options) { - Backbone.history.navigate('contacts', options); - assert.equal(router.contact, 'index'); - Backbone.history.navigate('contacts/new', options); - assert.equal(router.contact, 'new'); - Backbone.history.navigate('contacts/foo', options); - assert.equal(router.contact, 'load'); - }); - }); - - QUnit.test('loadUrl is not called for identical routes.', function(assert) { - assert.expect(0); - Backbone.history.loadUrl = function() { assert.ok(false); }; - location.replace('http://example.com#route'); - Backbone.history.navigate('route'); - Backbone.history.navigate('/route'); - Backbone.history.navigate('/route'); - }); - - QUnit.test('use implicit callback if none provided', function(assert) { - assert.expect(1); - router.count = 0; - router.navigate('implicit', {trigger: true}); - assert.equal(router.count, 1); - }); - - QUnit.test('routes via navigate with {replace: true}', function(assert) { - assert.expect(1); - location.replace('http://example.com#start_here'); - Backbone.history.checkUrl(); - location.replace = function(href) { - assert.strictEqual(href, new Location('http://example.com#end_here').href); - }; - Backbone.history.navigate('end_here', {replace: true}); - }); - - QUnit.test('routes (splats)', function(assert) { - assert.expect(1); - location.replace('http://example.com#splat/long-list/of/splatted_99args/end'); - Backbone.history.checkUrl(); - assert.equal(router.args, 'long-list/of/splatted_99args'); - }); - - QUnit.test('routes (github)', function(assert) { - assert.expect(3); - location.replace('http://example.com#backbone/compare/1.0...braddunbar:with/slash'); - Backbone.history.checkUrl(); - assert.equal(router.repo, 'backbone'); - assert.equal(router.from, '1.0'); - assert.equal(router.to, 'braddunbar:with/slash'); - }); - - QUnit.test('routes (optional)', function(assert) { - assert.expect(2); - location.replace('http://example.com#optional'); - Backbone.history.checkUrl(); - assert.ok(!router.arg); - location.replace('http://example.com#optional/thing'); - Backbone.history.checkUrl(); - assert.equal(router.arg, 'thing'); - }); - - QUnit.test('routes (complex)', function(assert) { - assert.expect(3); - location.replace('http://example.com#one/two/three/complex-part/four/five/six/seven'); - Backbone.history.checkUrl(); - assert.equal(router.first, 'one/two/three'); - assert.equal(router.part, 'part'); - assert.equal(router.rest, 'four/five/six/seven'); - }); - - QUnit.test('routes (query)', function(assert) { - assert.expect(5); - location.replace('http://example.com#query/mandel?a=b&c=d'); - Backbone.history.checkUrl(); - assert.equal(router.entity, 'mandel'); - assert.equal(router.queryArgs, 'a=b&c=d'); - assert.equal(lastRoute, 'query'); - assert.equal(lastArgs[0], 'mandel'); - assert.equal(lastArgs[1], 'a=b&c=d'); - }); - - QUnit.test('routes (anything)', function(assert) { - assert.expect(1); - location.replace('http://example.com#doesnt-match-a-route'); - Backbone.history.checkUrl(); - assert.equal(router.anything, 'doesnt-match-a-route'); - }); - - QUnit.test('routes (function)', function(assert) { - assert.expect(3); - router.on('route', function(name) { - assert.ok(name === ''); - }); - assert.equal(ExternalObject.value, 'unset'); - location.replace('http://example.com#function/set'); - Backbone.history.checkUrl(); - assert.equal(ExternalObject.value, 'set'); - }); - - QUnit.test('Decode named parameters, not splats.', function(assert) { - assert.expect(2); - location.replace('http://example.com#decode/a%2Fb/c%2Fd/e'); - Backbone.history.checkUrl(); - assert.strictEqual(router.named, 'a/b'); - assert.strictEqual(router.path, 'c/d/e'); - }); - - QUnit.test('fires event when router doesn\'t have callback on it', function(assert) { - assert.expect(1); - router.on('route:noCallback', function() { assert.ok(true); }); - location.replace('http://example.com#noCallback'); - Backbone.history.checkUrl(); - }); - - QUnit.test('No events are triggered if #execute returns false.', function(assert) { - assert.expect(1); - var MyRouter = Backbone.Router.extend({ - - routes: { - foo: function() { - assert.ok(true); - } - }, - - execute: function(callback, args) { - callback.apply(this, args); - return false; - } - - }); - - var myRouter = new MyRouter; - - myRouter.on('route route:foo', function() { - assert.ok(false); - }); - - Backbone.history.on('route', function() { - assert.ok(false); - }); - - location.replace('http://example.com#foo'); - Backbone.history.checkUrl(); - }); - - QUnit.test('#933, #908 - leading slash', function(assert) { - assert.expect(2); - location.replace('http://example.com/root/foo'); - - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - Backbone.history.start({root: '/root', hashChange: false, silent: true}); - assert.strictEqual(Backbone.history.getFragment(), 'foo'); - - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - Backbone.history.start({root: '/root/', hashChange: false, silent: true}); - assert.strictEqual(Backbone.history.getFragment(), 'foo'); - }); - - QUnit.test('#967 - Route callback gets passed encoded values.', function(assert) { - assert.expect(3); - var route = 'has%2Fslash/complex-has%23hash/has%20space'; - Backbone.history.navigate(route, {trigger: true}); - assert.strictEqual(router.first, 'has/slash'); - assert.strictEqual(router.part, 'has#hash'); - assert.strictEqual(router.rest, 'has space'); - }); - - QUnit.test('correctly handles URLs with % (#868)', function(assert) { - assert.expect(3); - location.replace('http://example.com#search/fat%3A1.5%25'); - Backbone.history.checkUrl(); - location.replace('http://example.com#search/fat'); - Backbone.history.checkUrl(); - assert.equal(router.query, 'fat'); - assert.equal(router.page, void 0); - assert.equal(lastRoute, 'search'); - }); - - QUnit.test('#2666 - Hashes with UTF8 in them.', function(assert) { - assert.expect(2); - Backbone.history.navigate('charñ', {trigger: true}); - assert.equal(router.charType, 'UTF'); - Backbone.history.navigate('char%C3%B1', {trigger: true}); - assert.equal(router.charType, 'UTF'); - }); - - QUnit.test('#1185 - Use pathname when hashChange is not wanted.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/path/name#hash'); - Backbone.history = _.extend(new Backbone.History, {location: location}); - Backbone.history.start({hashChange: false}); - var fragment = Backbone.history.getFragment(); - assert.strictEqual(fragment, location.pathname.replace(/^\//, '')); - }); - - QUnit.test('#1206 - Strip leading slash before location.assign.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root/'); - Backbone.history = _.extend(new Backbone.History, {location: location}); - Backbone.history.start({hashChange: false, root: '/root/'}); - location.assign = function(pathname) { - assert.strictEqual(pathname, '/root/fragment'); - }; - Backbone.history.navigate('/fragment'); - }); - - QUnit.test('#1387 - Root fragment without trailing slash.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root'); - Backbone.history = _.extend(new Backbone.History, {location: location}); - Backbone.history.start({hashChange: false, root: '/root/', silent: true}); - assert.strictEqual(Backbone.history.getFragment(), ''); - }); - - QUnit.test('#1366 - History does not prepend root to fragment.', function(assert) { - assert.expect(2); - Backbone.history.stop(); - location.replace('http://example.com/root/'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function(state, title, url) { - assert.strictEqual(url, '/root/x'); - } - } - }); - Backbone.history.start({ - root: '/root/', - pushState: true, - hashChange: false - }); - Backbone.history.navigate('x'); - assert.strictEqual(Backbone.history.fragment, 'x'); - }); - - QUnit.test('Normalize root.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function(state, title, url) { - assert.strictEqual(url, '/root/fragment'); - } - } - }); - Backbone.history.start({ - pushState: true, - root: '/root', - hashChange: false - }); - Backbone.history.navigate('fragment'); - }); - - QUnit.test('Normalize root.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root#fragment'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function(state, title, url) {}, - replaceState: function(state, title, url) { - assert.strictEqual(url, '/root/fragment'); - } - } - }); - Backbone.history.start({ - pushState: true, - root: '/root' - }); - }); - - QUnit.test('Normalize root.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root'); - Backbone.history = _.extend(new Backbone.History, {location: location}); - Backbone.history.loadUrl = function() { assert.ok(true); }; - Backbone.history.start({ - pushState: true, - root: '/root' - }); - }); - - QUnit.test('Normalize root - leading slash.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function() {}, - replaceState: function() {} - } - }); - Backbone.history.start({root: 'root'}); - assert.strictEqual(Backbone.history.root, '/root/'); - }); - - QUnit.test('Transition from hashChange to pushState.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root#x/y'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function() {}, - replaceState: function(state, title, url) { - assert.strictEqual(url, '/root/x/y'); - } - } - }); - Backbone.history.start({ - root: 'root', - pushState: true - }); - }); - - QUnit.test('#1619: Router: Normalize empty root', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function() {}, - replaceState: function() {} - } - }); - Backbone.history.start({root: ''}); - assert.strictEqual(Backbone.history.root, '/'); - }); - - QUnit.test('#1619: Router: nagivate with empty root', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function(state, title, url) { - assert.strictEqual(url, '/fragment'); - } - } - }); - Backbone.history.start({ - pushState: true, - root: '', - hashChange: false - }); - Backbone.history.navigate('fragment'); - }); - - QUnit.test('Transition from pushState to hashChange.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root/x/y?a=b'); - location.replace = function(url) { - assert.strictEqual(url, '/root#x/y?a=b'); - }; - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: null, - replaceState: null - } - }); - Backbone.history.start({ - root: 'root', - pushState: true - }); - }); - - QUnit.test('#1695 - hashChange to pushState with search.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root#x/y?a=b'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function() {}, - replaceState: function(state, title, url) { - assert.strictEqual(url, '/root/x/y?a=b'); - } - } - }); - Backbone.history.start({ - root: 'root', - pushState: true - }); - }); - - QUnit.test('#1746 - Router allows empty route.', function(assert) { - assert.expect(1); - var MyRouter = Backbone.Router.extend({ - routes: {'': 'empty'}, - empty: function() {}, - route: function(route) { - assert.strictEqual(route, ''); - } - }); - new MyRouter; - }); - - QUnit.test('#1794 - Trailing space in fragments.', function(assert) { - assert.expect(1); - var history = new Backbone.History; - assert.strictEqual(history.getFragment('fragment '), 'fragment'); - }); - - QUnit.test('#1820 - Leading slash and trailing space.', function(assert) { - assert.expect(1); - var history = new Backbone.History; - assert.strictEqual(history.getFragment('/fragment '), 'fragment'); - }); - - QUnit.test('#1980 - Optional parameters.', function(assert) { - assert.expect(2); - location.replace('http://example.com#named/optional/y'); - Backbone.history.checkUrl(); - assert.strictEqual(router.z, undefined); - location.replace('http://example.com#named/optional/y123'); - Backbone.history.checkUrl(); - assert.strictEqual(router.z, '123'); - }); - - QUnit.test('#2062 - Trigger "route" event on router instance.', function(assert) { - assert.expect(2); - router.on('route', function(name, args) { - assert.strictEqual(name, 'routeEvent'); - assert.deepEqual(args, ['x', null]); - }); - location.replace('http://example.com#route-event/x'); - Backbone.history.checkUrl(); - }); - - QUnit.test('#2255 - Extend routes by making routes a function.', function(assert) { - assert.expect(1); - var RouterBase = Backbone.Router.extend({ - routes: function() { - return { - home: 'root', - index: 'index.html' - }; - } - }); - - var RouterExtended = RouterBase.extend({ - routes: function() { - var _super = RouterExtended.__super__.routes; - return _.extend(_super(), {show: 'show', search: 'search'}); - } - }); - - var myRouter = new RouterExtended(); - assert.deepEqual({home: 'root', index: 'index.html', show: 'show', search: 'search'}, myRouter.routes); - }); - - QUnit.test('#2538 - hashChange to pushState only if both requested.', function(assert) { - assert.expect(0); - Backbone.history.stop(); - location.replace('http://example.com/root?a=b#x/y'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function() {}, - replaceState: function() { assert.ok(false); } - } - }); - Backbone.history.start({ - root: 'root', - pushState: true, - hashChange: false - }); - }); - - QUnit.test('No hash fallback.', function(assert) { - assert.expect(0); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function() {}, - replaceState: function() {} - } - }); - - var MyRouter = Backbone.Router.extend({ - routes: { - hash: function() { assert.ok(false); } - } - }); - var myRouter = new MyRouter; - - location.replace('http://example.com/'); - Backbone.history.start({ - pushState: true, - hashChange: false - }); - location.replace('http://example.com/nomatch#hash'); - Backbone.history.checkUrl(); - }); - - QUnit.test('#2656 - No trailing slash on root.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function(state, title, url) { - assert.strictEqual(url, '/root'); - } - } - }); - location.replace('http://example.com/root/path'); - Backbone.history.start({pushState: true, hashChange: false, root: 'root'}); - Backbone.history.navigate(''); - }); - - QUnit.test('#2656 - No trailing slash on root.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function(state, title, url) { - assert.strictEqual(url, '/'); - } - } - }); - location.replace('http://example.com/path'); - Backbone.history.start({pushState: true, hashChange: false}); - Backbone.history.navigate(''); - }); - - QUnit.test('#2656 - No trailing slash on root.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function(state, title, url) { - assert.strictEqual(url, '/root?x=1'); - } - } - }); - location.replace('http://example.com/root/path'); - Backbone.history.start({pushState: true, hashChange: false, root: 'root'}); - Backbone.history.navigate('?x=1'); - }); - - QUnit.test('#2765 - Fragment matching sans query/hash.', function(assert) { - assert.expect(2); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function(state, title, url) { - assert.strictEqual(url, '/path?query#hash'); - } - } - }); - - var MyRouter = Backbone.Router.extend({ - routes: { - path: function() { assert.ok(true); } - } - }); - var myRouter = new MyRouter; - - location.replace('http://example.com/'); - Backbone.history.start({pushState: true, hashChange: false}); - Backbone.history.navigate('path?query#hash', true); - }); - - QUnit.test('Do not decode the search params.', function(assert) { - assert.expect(1); - var MyRouter = Backbone.Router.extend({ - routes: { - path: function(params) { - assert.strictEqual(params, 'x=y%3Fz'); - } - } - }); - var myRouter = new MyRouter; - Backbone.history.navigate('path?x=y%3Fz', true); - }); - - QUnit.test('Navigate to a hash url.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - Backbone.history.start({pushState: true}); - var MyRouter = Backbone.Router.extend({ - routes: { - path: function(params) { - assert.strictEqual(params, 'x=y'); - } - } - }); - var myRouter = new MyRouter; - location.replace('http://example.com/path?x=y#hash'); - Backbone.history.checkUrl(); - }); - - QUnit.test('#navigate to a hash url.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - Backbone.history.start({pushState: true}); - var MyRouter = Backbone.Router.extend({ - routes: { - path: function(params) { - assert.strictEqual(params, 'x=y'); - } - } - }); - var myRouter = new MyRouter; - Backbone.history.navigate('path?x=y#hash', true); - }); - - QUnit.test('unicode pathname', function(assert) { - assert.expect(1); - location.replace('http://example.com/myyjä'); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: { - myyjä: function() { - assert.ok(true); - } - } - }); - new MyRouter; - Backbone.history.start({pushState: true}); - }); - - QUnit.test('unicode pathname with % in a parameter', function(assert) { - assert.expect(1); - location.replace('http://example.com/myyjä/foo%20%25%3F%2f%40%25%20bar'); - location.pathname = '/myyj%C3%A4/foo%20%25%3F%2f%40%25%20bar'; - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: { - 'myyjä/:query': function(query) { - assert.strictEqual(query, 'foo %?/@% bar'); - } - } - }); - new MyRouter; - Backbone.history.start({pushState: true}); - }); - - QUnit.test('newline in route', function(assert) { - assert.expect(1); - location.replace('http://example.com/stuff%0Anonsense?param=foo%0Abar'); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: { - 'stuff\nnonsense': function() { - assert.ok(true); - } - } - }); - new MyRouter; - Backbone.history.start({pushState: true}); - }); - - QUnit.test('Router#execute receives callback, args, name.', function(assert) { - assert.expect(3); - location.replace('http://example.com#foo/123/bar?x=y'); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: {'foo/:id/bar': 'foo'}, - foo: function() {}, - execute: function(callback, args, name) { - assert.strictEqual(callback, this.foo); - assert.deepEqual(args, ['123', 'x=y']); - assert.strictEqual(name, 'foo'); - } - }); - var myRouter = new MyRouter; - Backbone.history.start(); - }); - - QUnit.test('pushState to hashChange with only search params.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com?a=b'); - location.replace = function(url) { - assert.strictEqual(url, '/#?a=b'); - }; - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: null - }); - Backbone.history.start({pushState: true}); - }); - - QUnit.test('#3123 - History#navigate decodes before comparison.', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/shop/search?keyword=short%20dress'); - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: function() { assert.ok(false); }, - replaceState: function() { assert.ok(false); } - } - }); - Backbone.history.start({pushState: true}); - Backbone.history.navigate('shop/search?keyword=short%20dress', true); - assert.strictEqual(Backbone.history.fragment, 'shop/search?keyword=short dress'); - }); - - QUnit.test('#3175 - Urls in the params', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com#login?a=value&backUrl=https%3A%2F%2Fwww.msn.com%2Fidp%2Fidpdemo%3Fspid%3Dspdemo%26target%3Db'); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var myRouter = new Backbone.Router; - myRouter.route('login', function(params) { - assert.strictEqual(params, 'a=value&backUrl=https%3A%2F%2Fwww.msn.com%2Fidp%2Fidpdemo%3Fspid%3Dspdemo%26target%3Db'); - }); - Backbone.history.start(); - }); - - QUnit.test('#3358 - pushState to hashChange transition with search params', function(assert) { - assert.expect(1); - Backbone.history.stop(); - location.replace('http://example.com/root?foo=bar'); - location.replace = function(url) { - assert.strictEqual(url, '/root#?foo=bar'); - }; - Backbone.history = _.extend(new Backbone.History, { - location: location, - history: { - pushState: undefined, - replaceState: undefined - } - }); - Backbone.history.start({root: '/root', pushState: true}); - }); - - QUnit.test('Paths that don\'t match the root should not match no root', function(assert) { - assert.expect(0); - location.replace('http://example.com/foo'); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: { - foo: function() { - assert.ok(false, 'should not match unless root matches'); - } - } - }); - var myRouter = new MyRouter; - Backbone.history.start({root: 'root', pushState: true}); - }); - - QUnit.test('Paths that don\'t match the root should not match roots of the same length', function(assert) { - assert.expect(0); - location.replace('http://example.com/xxxx/foo'); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: { - foo: function() { - assert.ok(false, 'should not match unless root matches'); - } - } - }); - var myRouter = new MyRouter; - Backbone.history.start({root: 'root', pushState: true}); - }); - - QUnit.test('roots with regex characters', function(assert) { - assert.expect(1); - location.replace('http://example.com/x+y.z/foo'); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: {foo: function() { assert.ok(true); }} - }); - var myRouter = new MyRouter; - Backbone.history.start({root: 'x+y.z', pushState: true}); - }); - - QUnit.test('roots with unicode characters', function(assert) { - assert.expect(1); - location.replace('http://example.com/®ooτ/foo'); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: {foo: function() { assert.ok(true); }} - }); - var myRouter = new MyRouter; - Backbone.history.start({root: '®ooτ', pushState: true}); - }); - - QUnit.test('roots without slash', function(assert) { - assert.expect(1); - location.replace('http://example.com/®ooτ'); - Backbone.history.stop(); - Backbone.history = _.extend(new Backbone.History, {location: location}); - var MyRouter = Backbone.Router.extend({ - routes: {'': function() { assert.ok(true); }} - }); - var myRouter = new MyRouter; - Backbone.history.start({root: '®ooτ', pushState: true}); - }); - - QUnit.test('#4025 - navigate updates URL hash as is', function(assert) { - assert.expect(1); - var route = 'search/has%20space'; - Backbone.history.navigate(route); - assert.strictEqual(location.hash, '#' + route); - }); - -})(QUnit); diff --git a/public/vendor/lodash/vendor/backbone/test/setup/dom-setup.js b/public/vendor/lodash/vendor/backbone/test/setup/dom-setup.js deleted file mode 100644 index f2242282c6f..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/setup/dom-setup.js +++ /dev/null @@ -1,4 +0,0 @@ -$('body').append( - '
' + - '
' -); diff --git a/public/vendor/lodash/vendor/backbone/test/setup/environment.js b/public/vendor/lodash/vendor/backbone/test/setup/environment.js deleted file mode 100644 index 6461b5bbdc7..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/setup/environment.js +++ /dev/null @@ -1,45 +0,0 @@ -(function(QUnit) { - - var sync = Backbone.sync; - var ajax = Backbone.ajax; - var emulateHTTP = Backbone.emulateHTTP; - var emulateJSON = Backbone.emulateJSON; - var history = window.history; - var pushState = history.pushState; - var replaceState = history.replaceState; - - QUnit.config.noglobals = true; - - QUnit.testStart(function() { - var env = QUnit.config.current.testEnvironment; - - // We never want to actually call these during tests. - history.pushState = history.replaceState = function() {}; - - // Capture ajax settings for comparison. - Backbone.ajax = function(settings) { - env.ajaxSettings = settings; - }; - - // Capture the arguments to Backbone.sync for comparison. - Backbone.sync = function(method, model, options) { - env.syncArgs = { - method: method, - model: model, - options: options - }; - sync.apply(this, arguments); - }; - - }); - - QUnit.testDone(function() { - Backbone.sync = sync; - Backbone.ajax = ajax; - Backbone.emulateHTTP = emulateHTTP; - Backbone.emulateJSON = emulateJSON; - history.pushState = pushState; - history.replaceState = replaceState; - }); - -})(QUnit); diff --git a/public/vendor/lodash/vendor/backbone/test/sync.js b/public/vendor/lodash/vendor/backbone/test/sync.js deleted file mode 100644 index cd314a18559..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/sync.js +++ /dev/null @@ -1,239 +0,0 @@ -(function(QUnit) { - - var Library = Backbone.Collection.extend({ - url: function() { return '/library'; } - }); - var library; - - var attrs = { - title: 'The Tempest', - author: 'Bill Shakespeare', - length: 123 - }; - - QUnit.module('Backbone.sync', { - - beforeEach: function(assert) { - library = new Library; - library.create(attrs, {wait: false}); - }, - - afterEach: function(assert) { - Backbone.emulateHTTP = false; - } - - }); - - QUnit.test('read', function(assert) { - assert.expect(4); - library.fetch(); - assert.equal(this.ajaxSettings.url, '/library'); - assert.equal(this.ajaxSettings.type, 'GET'); - assert.equal(this.ajaxSettings.dataType, 'json'); - assert.ok(_.isEmpty(this.ajaxSettings.data)); - }); - - QUnit.test('passing data', function(assert) { - assert.expect(3); - library.fetch({data: {a: 'a', one: 1}}); - assert.equal(this.ajaxSettings.url, '/library'); - assert.equal(this.ajaxSettings.data.a, 'a'); - assert.equal(this.ajaxSettings.data.one, 1); - }); - - QUnit.test('create', function(assert) { - assert.expect(6); - assert.equal(this.ajaxSettings.url, '/library'); - assert.equal(this.ajaxSettings.type, 'POST'); - assert.equal(this.ajaxSettings.dataType, 'json'); - var data = JSON.parse(this.ajaxSettings.data); - assert.equal(data.title, 'The Tempest'); - assert.equal(data.author, 'Bill Shakespeare'); - assert.equal(data.length, 123); - }); - - QUnit.test('update', function(assert) { - assert.expect(7); - library.first().save({id: '1-the-tempest', author: 'William Shakespeare'}); - assert.equal(this.ajaxSettings.url, '/library/1-the-tempest'); - assert.equal(this.ajaxSettings.type, 'PUT'); - assert.equal(this.ajaxSettings.dataType, 'json'); - var data = JSON.parse(this.ajaxSettings.data); - assert.equal(data.id, '1-the-tempest'); - assert.equal(data.title, 'The Tempest'); - assert.equal(data.author, 'William Shakespeare'); - assert.equal(data.length, 123); - }); - - QUnit.test('update with emulateHTTP and emulateJSON', function(assert) { - assert.expect(7); - library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, { - emulateHTTP: true, - emulateJSON: true - }); - assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); - assert.equal(this.ajaxSettings.type, 'POST'); - assert.equal(this.ajaxSettings.dataType, 'json'); - assert.equal(this.ajaxSettings.data._method, 'PUT'); - var data = JSON.parse(this.ajaxSettings.data.model); - assert.equal(data.id, '2-the-tempest'); - assert.equal(data.author, 'Tim Shakespeare'); - assert.equal(data.length, 123); - }); - - QUnit.test('update with just emulateHTTP', function(assert) { - assert.expect(6); - library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, { - emulateHTTP: true - }); - assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); - assert.equal(this.ajaxSettings.type, 'POST'); - assert.equal(this.ajaxSettings.contentType, 'application/json'); - var data = JSON.parse(this.ajaxSettings.data); - assert.equal(data.id, '2-the-tempest'); - assert.equal(data.author, 'Tim Shakespeare'); - assert.equal(data.length, 123); - }); - - QUnit.test('update with just emulateJSON', function(assert) { - assert.expect(6); - library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}, { - emulateJSON: true - }); - assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); - assert.equal(this.ajaxSettings.type, 'PUT'); - assert.equal(this.ajaxSettings.contentType, 'application/x-www-form-urlencoded'); - var data = JSON.parse(this.ajaxSettings.data.model); - assert.equal(data.id, '2-the-tempest'); - assert.equal(data.author, 'Tim Shakespeare'); - assert.equal(data.length, 123); - }); - - QUnit.test('read model', function(assert) { - assert.expect(3); - library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); - library.first().fetch(); - assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); - assert.equal(this.ajaxSettings.type, 'GET'); - assert.ok(_.isEmpty(this.ajaxSettings.data)); - }); - - QUnit.test('destroy', function(assert) { - assert.expect(3); - library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); - library.first().destroy({wait: true}); - assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); - assert.equal(this.ajaxSettings.type, 'DELETE'); - assert.equal(this.ajaxSettings.data, null); - }); - - QUnit.test('destroy with emulateHTTP', function(assert) { - assert.expect(3); - library.first().save({id: '2-the-tempest', author: 'Tim Shakespeare'}); - library.first().destroy({ - emulateHTTP: true, - emulateJSON: true - }); - assert.equal(this.ajaxSettings.url, '/library/2-the-tempest'); - assert.equal(this.ajaxSettings.type, 'POST'); - assert.equal(JSON.stringify(this.ajaxSettings.data), '{"_method":"DELETE"}'); - }); - - QUnit.test('urlError', function(assert) { - assert.expect(2); - var model = new Backbone.Model(); - assert.raises(function() { - model.fetch(); - }); - model.fetch({url: '/one/two'}); - assert.equal(this.ajaxSettings.url, '/one/two'); - }); - - QUnit.test('#1052 - `options` is optional.', function(assert) { - assert.expect(0); - var model = new Backbone.Model(); - model.url = '/test'; - Backbone.sync('create', model); - }); - - QUnit.test('Backbone.ajax', function(assert) { - assert.expect(1); - Backbone.ajax = function(settings) { - assert.strictEqual(settings.url, '/test'); - }; - var model = new Backbone.Model(); - model.url = '/test'; - Backbone.sync('create', model); - }); - - QUnit.test('Call provided error callback on error.', function(assert) { - assert.expect(1); - var model = new Backbone.Model; - model.url = '/test'; - Backbone.sync('read', model, { - error: function() { assert.ok(true); } - }); - this.ajaxSettings.error(); - }); - - QUnit.test('Use Backbone.emulateHTTP as default.', function(assert) { - assert.expect(2); - var model = new Backbone.Model; - model.url = '/test'; - - Backbone.emulateHTTP = true; - model.sync('create', model); - assert.strictEqual(this.ajaxSettings.emulateHTTP, true); - - Backbone.emulateHTTP = false; - model.sync('create', model); - assert.strictEqual(this.ajaxSettings.emulateHTTP, false); - }); - - QUnit.test('Use Backbone.emulateJSON as default.', function(assert) { - assert.expect(2); - var model = new Backbone.Model; - model.url = '/test'; - - Backbone.emulateJSON = true; - model.sync('create', model); - assert.strictEqual(this.ajaxSettings.emulateJSON, true); - - Backbone.emulateJSON = false; - model.sync('create', model); - assert.strictEqual(this.ajaxSettings.emulateJSON, false); - }); - - QUnit.test('#1756 - Call user provided beforeSend function.', function(assert) { - assert.expect(4); - Backbone.emulateHTTP = true; - var model = new Backbone.Model; - model.url = '/test'; - var xhr = { - setRequestHeader: function(header, value) { - assert.strictEqual(header, 'X-HTTP-Method-Override'); - assert.strictEqual(value, 'DELETE'); - } - }; - model.sync('delete', model, { - beforeSend: function(_xhr) { - assert.ok(_xhr === xhr); - return false; - } - }); - assert.strictEqual(this.ajaxSettings.beforeSend(xhr), false); - }); - - QUnit.test('#2928 - Pass along `textStatus` and `errorThrown`.', function(assert) { - assert.expect(2); - var model = new Backbone.Model; - model.url = '/test'; - model.on('error', function(m, xhr, options) { - assert.strictEqual(options.textStatus, 'textStatus'); - assert.strictEqual(options.errorThrown, 'errorThrown'); - }); - model.fetch(); - this.ajaxSettings.error({}, 'textStatus', 'errorThrown'); - }); - -})(QUnit); diff --git a/public/vendor/lodash/vendor/backbone/test/view.js b/public/vendor/lodash/vendor/backbone/test/view.js deleted file mode 100644 index 13270c84004..00000000000 --- a/public/vendor/lodash/vendor/backbone/test/view.js +++ /dev/null @@ -1,516 +0,0 @@ -(function(QUnit) { - - var view; - - QUnit.module('Backbone.View', { - - beforeEach: function() { - $('#qunit-fixture').append( - '

Test

' - ); - - view = new Backbone.View({ - id: 'test-view', - className: 'test-view', - other: 'non-special-option' - }); - }, - - afterEach: function() { - $('#testElement').remove(); - $('#test-view').remove(); - } - - }); - - QUnit.test('constructor', function(assert) { - assert.expect(3); - assert.equal(view.el.id, 'test-view'); - assert.equal(view.el.className, 'test-view'); - assert.equal(view.el.other, void 0); - }); - - QUnit.test('$', function(assert) { - assert.expect(2); - var myView = new Backbone.View; - myView.setElement('

test

'); - var result = myView.$('a b'); - - assert.strictEqual(result[0].innerHTML, 'test'); - assert.ok(result.length === +result.length); - }); - - QUnit.test('$el', function(assert) { - assert.expect(3); - var myView = new Backbone.View; - myView.setElement('

test

'); - assert.strictEqual(myView.el.nodeType, 1); - - assert.ok(myView.$el instanceof Backbone.$); - assert.strictEqual(myView.$el[0], myView.el); - }); - - QUnit.test('initialize', function(assert) { - assert.expect(1); - var View = Backbone.View.extend({ - initialize: function() { - this.one = 1; - } - }); - - assert.strictEqual(new View().one, 1); - }); - - QUnit.test('preinitialize', function(assert) { - assert.expect(1); - var View = Backbone.View.extend({ - preinitialize: function() { - this.one = 1; - } - }); - - assert.strictEqual(new View().one, 1); - }); - - QUnit.test('preinitialize occurs before the view is set up', function(assert) { - assert.expect(2); - var View = Backbone.View.extend({ - preinitialize: function() { - assert.equal(this.el, undefined); - } - }); - var _view = new View({}); - assert.notEqual(_view.el, undefined); - }); - - QUnit.test('render', function(assert) { - assert.expect(1); - var myView = new Backbone.View; - assert.equal(myView.render(), myView, '#render returns the view instance'); - }); - - QUnit.test('delegateEvents', function(assert) { - assert.expect(6); - var counter1 = 0, counter2 = 0; - - var myView = new Backbone.View({el: '#testElement'}); - myView.increment = function() { counter1++; }; - myView.$el.on('click', function() { counter2++; }); - - var events = {'click h1': 'increment'}; - - myView.delegateEvents(events); - myView.$('h1').trigger('click'); - assert.equal(counter1, 1); - assert.equal(counter2, 1); - - myView.$('h1').trigger('click'); - assert.equal(counter1, 2); - assert.equal(counter2, 2); - - myView.delegateEvents(events); - myView.$('h1').trigger('click'); - assert.equal(counter1, 3); - assert.equal(counter2, 3); - }); - - QUnit.test('delegate', function(assert) { - assert.expect(3); - var myView = new Backbone.View({el: '#testElement'}); - myView.delegate('click', 'h1', function() { - assert.ok(true); - }); - myView.delegate('click', function() { - assert.ok(true); - }); - myView.$('h1').trigger('click'); - - assert.equal(myView.delegate(), myView, '#delegate returns the view instance'); - }); - - QUnit.test('delegateEvents allows functions for callbacks', function(assert) { - assert.expect(3); - var myView = new Backbone.View({el: '

'}); - myView.counter = 0; - - var events = { - click: function() { - this.counter++; - } - }; - - myView.delegateEvents(events); - myView.$el.trigger('click'); - assert.equal(myView.counter, 1); - - myView.$el.trigger('click'); - assert.equal(myView.counter, 2); - - myView.delegateEvents(events); - myView.$el.trigger('click'); - assert.equal(myView.counter, 3); - }); - - QUnit.test('delegateEvents ignore undefined methods', function(assert) { - assert.expect(0); - var myView = new Backbone.View({el: '

'}); - myView.delegateEvents({click: 'undefinedMethod'}); - myView.$el.trigger('click'); - }); - - QUnit.test('undelegateEvents', function(assert) { - assert.expect(7); - var counter1 = 0, counter2 = 0; - - var myView = new Backbone.View({el: '#testElement'}); - myView.increment = function() { counter1++; }; - myView.$el.on('click', function() { counter2++; }); - - var events = {'click h1': 'increment'}; - - myView.delegateEvents(events); - myView.$('h1').trigger('click'); - assert.equal(counter1, 1); - assert.equal(counter2, 1); - - myView.undelegateEvents(); - myView.$('h1').trigger('click'); - assert.equal(counter1, 1); - assert.equal(counter2, 2); - - myView.delegateEvents(events); - myView.$('h1').trigger('click'); - assert.equal(counter1, 2); - assert.equal(counter2, 3); - - assert.equal(myView.undelegateEvents(), myView, '#undelegateEvents returns the view instance'); - }); - - QUnit.test('undelegate', function(assert) { - assert.expect(1); - var myView = new Backbone.View({el: '#testElement'}); - myView.delegate('click', function() { assert.ok(false); }); - myView.delegate('click', 'h1', function() { assert.ok(false); }); - - myView.undelegate('click'); - - myView.$('h1').trigger('click'); - myView.$el.trigger('click'); - - assert.equal(myView.undelegate(), myView, '#undelegate returns the view instance'); - }); - - QUnit.test('undelegate with passed handler', function(assert) { - assert.expect(1); - var myView = new Backbone.View({el: '#testElement'}); - var listener = function() { assert.ok(false); }; - myView.delegate('click', listener); - myView.delegate('click', function() { assert.ok(true); }); - myView.undelegate('click', listener); - myView.$el.trigger('click'); - }); - - QUnit.test('undelegate with selector', function(assert) { - assert.expect(2); - var myView = new Backbone.View({el: '#testElement'}); - myView.delegate('click', function() { assert.ok(true); }); - myView.delegate('click', 'h1', function() { assert.ok(false); }); - myView.undelegate('click', 'h1'); - myView.$('h1').trigger('click'); - myView.$el.trigger('click'); - }); - - QUnit.test('undelegate with handler and selector', function(assert) { - assert.expect(2); - var myView = new Backbone.View({el: '#testElement'}); - myView.delegate('click', function() { assert.ok(true); }); - var handler = function() { assert.ok(false); }; - myView.delegate('click', 'h1', handler); - myView.undelegate('click', 'h1', handler); - myView.$('h1').trigger('click'); - myView.$el.trigger('click'); - }); - - QUnit.test('tagName can be provided as a string', function(assert) { - assert.expect(1); - var View = Backbone.View.extend({ - tagName: 'span' - }); - - assert.equal(new View().el.tagName, 'SPAN'); - }); - - QUnit.test('tagName can be provided as a function', function(assert) { - assert.expect(1); - var View = Backbone.View.extend({ - tagName: function() { - return 'p'; - } - }); - - assert.ok(new View().$el.is('p')); - }); - - QUnit.test('_ensureElement with DOM node el', function(assert) { - assert.expect(1); - var View = Backbone.View.extend({ - el: document.body - }); - - assert.equal(new View().el, document.body); - }); - - QUnit.test('_ensureElement with string el', function(assert) { - assert.expect(3); - var View = Backbone.View.extend({ - el: 'body' - }); - assert.strictEqual(new View().el, document.body); - - View = Backbone.View.extend({ - el: '#testElement > h1' - }); - assert.strictEqual(new View().el, $('#testElement > h1').get(0)); - - View = Backbone.View.extend({ - el: '#nonexistent' - }); - assert.ok(!new View().el); - }); - - QUnit.test('with className and id functions', function(assert) { - assert.expect(2); - var View = Backbone.View.extend({ - className: function() { - return 'className'; - }, - id: function() { - return 'id'; - } - }); - - assert.strictEqual(new View().el.className, 'className'); - assert.strictEqual(new View().el.id, 'id'); - }); - - QUnit.test('with attributes', function(assert) { - assert.expect(2); - var View = Backbone.View.extend({ - attributes: { - 'id': 'id', - 'class': 'class' - } - }); - - assert.strictEqual(new View().el.className, 'class'); - assert.strictEqual(new View().el.id, 'id'); - }); - - QUnit.test('with attributes as a function', function(assert) { - assert.expect(1); - var View = Backbone.View.extend({ - attributes: function() { - return {'class': 'dynamic'}; - } - }); - - assert.strictEqual(new View().el.className, 'dynamic'); - }); - - QUnit.test('should default to className/id properties', function(assert) { - assert.expect(4); - var View = Backbone.View.extend({ - className: 'backboneClass', - id: 'backboneId', - attributes: { - 'class': 'attributeClass', - 'id': 'attributeId' - } - }); - - var myView = new View; - assert.strictEqual(myView.el.className, 'backboneClass'); - assert.strictEqual(myView.el.id, 'backboneId'); - assert.strictEqual(myView.$el.attr('class'), 'backboneClass'); - assert.strictEqual(myView.$el.attr('id'), 'backboneId'); - }); - - QUnit.test('multiple views per element', function(assert) { - assert.expect(3); - var count = 0; - var $el = $('

'); - - var View = Backbone.View.extend({ - el: $el, - events: { - click: function() { - count++; - } - } - }); - - var view1 = new View; - $el.trigger('click'); - assert.equal(1, count); - - var view2 = new View; - $el.trigger('click'); - assert.equal(3, count); - - view1.delegateEvents(); - $el.trigger('click'); - assert.equal(5, count); - }); - - QUnit.test('custom events', function(assert) { - assert.expect(2); - var View = Backbone.View.extend({ - el: $('body'), - events: { - fake$event: function() { assert.ok(true); } - } - }); - - var myView = new View; - $('body').trigger('fake$event').trigger('fake$event'); - - $('body').off('fake$event'); - $('body').trigger('fake$event'); - }); - - QUnit.test('#1048 - setElement uses provided object.', function(assert) { - assert.expect(2); - var $el = $('body'); - - var myView = new Backbone.View({el: $el}); - assert.ok(myView.$el === $el); - - myView.setElement($el = $($el)); - assert.ok(myView.$el === $el); - }); - - QUnit.test('#986 - Undelegate before changing element.', function(assert) { - assert.expect(1); - var button1 = $(''); - var button2 = $(''); - - var View = Backbone.View.extend({ - events: { - click: function(e) { - assert.ok(myView.el === e.target); - } - } - }); - - var myView = new View({el: button1}); - myView.setElement(button2); - - button1.trigger('click'); - button2.trigger('click'); - }); - - QUnit.test('#1172 - Clone attributes object', function(assert) { - assert.expect(2); - var View = Backbone.View.extend({ - attributes: {foo: 'bar'} - }); - - var view1 = new View({id: 'foo'}); - assert.strictEqual(view1.el.id, 'foo'); - - var view2 = new View(); - assert.ok(!view2.el.id); - }); - - QUnit.test('views stopListening', function(assert) { - assert.expect(0); - var View = Backbone.View.extend({ - initialize: function() { - this.listenTo(this.model, 'all x', function() { assert.ok(false); }); - this.listenTo(this.collection, 'all x', function() { assert.ok(false); }); - } - }); - - var myView = new View({ - model: new Backbone.Model, - collection: new Backbone.Collection - }); - - myView.stopListening(); - myView.model.trigger('x'); - myView.collection.trigger('x'); - }); - - QUnit.test('Provide function for el.', function(assert) { - assert.expect(2); - var View = Backbone.View.extend({ - el: function() { - return '

'; - } - }); - - var myView = new View; - assert.ok(myView.$el.is('p')); - assert.ok(myView.$el.has('a')); - }); - - QUnit.test('events passed in options', function(assert) { - assert.expect(1); - var counter = 0; - - var View = Backbone.View.extend({ - el: '#testElement', - increment: function() { - counter++; - } - }); - - var myView = new View({ - events: { - 'click h1': 'increment' - } - }); - - myView.$('h1').trigger('click').trigger('click'); - assert.equal(counter, 2); - }); - - QUnit.test('remove', function(assert) { - assert.expect(2); - var myView = new Backbone.View; - document.body.appendChild(view.el); - - myView.delegate('click', function() { assert.ok(false); }); - myView.listenTo(myView, 'all x', function() { assert.ok(false); }); - - assert.equal(myView.remove(), myView, '#remove returns the view instance'); - myView.$el.trigger('click'); - myView.trigger('x'); - - // In IE8 and below, parentNode still exists but is not document.body. - assert.notEqual(myView.el.parentNode, document.body); - }); - - QUnit.test('setElement', function(assert) { - assert.expect(3); - var myView = new Backbone.View({ - events: { - click: function() { assert.ok(false); } - } - }); - myView.events = { - click: function() { assert.ok(true); } - }; - var oldEl = myView.el; - var $oldEl = myView.$el; - - myView.setElement(document.createElement('div')); - - $oldEl.click(); - myView.$el.click(); - - assert.notEqual(oldEl, myView.el); - assert.notEqual($oldEl, myView.$el); - }); - -})(QUnit); diff --git a/public/vendor/lodash/vendor/firebug-lite/license.txt b/public/vendor/lodash/vendor/firebug-lite/license.txt deleted file mode 100644 index ba43b7514b3..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/license.txt +++ /dev/null @@ -1,30 +0,0 @@ -Software License Agreement (BSD License) - -Copyright (c) 2007, Parakey Inc. -All rights reserved. - -Redistribution and use of this software in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of Parakey Inc. nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of Parakey Inc. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/blank.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/blank.gif deleted file mode 100644 index 6865c960497..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/blank.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/buttonBg.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/buttonBg.png deleted file mode 100644 index f367b427e60..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/buttonBg.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/buttonBgHover.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/buttonBgHover.png deleted file mode 100644 index cd37a0d52de..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/buttonBgHover.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/debugger.css b/public/vendor/lodash/vendor/firebug-lite/skin/xp/debugger.css deleted file mode 100644 index ba55c7ea8c8..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/skin/xp/debugger.css +++ /dev/null @@ -1,331 +0,0 @@ -/* See license.txt for terms of usage */ - -.panelNode-script { - overflow: hidden; - font-family: monospace; -} - -/************************************************************************************************/ - -.scriptTooltip { - position: fixed; - z-index: 2147483647; - padding: 2px 3px; - border: 1px solid #CBE087; - background: LightYellow; - font-family: monospace; - color: #000000; -} - -/************************************************************************************************/ - -.sourceBox { - /* TODO: xxxpedro problem with sourceBox and scrolling elements */ - /*overflow: scroll; /* see issue 1479 */ - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; -} - -.sourceRow { - white-space: nowrap; - -moz-user-select: text; -} - -.sourceRow.hovered { - background-color: #EEEEEE; -} - -/************************************************************************************************/ - -.sourceLine { - -moz-user-select: none; - margin-right: 10px; - border-right: 1px solid #CCCCCC; - padding: 0px 4px 0 20px; - background: #EEEEEE no-repeat 2px 0px; - color: #888888; - white-space: pre; - font-family: monospace; /* see issue 2953 */ -} - -.noteInToolTip { /* below sourceLine, so it overrides it */ - background-color: #FFD472; -} - -.useA11y .sourceBox .sourceViewport:focus .sourceLine { - background-color: #FFFFC0; - color: navy; - border-right: 1px solid black; -} - -.useA11y .sourceBox .sourceViewport:focus { - outline: none; -} - -.a11y1emSize { - width: 1em; - height: 1em; - position: absolute; -} - -.useA11y .panelStatusLabel:focus { - outline-offset: -2px !important; - } - -.sourceBox > .sourceRow > .sourceLine { - cursor: pointer; -} - -.sourceLine:hover { - text-decoration: none; -} - -.sourceRowText { - white-space: pre; -} - -.sourceRow[exe_line="true"] { - outline: 1px solid #D9D9B6; - margin-right: 1px; - background-color: lightgoldenrodyellow; -} - -.sourceRow[executable="true"] > .sourceLine { - content: "-"; - color: #4AA02C; /* Spring Green */ - font-weight: bold; -} - -.sourceRow[exe_line="true"] > .sourceLine { - background-image: url(chrome://firebug/skin/exe.png); - color: #000000; -} - -.sourceRow[breakpoint="true"] > .sourceLine { - background-image: url(chrome://firebug/skin/breakpoint.png); -} - -.sourceRow[breakpoint="true"][condition="true"] > .sourceLine { - background-image: url(chrome://firebug/skin/breakpointCondition.png); -} - -.sourceRow[breakpoint="true"][disabledBreakpoint="true"] > .sourceLine { - background-image: url(chrome://firebug/skin/breakpointDisabled.png); -} - -.sourceRow[breakpoint="true"][exe_line="true"] > .sourceLine { - background-image: url(chrome://firebug/skin/breakpointExe.png); -} - -.sourceRow[breakpoint="true"][exe_line="true"][disabledBreakpoint="true"] > .sourceLine { - background-image: url(chrome://firebug/skin/breakpointDisabledExe.png); -} - -.sourceLine.editing { - background-image: url(chrome://firebug/skin/breakpoint.png); -} - -/************************************************************************************************/ - -.conditionEditor { - z-index: 2147483647; - position: absolute; - margin-top: 0; - left: 2px; - width: 90%; -} - -.conditionEditorInner { - position: relative; - top: -26px; - height: 0; -} - -.conditionCaption { - margin-bottom: 2px; - font-family: Lucida Grande, sans-serif; - font-weight: bold; - font-size: 11px; - color: #226679; -} - -.conditionInput { - width: 100%; - border: 1px solid #0096C0; - font-family: monospace; - font-size: inherit; -} - -.conditionEditorInner1 { - padding-left: 37px; - background: url(condBorders.png) repeat-y; -} - -.conditionEditorInner2 { - padding-right: 25px; - background: url(condBorders.png) repeat-y 100% 0; -} - -.conditionEditorTop1 { - background: url(condCorners.png) no-repeat 100% 0; - margin-left: 37px; - height: 35px; -} - -.conditionEditorTop2 { - position: relative; - left: -37px; - width: 37px; - height: 35px; - background: url(condCorners.png) no-repeat; -} - -.conditionEditorBottom1 { - background: url(condCorners.png) no-repeat 100% 100%; - margin-left: 37px; - height: 33px; -} - -.conditionEditorBottom2 { - position: relative; left: -37px; - width: 37px; - height: 33px; - background: url(condCorners.png) no-repeat 0 100%; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.upsideDown { - margin-top: 2px; -} - -.upsideDown .conditionEditorInner { - top: -8px; -} - -.upsideDown .conditionEditorInner1 { - padding-left: 33px; - background: url(condBordersUps.png) repeat-y; -} - -.upsideDown .conditionEditorInner2 { - padding-right: 25px; - background: url(condBordersUps.png) repeat-y 100% 0; -} - -.upsideDown .conditionEditorTop1 { - background: url(condCornersUps.png) no-repeat 100% 0; - margin-left: 33px; - height: 25px; -} - -.upsideDown .conditionEditorTop2 { - position: relative; - left: -33px; - width: 33px; - height: 25px; - background: url(condCornersUps.png) no-repeat; -} - -.upsideDown .conditionEditorBottom1 { - background: url(condCornersUps.png) no-repeat 100% 100%; - margin-left: 33px; - height: 43px; -} - -.upsideDown .conditionEditorBottom2 { - position: relative; - left: -33px; - width: 33px; - height: 43px; - background: url(condCornersUps.png) no-repeat 0 100%; -} - -/************************************************************************************************/ - -.breakpointsGroupListBox { - overflow: hidden; -} - -.breakpointBlockHead { - position: relative; - padding-top: 4px; -} - -.breakpointBlockHead > .checkbox { - margin-right: 4px; -} - -.breakpointBlockHead > .objectLink-sourceLink { - top: 4px; - right: 20px; - background-color: #FFFFFF; /* issue 3308 */ -} - -.breakpointBlockHead > .closeButton { - position: absolute; - top: 2px; - right: 2px; -} - -.breakpointCheckbox { - margin-top: 0; - vertical-align: top; -} - -.breakpointName { - margin-left: 4px; - font-weight: bold; -} - -.breakpointRow[aria-checked="false"] > .breakpointBlockHead > *, -.breakpointRow[aria-checked="false"] > .breakpointCode { - opacity: 0.5; -} - -.breakpointRow[aria-checked="false"] .breakpointCheckbox, -.breakpointRow[aria-checked="false"] .objectLink-sourceLink, -.breakpointRow[aria-checked="false"] .closeButton, -.breakpointRow[aria-checked="false"] .breakpointMutationType { - opacity: 1.0 !important; -} - -.breakpointCode { - overflow: hidden; - white-space: nowrap; - padding-left: 24px; - padding-bottom: 2px; - border-bottom: 1px solid #D7D7D7; - font-family: monospace; - color: DarkGreen; -} - -.breakpointCondition { - white-space: nowrap; - padding-left: 24px; - padding-bottom: 2px; - border-bottom: 1px solid #D7D7D7; - font-family: monospace; - color: Gray; -} - -.breakpointBlock-breakpoints > .groupHeader { - display: none; -} - -.breakpointBlock-monitors > .breakpointCode { - padding: 0; -} - -.breakpointBlock-errorBreakpoints .breakpointCheckbox, -.breakpointBlock-monitors .breakpointCheckbox { - display: none; -} - -.breakpointHeader { - margin: 0 !important; - border-top: none !important; -} diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/detach.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/detach.png deleted file mode 100644 index 0ddb9a1764a..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/detach.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/detachHover.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/detachHover.png deleted file mode 100644 index e419272912b..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/detachHover.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/disable.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/disable.gif deleted file mode 100644 index dd9eb0e3ef6..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/disable.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/disable.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/disable.png deleted file mode 100644 index c28bcdf24a8..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/disable.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/disableHover.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/disableHover.gif deleted file mode 100644 index 70565a83cce..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/disableHover.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/disableHover.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/disableHover.png deleted file mode 100644 index 26fe37542f8..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/disableHover.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/down.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/down.png deleted file mode 100644 index acbbd30c065..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/down.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/downActive.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/downActive.png deleted file mode 100644 index f4312b2ffbc..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/downActive.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/downHover.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/downHover.png deleted file mode 100644 index 8144e63787d..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/downHover.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon-sm.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon-sm.png deleted file mode 100644 index 0c377e307e5..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon-sm.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon.gif deleted file mode 100644 index 8ee8116a543..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon.png deleted file mode 100644 index 2d75261bb67..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/errorIcon.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug-1.3a2.css b/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug-1.3a2.css deleted file mode 100644 index 42f9faf5d58..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug-1.3a2.css +++ /dev/null @@ -1,817 +0,0 @@ -.fbBtnPressed { - background: #ECEBE3; - padding: 3px 6px 2px 7px !important; - margin: 1px 0 0 1px; - _margin: 1px -1px 0 1px; - border: 1px solid #ACA899 !important; - border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; -} - -.fbToolbarButtons { - display: none; -} - -#fbStatusBarBox { - display: none; -} - -/************************************************************************************************ - Error Popup -*************************************************************************************************/ -#fbErrorPopup { - position: absolute; - right: 0; - bottom: 0; - height: 19px; - width: 75px; - background: url(sprite.png) #f1f2ee 0 0; - z-index: 999; -} - -#fbErrorPopupContent { - position: absolute; - right: 0; - top: 1px; - height: 18px; - width: 75px; - _width: 74px; - border-left: 1px solid #aca899; -} - -#fbErrorIndicator { - position: absolute; - top: 2px; - right: 5px; -} - - - - - - - - - - -.fbBtnInspectActive { - background: #aaa; - color: #fff !important; -} - -/************************************************************************************************ - General -*************************************************************************************************/ -html, body { - margin: 0; - padding: 0; - overflow: hidden; -} - -body { - font-family: Lucida Grande, Tahoma, sans-serif; - font-size: 11px; - background: #fff; -} - -.clear { - clear: both; -} - -/************************************************************************************************ - Mini Chrome -*************************************************************************************************/ -#fbMiniChrome { - display: none; - right: 0; - height: 27px; - background: url(sprite.png) #f1f2ee 0 0; - margin-left: 1px; -} - -#fbMiniContent { - display: block; - position: relative; - left: -1px; - right: 0; - top: 1px; - height: 25px; - border-left: 1px solid #aca899; -} - -#fbToolbarSearch { - float: right; - border: 1px solid #ccc; - margin: 0 5px 0 0; - background: #fff url(search.png) no-repeat 4px 2px; - padding-left: 20px; - font-size: 11px; -} - -#fbToolbarErrors { - float: right; - margin: 1px 4px 0 0; - font-size: 11px; -} - -#fbLeftToolbarErrors { - float: left; - margin: 7px 0px 0 5px; - font-size: 11px; -} - -.fbErrors { - padding-left: 20px; - height: 14px; - background: url(errorIcon.png) no-repeat; - color: #f00; - font-weight: bold; -} - -#fbMiniErrors { - display: inline; - display: none; - float: right; - margin: 5px 2px 0 5px; -} - -#fbMiniIcon { - float: right; - margin: 3px 4px 0; - height: 20px; - width: 20px; - float: right; - background: url(sprite.png) 0 -135px; - cursor: pointer; -} - - -/************************************************************************************************ - Master Layout -*************************************************************************************************/ -#fbChrome { - position: fixed; - overflow: hidden; - height: 100%; - width: 100%; - border-collapse: collapse; - background: #fff; -} - -#fbTop { - height: 49px; -} - -#fbToolbar { - position: absolute; - z-index: 5; - width: 100%; - top: 0; - background: url(sprite.png) #f1f2ee 0 0; - height: 27px; - font-size: 11px; - overflow: hidden; -} - -#fbPanelBarBox { - top: 27px; - position: absolute; - z-index: 8; - width: 100%; - background: url(sprite.png) #dbd9c9 0 -27px; - height: 22px; -} - -#fbContent { - height: 100%; - vertical-align: top; -} - -#fbBottom { - height: 18px; - background: #fff; -} - -/************************************************************************************************ - Sub-Layout -*************************************************************************************************/ - -/* fbToolbar -*************************************************************************************************/ -#fbToolbarIcon { - float: left; - padding: 4px 5px 0; -} - -#fbToolbarIcon a { - display: block; - height: 20px; - width: 20px; - background: url(sprite.png) 0 -135px; - text-decoration: none; - cursor: default; -} - -#fbToolbarButtons { - float: left; - padding: 4px 2px 0 5px; -} - -#fbToolbarButtons a { - text-decoration: none; - display: block; - float: left; - color: #000; - padding: 4px 8px 4px; - cursor: default; -} - -#fbToolbarButtons a:hover { - color: #333; - padding: 3px 7px 3px; - border: 1px solid #fff; - border-bottom: 1px solid #bbb; - border-right: 1px solid #bbb; -} - -#fbStatusBarBox { - position: relative; - top: 5px; - line-height: 19px; - cursor: default; -} - -.fbToolbarSeparator{ - overflow: hidden; - border: 1px solid; - border-color: transparent #fff transparent #777; - _border-color: #eee #fff #eee #777; - height: 7px; - margin: 10px 6px 0 0; - float: left; -} - -.fbStatusBar span { - color: #808080; - padding: 0 4px 0 0; -} - -.fbStatusBar span a { - text-decoration: none; - color: black; -} - -.fbStatusBar span a:hover { - color: blue; - cursor: pointer; -} - - -#fbWindowButtons { - position: absolute; - white-space: nowrap; - right: 0; - top: 0; - height: 17px; - _width: 50px; - padding: 5px 0 5px 5px; - z-index: 6; - background: url(sprite.png) #f1f2ee 0 0; -} - -/* fbPanelBarBox -*************************************************************************************************/ - -#fbPanelBar1 { - width: 255px; /* fixed width to avoid tabs breaking line */ - z-index: 8; - left: 0; - white-space: nowrap; - background: url(sprite.png) #dbd9c9 0 -27px; - position: absolute; - left: 4px; -} - -#fbPanelBar2Box { - background: url(sprite.png) #dbd9c9 0 -27px; - position: absolute; - height: 22px; - width: 300px; /* fixed width to avoid tabs breaking line */ - z-index: 9; - right: 0; -} - -#fbPanelBar2 { - position: absolute; - width: 290px; /* fixed width to avoid tabs breaking line */ - height: 22px; - padding-left: 10px; -} - -/* body -*************************************************************************************************/ -.fbPanel { - display: none; -} - -#fbPanelBox1, #fbPanelBox2 { - max-height: inherit; - height: 100%; - font-size: 11px; -} - -#fbPanelBox2 { - background: #fff; -} - -#fbPanelBox2 { - width: 300px; - background: #fff; -} - -#fbPanel2 { - padding-left: 6px; - background: #fff; -} - -.hide { - overflow: hidden !important; - position: fixed !important; - display: none !important; - visibility: hidden !important; -} - -/* fbBottom -*************************************************************************************************/ - -#fbCommand { - height: 18px; -} - -#fbCommandBox { - position: absolute; - width: 100%; - height: 18px; - bottom: 0; - overflow: hidden; - z-index: 9; - background: #fff; - border: 0; - border-top: 1px solid #ccc; -} - -#fbCommandIcon { - position: absolute; - color: #00f; - top: 2px; - left: 7px; - display: inline; - font: 11px Monaco, monospace; - z-index: 10; -} - -#fbCommandLine { - position: absolute; - width: 100%; - top: 0; - left: 0; - border: 0; - margin: 0; - padding: 2px 0 2px 32px; - font: 11px Monaco, monospace; - z-index: 9; -} - -div.fbFitHeight { - overflow: auto; - _position: absolute; -} - - -/************************************************************************************************ - Layout Controls -*************************************************************************************************/ - -/* fbToolbar buttons -*************************************************************************************************/ -#fbWindowButtons a { - font-size: 1px; - width: 16px; - height: 16px; - display: block; - float: right; - margin-right: 4px; - text-decoration: none; - cursor: default; -} - -#fbWindow_btClose { - background: url(sprite.png) 0 -119px; -} - -#fbWindow_btClose:hover { - background: url(sprite.png) -16px -119px; -} - -#fbWindow_btDetach { - background: url(sprite.png) -32px -119px; -} - -#fbWindow_btDetach:hover { - background: url(sprite.png) -48px -119px; -} - -/* fbPanelBarBox tabs -*************************************************************************************************/ -.fbTab { - text-decoration: none; - display: none; - float: left; - width: auto; - float: left; - cursor: default; - font-family: Lucida Grande, Tahoma, sans-serif; - font-size: 11px; - font-weight: bold; - height: 22px; - color: #565656; -} - -.fbPanelBar span { - display: block; - float: left; -} - -.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { - height: 22px; - width: 8px; -} - -.fbPanelBar .fbTabText { - padding: 4px 1px 0; -} - -a.fbTab:hover { - background: url(sprite.png) 0 -73px; -} - -a.fbTab:hover .fbTabL { - background: url(sprite.png) -16px -96px; -} - -a.fbTab:hover .fbTabR { - background: url(sprite.png) -24px -96px; -} - -.fbSelectedTab { - background: url(sprite.png) #f1f2ee 0 -50px !important; - color: #000; -} - -.fbSelectedTab .fbTabL { - background: url(sprite.png) 0 -96px !important; -} - -.fbSelectedTab .fbTabR { - background: url(sprite.png) -8px -96px !important; -} - -/* splitters -*************************************************************************************************/ -#fbHSplitter { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 5px; - overflow: hidden; - cursor: n-resize !important; - background: url(pixel_transparent.gif); - z-index: 9; -} - -#fbHSplitter.fbOnMovingHSplitter { - height: 100%; - z-index: 100; -} - -.fbVSplitter { - background: #ece9d8; - color: #000; - border: 1px solid #716f64; - border-width: 0 1px; - border-left-color: #aca899; - width: 4px; - cursor: e-resize; - overflow: hidden; - right: 294px; - text-decoration: none; - z-index: 9; - position: absolute; - height: 100%; - top: 27px; - _width: 6px; -} - -/************************************************************************************************/ -div.lineNo { - font: 11px Monaco, monospace; - float: left; - display: inline; - position: relative; - margin: 0; - padding: 0 5px 0 20px; - background: #eee; - color: #888; - border-right: 1px solid #ccc; - text-align: right; -} - -pre.nodeCode { - font: 11px Monaco, monospace; - margin: 0; - padding-left: 10px; - overflow: hidden; - /* - _width: 100%; - /**/ -} - -/************************************************************************************************/ -.nodeControl { - margin-top: 3px; - margin-left: -14px; - float: left; - width: 9px; - height: 9px; - overflow: hidden; - cursor: default; - background: url(tree_open.gif); - _float: none; - _display: inline; - _position: absolute; -} - -div.nodeMaximized { - background: url(tree_close.gif); -} - -div.objectBox-element { - padding: 1px 3px; -} -.objectBox-selector{ - cursor: default; -} - -.selectedElement{ - background: highlight; - /* background: url(roundCorner.svg); Opera */ - color: #fff !important; -} -.selectedElement span{ - color: #fff !important; -} - -/* Webkit CSS Hack - bug in "highlight" named color */ -@media screen and (-webkit-min-device-pixel-ratio:0) { - .selectedElement{ - background: #316AC5; - color: #fff !important; - } -} - -/************************************************************************************************/ -/************************************************************************************************/ -.logRow * { - font-size: 11px; -} - -.logRow { - position: relative; - border-bottom: 1px solid #D7D7D7; - padding: 2px 4px 1px 6px; - background-color: #FFFFFF; -} - -.logRow-command { - font-family: Monaco, monospace; - color: blue; -} - -.objectBox-string, -.objectBox-text, -.objectBox-number, -.objectBox-function, -.objectLink-element, -.objectLink-textNode, -.objectLink-function, -.objectBox-stackTrace, -.objectLink-profile { - font-family: Monaco, monospace; -} - -.objectBox-null { - padding: 0 2px; - border: 1px solid #666666; - background-color: #888888; - color: #FFFFFF; -} - -.objectBox-string { - color: red; - white-space: pre; -} - -.objectBox-number { - color: #000088; -} - -.objectBox-function { - color: DarkGreen; -} - -.objectBox-object { - color: DarkGreen; - font-weight: bold; - font-family: Lucida Grande, sans-serif; -} - -.objectBox-array { - color: #000; -} - -/************************************************************************************************/ -.logRow-info,.logRow-error,.logRow-warning { - background: #fff no-repeat 2px 2px; - padding-left: 20px; - padding-bottom: 3px; -} - -.logRow-info { - background-image: url(infoIcon.png); -} - -.logRow-warning { - background-color: cyan; - background-image: url(warningIcon.png); -} - -.logRow-error { - background-color: LightYellow; - background-image: url(errorIcon.png); - color: #f00; -} - -.errorMessage { - vertical-align: top; - color: #f00; -} - -.objectBox-sourceLink { - position: absolute; - right: 4px; - top: 2px; - padding-left: 8px; - font-family: Lucida Grande, sans-serif; - font-weight: bold; - color: #0000FF; -} - -/************************************************************************************************/ -.logRow-group { - background: #EEEEEE; - border-bottom: none; -} - -.logGroup { - background: #EEEEEE; -} - -.logGroupBox { - margin-left: 24px; - border-top: 1px solid #D7D7D7; - border-left: 1px solid #D7D7D7; -} - -/************************************************************************************************/ -.selectorTag,.selectorId,.selectorClass { - font-family: Monaco, monospace; - font-weight: normal; -} - -.selectorTag { - color: #0000FF; -} - -.selectorId { - color: DarkBlue; -} - -.selectorClass { - color: red; -} - -/************************************************************************************************/ -.objectBox-element { - font-family: Monaco, monospace; - color: #000088; -} - -.nodeChildren { - padding-left: 26px; -} - -.nodeTag { - color: blue; - cursor: pointer; -} - -.nodeValue { - color: #FF0000; - font-weight: normal; -} - -.nodeText,.nodeComment { - margin: 0 2px; - vertical-align: top; -} - -.nodeText { - color: #333333; - font-family: Monaco, monospace; -} - -.nodeComment { - color: DarkGreen; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.nodeHidden, .nodeHidden * { - color: #888888; -} - -.nodeHidden .nodeTag { - color: #5F82D9; -} - -.nodeHidden .nodeValue { - color: #D86060; -} - -.selectedElement .nodeHidden, .selectedElement .nodeHidden * { - color: SkyBlue !important; -} - - -/************************************************************************************************/ -.log-object { - /* - _position: relative; - _height: 100%; - /**/ -} - -.property { - position: relative; - clear: both; - height: 15px; -} - -.propertyNameCell { - vertical-align: top; - float: left; - width: 28%; - position: absolute; - left: 0; - z-index: 0; -} - -.propertyValueCell { - float: right; - width: 68%; - background: #fff; - position: absolute; - padding-left: 5px; - display: table-cell; - right: 0; - z-index: 1; - /* - _position: relative; - /**/ -} - -.propertyName { - font-weight: bold; -} - -.FirebugPopup { - height: 100% !important; -} - -.FirebugPopup #fbWindowButtons { - display: none !important; -} - -.FirebugPopup #fbHSplitter { - display: none !important; -} diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.IE6.css b/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.IE6.css deleted file mode 100644 index 13a41d284b8..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.IE6.css +++ /dev/null @@ -1,20 +0,0 @@ -/************************************************************************************************/ -#fbToolbarSearch { - background-image: url(search.gif) !important; -} -/************************************************************************************************/ -.fbErrors { - background-image: url(errorIcon.gif) !important; -} -/************************************************************************************************/ -.logRow-info { - background-image: url(infoIcon.gif) !important; -} - -.logRow-warning { - background-image: url(warningIcon.gif) !important; -} - -.logRow-error { - background-image: url(errorIcon.gif) !important; -} diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.css b/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.css deleted file mode 100644 index a1465ec5f35..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.css +++ /dev/null @@ -1,3147 +0,0 @@ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* Loose */ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* -.netInfoResponseHeadersTitle, netInfoResponseHeadersBody { - display: none; -} -/**/ - -.obscured { - left: -999999px !important; -} - -/* IE6 need a separated rule, otherwise it will not recognize it */ -.collapsed { - display: none; -} - -[collapsed="true"] { - display: none; -} - -#fbCSS { - padding: 0 !important; -} - -.cssPropDisable { - float: left; - display: block; - width: 2em; - cursor: default; -} - -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* panelBase */ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ - -/************************************************************************************************/ - -.infoTip { - z-index: 2147483647; - position: fixed; - padding: 2px 3px; - border: 1px solid #CBE087; - background: LightYellow; - font-family: Monaco, monospace; - color: #000000; - display: none; - white-space: nowrap; - pointer-events: none; -} - -.infoTip[active="true"] { - display: block; -} - -.infoTipLoading { - width: 16px; - height: 16px; - background: url(chrome://firebug/skin/loading_16.gif) no-repeat; -} - -.infoTipImageBox { - font-size: 11px; - min-width: 100px; - text-align: center; -} - -.infoTipCaption { - font-size: 11px; - font: Monaco, monospace; -} - -.infoTipLoading > .infoTipImage, -.infoTipLoading > .infoTipCaption { - display: none; -} - -/************************************************************************************************/ - -h1.groupHeader { - padding: 2px 4px; - margin: 0 0 4px 0; - border-top: 1px solid #CCCCCC; - border-bottom: 1px solid #CCCCCC; - background: #eee url(group.gif) repeat-x; - font-size: 11px; - font-weight: bold; - _position: relative; -} - -/************************************************************************************************/ - -.inlineEditor, -.fixedWidthEditor { - z-index: 2147483647; - position: absolute; - display: none; -} - -.inlineEditor { - margin-left: -6px; - margin-top: -3px; - /* - _margin-left: -7px; - _margin-top: -5px; - /**/ -} - -.textEditorInner, -.fixedWidthEditor { - margin: 0 0 0 0 !important; - padding: 0; - border: none !important; - font: inherit; - text-decoration: inherit; - background-color: #FFFFFF; -} - -.fixedWidthEditor { - border-top: 1px solid #888888 !important; - border-bottom: 1px solid #888888 !important; -} - -.textEditorInner { - position: relative; - top: -7px; - left: -5px; - - outline: none; - resize: none; - - /* - _border: 1px solid #999 !important; - _padding: 1px !important; - _filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color="#55404040"); - /**/ -} - -.textEditorInner1 { - padding-left: 11px; - background: url(textEditorBorders.png) repeat-y; - _background: url(textEditorBorders.gif) repeat-y; - _overflow: hidden; -} - -.textEditorInner2 { - position: relative; - padding-right: 2px; - background: url(textEditorBorders.png) repeat-y 100% 0; - _background: url(textEditorBorders.gif) repeat-y 100% 0; - _position: fixed; -} - -.textEditorTop1 { - background: url(textEditorCorners.png) no-repeat 100% 0; - margin-left: 11px; - height: 10px; - _background: url(textEditorCorners.gif) no-repeat 100% 0; - _overflow: hidden; -} - -.textEditorTop2 { - position: relative; - left: -11px; - width: 11px; - height: 10px; - background: url(textEditorCorners.png) no-repeat; - _background: url(textEditorCorners.gif) no-repeat; -} - -.textEditorBottom1 { - position: relative; - background: url(textEditorCorners.png) no-repeat 100% 100%; - margin-left: 11px; - height: 12px; - _background: url(textEditorCorners.gif) no-repeat 100% 100%; -} - -.textEditorBottom2 { - position: relative; - left: -11px; - width: 11px; - height: 12px; - background: url(textEditorCorners.png) no-repeat 0 100%; - _background: url(textEditorCorners.gif) no-repeat 0 100%; -} - - -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* CSS */ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ - -/* See license.txt for terms of usage */ - -.panelNode-css { - overflow-x: hidden; -} - -.cssSheet > .insertBefore { - height: 1.5em; -} - -.cssRule { - position: relative; - margin: 0; - padding: 1em 0 0 6px; - font-family: Monaco, monospace; - color: #000000; -} - -.cssRule:first-child { - padding-top: 6px; -} - -.cssElementRuleContainer { - position: relative; -} - -.cssHead { - padding-right: 150px; -} - -.cssProp { - /*padding-left: 2em;*/ -} - -.cssPropName { - color: DarkGreen; -} - -.cssPropValue { - margin-left: 8px; - color: DarkBlue; -} - -.cssOverridden span { - text-decoration: line-through; -} - -.cssInheritedRule { -} - -.cssInheritLabel { - margin-right: 0.5em; - font-weight: bold; -} - -.cssRule .objectLink-sourceLink { - top: 0; -} - -.cssProp.editGroup:hover { - background: url(disable.png) no-repeat 2px 1px; - _background: url(disable.gif) no-repeat 2px 1px; -} - -.cssProp.editGroup.editing { - background: none; -} - -.cssProp.disabledStyle { - background: url(disableHover.png) no-repeat 2px 1px; - _background: url(disableHover.gif) no-repeat 2px 1px; - opacity: 1; - color: #CCCCCC; -} - -.disabledStyle .cssPropName, -.disabledStyle .cssPropValue { - color: #CCCCCC; -} - -.cssPropValue.editing + .cssSemi, -.inlineExpander + .cssSemi { - display: none; -} - -.cssPropValue.editing { - white-space: nowrap; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.stylePropName { - font-weight: bold; - padding: 0 4px 4px 4px; - width: 50%; -} - -.stylePropValue { - width: 50%; -} -/* -.useA11y .a11yCSSView .focusRow:focus { - outline: none; - background-color: transparent - } - - .useA11y .a11yCSSView .focusRow:focus .cssSelector, - .useA11y .a11yCSSView .focusRow:focus .cssPropName, - .useA11y .a11yCSSView .focusRow:focus .cssPropValue, - .useA11y .a11yCSSView .computedStyleRow:focus, - .useA11y .a11yCSSView .groupHeader:focus { - outline: 2px solid #FF9933; - outline-offset: -2px; - background-color: #FFFFD6; - } - - .useA11y .a11yCSSView .groupHeader:focus { - outline-offset: -2px; - } -/**/ - - -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* Net */ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ - -/* See license.txt for terms of usage */ - -.panelNode-net { - overflow-x: hidden; -} - -.netTable { - width: 100%; -} - -/************************************************************************************************/ - -.hideCategory-undefined .category-undefined, -.hideCategory-html .category-html, -.hideCategory-css .category-css, -.hideCategory-js .category-js, -.hideCategory-image .category-image, -.hideCategory-xhr .category-xhr, -.hideCategory-flash .category-flash, -.hideCategory-txt .category-txt, -.hideCategory-bin .category-bin { - display: none; -} - -/************************************************************************************************/ - -.netHeadRow { - background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; -} - -.netHeadCol { - border-bottom: 1px solid #CCCCCC; - padding: 2px 4px 2px 18px; - font-weight: bold; -} - -.netHeadLabel { - white-space: nowrap; - overflow: hidden; -} - -/************************************************************************************************/ -/* Header for Net panel table */ - -.netHeaderRow { - height: 16px; -} - -.netHeaderCell { - cursor: pointer; - -moz-user-select: none; - border-bottom: 1px solid #9C9C9C; - padding: 0 !important; - font-weight: bold; - background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x; - white-space: nowrap; -} - -.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox { - padding: 2px 14px 2px 18px; -} - -.netHeaderCellBox { - padding: 2px 14px 2px 10px; - border-left: 1px solid #D9D9D9; - border-right: 1px solid #9C9C9C; -} - -.netHeaderCell:hover:active { - background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x; -} - -.netHeaderSorted { - background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x; -} - -.netHeaderSorted > .netHeaderCellBox { - border-right-color: #6B7C93; - background: url(chrome://firebug/skin/arrowDown.png) no-repeat right; -} - -.netHeaderSorted.sortedAscending > .netHeaderCellBox { - background-image: url(chrome://firebug/skin/arrowUp.png); -} - -.netHeaderSorted:hover:active { - background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x; -} - -/************************************************************************************************/ -/* Breakpoints */ - -.panelNode-net .netRowHeader { - display: block; -} - -.netRowHeader { - cursor: pointer; - display: none; - height: 15px; - margin-right: 0 !important; -} - -/* Display brekpoint disc */ -.netRow .netRowHeader { - background-position: 5px 1px; -} - -.netRow[breakpoint="true"] .netRowHeader { - background-image: url(chrome://firebug/skin/breakpoint.png); -} - -.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader { - background-image: url(chrome://firebug/skin/breakpointDisabled.png); -} - -.netRow.category-xhr:hover .netRowHeader { - background-color: #F6F6F6; -} - -#netBreakpointBar { - max-width: 38px; -} - -#netHrefCol > .netHeaderCellBox { - border-left: 0px; -} - -.netRow .netRowHeader { - width: 3px; -} - -.netInfoRow .netRowHeader { - display: table-cell; -} - -/************************************************************************************************/ -/* Column visibility */ - -.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"], -.netTable[hiddenCols~=netHrefCol] TD.netHrefCol, -.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"], -.netTable[hiddenCols~=netStatusCol] TD.netStatusCol, -.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"], -.netTable[hiddenCols~=netDomainCol] TD.netDomainCol, -.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"], -.netTable[hiddenCols~=netSizeCol] TD.netSizeCol, -.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"], -.netTable[hiddenCols~=netTimeCol] TD.netTimeCol { - display: none; -} - -/************************************************************************************************/ - -.netRow { - background: LightYellow; -} - -.netRow.loaded { - background: #FFFFFF; -} - -.netRow.loaded:hover { - background: #EFEFEF; -} - -.netCol { - padding: 0; - vertical-align: top; - border-bottom: 1px solid #EFEFEF; - white-space: nowrap; - height: 17px; -} - -.netLabel { - width: 100%; -} - -.netStatusCol { - padding-left: 10px; - color: rgb(128, 128, 128); -} - -.responseError > .netStatusCol { - color: red; -} - -.netDomainCol { - padding-left: 5px; -} - -.netSizeCol { - text-align: right; - padding-right: 10px; -} - -.netHrefLabel { - -moz-box-sizing: padding-box; - overflow: hidden; - z-index: 10; - position: absolute; - padding-left: 18px; - padding-top: 1px; - max-width: 15%; - font-weight: bold; -} - -.netFullHrefLabel { - display: none; - -moz-user-select: none; - padding-right: 10px; - padding-bottom: 3px; - max-width: 100%; - background: #FFFFFF; - z-index: 200; -} - -.netHrefCol:hover > .netFullHrefLabel { - display: block; -} - -.netRow.loaded:hover .netCol > .netFullHrefLabel { - background-color: #EFEFEF; -} - -.useA11y .a11yShowFullLabel { - display: block; - background-image: none !important; - border: 1px solid #CBE087; - background-color: LightYellow; - font-family: Monaco, monospace; - color: #000000; - font-size: 10px; - z-index: 2147483647; -} - -.netSizeLabel { - padding-left: 6px; -} - -.netStatusLabel, -.netDomainLabel, -.netSizeLabel, -.netBar { - padding: 1px 0 2px 0 !important; -} - -.responseError { - color: red; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.hasHeaders .netHrefLabel:hover { - cursor: pointer; - color: blue; - text-decoration: underline; -} - -/************************************************************************************************/ - -.netLoadingIcon { - position: absolute; - border: 0; - margin-left: 14px; - width: 16px; - height: 16px; - background: transparent no-repeat 0 0; - background-image: url(chrome://firebug/skin/loading_16.gif); - display:inline-block; -} - -.loaded .netLoadingIcon { - display: none; -} - -/************************************************************************************************/ - -.netBar, .netSummaryBar { - position: relative; - border-right: 50px solid transparent; -} - -.netResolvingBar { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: #FFFFFF url(chrome://firebug/skin/netBarResolving.gif) repeat-x; - z-index:60; -} - -.netConnectingBar { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: #FFFFFF url(chrome://firebug/skin/netBarConnecting.gif) repeat-x; - z-index:50; -} - -.netBlockingBar { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: #FFFFFF url(chrome://firebug/skin/netBarWaiting.gif) repeat-x; - z-index:40; -} - -.netSendingBar { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: #FFFFFF url(chrome://firebug/skin/netBarSending.gif) repeat-x; - z-index:30; -} - -.netWaitingBar { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: #FFFFFF url(chrome://firebug/skin/netBarResponded.gif) repeat-x; - z-index:20; - min-width: 1px; -} - -.netReceivingBar { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: #38D63B url(chrome://firebug/skin/netBarLoading.gif) repeat-x; - z-index:10; -} - -.netWindowLoadBar, -.netContentLoadBar { - position: absolute; - left: 0; - top: 0; - bottom: 0; - width: 1px; - background-color: red; - z-index: 70; - opacity: 0.5; - display: none; - margin-bottom:-1px; -} - -.netContentLoadBar { - background-color: Blue; -} - -.netTimeLabel { - -moz-box-sizing: padding-box; - position: absolute; - top: 1px; - left: 100%; - padding-left: 6px; - color: #444444; - min-width: 16px; -} - -/* - * Timing info tip is reusing net timeline styles to display the same - * colors for individual request phases. Notice that the info tip must - * respect also loaded and fromCache styles that also modify the - * actual color. These are used both on the same element in case - * of the tooltip. - */ -.loaded .netReceivingBar, -.loaded.netReceivingBar { - background: #B6B6B6 url(chrome://firebug/skin/netBarLoaded.gif) repeat-x; - border-color: #B6B6B6; -} - -.fromCache .netReceivingBar, -.fromCache.netReceivingBar { - background: #D6D6D6 url(chrome://firebug/skin/netBarCached.gif) repeat-x; - border-color: #D6D6D6; -} - -.netSummaryRow .netTimeLabel, -.loaded .netTimeLabel { - background: transparent; -} - -/************************************************************************************************/ -/* Time Info tip */ - -.timeInfoTip { - width: 150px; - height: 40px -} - -.timeInfoTipBar, -.timeInfoTipEventBar { - position: relative; - display: block; - margin: 0; - opacity: 1; - height: 15px; - width: 4px; -} - -.timeInfoTipEventBar { - width: 1px !important; -} - -.timeInfoTipCell.startTime { - padding-right: 8px; -} - -.timeInfoTipCell.elapsedTime { - text-align: right; - padding-right: 8px; -} - -/************************************************************************************************/ -/* Size Info tip */ - -.sizeInfoLabelCol { - font-weight: bold; - padding-right: 10px; - font-family: Lucida Grande, Tahoma, sans-serif; - font-size: 11px; -} - -.sizeInfoSizeCol { - font-weight: bold; -} - -.sizeInfoDetailCol { - color: gray; - text-align: right; -} - -.sizeInfoDescCol { - font-style: italic; -} - -/************************************************************************************************/ -/* Summary */ - -.netSummaryRow .netReceivingBar { - background: #BBBBBB; - border: none; -} - -.netSummaryLabel { - color: #222222; -} - -.netSummaryRow { - background: #BBBBBB !important; - font-weight: bold; -} - -.netSummaryRow .netBar { - border-right-color: #BBBBBB; -} - -.netSummaryRow > .netCol { - border-top: 1px solid #999999; - border-bottom: 2px solid; - -moz-border-bottom-colors: #EFEFEF #999999; - padding-top: 1px; - padding-bottom: 2px; -} - -.netSummaryRow > .netHrefCol:hover { - background: transparent !important; -} - -.netCountLabel { - padding-left: 18px; -} - -.netTotalSizeCol { - text-align: right; - padding-right: 10px; -} - -.netTotalTimeCol { - text-align: right; -} - -.netCacheSizeLabel { - position: absolute; - z-index: 1000; - left: 0; - top: 0; -} - -/************************************************************************************************/ - -.netLimitRow { - background: rgb(255, 255, 225) !important; - font-weight:normal; - color: black; - font-weight:normal; -} - -.netLimitLabel { - padding-left: 18px; -} - -.netLimitRow > .netCol { - border-bottom: 2px solid; - -moz-border-bottom-colors: #EFEFEF #999999; - vertical-align: middle !important; - padding-top: 2px; - padding-bottom: 2px; -} - -.netLimitButton { - font-size: 11px; - padding-top: 1px; - padding-bottom: 1px; -} - -/************************************************************************************************/ - -.netInfoCol { - border-top: 1px solid #EEEEEE; - background: url(chrome://firebug/skin/group.gif) repeat-x #FFFFFF; -} - -.netInfoBody { - margin: 10px 0 4px 10px; -} - -.netInfoTabs { - position: relative; - padding-left: 17px; -} - -.netInfoTab { - position: relative; - top: -3px; - margin-top: 10px; - padding: 4px 6px; - border: 1px solid transparent; - border-bottom: none; - _border: none; - font-weight: bold; - color: #565656; - cursor: pointer; -} - -/*.netInfoTab:hover { - cursor: pointer; -}*/ - -/* replaced by .netInfoTabSelected for IE6 support -.netInfoTab[selected="true"] { - cursor: default !important; - border: 1px solid #D7D7D7 !important; - border-bottom: none !important; - -moz-border-radius: 4px 4px 0 0; - background-color: #FFFFFF; -} -/**/ -.netInfoTabSelected { - cursor: default !important; - border: 1px solid #D7D7D7 !important; - border-bottom: none !important; - -moz-border-radius: 4px 4px 0 0; - -webkit-border-radius: 4px 4px 0 0; - border-radius: 4px 4px 0 0; - background-color: #FFFFFF; -} - -.logRow-netInfo.error .netInfoTitle { - color: red; -} - -.logRow-netInfo.loading .netInfoResponseText { - font-style: italic; - color: #888888; -} - -.loading .netInfoResponseHeadersTitle { - display: none; -} - -.netInfoResponseSizeLimit { - font-family: Lucida Grande, Tahoma, sans-serif; - padding-top: 10px; - font-size: 11px; -} - -.netInfoText { - display: none; - margin: 0; - border: 1px solid #D7D7D7; - border-right: none; - padding: 8px; - background-color: #FFFFFF; - font-family: Monaco, monospace; - white-space: pre-wrap; - /*overflow-x: auto; HTML is damaged in case of big (2-3MB) responses */ -} - -/* replaced by .netInfoTextSelected for IE6 support -.netInfoText[selected="true"] { - display: block; -} -/**/ -.netInfoTextSelected { - display: block; -} - -.netInfoParamName { - padding-right: 10px; - font-family: Lucida Grande, Tahoma, sans-serif; - font-weight: bold; - vertical-align: top; - text-align: right; - white-space: nowrap; -} - -.netInfoPostText .netInfoParamName { - width: 1px; /* Google Chrome need this otherwise the first column of - the post variables table will be larger than expected */ -} - -.netInfoParamValue { - width: 100%; -} - -.netInfoHeadersText, -.netInfoPostText, -.netInfoPutText { - padding-top: 0; -} - -.netInfoHeadersGroup, -.netInfoPostParams, -.netInfoPostSource { - margin-bottom: 4px; - border-bottom: 1px solid #D7D7D7; - padding-top: 8px; - padding-bottom: 2px; - font-family: Lucida Grande, Tahoma, sans-serif; - font-weight: bold; - color: #565656; -} - -.netInfoPostParamsTable, -.netInfoPostPartsTable, -.netInfoPostJSONTable, -.netInfoPostXMLTable, -.netInfoPostSourceTable { - margin-bottom: 10px; - width: 100%; -} - -.netInfoPostContentType { - color: #bdbdbd; - padding-left: 50px; - font-weight: normal; -} - -.netInfoHtmlPreview { - border: 0; - width: 100%; - height:100%; -} - -/************************************************************************************************/ -/* Request & Response Headers */ - -.netHeadersViewSource { - color: #bdbdbd; - margin-left: 200px; - font-weight: normal; -} - -.netHeadersViewSource:hover { - color: blue; - cursor: pointer; -} - -/************************************************************************************************/ - -.netActivationRow, -.netPageSeparatorRow { - background: rgb(229, 229, 229) !important; - font-weight: normal; - color: black; -} - -.netActivationLabel { - background: url(chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px; - padding-left: 22px; -} - -/************************************************************************************************/ - -.netPageSeparatorRow { - height: 5px !important; -} - -.netPageSeparatorLabel { - padding-left: 22px; - height: 5px !important; -} - -.netPageRow { - background-color: rgb(255, 255, 255); -} - -.netPageRow:hover { - background: #EFEFEF; -} - -.netPageLabel { - padding: 1px 0 2px 18px !important; - font-weight: bold; -} - -/************************************************************************************************/ - -.netActivationRow > .netCol { - border-bottom: 2px solid; - -moz-border-bottom-colors: #EFEFEF #999999; - padding-top: 2px; - padding-bottom: 3px; -} -/* -.useA11y .panelNode-net .a11yFocus:focus, -.useA11y .panelNode-net .focusRow:focus { - outline-offset: -2px; - background-color: #FFFFD6 !important; -} - -.useA11y .panelNode-net .netHeaderCell:focus, -.useA11y .panelNode-net :focus .netHeaderCell, -.useA11y .panelNode-net :focus .netReceivingBar, -.useA11y .netSummaryRow :focus .netBar, -.useA11y .netSummaryRow:focus .netBar { - background-color: #FFFFD6; - background-image: none; - border-color: #FFFFD6; -} -/**/ - -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* Windows */ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ - - -/************************************************************************************************/ -/* Twisties */ - -.twisty, -.logRow-errorMessage > .hasTwisty > .errorTitle, -.logRow-log > .objectBox-array.hasTwisty, -.logRow-spy .spyHead .spyTitle, -.logGroup > .logRow, -.memberRow.hasChildren > .memberLabelCell > .memberLabel, -.hasHeaders .netHrefLabel, -.netPageRow > .netCol > .netPageTitle { - background-image: url(tree_open.gif); - background-repeat: no-repeat; - background-position: 2px 2px; - min-height: 12px; -} - -.logRow-errorMessage > .hasTwisty.opened > .errorTitle, -.logRow-log > .objectBox-array.hasTwisty.opened, -.logRow-spy.opened .spyHead .spyTitle, -.logGroup.opened > .logRow, -.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel, -.nodeBox.highlightOpen > .nodeLabel > .twisty, -.nodeBox.open > .nodeLabel > .twisty, -.netRow.opened > .netCol > .netHrefLabel, -.netPageRow.opened > .netCol > .netPageTitle { - background-image: url(tree_close.gif); -} - -.twisty { - background-position: 4px 4px; -} - - - -/************************************************************************************************/ -/* Twisties IE6 */ - -/* IE6 has problems with > operator, and multiple classes */ - -* html .logRow-spy .spyHead .spyTitle, -* html .logGroup .logGroupLabel, -* html .hasChildren .memberLabelCell .memberLabel, -* html .hasHeaders .netHrefLabel { - background-image: url(tree_open.gif); - background-repeat: no-repeat; - background-position: 2px 2px; -} - -* html .opened .spyHead .spyTitle, -* html .opened .logGroupLabel, -* html .opened .memberLabelCell .memberLabel { - background-image: url(tree_close.gif); - background-repeat: no-repeat; - background-position: 2px 2px; -} - - - -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* Console */ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ - - -/* See license.txt for terms of usage */ - -.panelNode-console { - overflow-x: hidden; -} - -.objectLink { - text-decoration: none; -} - -.objectLink:hover { - cursor: pointer; - text-decoration: underline; -} - -.logRow { - position: relative; - margin: 0; - border-bottom: 1px solid #D7D7D7; - padding: 2px 4px 1px 6px; - background-color: #FFFFFF; - overflow: hidden !important; /* IE need this to avoid disappearing bug with collapsed logs */ -} - -.useA11y .logRow:focus { - border-bottom: 1px solid #000000 !important; - outline: none !important; - background-color: #FFFFAD !important; -} - -.useA11y .logRow:focus a.objectLink-sourceLink { - background-color: #FFFFAD; -} - -.useA11y .a11yFocus:focus, .useA11y .objectBox:focus { - outline: 2px solid #FF9933; - background-color: #FFFFAD; -} - -.useA11y .objectBox-null:focus, .useA11y .objectBox-undefined:focus{ - background-color: #888888 !important; -} - -.useA11y .logGroup.opened > .logRow { - border-bottom: 1px solid #ffffff; -} - -.logGroup { - background: url(group.gif) repeat-x #FFFFFF; - padding: 0 !important; - border: none !important; -} - -.logGroupBody { - display: none; - margin-left: 16px; - border-left: 1px solid #D7D7D7; - border-top: 1px solid #D7D7D7; - background: #FFFFFF; -} - -.logGroup > .logRow { - background-color: transparent !important; - font-weight: bold; -} - -.logGroup.opened > .logRow { - border-bottom: none; -} - -.logGroup.opened > .logGroupBody { - display: block; -} - -/*****************************************************************************************/ - -.logRow-command > .objectBox-text { - font-family: Monaco, monospace; - color: #0000FF; - white-space: pre-wrap; -} - -.logRow-info, -.logRow-warn, -.logRow-error, -.logRow-assert, -.logRow-warningMessage, -.logRow-errorMessage { - padding-left: 22px; - background-repeat: no-repeat; - background-position: 4px 2px; -} - -.logRow-assert, -.logRow-warningMessage, -.logRow-errorMessage { - padding-top: 0; - padding-bottom: 0; -} - -.logRow-info, -.logRow-info .objectLink-sourceLink { - background-color: #FFFFFF; -} - -.logRow-warn, -.logRow-warningMessage, -.logRow-warn .objectLink-sourceLink, -.logRow-warningMessage .objectLink-sourceLink { - background-color: cyan; -} - -.logRow-error, -.logRow-assert, -.logRow-errorMessage, -.logRow-error .objectLink-sourceLink, -.logRow-errorMessage .objectLink-sourceLink { - background-color: LightYellow; -} - -.logRow-error, -.logRow-assert, -.logRow-errorMessage { - color: #FF0000; -} - -.logRow-info { - /*background-image: url(chrome://firebug/skin/infoIcon.png);*/ -} - -.logRow-warn, -.logRow-warningMessage { - /*background-image: url(chrome://firebug/skin/warningIcon.png);*/ -} - -.logRow-error, -.logRow-assert, -.logRow-errorMessage { - /*background-image: url(chrome://firebug/skin/errorIcon.png);*/ -} - -/*****************************************************************************************/ - -.objectBox-string, -.objectBox-text, -.objectBox-number, -.objectLink-element, -.objectLink-textNode, -.objectLink-function, -.objectBox-stackTrace, -.objectLink-profile { - font-family: Monaco, monospace; -} - -.objectBox-string, -.objectBox-text, -.objectLink-textNode { - white-space: pre-wrap; -} - -.objectBox-number, -.objectLink-styleRule, -.objectLink-element, -.objectLink-textNode { - color: #000088; -} - -.objectBox-string { - color: #FF0000; -} - -.objectLink-function, -.objectBox-stackTrace, -.objectLink-profile { - color: DarkGreen; -} - -.objectBox-null, -.objectBox-undefined { - padding: 0 2px; - border: 1px solid #666666; - background-color: #888888; - color: #FFFFFF; -} - -.objectBox-exception { - padding: 0 2px 0 18px; - /*background: url(chrome://firebug/skin/errorIcon-sm.png) no-repeat 0 0;*/ - color: red; -} - -.objectLink-sourceLink { - position: absolute; - right: 4px; - top: 2px; - padding-left: 8px; - font-family: Lucida Grande, sans-serif; - font-weight: bold; - color: #0000FF; -} - -/************************************************************************************************/ - -.errorTitle { - margin-top: 0px; - margin-bottom: 1px; - padding-top: 2px; - padding-bottom: 2px; -} - -.errorTrace { - margin-left: 17px; -} - -.errorSourceBox { - margin: 2px 0; -} - -.errorSource-none { - display: none; -} - -.errorSource-syntax > .errorBreak { - visibility: hidden; -} - -.errorSource { - cursor: pointer; - font-family: Monaco, monospace; - color: DarkGreen; -} - -.errorSource:hover { - text-decoration: underline; -} - -.errorBreak { - cursor: pointer; - display: none; - margin: 0 6px 0 0; - width: 13px; - height: 14px; - vertical-align: bottom; - /*background: url(chrome://firebug/skin/breakpoint.png) no-repeat;*/ - opacity: 0.1; -} - -.hasBreakSwitch .errorBreak { - display: inline; -} - -.breakForError .errorBreak { - opacity: 1; -} - -.assertDescription { - margin: 0; -} - -/************************************************************************************************/ - -.logRow-profile > .logRow > .objectBox-text { - font-family: Lucida Grande, Tahoma, sans-serif; - color: #000000; -} - -.logRow-profile > .logRow > .objectBox-text:last-child { - color: #555555; - font-style: italic; -} - -.logRow-profile.opened > .logRow { - padding-bottom: 4px; -} - -.profilerRunning > .logRow { - /*background: transparent url(chrome://firebug/skin/loading_16.gif) no-repeat 2px 0 !important;*/ - padding-left: 22px !important; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.profileSizer { - width:100%; - overflow-x:auto; - overflow-y: scroll; -} - -.profileTable { - border-bottom: 1px solid #D7D7D7; - padding: 0 0 4px 0; -} - -.profileTable tr[odd="1"] { - background-color: #F5F5F5; - vertical-align:middle; -} - -.profileTable a { - vertical-align:middle; -} - -.profileTable td { - padding: 1px 4px 0 4px; -} - -.headerCell { - cursor: pointer; - -moz-user-select: none; - border-bottom: 1px solid #9C9C9C; - padding: 0 !important; - font-weight: bold; - /*background: #BBBBBB url(chrome://firebug/skin/tableHeader.gif) repeat-x;*/ -} - -.headerCellBox { - padding: 2px 4px; - border-left: 1px solid #D9D9D9; - border-right: 1px solid #9C9C9C; -} - -.headerCell:hover:active { - /*background: #959595 url(chrome://firebug/skin/tableHeaderActive.gif) repeat-x;*/ -} - -.headerSorted { - /*background: #7D93B2 url(chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;*/ -} - -.headerSorted > .headerCellBox { - border-right-color: #6B7C93; - /*background: url(chrome://firebug/skin/arrowDown.png) no-repeat right;*/ -} - -.headerSorted.sortedAscending > .headerCellBox { - /*background-image: url(chrome://firebug/skin/arrowUp.png);*/ -} - -.headerSorted:hover:active { - /*background: #536B90 url(chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;*/ -} - -.linkCell { - text-align: right; -} - -.linkCell > .objectLink-sourceLink { - position: static; -} - -/*****************************************************************************************/ - -.logRow-stackTrace { - padding-top: 0; - background: #f8f8f8; -} - -.logRow-stackTrace > .objectBox-stackFrame { - position: relative; - padding-top: 2px; -} - -/************************************************************************************************/ - -.objectLink-object { - font-family: Lucida Grande, sans-serif; - font-weight: bold; - color: DarkGreen; - white-space: pre-wrap; -} - -/* xxxpedro reps object representation .................................... */ -.objectProp-object { - color: DarkGreen; -} - -.objectProps { - color: #000; - font-weight: normal; -} - -.objectPropName { - /*font-style: italic;*/ - color: #777; -} - -/* -.objectProps .objectProp-string, -.objectProps .objectProp-number, -.objectProps .objectProp-object -{ - font-style: italic; -} -/**/ - -.objectProps .objectProp-string -{ - /*font-family: Monaco, monospace;*/ - color: #f55; -} -.objectProps .objectProp-number -{ - /*font-family: Monaco, monospace;*/ - color: #55a; -} -.objectProps .objectProp-object -{ - /*font-family: Lucida Grande,sans-serif;*/ - color: #585; -} -/* xxxpedro reps object representation .................................... */ - -/************************************************************************************************/ - -.selectorTag, -.selectorId, -.selectorClass { - font-family: Monaco, monospace; - font-weight: normal; -} - -.selectorTag { - color: #0000FF; -} - -.selectorId { - color: DarkBlue; -} - -.selectorClass { - color: red; -} - -.selectorHidden > .selectorTag { - color: #5F82D9; -} - -.selectorHidden > .selectorId { - color: #888888; -} - -.selectorHidden > .selectorClass { - color: #D86060; -} - -.selectorValue { - font-family: Lucida Grande, sans-serif; - font-style: italic; - color: #555555; -} - -/*****************************************************************************************/ - -.panelNode.searching .logRow { - display: none; -} - -.logRow.matched { - display: block !important; -} - -.logRow.matching { - position: absolute; - left: -1000px; - top: -1000px; - max-width: 0; - max-height: 0; - overflow: hidden; -} - -/*****************************************************************************************/ - -.objectLeftBrace, -.objectRightBrace, -.objectEqual, -.objectComma, -.arrayLeftBracket, -.arrayRightBracket, -.arrayComma { - font-family: Monaco, monospace; -} - -.objectLeftBrace, -.objectRightBrace, -.arrayLeftBracket, -.arrayRightBracket { - font-weight: bold; -} - -.objectLeftBrace, -.arrayLeftBracket { - margin-right: 4px; -} - -.objectRightBrace, -.arrayRightBracket { - margin-left: 4px; -} - -/*****************************************************************************************/ - -.logRow-dir { - padding: 0; -} - -/************************************************************************************************/ - -/* -.logRow-errorMessage > .hasTwisty > .errorTitle, -.logRow-spy .spyHead .spyTitle, -.logGroup > .logRow -*/ -.logRow-errorMessage .hasTwisty .errorTitle, -.logRow-spy .spyHead .spyTitle, -.logGroup .logRow { - cursor: pointer; - padding-left: 18px; - background-repeat: no-repeat; - background-position: 3px 3px; -} - -.logRow-errorMessage > .hasTwisty > .errorTitle { - background-position: 2px 3px; -} - -.logRow-errorMessage > .hasTwisty > .errorTitle:hover, -.logRow-spy .spyHead .spyTitle:hover, -.logGroup > .logRow:hover { - text-decoration: underline; -} - -/*****************************************************************************************/ - -.logRow-spy { - padding: 0 !important; -} - -.logRow-spy, -.logRow-spy .objectLink-sourceLink { - background: url(group.gif) repeat-x #FFFFFF; - padding-right: 4px; - right: 0; -} - -.logRow-spy.opened { - padding-bottom: 4px; - border-bottom: none; -} - -.spyTitle { - color: #000000; - font-weight: bold; - -moz-box-sizing: padding-box; - overflow: hidden; - z-index: 100; - padding-left: 18px; -} - -.spyCol { - padding: 0; - white-space: nowrap; - height: 16px; -} - -.spyTitleCol:hover > .objectLink-sourceLink, -.spyTitleCol:hover > .spyTime, -.spyTitleCol:hover > .spyStatus, -.spyTitleCol:hover > .spyTitle { - display: none; -} - -.spyFullTitle { - display: none; - -moz-user-select: none; - max-width: 100%; - background-color: Transparent; -} - -.spyTitleCol:hover > .spyFullTitle { - display: block; -} - -.spyStatus { - padding-left: 10px; - color: rgb(128, 128, 128); -} - -.spyTime { - margin-left:4px; - margin-right:4px; - color: rgb(128, 128, 128); -} - -.spyIcon { - margin-right: 4px; - margin-left: 4px; - width: 16px; - height: 16px; - vertical-align: middle; - background: transparent no-repeat 0 0; - display: none; -} - -.loading .spyHead .spyRow .spyIcon { - background-image: url(loading_16.gif); - display: block; -} - -.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon { - width: 0; - margin: 0; -} - -.logRow-spy.error .spyHead .spyRow .spyIcon { - background-image: url(errorIcon-sm.png); - display: block; - background-position: 2px 2px; -} - -.logRow-spy .spyHead .netInfoBody { - display: none; -} - -.logRow-spy.opened .spyHead .netInfoBody { - margin-top: 10px; - display: block; -} - -.logRow-spy.error .spyTitle, -.logRow-spy.error .spyStatus, -.logRow-spy.error .spyTime { - color: red; -} - -.logRow-spy.loading .spyResponseText { - font-style: italic; - color: #888888; -} - -/************************************************************************************************/ - -.caption { - font-family: Lucida Grande, Tahoma, sans-serif; - font-weight: bold; - color: #444444; -} - -.warning { - padding: 10px; - font-family: Lucida Grande, Tahoma, sans-serif; - font-weight: bold; - color: #888888; -} - - - - -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* DOM */ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ - - -/* See license.txt for terms of usage */ - -.panelNode-dom { - overflow-x: hidden !important; -} - -.domTable { - font-size: 1em; - width: 100%; - table-layout: fixed; - background: #fff; -} - -.domTableIE { - width: auto; -} - -.memberLabelCell { - padding: 2px 0 2px 0; - vertical-align: top; -} - -.memberValueCell { - padding: 1px 0 1px 5px; - display: block; - overflow: hidden; -} - -.memberLabel { - display: block; - cursor: default; - -moz-user-select: none; - overflow: hidden; - /*position: absolute;*/ - padding-left: 18px; - /*max-width: 30%;*/ - /*white-space: nowrap;*/ - background-color: #FFFFFF; - text-decoration: none; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.memberRow.hasChildren .memberLabelCell .memberLabel:hover { - cursor: pointer; - color: blue; - text-decoration: underline; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.userLabel { - color: #000000; - font-weight: bold; -} - -.userClassLabel { - color: #E90000; - font-weight: bold; -} - -.userFunctionLabel { - color: #025E2A; - font-weight: bold; -} - -.domLabel { - color: #000000; -} - -.domFunctionLabel { - color: #025E2A; -} - -.ordinalLabel { - color: SlateBlue; - font-weight: bold; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -.scopesRow { - padding: 2px 18px; - background-color: LightYellow; - border-bottom: 5px solid #BEBEBE; - color: #666666; -} -.scopesLabel { - background-color: LightYellow; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.watchEditCell { - padding: 2px 18px; - background-color: LightYellow; - border-bottom: 1px solid #BEBEBE; - color: #666666; -} - -.editor-watchNewRow, -.editor-memberRow { - font-family: Monaco, monospace !important; -} - -.editor-memberRow { - padding: 1px 0 !important; -} - -.editor-watchRow { - padding-bottom: 0 !important; -} - -.watchRow > .memberLabelCell { - font-family: Monaco, monospace; - padding-top: 1px; - padding-bottom: 1px; -} - -.watchRow > .memberLabelCell > .memberLabel { - background-color: transparent; -} - -.watchRow > .memberValueCell { - padding-top: 2px; - padding-bottom: 2px; -} - -.watchRow > .memberLabelCell, -.watchRow > .memberValueCell { - background-color: #F5F5F5; - border-bottom: 1px solid #BEBEBE; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.watchToolbox { - z-index: 2147483647; - position: absolute; - right: 0; - padding: 1px 2px; -} - - -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/*************************************************************************************************/ -/* FROM ORIGINAL FIREBUG */ - - - - -/************************************************************************************************ - CSS Not organized -*************************************************************************************************/ -#fbConsole { - overflow-x: hidden !important; -} - -#fbCSS { - font: 1em Monaco, monospace; - padding: 0 7px; -} - -#fbstylesheetButtons select, #fbScriptButtons select { - font: 11px Lucida Grande, Tahoma, sans-serif; - margin-top: 1px; - padding-left: 3px; - background: #fafafa; - border: 1px inset #fff; - width: 220px; - outline: none; -} - -.Selector { margin-top:10px } -.CSSItem {margin-left: 4% } -.CSSText { padding-left:20px; } -.CSSProperty { color:#005500; } -.CSSValue { padding-left:5px; color:#000088; } - - -/************************************************************************************************ - Not organized -*************************************************************************************************/ - -#fbHTMLStatusBar { - display: inline; -} - -.fbToolbarButtons { - display: none; -} - -.fbStatusSeparator{ - display: block; - float: left; - padding-top: 4px; -} - -#fbStatusBarBox { - display: none; -} - -#fbToolbarContent { - display: block; - position: absolute; - _position: absolute; - top: 0; - padding-top: 4px; - height: 23px; - clip: rect(0, 2048px, 27px, 0); -} - -.fbTabMenuTarget { - display: none !important; - float: left; - width: 10px; - height: 10px; - margin-top: 6px; - background: url(tabMenuTarget.png); -} - -.fbTabMenuTarget:hover { - background: url(tabMenuTargetHover.png); -} - -.fbShadow { - float: left; - background: url(shadowAlpha.png) no-repeat bottom right !important; - background: url(shadow2.gif) no-repeat bottom right; - margin: 10px 0 0 10px !important; - margin: 10px 0 0 5px; -} - -.fbShadowContent { - display: block; - position: relative; - background-color: #fff; - border: 1px solid #a9a9a9; - top: -6px; - left: -6px; -} - -.fbMenu { - display: none; - position: absolute; - font-size: 11px; - line-height: 13px; - z-index: 2147483647; -} - -.fbMenuContent { - padding: 2px; -} - -.fbMenuSeparator { - display: block; - position: relative; - padding: 1px 18px 0; - text-decoration: none; - color: #000; - cursor: default; - background: #ACA899; - margin: 4px 0; -} - -.fbMenuOption -{ - display: block; - position: relative; - padding: 2px 18px; - text-decoration: none; - color: #000; - cursor: default; -} - -.fbMenuOption:hover -{ - color: #fff; - background: #316AC5; -} - -.fbMenuGroup { - background: transparent url(tabMenuPin.png) no-repeat right 0; -} - -.fbMenuGroup:hover { - background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; -} - -.fbMenuGroupSelected { - color: #fff; - background: #316AC5 url(tabMenuPin.png) no-repeat right -17px; -} - -.fbMenuChecked { - background: transparent url(tabMenuCheckbox.png) no-repeat 4px 0; -} - -.fbMenuChecked:hover { - background: #316AC5 url(tabMenuCheckbox.png) no-repeat 4px -17px; -} - -.fbMenuRadioSelected { - background: transparent url(tabMenuRadio.png) no-repeat 4px 0; -} - -.fbMenuRadioSelected:hover { - background: #316AC5 url(tabMenuRadio.png) no-repeat 4px -17px; -} - -.fbMenuShortcut { - padding-right: 85px; -} - -.fbMenuShortcutKey { - position: absolute; - right: 0; - top: 2px; - width: 77px; -} - -#fbFirebugMenu { - top: 22px; - left: 0; -} - -.fbMenuDisabled { - color: #ACA899 !important; -} - -#fbFirebugSettingsMenu { - left: 245px; - top: 99px; -} - -#fbConsoleMenu { - top: 42px; - left: 48px; -} - -.fbIconButton { - display: block; -} - -.fbIconButton { - display: block; -} - -.fbIconButton { - display: block; - float: left; - height: 20px; - width: 20px; - color: #000; - margin-right: 2px; - text-decoration: none; - cursor: default; -} - -.fbIconButton:hover { - position: relative; - top: -1px; - left: -1px; - margin-right: 0; - _margin-right: 1px; - color: #333; - border: 1px solid #fff; - border-bottom: 1px solid #bbb; - border-right: 1px solid #bbb; -} - -.fbIconPressed { - position: relative; - margin-right: 0; - _margin-right: 1px; - top: 0 !important; - left: 0 !important; - height: 19px; - color: #333 !important; - border: 1px solid #bbb !important; - border-bottom: 1px solid #cfcfcf !important; - border-right: 1px solid #ddd !important; -} - - - -/************************************************************************************************ - Error Popup -*************************************************************************************************/ -#fbErrorPopup { - position: absolute; - right: 0; - bottom: 0; - height: 19px; - width: 75px; - background: url(sprite.png) #f1f2ee 0 0; - z-index: 999; -} - -#fbErrorPopupContent { - position: absolute; - right: 0; - top: 1px; - height: 18px; - width: 75px; - _width: 74px; - border-left: 1px solid #aca899; -} - -#fbErrorIndicator { - position: absolute; - top: 2px; - right: 5px; -} - - - - - - - - - - -.fbBtnInspectActive { - background: #aaa; - color: #fff !important; -} - -/************************************************************************************************ - General -*************************************************************************************************/ -.fbBody { - margin: 0; - padding: 0; - overflow: hidden; - - font-family: Lucida Grande, Tahoma, sans-serif; - font-size: 11px; - background: #fff; -} - -.clear { - clear: both; -} - -/************************************************************************************************ - Mini Chrome -*************************************************************************************************/ -#fbMiniChrome { - display: none; - right: 0; - height: 27px; - background: url(sprite.png) #f1f2ee 0 0; - margin-left: 1px; -} - -#fbMiniContent { - display: block; - position: relative; - left: -1px; - right: 0; - top: 1px; - height: 25px; - border-left: 1px solid #aca899; -} - -#fbToolbarSearch { - float: right; - border: 1px solid #ccc; - margin: 0 5px 0 0; - background: #fff url(search.png) no-repeat 4px 2px !important; - background: #fff url(search.gif) no-repeat 4px 2px; - padding-left: 20px; - font-size: 11px; -} - -#fbToolbarErrors { - float: right; - margin: 1px 4px 0 0; - font-size: 11px; -} - -#fbLeftToolbarErrors { - float: left; - margin: 7px 0px 0 5px; - font-size: 11px; -} - -.fbErrors { - padding-left: 20px; - height: 14px; - background: url(errorIcon.png) no-repeat !important; - background: url(errorIcon.gif) no-repeat; - color: #f00; - font-weight: bold; -} - -#fbMiniErrors { - display: inline; - display: none; - float: right; - margin: 5px 2px 0 5px; -} - -#fbMiniIcon { - float: right; - margin: 3px 4px 0; - height: 20px; - width: 20px; - float: right; - background: url(sprite.png) 0 -135px; - cursor: pointer; -} - - -/************************************************************************************************ - Master Layout -*************************************************************************************************/ -#fbChrome { - font-family: Lucida Grande, Tahoma, sans-serif; - font-size: 11px; - position: absolute; - _position: static; - top: 0; - left: 0; - height: 100%; - width: 100%; - border-collapse: collapse; - border-spacing: 0; - background: #fff; - overflow: hidden; -} - -#fbChrome > tbody > tr > td { - padding: 0; -} - -#fbTop { - height: 49px; -} - -#fbToolbar { - background: url(sprite.png) #f1f2ee 0 0; - height: 27px; - font-size: 11px; - line-height: 13px; -} - -#fbPanelBarBox { - background: url(sprite.png) #dbd9c9 0 -27px; - height: 22px; -} - -#fbContent { - height: 100%; - vertical-align: top; -} - -#fbBottom { - height: 18px; - background: #fff; -} - -/************************************************************************************************ - Sub-Layout -*************************************************************************************************/ - -/* fbToolbar -*************************************************************************************************/ -#fbToolbarIcon { - float: left; - padding: 0 5px 0; -} - -#fbToolbarIcon a { - background: url(sprite.png) 0 -135px; -} - -#fbToolbarButtons { - padding: 0 2px 0 5px; -} - -#fbToolbarButtons { - padding: 0 2px 0 5px; -} -/* -#fbStatusBarBox a { - text-decoration: none; - display: block; - float: left; - color: #000; - padding: 4px 5px; - margin: 0 0 0 1px; - cursor: default; -} - -#fbStatusBarBox a:hover { - color: #333; - padding: 3px 4px; - border: 1px solid #fff; - border-bottom: 1px solid #bbb; - border-right: 1px solid #bbb; -} -/**/ - -.fbButton { - text-decoration: none; - display: block; - float: left; - color: #000; - padding: 4px 6px 4px 7px; - cursor: default; -} - -.fbButton:hover { - color: #333; - background: #f5f5ef url(buttonBg.png); - padding: 3px 5px 3px 6px; - border: 1px solid #fff; - border-bottom: 1px solid #bbb; - border-right: 1px solid #bbb; -} - -.fbBtnPressed { - background: #e3e3db url(buttonBgHover.png) !important; - padding: 3px 4px 2px 6px !important; - margin: 1px 0 0 1px !important; - border: 1px solid #ACA899 !important; - border-color: #ACA899 #ECEBE3 #ECEBE3 #ACA899 !important; -} - -#fbStatusBarBox { - top: 4px; - cursor: default; -} - -.fbToolbarSeparator { - overflow: hidden; - border: 1px solid; - border-color: transparent #fff transparent #777; - _border-color: #eee #fff #eee #777; - height: 7px; - margin: 6px 3px; - float: left; -} - -.fbBtnSelected { - font-weight: bold; -} - -.fbStatusBar { - color: #aca899; -} - -.fbStatusBar a { - text-decoration: none; - color: black; -} - -.fbStatusBar a:hover { - color: blue; - cursor: pointer; -} - - -#fbWindowButtons { - position: absolute; - white-space: nowrap; - right: 0; - top: 0; - height: 17px; - width: 48px; - padding: 5px; - z-index: 6; - background: url(sprite.png) #f1f2ee 0 0; -} - -/* fbPanelBarBox -*************************************************************************************************/ - -#fbPanelBar1 { - width: 1024px; /* fixed width to avoid tabs breaking line */ - z-index: 8; - left: 0; - white-space: nowrap; - background: url(sprite.png) #dbd9c9 0 -27px; - position: absolute; - left: 4px; -} - -#fbPanelBar2Box { - background: url(sprite.png) #dbd9c9 0 -27px; - position: absolute; - height: 22px; - width: 300px; /* fixed width to avoid tabs breaking line */ - z-index: 9; - right: 0; -} - -#fbPanelBar2 { - position: absolute; - width: 290px; /* fixed width to avoid tabs breaking line */ - height: 22px; - padding-left: 4px; -} - -/* body -*************************************************************************************************/ -.fbPanel { - display: none; -} - -#fbPanelBox1, #fbPanelBox2 { - max-height: inherit; - height: 100%; - font-size: 1em; -} - -#fbPanelBox2 { - background: #fff; -} - -#fbPanelBox2 { - width: 300px; - background: #fff; -} - -#fbPanel2 { - margin-left: 6px; - background: #fff; -} - -#fbLargeCommandLine { - display: none; - position: absolute; - z-index: 9; - top: 27px; - right: 0; - width: 294px; - height: 201px; - border-width: 0; - margin: 0; - padding: 2px 0 0 2px; - resize: none; - outline: none; - font-size: 11px; - overflow: auto; - border-top: 1px solid #B9B7AF; - _right: -1px; - _border-left: 1px solid #fff; -} - -#fbLargeCommandButtons { - display: none; - background: #ECE9D8; - bottom: 0; - right: 0; - width: 294px; - height: 21px; - padding-top: 1px; - position: fixed; - border-top: 1px solid #ACA899; - z-index: 9; -} - -#fbSmallCommandLineIcon { - background: url(down.png) no-repeat; - position: absolute; - right: 2px; - bottom: 3px; - - z-index: 99; -} - -#fbSmallCommandLineIcon:hover { - background: url(downHover.png) no-repeat; -} - -.hide { - overflow: hidden !important; - position: fixed !important; - display: none !important; - visibility: hidden !important; -} - -/* fbBottom -*************************************************************************************************/ - -#fbCommand { - height: 18px; -} - -#fbCommandBox { - position: fixed; - _position: absolute; - width: 100%; - height: 18px; - bottom: 0; - overflow: hidden; - z-index: 9; - background: #fff; - border: 0; - border-top: 1px solid #ccc; -} - -#fbCommandIcon { - position: absolute; - color: #00f; - top: 2px; - left: 6px; - display: inline; - font: 11px Monaco, monospace; - z-index: 10; -} - -#fbCommandLine { - position: absolute; - width: 100%; - top: 0; - left: 0; - border: 0; - margin: 0; - padding: 2px 0 2px 32px; - font: 11px Monaco, monospace; - z-index: 9; - outline: none; -} - -#fbLargeCommandLineIcon { - background: url(up.png) no-repeat; - position: absolute; - right: 1px; - bottom: 1px; - z-index: 10; -} - -#fbLargeCommandLineIcon:hover { - background: url(upHover.png) no-repeat; -} - -div.fbFitHeight { - overflow: auto; - position: relative; -} - - -/************************************************************************************************ - Layout Controls -*************************************************************************************************/ - -/* fbToolbar buttons -*************************************************************************************************/ -.fbSmallButton { - overflow: hidden; - width: 16px; - height: 16px; - display: block; - text-decoration: none; - cursor: default; -} - -#fbWindowButtons .fbSmallButton { - float: right; -} - -#fbWindow_btClose { - background: url(min.png); -} - -#fbWindow_btClose:hover { - background: url(minHover.png); -} - -#fbWindow_btDetach { - background: url(detach.png); -} - -#fbWindow_btDetach:hover { - background: url(detachHover.png); -} - -#fbWindow_btDeactivate { - background: url(off.png); -} - -#fbWindow_btDeactivate:hover { - background: url(offHover.png); -} - - -/* fbPanelBarBox tabs -*************************************************************************************************/ -.fbTab { - text-decoration: none; - display: none; - float: left; - width: auto; - float: left; - cursor: default; - font-family: Lucida Grande, Tahoma, sans-serif; - font-size: 11px; - line-height: 13px; - font-weight: bold; - height: 22px; - color: #565656; -} - -.fbPanelBar span { - /*display: block; TODO: safe to remove this? */ - float: left; -} - -.fbPanelBar .fbTabL,.fbPanelBar .fbTabR { - height: 22px; - width: 8px; -} - -.fbPanelBar .fbTabText { - padding: 4px 1px 0; -} - -a.fbTab:hover { - background: url(sprite.png) 0 -73px; -} - -a.fbTab:hover .fbTabL { - background: url(sprite.png) -16px -96px; -} - -a.fbTab:hover .fbTabR { - background: url(sprite.png) -24px -96px; -} - -.fbSelectedTab { - background: url(sprite.png) #f1f2ee 0 -50px !important; - color: #000; -} - -.fbSelectedTab .fbTabL { - background: url(sprite.png) 0 -96px !important; -} - -.fbSelectedTab .fbTabR { - background: url(sprite.png) -8px -96px !important; -} - -/* splitters -*************************************************************************************************/ -#fbHSplitter { - position: fixed; - _position: absolute; - left: 0; - top: 0; - width: 100%; - height: 5px; - overflow: hidden; - cursor: n-resize !important; - background: url(pixel_transparent.gif); - z-index: 9; -} - -#fbHSplitter.fbOnMovingHSplitter { - height: 100%; - z-index: 100; -} - -.fbVSplitter { - background: #ece9d8; - color: #000; - border: 1px solid #716f64; - border-width: 0 1px; - border-left-color: #aca899; - width: 4px; - cursor: e-resize; - overflow: hidden; - right: 294px; - text-decoration: none; - z-index: 10; - position: absolute; - height: 100%; - top: 27px; -} - -/************************************************************************************************/ -div.lineNo { - font: 1em/1.4545em Monaco, monospace; - position: relative; - float: left; - top: 0; - left: 0; - margin: 0 5px 0 0; - padding: 0 5px 0 10px; - background: #eee; - color: #888; - border-right: 1px solid #ccc; - text-align: right; -} - -.sourceBox { - position: absolute; -} - -.sourceCode { - font: 1em Monaco, monospace; - overflow: hidden; - white-space: pre; - display: inline; -} - -/************************************************************************************************/ -.nodeControl { - margin-top: 3px; - margin-left: -14px; - float: left; - width: 9px; - height: 9px; - overflow: hidden; - cursor: default; - background: url(tree_open.gif); - _float: none; - _display: inline; - _position: absolute; -} - -div.nodeMaximized { - background: url(tree_close.gif); -} - -div.objectBox-element { - padding: 1px 3px; -} -.objectBox-selector{ - cursor: default; -} - -.selectedElement{ - background: highlight; - /* background: url(roundCorner.svg); Opera */ - color: #fff !important; -} -.selectedElement span{ - color: #fff !important; -} - -/* IE6 need this hack */ -* html .selectedElement { - position: relative; -} - -/* Webkit CSS Hack - bug in "highlight" named color */ -@media screen and (-webkit-min-device-pixel-ratio:0) { - .selectedElement{ - background: #316AC5; - color: #fff !important; - } -} - -/************************************************************************************************/ -/************************************************************************************************/ -.logRow * { - font-size: 1em; -} - -/* TODO: remove this? */ -/* TODO: xxxpedro - IE need this in windowless mode (cnn.com) check if the issue is related to -position. if so, override it at chrome.js initialization when creating the div */ -.logRow { - position: relative; - border-bottom: 1px solid #D7D7D7; - padding: 2px 4px 1px 6px; - zbackground-color: #FFFFFF; -} -/**/ - -.logRow-command { - font-family: Monaco, monospace; - color: blue; -} - -.objectBox-string, -.objectBox-text, -.objectBox-number, -.objectBox-function, -.objectLink-element, -.objectLink-textNode, -.objectLink-function, -.objectBox-stackTrace, -.objectLink-profile { - font-family: Monaco, monospace; -} - -.objectBox-null { - padding: 0 2px; - border: 1px solid #666666; - background-color: #888888; - color: #FFFFFF; -} - -.objectBox-string { - color: red; - - /* TODO: xxxpedro make long strings break line */ - /*white-space: pre; */ -} - -.objectBox-number { - color: #000088; -} - -.objectBox-function { - color: DarkGreen; -} - -.objectBox-object { - color: DarkGreen; - font-weight: bold; - font-family: Lucida Grande, sans-serif; -} - -.objectBox-array { - color: #000; -} - -/************************************************************************************************/ -.logRow-info,.logRow-error,.logRow-warn { - background: #fff no-repeat 2px 2px; - padding-left: 20px; - padding-bottom: 3px; -} - -.logRow-info { - background-image: url(infoIcon.png) !important; - background-image: url(infoIcon.gif); -} - -.logRow-warn { - background-color: cyan; - background-image: url(warningIcon.png) !important; - background-image: url(warningIcon.gif); -} - -.logRow-error { - background-color: LightYellow; - background-image: url(errorIcon.png) !important; - background-image: url(errorIcon.gif); - color: #f00; -} - -.errorMessage { - vertical-align: top; - color: #f00; -} - -.objectBox-sourceLink { - position: absolute; - right: 4px; - top: 2px; - padding-left: 8px; - font-family: Lucida Grande, sans-serif; - font-weight: bold; - color: #0000FF; -} - -/************************************************************************************************/ -/* -//TODO: remove this when console2 is finished -*/ -/* -.logRow-group { - background: #EEEEEE; - border-bottom: none; -} - -.logGroup { - background: #EEEEEE; -} - -.logGroupBox { - margin-left: 24px; - border-top: 1px solid #D7D7D7; - border-left: 1px solid #D7D7D7; -}/**/ - -/************************************************************************************************/ -.selectorTag,.selectorId,.selectorClass { - font-family: Monaco, monospace; - font-weight: normal; -} - -.selectorTag { - color: #0000FF; -} - -.selectorId { - color: DarkBlue; -} - -.selectorClass { - color: red; -} - -/************************************************************************************************/ -.objectBox-element { - font-family: Monaco, monospace; - color: #000088; -} - -.nodeChildren { - padding-left: 26px; -} - -.nodeTag { - color: blue; - cursor: pointer; -} - -.nodeValue { - color: #FF0000; - font-weight: normal; -} - -.nodeText,.nodeComment { - margin: 0 2px; - vertical-align: top; -} - -.nodeText { - color: #333333; - font-family: Monaco, monospace; -} - -.nodeComment { - color: DarkGreen; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.nodeHidden, .nodeHidden * { - color: #888888; -} - -.nodeHidden .nodeTag { - color: #5F82D9; -} - -.nodeHidden .nodeValue { - color: #D86060; -} - -.selectedElement .nodeHidden, .selectedElement .nodeHidden * { - color: SkyBlue !important; -} - - -/************************************************************************************************/ -.log-object { - /* - _position: relative; - _height: 100%; - /**/ -} - -.property { - position: relative; - clear: both; - height: 15px; -} - -.propertyNameCell { - vertical-align: top; - float: left; - width: 28%; - position: absolute; - left: 0; - z-index: 0; -} - -.propertyValueCell { - float: right; - width: 68%; - background: #fff; - position: absolute; - padding-left: 5px; - display: table-cell; - right: 0; - z-index: 1; - /* - _position: relative; - /**/ -} - -.propertyName { - font-weight: bold; -} - -.FirebugPopup { - height: 100% !important; -} - -.FirebugPopup #fbWindowButtons { - display: none !important; -} - -.FirebugPopup #fbHSplitter { - display: none !important; -} diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.html b/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.html deleted file mode 100644 index aa078099fb4..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.html +++ /dev/null @@ -1,215 +0,0 @@ - - - - -Firebug Lite - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
-   -   -   -
- - -
-
- - - -   - - - - - - - - - Inspect - - - - - Clear - - - - - - - - - - - - - -
- -
- - - - - -
 
- -
-
-
-
-
-
- - -
 
- - -
- - -
-
-
- -
- - - - - -
- Run - Clear - - -
- -
-
-
>>>
- - -
-
- - - - - - - - - \ No newline at end of file diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.png deleted file mode 100644 index e10affebb48..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/firebug.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/group.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/group.gif deleted file mode 100644 index 8db97c2104b..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/group.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/html.css b/public/vendor/lodash/vendor/firebug-lite/skin/xp/html.css deleted file mode 100644 index 5b7c5f4baf7..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/skin/xp/html.css +++ /dev/null @@ -1,272 +0,0 @@ -/* See license.txt for terms of usage */ - -.panelNode-html { - -moz-box-sizing: padding-box; - padding: 4px 0 0 2px; -} - -.nodeBox { - position: relative; - font-family: Monaco, monospace; - padding-left: 13px; - -moz-user-select: -moz-none; -} -.nodeBox.search-selection { - -moz-user-select: text; -} -.twisty { - position: absolute; - left: 0px; - top: 0px; - width: 14px; - height: 14px; -} - -.nodeChildBox { - margin-left: 12px; - display: none; -} - -.nodeLabel, -.nodeCloseLabel { - margin: -2px 2px 0 2px; - border: 2px solid transparent; - -moz-border-radius: 3px; - padding: 0 2px; - color: #000088; -} - -.nodeCloseLabel { - display: none; -} - -.nodeTag { - cursor: pointer; - color: blue; -} - -.nodeValue { - color: #FF0000; - font-weight: normal; -} - -.nodeText, -.nodeComment { - margin: 0 2px; - vertical-align: top; -} - -.nodeText { - color: #333333; -} - -.nodeWhiteSpace { - border: 1px solid LightGray; - white-space: pre; /* otherwise the border will be collapsed around zero pixels */ - margin-left: 1px; - color: gray; -} - - -.nodeWhiteSpace_Space { - border: 1px solid #ddd; -} - -.nodeTextEntity { - border: 1px solid gray; - white-space: pre; /* otherwise the border will be collapsed around zero pixels */ - margin-left: 1px; -} - -.nodeComment { - color: DarkGreen; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.nodeBox.highlightOpen > .nodeLabel { - background-color: #EEEEEE; -} - -.nodeBox.highlightOpen > .nodeCloseLabel, -.nodeBox.highlightOpen > .nodeChildBox, -.nodeBox.open > .nodeCloseLabel, -.nodeBox.open > .nodeChildBox { - display: block; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.nodeBox.selected > .nodeLabel > .nodeLabelBox, -.nodeBox.selected > .nodeLabel { - border-color: Highlight; - background-color: Highlight; - color: HighlightText !important; -} - -.nodeBox.selected > .nodeLabel > .nodeLabelBox, -.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeTag, -.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue, -.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText { - color: inherit !important; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.nodeBox.highlighted > .nodeLabel { - border-color: Highlight !important; - background-color: cyan !important; - color: #000000 !important; -} - -.nodeBox.highlighted > .nodeLabel > .nodeLabelBox, -.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeTag, -.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue, -.nodeBox.highlighted > .nodeLabel > .nodeLabelBox > .nodeText { - color: #000000 !important; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox, -.nodeBox.nodeHidden .nodeCloseLabel, -.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeText, -.nodeBox.nodeHidden .nodeText { - color: #888888; -} - -.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeTag, -.nodeBox.nodeHidden .nodeCloseLabel > .nodeCloseLabelBox > .nodeTag { - color: #5F82D9; -} - -.nodeBox.nodeHidden .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue { - color: #D86060; -} - -.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox, -.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeTag, -.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue, -.nodeBox.nodeHidden.selected > .nodeLabel > .nodeLabelBox > .nodeText { - color: SkyBlue !important; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -.nodeBox.mutated > .nodeLabel, -.nodeAttr.mutated, -.nodeValue.mutated, -.nodeText.mutated, -.nodeBox.mutated > .nodeText { - background-color: #EFFF79; - color: #FF0000 !important; -} - -.nodeBox.selected.mutated > .nodeLabel, -.nodeBox.selected.mutated > .nodeLabel > .nodeLabelBox, -.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr.mutated > .nodeValue, -.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeAttr > .nodeValue.mutated, -.nodeBox.selected > .nodeLabel > .nodeLabelBox > .nodeText.mutated { - background-color: #EFFF79; - border-color: #EFFF79; - color: #FF0000 !important; -} - -/************************************************************************************************/ - -.logRow-dirxml { - padding-left: 0; -} - -.soloElement > .nodeBox { - padding-left: 0; -} - -.useA11y .nodeLabel.focused { - outline: 2px solid #FF9933; - -moz-outline-radius: 3px; - outline-offset: -2px; -} - -.useA11y .nodeLabelBox:focus { - outline: none; -} - -/************************************************************************************************/ - -.breakpointCode .twisty { - display: none; -} - -.breakpointCode .nodeBox.containerNodeBox, -.breakpointCode .nodeLabel { - padding-left: 0px; - margin-left: 0px; - font-family: Monaco, monospace !important; -} - -.breakpointCode .nodeTag, -.breakpointCode .nodeAttr, -.breakpointCode .nodeText, -.breakpointCode .nodeValue, -.breakpointCode .nodeLabel { - color: DarkGreen !important; -} - -.breakpointMutationType { - position: absolute; - top: 4px; - right: 20px; - color: gray; -} - - - - - - -/************************************************************************************************/ -/************************************************************************************************/ -/************************************************************************************************/ -/************************************************************************************************/ -/************************************************************************************************/ -/************************************************************************************************/ -/************************************************************************************************/ -/************************************************************************************************/ -/************************************************************************************************/ -/************************************************************************************************/ - - - -/************************************************************************************************/ -/* Twisties */ - -.twisty, -.logRow-errorMessage > .hasTwisty > .errorTitle, -.logRow-log > .objectBox-array.hasTwisty, -.logRow-spy .spyHead .spyTitle, -.logGroup > .logRow, -.memberRow.hasChildren > .memberLabelCell > .memberLabel, -.hasHeaders .netHrefLabel, -.netPageRow > .netCol > .netPageTitle { - background-image: url(twistyClosed.png); - background-repeat: no-repeat; - background-position: 2px 2px; - min-height: 12px; -} - -.logRow-errorMessage > .hasTwisty.opened > .errorTitle, -.logRow-log > .objectBox-array.hasTwisty.opened, -.logRow-spy.opened .spyHead .spyTitle, -.logGroup.opened > .logRow, -.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel, -.nodeBox.highlightOpen > .nodeLabel > .twisty, -.nodeBox.open > .nodeLabel > .twisty, -.netRow.opened > .netCol > .netHrefLabel, -.netPageRow.opened > .netCol > .netPageTitle { - background-image: url(twistyOpen.png); -} - -.twisty { - background-position: 4px 4px; -} \ No newline at end of file diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/infoIcon.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/infoIcon.gif deleted file mode 100644 index 0618e208c34..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/infoIcon.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/infoIcon.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/infoIcon.png deleted file mode 100644 index da1e5334c19..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/infoIcon.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/loading_16.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/loading_16.gif deleted file mode 100644 index 085ccaecaf5..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/loading_16.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/min.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/min.png deleted file mode 100644 index 1034d66fb44..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/min.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/minHover.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/minHover.png deleted file mode 100644 index b0d1e1afdcc..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/minHover.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/off.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/off.png deleted file mode 100644 index b70b1d24d88..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/off.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/offHover.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/offHover.png deleted file mode 100644 index f3670f19ff3..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/offHover.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/pixel_transparent.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/pixel_transparent.gif deleted file mode 100644 index 6865c960497..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/pixel_transparent.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/roundCorner.svg b/public/vendor/lodash/vendor/firebug-lite/skin/xp/roundCorner.svg deleted file mode 100644 index 2dfa72800e5..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/skin/xp/roundCorner.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/search.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/search.gif deleted file mode 100644 index 2a620987e0e..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/search.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/search.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/search.png deleted file mode 100644 index fba33b8a57d..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/search.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadow.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadow.gif deleted file mode 100644 index af7f537e391..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadow.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadow2.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadow2.gif deleted file mode 100644 index 099cbf35d45..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadow2.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadowAlpha.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadowAlpha.png deleted file mode 100644 index a2561df9717..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/shadowAlpha.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/sprite.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/sprite.png deleted file mode 100644 index 33d2c4d4649..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/sprite.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverLeft.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverLeft.png deleted file mode 100644 index 0fb24d0c855..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverLeft.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverMid.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverMid.png deleted file mode 100644 index fbccab54d05..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverMid.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverRight.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverRight.png deleted file mode 100644 index 3db0f361799..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabHoverRight.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabLeft.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabLeft.png deleted file mode 100644 index a6cc9e94a9b..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabLeft.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuCheckbox.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuCheckbox.png deleted file mode 100644 index 4726e62208e..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuCheckbox.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuPin.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuPin.png deleted file mode 100644 index eb4b11efe5e..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuPin.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuRadio.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuRadio.png deleted file mode 100644 index 55b982d7c8e..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuRadio.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuTarget.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuTarget.png deleted file mode 100644 index 957bd9f2ada..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuTarget.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuTargetHover.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuTargetHover.png deleted file mode 100644 index 200a37083d6..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMenuTargetHover.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMid.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMid.png deleted file mode 100644 index 68986c3b0bd..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabMid.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabRight.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabRight.png deleted file mode 100644 index 501130796a5..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tabRight.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.gif deleted file mode 100644 index 0ee5497874c..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.png deleted file mode 100644 index 21682c3dcaf..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorBorders.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.gif deleted file mode 100644 index 04f84215233..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.png deleted file mode 100644 index a0f839dc598..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/textEditorCorners.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/titlebarMid.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/titlebarMid.png deleted file mode 100644 index 10998ae7b37..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/titlebarMid.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/toolbarMid.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/toolbarMid.png deleted file mode 100644 index aa21dee6a77..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/toolbarMid.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tree_close.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tree_close.gif deleted file mode 100644 index e26728ab36b..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tree_close.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tree_open.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/tree_open.gif deleted file mode 100644 index edf662f36f3..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/tree_open.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/twistyClosed.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/twistyClosed.png deleted file mode 100644 index f80319b0a4e..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/twistyClosed.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/twistyOpen.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/twistyOpen.png deleted file mode 100644 index 86801243459..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/twistyOpen.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/up.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/up.png deleted file mode 100644 index 2174d03a9c9..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/up.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/upActive.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/upActive.png deleted file mode 100644 index 236cf6768e3..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/upActive.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/upHover.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/upHover.png deleted file mode 100644 index cd8131707e2..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/upHover.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/warningIcon.gif b/public/vendor/lodash/vendor/firebug-lite/skin/xp/warningIcon.gif deleted file mode 100644 index 84972788620..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/warningIcon.gif and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/skin/xp/warningIcon.png b/public/vendor/lodash/vendor/firebug-lite/skin/xp/warningIcon.png deleted file mode 100644 index de51084e848..00000000000 Binary files a/public/vendor/lodash/vendor/firebug-lite/skin/xp/warningIcon.png and /dev/null differ diff --git a/public/vendor/lodash/vendor/firebug-lite/src/firebug-lite-debug.js b/public/vendor/lodash/vendor/firebug-lite/src/firebug-lite-debug.js deleted file mode 100644 index 40b1ae70cb3..00000000000 --- a/public/vendor/lodash/vendor/firebug-lite/src/firebug-lite-debug.js +++ /dev/null @@ -1,31176 +0,0 @@ -(function(){ - -/*!************************************************************* - * - * Firebug Lite 1.4.0 - * - * Copyright (c) 2007, Parakey Inc. - * Released under BSD license. - * More information: http://getfirebug.com/firebuglite - * - **************************************************************/ - -/*! - * CSS selectors powered by: - * - * Sizzle CSS Selector Engine - v1.0 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ - -/** @namespace describe lib */ - -// FIXME: xxxpedro if we use "var FBL = {}" the FBL won't appear in the DOM Panel in IE -var FBL = {}; - -( /** @scope s_lib @this FBL */ function() { -// ************************************************************************************************ - -// ************************************************************************************************ -// Constants - -var productionDir = "http://getfirebug.com/releases/lite/"; -var bookmarkletVersion = 4; - -// ************************************************************************************************ - -var reNotWhitespace = /[^\s]/; -var reSplitFile = /:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/; - -// Globals -this.reJavascript = /\s*javascript:\s*(.*)/; -this.reChrome = /chrome:\/\/([^\/]*)\//; -this.reFile = /file:\/\/([^\/]*)\//; - - -// ************************************************************************************************ -// properties - -var userAgent = navigator.userAgent.toLowerCase(); -this.isFirefox = /firefox/.test(userAgent); -this.isOpera = /opera/.test(userAgent); -this.isSafari = /webkit/.test(userAgent); -this.isIE = /msie/.test(userAgent) && !/opera/.test(userAgent); -this.isIE6 = /msie 6/i.test(navigator.appVersion); -this.browserVersion = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1]; -this.isIElt8 = this.isIE && (this.browserVersion-0 < 8); - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.NS = null; -this.pixelsPerInch = null; - - -// ************************************************************************************************ -// Namespaces - -var namespaces = []; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.ns = function(fn) -{ - var ns = {}; - namespaces.push(fn, ns); - return ns; -}; - -var FBTrace = null; - -this.initialize = function() -{ - // Firebug Lite is already running in persistent mode so we just quit - if (window.firebug && firebug.firebuglite || window.console && console.firebuglite) - return; - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // initialize environment - - // point the FBTrace object to the local variable - if (FBL.FBTrace) - FBTrace = FBL.FBTrace; - else - FBTrace = FBL.FBTrace = {}; - - // check if the actual window is a persisted chrome context - var isChromeContext = window.Firebug && typeof window.Firebug.SharedEnv == "object"; - - // chrome context of the persistent application - if (isChromeContext) - { - // TODO: xxxpedro persist - make a better synchronization - sharedEnv = window.Firebug.SharedEnv; - delete window.Firebug.SharedEnv; - - FBL.Env = sharedEnv; - FBL.Env.isChromeContext = true; - FBTrace.messageQueue = FBL.Env.traceMessageQueue; - } - // non-persistent application - else - { - FBL.NS = document.documentElement.namespaceURI; - FBL.Env.browser = window; - FBL.Env.destroy = destroyEnvironment; - - if (document.documentElement.getAttribute("debug") == "true") - FBL.Env.Options.startOpened = true; - - // find the URL location of the loaded application - findLocation(); - - // TODO: get preferences here... - // The problem is that we don't have the Firebug object yet, so we can't use - // Firebug.loadPrefs. We're using the Store module directly instead. - var prefs = FBL.Store.get("FirebugLite") || {}; - FBL.Env.DefaultOptions = FBL.Env.Options; - FBL.Env.Options = FBL.extend(FBL.Env.Options, prefs.options || {}); - - if (FBL.isFirefox && - typeof FBL.Env.browser.console == "object" && - FBL.Env.browser.console.firebug && - FBL.Env.Options.disableWhenFirebugActive) - return; - } - - // exposes the FBL to the global namespace when in debug mode - if (FBL.Env.isDebugMode) - { - FBL.Env.browser.FBL = FBL; - } - - // check browser compatibilities - this.isQuiksMode = FBL.Env.browser.document.compatMode == "BackCompat"; - this.isIEQuiksMode = this.isIE && this.isQuiksMode; - this.isIEStantandMode = this.isIE && !this.isQuiksMode; - - this.noFixedPosition = this.isIE6 || this.isIEQuiksMode; - - // after creating/synchronizing the environment, initialize the FBTrace module - if (FBL.Env.Options.enableTrace) FBTrace.initialize(); - - if (FBTrace.DBG_INITIALIZE && isChromeContext) FBTrace.sysout("FBL.initialize - persistent application", "initialize chrome context"); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // initialize namespaces - - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces BEGIN"); - - for (var i = 0; i < namespaces.length; i += 2) - { - var fn = namespaces[i]; - var ns = namespaces[i+1]; - fn.apply(ns); - } - - if (FBTrace.DBG_INITIALIZE) { - FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces END"); - FBTrace.sysout("FBL waitForDocument", "waiting document load"); - } - - FBL.Ajax.initialize(); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // finish environment initialization - FBL.Firebug.loadPrefs(); - - if (FBL.Env.Options.enablePersistent) - { - // TODO: xxxpedro persist - make a better synchronization - if (isChromeContext) - { - FBL.FirebugChrome.clone(FBL.Env.FirebugChrome); - } - else - { - FBL.Env.FirebugChrome = FBL.FirebugChrome; - FBL.Env.traceMessageQueue = FBTrace.messageQueue; - } - } - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // wait document load - - waitForDocument(); -}; - -var waitForDocument = function waitForDocument() -{ - // document.body not available in XML+XSL documents in Firefox - var doc = FBL.Env.browser.document; - var body = doc.getElementsByTagName("body")[0]; - - if (body) - { - calculatePixelsPerInch(doc, body); - onDocumentLoad(); - } - else - setTimeout(waitForDocument, 50); -}; - -var onDocumentLoad = function onDocumentLoad() -{ - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL onDocumentLoad", "document loaded"); - - // fix IE6 problem with cache of background images, causing a lot of flickering - if (FBL.isIE6) - fixIE6BackgroundImageCache(); - - // chrome context of the persistent application - if (FBL.Env.Options.enablePersistent && FBL.Env.isChromeContext) - { - // finally, start the application in the chrome context - FBL.Firebug.initialize(); - - // if is not development mode, remove the shared environment cache object - // used to synchronize the both persistent contexts - if (!FBL.Env.isDevelopmentMode) - { - sharedEnv.destroy(); - sharedEnv = null; - } - } - // non-persistent application - else - { - FBL.FirebugChrome.create(); - } -}; - -// ************************************************************************************************ -// Env - -var sharedEnv; - -this.Env = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Env Options (will be transported to Firebug options) - Options: - { - saveCookies: true, - - saveWindowPosition: false, - saveCommandLineHistory: false, - - startOpened: false, - startInNewWindow: false, - showIconWhenHidden: true, - - overrideConsole: true, - ignoreFirebugElements: true, - disableWhenFirebugActive: true, - - disableXHRListener: false, - disableResourceFetching: false, - - enableTrace: false, - enablePersistent: false - - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Library location - Location: - { - sourceDir: null, - baseDir: null, - skinDir: null, - skin: null, - app: null - }, - - skin: "xp", - useLocalSkin: false, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Env states - isDevelopmentMode: false, - isDebugMode: false, - isChromeContext: false, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Env references - browser: null, - chrome: null -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var destroyEnvironment = function destroyEnvironment() -{ - setTimeout(function() - { - FBL = null; - }, 100); -}; - -// ************************************************************************************************ -// Library location - -var findLocation = function findLocation() -{ - var reFirebugFile = /(firebug-lite(?:-\w+)?(?:\.js|\.jgz))(?:#(.+))?$/; - var reGetFirebugSite = /(?:http|https):\/\/getfirebug.com\//; - var isGetFirebugSite; - - var rePath = /^(.*\/)/; - var reProtocol = /^\w+:\/\//; - var path = null; - var doc = document; - - // Firebug Lite 1.3.0 bookmarklet identification - var script = doc.getElementById("FirebugLite"); - - var scriptSrc; - var hasSrcAttribute = true; - - // If the script was loaded via bookmarklet, we already have the script tag - if (script) - { - scriptSrc = script.src; - file = reFirebugFile.exec(scriptSrc); - - var version = script.getAttribute("FirebugLite"); - var number = version ? parseInt(version) : 0; - - if (!version || !number || number < bookmarkletVersion) - { - FBL.Env.bookmarkletOutdated = true; - } - } - // otherwise we must search for the correct script tag - else - { - for(var i=0, s=doc.getElementsByTagName("script"), si; si=s[i]; i++) - { - var file = null; - if ( si.nodeName.toLowerCase() == "script" ) - { - if (file = reFirebugFile.exec(si.getAttribute("firebugSrc"))) - { - scriptSrc = si.getAttribute("firebugSrc"); - hasSrcAttribute = false; - } - else if (file = reFirebugFile.exec(si.src)) - { - scriptSrc = si.src; - } - else - continue; - - script = si; - break; - } - } - } - - // mark the script tag to be ignored by Firebug Lite - if (script) - script.firebugIgnore = true; - - if (file) - { - var fileName = file[1]; - var fileOptions = file[2]; - - // absolute path - if (reProtocol.test(scriptSrc)) { - path = rePath.exec(scriptSrc)[1]; - - } - // relative path - else - { - var r = rePath.exec(scriptSrc); - var src = r ? r[1] : scriptSrc; - var backDir = /^((?:\.\.\/)+)(.*)/.exec(src); - var reLastDir = /^(.*\/)[^\/]+\/$/; - path = rePath.exec(location.href)[1]; - - // "../some/path" - if (backDir) - { - var j = backDir[1].length/3; - var p; - while (j-- > 0) - path = reLastDir.exec(path)[1]; - - path += backDir[2]; - } - - else if(src.indexOf("/") != -1) - { - // "./some/path" - if(/^\.\/./.test(src)) - { - path += src.substring(2); - } - // "/some/path" - else if(/^\/./.test(src)) - { - var domain = /^(\w+:\/\/[^\/]+)/.exec(path); - path = domain[1] + src; - } - // "some/path" - else - { - path += src; - } - } - } - } - - FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome"; - if (FBL.Env.isChromeExtension) - { - path = productionDir; - FBL.Env.bookmarkletOutdated = false; - script = {innerHTML: "{showIconWhenHidden:false}"}; - } - - isGetFirebugSite = reGetFirebugSite.test(path); - - if (isGetFirebugSite && path.indexOf("/releases/lite/") == -1) - { - // See Issue 4587 - If we are loading the script from getfirebug.com shortcut, like - // https://getfirebug.com/firebug-lite.js, then we must manually add the full path, - // otherwise the Env.Location will hold the wrong path, which will in turn lead to - // undesirable effects like the problem in Issue 4587 - path += "releases/lite/" + (fileName == "firebug-lite-beta.js" ? "beta/" : "latest/"); - } - - var m = path && path.match(/([^\/]+)\/$/) || null; - - if (path && m) - { - var Env = FBL.Env; - - // Always use the local skin when running in the same domain - // See Issue 3554: Firebug Lite should use local images when loaded locally - Env.useLocalSkin = path.indexOf(location.protocol + "//" + location.host + "/") == 0 && - // but we cannot use the locan skin when loaded from getfirebug.com, otherwise - // the bookmarklet won't work when visiting getfirebug.com - !isGetFirebugSite; - - // detecting development and debug modes via file name - if (fileName == "firebug-lite-dev.js") - { - Env.isDevelopmentMode = true; - Env.isDebugMode = true; - } - else if (fileName == "firebug-lite-debug.js") - { - Env.isDebugMode = true; - } - - // process the - if (Env.browser.document.documentElement.getAttribute("debug") == "true") - { - Env.Options.startOpened = true; - } - - // process the Script URL Options - if (fileOptions) - { - var options = fileOptions.split(","); - - for (var i = 0, length = options.length; i < length; i++) - { - var option = options[i]; - var name, value; - - if (option.indexOf("=") != -1) - { - var parts = option.split("="); - name = parts[0]; - value = eval(unescape(parts[1])); - } - else - { - name = option; - value = true; - } - - if (name == "debug") - { - Env.isDebugMode = !!value; - } - else if (name in Env.Options) - { - Env.Options[name] = value; - } - else - { - Env[name] = value; - } - } - } - - // process the Script JSON Options - if (hasSrcAttribute) - { - var innerOptions = FBL.trim(script.innerHTML); - if (innerOptions) - { - var innerOptionsObject = eval("(" + innerOptions + ")"); - - for (var name in innerOptionsObject) - { - var value = innerOptionsObject[name]; - - if (name == "debug") - { - Env.isDebugMode = !!value; - } - else if (name in Env.Options) - { - Env.Options[name] = value; - } - else - { - Env[name] = value; - } - } - } - } - - if (!Env.Options.saveCookies) - FBL.Store.remove("FirebugLite"); - - // process the Debug Mode - if (Env.isDebugMode) - { - Env.Options.startOpened = true; - Env.Options.enableTrace = true; - Env.Options.disableWhenFirebugActive = false; - } - - var loc = Env.Location; - var isProductionRelease = path.indexOf(productionDir) != -1; - - loc.sourceDir = path; - loc.baseDir = path.substr(0, path.length - m[1].length - 1); - loc.skinDir = (isProductionRelease ? path : loc.baseDir) + "skin/" + Env.skin + "/"; - loc.skin = loc.skinDir + "firebug.html"; - loc.app = path + fileName; - } - else - { - throw new Error("Firebug Error: Library path not found"); - } -}; - -// ************************************************************************************************ -// Basics - -this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments); -{ - var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); - return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); }; -}; - -this.bindFixed = function() // fn, thisObject, args => thisObject.fn(args); -{ - var args = cloneArray(arguments), fn = args.shift(), object = args.shift(); - return function() { return fn.apply(object, args); }; -}; - -this.extend = function(l, r) -{ - var newOb = {}; - for (var n in l) - newOb[n] = l[n]; - for (var n in r) - newOb[n] = r[n]; - return newOb; -}; - -this.descend = function(prototypeParent, childProperties) -{ - function protoSetter() {}; - protoSetter.prototype = prototypeParent; - var newOb = new protoSetter(); - for (var n in childProperties) - newOb[n] = childProperties[n]; - return newOb; -}; - -this.append = function(l, r) -{ - for (var n in r) - l[n] = r[n]; - - return l; -}; - -this.keys = function(map) // At least sometimes the keys will be on user-level window objects -{ - var keys = []; - try - { - for (var name in map) // enumeration is safe - keys.push(name); // name is string, safe - } - catch (exc) - { - // Sometimes we get exceptions trying to iterate properties - } - - return keys; // return is safe -}; - -this.values = function(map) -{ - var values = []; - try - { - for (var name in map) - { - try - { - values.push(map[name]); - } - catch (exc) - { - // Sometimes we get exceptions trying to access properties - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("lib.values FAILED ", exc); - } - - } - } - catch (exc) - { - // Sometimes we get exceptions trying to iterate properties - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("lib.values FAILED ", exc); - } - - return values; -}; - -this.remove = function(list, item) -{ - for (var i = 0; i < list.length; ++i) - { - if (list[i] == item) - { - list.splice(i, 1); - break; - } - } -}; - -this.sliceArray = function(array, index) -{ - var slice = []; - for (var i = index; i < array.length; ++i) - slice.push(array[i]); - - return slice; -}; - -function cloneArray(array, fn) -{ - var newArray = []; - - if (fn) - for (var i = 0; i < array.length; ++i) - newArray.push(fn(array[i])); - else - for (var i = 0; i < array.length; ++i) - newArray.push(array[i]); - - return newArray; -} - -function extendArray(array, array2) -{ - var newArray = []; - newArray.push.apply(newArray, array); - newArray.push.apply(newArray, array2); - return newArray; -} - -this.extendArray = extendArray; -this.cloneArray = cloneArray; - -function arrayInsert(array, index, other) -{ - for (var i = 0; i < other.length; ++i) - array.splice(i+index, 0, other[i]); - - return array; -} - -// ************************************************************************************************ - -this.createStyleSheet = function(doc, url) -{ - //TODO: xxxpedro - //var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style"); - var style = this.createElement("link"); - style.setAttribute("charset","utf-8"); - style.firebugIgnore = true; - style.setAttribute("rel", "stylesheet"); - style.setAttribute("type", "text/css"); - style.setAttribute("href", url); - - //TODO: xxxpedro - //style.innerHTML = this.getResource(url); - return style; -}; - -this.addStyleSheet = function(doc, style) -{ - var heads = doc.getElementsByTagName("head"); - if (heads.length) - heads[0].appendChild(style); - else - doc.documentElement.appendChild(style); -}; - -this.appendStylesheet = function(doc, uri) -{ - // Make sure the stylesheet is not appended twice. - if (this.$(uri, doc)) - return; - - var styleSheet = this.createStyleSheet(doc, uri); - styleSheet.setAttribute("id", uri); - this.addStyleSheet(doc, styleSheet); -}; - -this.addScript = function(doc, id, src) -{ - var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script"); - element.setAttribute("type", "text/javascript"); - element.setAttribute("id", id); - if (!FBTrace.DBG_CONSOLE) - FBL.unwrapObject(element).firebugIgnore = true; - - element.innerHTML = src; - if (doc.documentElement) - doc.documentElement.appendChild(element); - else - { - // See issue 1079, the svg test case gives this error - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("lib.addScript doc has no documentElement:", doc); - } - return element; -}; - - -// ************************************************************************************************ - -this.getStyle = this.isIE ? - function(el, name) - { - return el.currentStyle[name] || el.style[name] || undefined; - } - : - function(el, name) - { - return el.ownerDocument.defaultView.getComputedStyle(el,null)[name] - || el.style[name] || undefined; - }; - - -// ************************************************************************************************ -// Whitespace and Entity conversions - -var entityConversionLists = this.entityConversionLists = { - normal : { - whitespace : { - '\t' : '\u200c\u2192', - '\n' : '\u200c\u00b6', - '\r' : '\u200c\u00ac', - ' ' : '\u200c\u00b7' - } - }, - reverse : { - whitespace : { - ' ' : '\t', - ' ' : '\n', - '\u200c\u2192' : '\t', - '\u200c\u00b6' : '\n', - '\u200c\u00ac' : '\r', - '\u200c\u00b7' : ' ' - } - } -}; - -var normal = entityConversionLists.normal, - reverse = entityConversionLists.reverse; - -function addEntityMapToList(ccode, entity) -{ - var lists = Array.prototype.slice.call(arguments, 2), - len = lists.length, - ch = String.fromCharCode(ccode); - for (var i = 0; i < len; i++) - { - var list = lists[i]; - normal[list]=normal[list] || {}; - normal[list][ch] = '&' + entity + ';'; - reverse[list]=reverse[list] || {}; - reverse[list]['&' + entity + ';'] = ch; - } -}; - -var e = addEntityMapToList, - white = 'whitespace', - text = 'text', - attr = 'attributes', - css = 'css', - editor = 'editor'; - -e(0x0022, 'quot', attr, css); -e(0x0026, 'amp', attr, text, css); -e(0x0027, 'apos', css); -e(0x003c, 'lt', attr, text, css); -e(0x003e, 'gt', attr, text, css); -e(0xa9, 'copy', text, editor); -e(0xae, 'reg', text, editor); -e(0x2122, 'trade', text, editor); - -// See http://en.wikipedia.org/wiki/Dash -e(0x2012, '#8210', attr, text, editor); // figure dash -e(0x2013, 'ndash', attr, text, editor); // en dash -e(0x2014, 'mdash', attr, text, editor); // em dash -e(0x2015, '#8213', attr, text, editor); // horizontal bar - -e(0x00a0, 'nbsp', attr, text, white, editor); -e(0x2002, 'ensp', attr, text, white, editor); -e(0x2003, 'emsp', attr, text, white, editor); -e(0x2009, 'thinsp', attr, text, white, editor); -e(0x200c, 'zwnj', attr, text, white, editor); -e(0x200d, 'zwj', attr, text, white, editor); -e(0x200e, 'lrm', attr, text, white, editor); -e(0x200f, 'rlm', attr, text, white, editor); -e(0x200b, '#8203', attr, text, white, editor); // zero-width space (ZWSP) - -//************************************************************************************************ -// Entity escaping - -var entityConversionRegexes = { - normal : {}, - reverse : {} - }; - -var escapeEntitiesRegEx = { - normal : function(list) - { - var chars = []; - for ( var ch in list) - { - chars.push(ch); - } - return new RegExp('([' + chars.join('') + '])', 'gm'); - }, - reverse : function(list) - { - var chars = []; - for ( var ch in list) - { - chars.push(ch); - } - return new RegExp('(' + chars.join('|') + ')', 'gm'); - } -}; - -function getEscapeRegexp(direction, lists) -{ - var name = '', re; - var groups = [].concat(lists); - for (i = 0; i < groups.length; i++) - { - name += groups[i].group; - } - re = entityConversionRegexes[direction][name]; - if (!re) - { - var list = {}; - if (groups.length > 1) - { - for ( var i = 0; i < groups.length; i++) - { - var aList = entityConversionLists[direction][groups[i].group]; - for ( var item in aList) - list[item] = aList[item]; - } - } else if (groups.length==1) - { - list = entityConversionLists[direction][groups[0].group]; // faster for special case - } else { - list = {}; // perhaps should print out an error here? - } - re = entityConversionRegexes[direction][name] = escapeEntitiesRegEx[direction](list); - } - return re; -}; - -function createSimpleEscape(name, direction) -{ - return function(value) - { - var list = entityConversionLists[direction][name]; - return String(value).replace( - getEscapeRegexp(direction, { - group : name, - list : list - }), - function(ch) - { - return list[ch]; - } - ); - }; -}; - -function escapeGroupsForEntities(str, lists) -{ - lists = [].concat(lists); - var re = getEscapeRegexp('normal', lists), - split = String(str).split(re), - len = split.length, - results = [], - cur, r, i, ri = 0, l, list, last = ''; - if (!len) - return [ { - str : String(str), - group : '', - name : '' - } ]; - for (i = 0; i < len; i++) - { - cur = split[i]; - if (cur == '') - continue; - for (l = 0; l < lists.length; l++) - { - list = lists[l]; - r = entityConversionLists.normal[list.group][cur]; - // if (cur == ' ' && list.group == 'whitespace' && last == ' ') // only show for runs of more than one space - // r = ' '; - if (r) - { - results[ri] = { - 'str' : r, - 'class' : list['class'], - 'extra' : list.extra[cur] ? list['class'] - + list.extra[cur] : '' - }; - break; - } - } - // last=cur; - if (!r) - results[ri] = { - 'str' : cur, - 'class' : '', - 'extra' : '' - }; - ri++; - } - return results; -}; - -this.escapeGroupsForEntities = escapeGroupsForEntities; - - -function unescapeEntities(str, lists) -{ - var re = getEscapeRegexp('reverse', lists), - split = String(str).split(re), - len = split.length, - results = [], - cur, r, i, ri = 0, l, list; - if (!len) - return str; - lists = [].concat(lists); - for (i = 0; i < len; i++) - { - cur = split[i]; - if (cur == '') - continue; - for (l = 0; l < lists.length; l++) - { - list = lists[l]; - r = entityConversionLists.reverse[list.group][cur]; - if (r) - { - results[ri] = r; - break; - } - } - if (!r) - results[ri] = cur; - ri++; - } - return results.join('') || ''; -}; - - -// ************************************************************************************************ -// String escaping - -var escapeForTextNode = this.escapeForTextNode = createSimpleEscape('text', 'normal'); -var escapeForHtmlEditor = this.escapeForHtmlEditor = createSimpleEscape('editor', 'normal'); -var escapeForElementAttribute = this.escapeForElementAttribute = createSimpleEscape('attributes', 'normal'); -var escapeForCss = this.escapeForCss = createSimpleEscape('css', 'normal'); - -// deprecated compatibility functions -//this.deprecateEscapeHTML = createSimpleEscape('text', 'normal'); -//this.deprecatedUnescapeHTML = createSimpleEscape('text', 'reverse'); -//this.escapeHTML = deprecated("use appropriate escapeFor... function", this.deprecateEscapeHTML); -//this.unescapeHTML = deprecated("use appropriate unescapeFor... function", this.deprecatedUnescapeHTML); - -var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal'); - -var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse'); - -this.unescapeForTextNode = function(str) -{ - if (Firebug.showTextNodesWithWhitespace) - str = unescapeWhitespace(str); - if (!Firebug.showTextNodesWithEntities) - str = escapeForElementAttribute(str); - return str; -}; - -this.escapeNewLines = function(value) -{ - return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n"); -}; - -this.stripNewLines = function(value) -{ - return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value; -}; - -this.escapeJS = function(value) -{ - return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g"); -}; - -function escapeHTMLAttribute(value) -{ - function replaceChars(ch) - { - switch (ch) - { - case "&": - return "&"; - case "'": - return apos; - case '"': - return quot; - } - return "?"; - }; - var apos = "'", quot = """, around = '"'; - if( value.indexOf('"') == -1 ) { - quot = '"'; - apos = "'"; - } else if( value.indexOf("'") == -1 ) { - quot = '"'; - around = "'"; - } - return around + (String(value).replace(/[&'"]/g, replaceChars)) + around; -} - - -function escapeHTML(value) -{ - function replaceChars(ch) - { - switch (ch) - { - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - case "'": - return "'"; - case '"': - return """; - } - return "?"; - }; - return String(value).replace(/[<>&"']/g, replaceChars); -} - -this.escapeHTML = escapeHTML; - -this.cropString = function(text, limit) -{ - text = text + ""; - - if (!limit) - var halfLimit = 50; - else - var halfLimit = limit / 2; - - if (text.length > limit) - return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit)); - else - return this.escapeNewLines(text); -}; - -this.isWhitespace = function(text) -{ - return !reNotWhitespace.exec(text); -}; - -this.splitLines = function(text) -{ - var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg; - var lines; - if (text.match) - { - lines = text.match(reSplitLines2); - } - else - { - var str = text+""; - lines = str.match(reSplitLines2); - } - lines.pop(); - return lines; -}; - - -// ************************************************************************************************ - -this.safeToString = function(ob) -{ - if (this.isIE) - { - try - { - // FIXME: xxxpedro this is failing in IE for the global "external" object - return ob + ""; - } - catch(E) - { - FBTrace.sysout("Lib.safeToString() failed for ", ob); - return ""; - } - } - - try - { - if (ob && "toString" in ob && typeof ob.toString == "function") - return ob.toString(); - } - catch (exc) - { - // xxxpedro it is not safe to use ob+""? - return ob + ""; - ///return "[an object with no toString() function]"; - } -}; - -// ************************************************************************************************ - -this.hasProperties = function(ob) -{ - try - { - for (var name in ob) - return true; - } catch (exc) {} - return false; -}; - -// ************************************************************************************************ -// String Util - -var reTrim = /^\s+|\s+$/g; -this.trim = function(s) -{ - return s.replace(reTrim, ""); -}; - - -// ************************************************************************************************ -// Empty - -this.emptyFn = function(){}; - - - -// ************************************************************************************************ -// Visibility - -this.isVisible = function(elt) -{ - /* - if (elt instanceof XULElement) - { - //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n"); - return (!elt.hidden && !elt.collapsed); - } - /**/ - - return this.getStyle(elt, "visibility") != "hidden" && - ( elt.offsetWidth > 0 || elt.offsetHeight > 0 - || elt.tagName in invisibleTags - || elt.namespaceURI == "http://www.w3.org/2000/svg" - || elt.namespaceURI == "http://www.w3.org/1998/Math/MathML" ); -}; - -this.collapse = function(elt, collapsed) -{ - // IE6 doesn't support the [collapsed] CSS selector. IE7 does support the selector, - // but it is causing a bug (the element disappears when you set the "collapsed" - // attribute, but it doesn't appear when you remove the attribute. So, for those - // cases, we need to use the class attribute. - if (this.isIElt8) - { - if (collapsed) - this.setClass(elt, "collapsed"); - else - this.removeClass(elt, "collapsed"); - } - else - elt.setAttribute("collapsed", collapsed ? "true" : "false"); -}; - -this.obscure = function(elt, obscured) -{ - if (obscured) - this.setClass(elt, "obscured"); - else - this.removeClass(elt, "obscured"); -}; - -this.hide = function(elt, hidden) -{ - elt.style.visibility = hidden ? "hidden" : "visible"; -}; - -this.clearNode = function(node) -{ - var nodeName = " " + node.nodeName.toLowerCase() + " "; - var ignoreTags = " table tbody thead tfoot th tr td "; - - // IE can't use innerHTML of table elements - if (this.isIE && ignoreTags.indexOf(nodeName) != -1) - this.eraseNode(node); - else - node.innerHTML = ""; -}; - -this.eraseNode = function(node) -{ - while (node.lastChild) - node.removeChild(node.lastChild); -}; - -// ************************************************************************************************ -// Window iteration - -this.iterateWindows = function(win, handler) -{ - if (!win || !win.document) - return; - - handler(win); - - if (win == top || !win.frames) return; // XXXjjb hack for chromeBug - - for (var i = 0; i < win.frames.length; ++i) - { - var subWin = win.frames[i]; - if (subWin != win) - this.iterateWindows(subWin, handler); - } -}; - -this.getRootWindow = function(win) -{ - for (; win; win = win.parent) - { - if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window")) - return win; - } - return null; -}; - -// ************************************************************************************************ -// Graphics - -this.getClientOffset = function(elt) -{ - var addOffset = function addOffset(elt, coords, view) - { - var p = elt.offsetParent; - - ///var style = isIE ? elt.currentStyle : view.getComputedStyle(elt, ""); - var chrome = Firebug.chrome; - - if (elt.offsetLeft) - ///coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth); - coords.x += elt.offsetLeft + chrome.getMeasurementInPixels(elt, "borderLeft"); - if (elt.offsetTop) - ///coords.y += elt.offsetTop + parseInt(style.borderTopWidth); - coords.y += elt.offsetTop + chrome.getMeasurementInPixels(elt, "borderTop"); - - if (p) - { - if (p.nodeType == 1) - addOffset(p, coords, view); - } - else - { - var otherView = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; - // IE will fail when reading the frameElement property of a popup window. - // We don't need it anyway once it is outside the (popup) viewport, so we're - // ignoring the frameElement check when the window is a popup - if (!otherView.opener && otherView.frameElement) - addOffset(otherView.frameElement, coords, otherView); - } - }; - - var isIE = this.isIE; - var coords = {x: 0, y: 0}; - if (elt) - { - var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView; - addOffset(elt, coords, view); - } - - return coords; -}; - -this.getViewOffset = function(elt, singleFrame) -{ - function addOffset(elt, coords, view) - { - var p = elt.offsetParent; - coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0); - coords.y += elt.offsetTop - (p ? p.scrollTop : 0); - - if (p) - { - if (p.nodeType == 1) - { - var parentStyle = view.getComputedStyle(p, ""); - if (parentStyle.position != "static") - { - coords.x += parseInt(parentStyle.borderLeftWidth); - coords.y += parseInt(parentStyle.borderTopWidth); - - if (p.localName == "TABLE") - { - coords.x += parseInt(parentStyle.paddingLeft); - coords.y += parseInt(parentStyle.paddingTop); - } - else if (p.localName == "BODY") - { - var style = view.getComputedStyle(elt, ""); - coords.x += parseInt(style.marginLeft); - coords.y += parseInt(style.marginTop); - } - } - else if (p.localName == "BODY") - { - coords.x += parseInt(parentStyle.borderLeftWidth); - coords.y += parseInt(parentStyle.borderTopWidth); - } - - var parent = elt.parentNode; - while (p != parent) - { - coords.x -= parent.scrollLeft; - coords.y -= parent.scrollTop; - parent = parent.parentNode; - } - addOffset(p, coords, view); - } - } - else - { - if (elt.localName == "BODY") - { - var style = view.getComputedStyle(elt, ""); - coords.x += parseInt(style.borderLeftWidth); - coords.y += parseInt(style.borderTopWidth); - - var htmlStyle = view.getComputedStyle(elt.parentNode, ""); - coords.x -= parseInt(htmlStyle.paddingLeft); - coords.y -= parseInt(htmlStyle.paddingTop); - } - - if (elt.scrollLeft) - coords.x += elt.scrollLeft; - if (elt.scrollTop) - coords.y += elt.scrollTop; - - var win = elt.ownerDocument.defaultView; - if (win && (!singleFrame && win.frameElement)) - addOffset(win.frameElement, coords, win); - } - - } - - var coords = {x: 0, y: 0}; - if (elt) - addOffset(elt, coords, elt.ownerDocument.defaultView); - - return coords; -}; - -this.getLTRBWH = function(elt) -{ - var bcrect, - dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0}; - - if (elt) - { - bcrect = elt.getBoundingClientRect(); - dims.left = bcrect.left; - dims.top = bcrect.top; - dims.right = bcrect.right; - dims.bottom = bcrect.bottom; - - if(bcrect.width) - { - dims.width = bcrect.width; - dims.height = bcrect.height; - } - else - { - dims.width = dims.right - dims.left; - dims.height = dims.bottom - dims.top; - } - } - return dims; -}; - -this.applyBodyOffsets = function(elt, clientRect) -{ - var od = elt.ownerDocument; - if (!od.body) - return clientRect; - - var style = od.defaultView.getComputedStyle(od.body, null); - - var pos = style.getPropertyValue('position'); - if(pos === 'absolute' || pos === 'relative') - { - var borderLeft = parseInt(style.getPropertyValue('border-left-width').replace('px', ''),10) || 0; - var borderTop = parseInt(style.getPropertyValue('border-top-width').replace('px', ''),10) || 0; - var paddingLeft = parseInt(style.getPropertyValue('padding-left').replace('px', ''),10) || 0; - var paddingTop = parseInt(style.getPropertyValue('padding-top').replace('px', ''),10) || 0; - var marginLeft = parseInt(style.getPropertyValue('margin-left').replace('px', ''),10) || 0; - var marginTop = parseInt(style.getPropertyValue('margin-top').replace('px', ''),10) || 0; - - var offsetX = borderLeft + paddingLeft + marginLeft; - var offsetY = borderTop + paddingTop + marginTop; - - clientRect.left -= offsetX; - clientRect.top -= offsetY; - clientRect.right -= offsetX; - clientRect.bottom -= offsetY; - } - - return clientRect; -}; - -this.getOffsetSize = function(elt) -{ - return {width: elt.offsetWidth, height: elt.offsetHeight}; -}; - -this.getOverflowParent = function(element) -{ - for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent) - { - if (scrollParent.scrollHeight > scrollParent.offsetHeight) - return scrollParent; - } -}; - -this.isScrolledToBottom = function(element) -{ - var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight; - if (FBTrace.DBG_CONSOLE) - FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight +" onBottom:"+onBottom); - return onBottom; -}; - -this.scrollToBottom = function(element) -{ - element.scrollTop = element.scrollHeight; - - if (FBTrace.DBG_CONSOLE) - { - FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight); - if (element.scrollHeight == element.offsetHeight) - FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element, element); - } - - return (element.scrollTop == element.scrollHeight); -}; - -this.move = function(element, x, y) -{ - element.style.left = x + "px"; - element.style.top = y + "px"; -}; - -this.resize = function(element, w, h) -{ - element.style.width = w + "px"; - element.style.height = h + "px"; -}; - -this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int} -{ - if (!scrollBox) - scrollBox = this.getOverflowParent(element); - - if (!scrollBox) - return; - - var offset = this.getClientOffset(element); - - var topSpace = offset.y - scrollBox.scrollTop; - var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) - - (offset.y + element.offsetHeight); - - if (topSpace < 0 || bottomSpace < 0) - { - var split = (scrollBox.clientHeight/2); - var centerY = offset.y - split; - scrollBox.scrollTop = centerY; - topSpace = split; - bottomSpace = split - element.offsetHeight; - } - - return {before: Math.round((topSpace/element.offsetHeight) + 0.5), - after: Math.round((bottomSpace/element.offsetHeight) + 0.5) }; -}; - -this.scrollIntoCenterView = function(element, scrollBox, notX, notY) -{ - if (!element) - return; - - if (!scrollBox) - scrollBox = this.getOverflowParent(element); - - if (!scrollBox) - return; - - var offset = this.getClientOffset(element); - - if (!notY) - { - var topSpace = offset.y - scrollBox.scrollTop; - var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight) - - (offset.y + element.offsetHeight); - - if (topSpace < 0 || bottomSpace < 0) - { - var centerY = offset.y - (scrollBox.clientHeight/2); - scrollBox.scrollTop = centerY; - } - } - - if (!notX) - { - var leftSpace = offset.x - scrollBox.scrollLeft; - var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth) - - (offset.x + element.clientWidth); - - if (leftSpace < 0 || rightSpace < 0) - { - var centerX = offset.x - (scrollBox.clientWidth/2); - scrollBox.scrollLeft = centerX; - } - } - if (FBTrace.DBG_SOURCEFILES) - FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML); -}; - - -// ************************************************************************************************ -// CSS - -var cssKeywordMap = null; -var cssPropNames = null; -var cssColorNames = null; -var imageRules = null; - -this.getCSSKeywordsByProperty = function(propName) -{ - if (!cssKeywordMap) - { - cssKeywordMap = {}; - - for (var name in this.cssInfo) - { - var list = []; - - var types = this.cssInfo[name]; - for (var i = 0; i < types.length; ++i) - { - var keywords = this.cssKeywords[types[i]]; - if (keywords) - list.push.apply(list, keywords); - } - - cssKeywordMap[name] = list; - } - } - - return propName in cssKeywordMap ? cssKeywordMap[propName] : []; -}; - -this.getCSSPropertyNames = function() -{ - if (!cssPropNames) - { - cssPropNames = []; - - for (var name in this.cssInfo) - cssPropNames.push(name); - } - - return cssPropNames; -}; - -this.isColorKeyword = function(keyword) -{ - if (keyword == "transparent") - return false; - - if (!cssColorNames) - { - cssColorNames = []; - - var colors = this.cssKeywords["color"]; - for (var i = 0; i < colors.length; ++i) - cssColorNames.push(colors[i].toLowerCase()); - - var systemColors = this.cssKeywords["systemColor"]; - for (var i = 0; i < systemColors.length; ++i) - cssColorNames.push(systemColors[i].toLowerCase()); - } - - return cssColorNames.indexOf ? // Array.indexOf is not available in IE - cssColorNames.indexOf(keyword.toLowerCase()) != -1 : - (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1; -}; - -this.isImageRule = function(rule) -{ - if (!imageRules) - { - imageRules = []; - - for (var i in this.cssInfo) - { - var r = i.toLowerCase(); - var suffix = "image"; - if (r.match(suffix + "$") == suffix || r == "background") - imageRules.push(r); - } - } - - return imageRules.indexOf ? // Array.indexOf is not available in IE - imageRules.indexOf(rule.toLowerCase()) != -1 : - (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1; -}; - -this.copyTextStyles = function(fromNode, toNode, style) -{ - var view = this.isIE ? - fromNode.ownerDocument.parentWindow : - fromNode.ownerDocument.defaultView; - - if (view) - { - if (!style) - style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); - - toNode.style.fontFamily = style.fontFamily; - - // TODO: xxxpedro need to create a FBL.getComputedStyle() because IE - // returns wrong computed styles for inherited properties (like font-*) - // - // Also would be good to create a FBL.getStyle() - toNode.style.fontSize = style.fontSize; - toNode.style.fontWeight = style.fontWeight; - toNode.style.fontStyle = style.fontStyle; - - return style; - } -}; - -this.copyBoxStyles = function(fromNode, toNode, style) -{ - var view = this.isIE ? - fromNode.ownerDocument.parentWindow : - fromNode.ownerDocument.defaultView; - - if (view) - { - if (!style) - style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, ""); - - toNode.style.marginTop = style.marginTop; - toNode.style.marginRight = style.marginRight; - toNode.style.marginBottom = style.marginBottom; - toNode.style.marginLeft = style.marginLeft; - toNode.style.borderTopWidth = style.borderTopWidth; - toNode.style.borderRightWidth = style.borderRightWidth; - toNode.style.borderBottomWidth = style.borderBottomWidth; - toNode.style.borderLeftWidth = style.borderLeftWidth; - - return style; - } -}; - -this.readBoxStyles = function(style) -{ - var styleNames = { - "margin-top": "marginTop", "margin-right": "marginRight", - "margin-left": "marginLeft", "margin-bottom": "marginBottom", - "border-top-width": "borderTop", "border-right-width": "borderRight", - "border-left-width": "borderLeft", "border-bottom-width": "borderBottom", - "padding-top": "paddingTop", "padding-right": "paddingRight", - "padding-left": "paddingLeft", "padding-bottom": "paddingBottom", - "z-index": "zIndex" - }; - - var styles = {}; - for (var styleName in styleNames) - styles[styleNames[styleName]] = parseInt(style.getPropertyCSSValue(styleName).cssText) || 0; - if (FBTrace.DBG_INSPECT) - FBTrace.sysout("readBoxStyles ", styles); - return styles; -}; - -this.getBoxFromStyles = function(style, element) -{ - var args = this.readBoxStyles(style); - args.width = element.offsetWidth - - (args.paddingLeft+args.paddingRight+args.borderLeft+args.borderRight); - args.height = element.offsetHeight - - (args.paddingTop+args.paddingBottom+args.borderTop+args.borderBottom); - return args; -}; - -this.getElementCSSSelector = function(element) -{ - var label = element.localName.toLowerCase(); - if (element.id) - label += "#" + element.id; - if (element.hasAttribute("class")) - label += "." + element.getAttribute("class").split(" ")[0]; - - return label; -}; - -this.getURLForStyleSheet= function(styleSheet) -{ - //http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-StyleSheet. For inline style sheets, the value of this attribute is null. - return (styleSheet.href ? styleSheet.href : styleSheet.ownerNode.ownerDocument.URL); -}; - -this.getDocumentForStyleSheet = function(styleSheet) -{ - while (styleSheet.parentStyleSheet && !styleSheet.ownerNode) - { - styleSheet = styleSheet.parentStyleSheet; - } - if (styleSheet.ownerNode) - return styleSheet.ownerNode.ownerDocument; -}; - -/** - * Retrieves the instance number for a given style sheet. The instance number - * is sheet's index within the set of all other sheets whose URL is the same. - */ -this.getInstanceForStyleSheet = function(styleSheet, ownerDocument) -{ - // System URLs are always unique (or at least we are making this assumption) - if (FBL.isSystemStyleSheet(styleSheet)) - return 0; - - // ownerDocument is an optional hint for performance - if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: " + styleSheet.href + " " + styleSheet.media.mediaText + " " + (styleSheet.ownerNode && FBL.getElementXPath(styleSheet.ownerNode)), ownerDocument); - ownerDocument = ownerDocument || FBL.getDocumentForStyleSheet(styleSheet); - - var ret = 0, - styleSheets = ownerDocument.styleSheets, - href = styleSheet.href; - for (var i = 0; i < styleSheets.length; i++) - { - var curSheet = styleSheets[i]; - if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: compare href " + i + " " + curSheet.href + " " + curSheet.media.mediaText + " " + (curSheet.ownerNode && FBL.getElementXPath(curSheet.ownerNode))); - if (curSheet == styleSheet) - break; - if (curSheet.href == href) - ret++; - } - return ret; -}; - -// ************************************************************************************************ -// HTML and XML Serialization - - -var getElementType = this.getElementType = function(node) -{ - if (isElementXUL(node)) - return 'xul'; - else if (isElementSVG(node)) - return 'svg'; - else if (isElementMathML(node)) - return 'mathml'; - else if (isElementXHTML(node)) - return 'xhtml'; - else if (isElementHTML(node)) - return 'html'; -}; - -var getElementSimpleType = this.getElementSimpleType = function(node) -{ - if (isElementSVG(node)) - return 'svg'; - else if (isElementMathML(node)) - return 'mathml'; - else - return 'html'; -}; - -var isElementHTML = this.isElementHTML = function(node) -{ - return node.nodeName == node.nodeName.toUpperCase(); -}; - -var isElementXHTML = this.isElementXHTML = function(node) -{ - return node.nodeName == node.nodeName.toLowerCase(); -}; - -var isElementMathML = this.isElementMathML = function(node) -{ - return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML'; -}; - -var isElementSVG = this.isElementSVG = function(node) -{ - return node.namespaceURI == 'http://www.w3.org/2000/svg'; -}; - -var isElementXUL = this.isElementXUL = function(node) -{ - return node instanceof XULElement; -}; - -this.isSelfClosing = function(element) -{ - if (isElementSVG(element) || isElementMathML(element)) - return true; - var tag = element.localName.toLowerCase(); - return (this.selfClosingTags.hasOwnProperty(tag)); -}; - -this.getElementHTML = function(element) -{ - var self=this; - function toHTML(elt) - { - if (elt.nodeType == Node.ELEMENT_NODE) - { - if (unwrapObject(elt).firebugIgnore) - return; - - html.push('<', elt.nodeName.toLowerCase()); - - for (var i = 0; i < elt.attributes.length; ++i) - { - var attr = elt.attributes[i]; - - // Hide attributes set by Firebug - if (attr.localName.indexOf("firebug-") == 0) - continue; - - // MathML - if (attr.localName.indexOf("-moz-math") == 0) - { - // just hide for now - continue; - } - - html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); - } - - if (elt.firstChild) - { - html.push('>'); - - var pureText=true; - for (var child = element.firstChild; child; child = child.nextSibling) - pureText=pureText && (child.nodeType == Node.TEXT_NODE); - - if (pureText) - html.push(escapeForHtmlEditor(elt.textContent)); - else { - for (var child = elt.firstChild; child; child = child.nextSibling) - toHTML(child); - } - - html.push(''); - } - else if (isElementSVG(elt) || isElementMathML(elt)) - { - html.push('/>'); - } - else if (self.isSelfClosing(elt)) - { - html.push((isElementXHTML(elt))?'/>':'>'); - } - else - { - html.push('>'); - } - } - else if (elt.nodeType == Node.TEXT_NODE) - html.push(escapeForTextNode(elt.textContent)); - else if (elt.nodeType == Node.CDATA_SECTION_NODE) - html.push(''); - else if (elt.nodeType == Node.COMMENT_NODE) - html.push(''); - } - - var html = []; - toHTML(element); - return html.join(""); -}; - -this.getElementXML = function(element) -{ - function toXML(elt) - { - if (elt.nodeType == Node.ELEMENT_NODE) - { - if (unwrapObject(elt).firebugIgnore) - return; - - xml.push('<', elt.nodeName.toLowerCase()); - - for (var i = 0; i < elt.attributes.length; ++i) - { - var attr = elt.attributes[i]; - - // Hide attributes set by Firebug - if (attr.localName.indexOf("firebug-") == 0) - continue; - - // MathML - if (attr.localName.indexOf("-moz-math") == 0) - { - // just hide for now - continue; - } - - xml.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"'); - } - - if (elt.firstChild) - { - xml.push('>'); - - for (var child = elt.firstChild; child; child = child.nextSibling) - toXML(child); - - xml.push(''); - } - else - xml.push('/>'); - } - else if (elt.nodeType == Node.TEXT_NODE) - xml.push(elt.nodeValue); - else if (elt.nodeType == Node.CDATA_SECTION_NODE) - xml.push(''); - else if (elt.nodeType == Node.COMMENT_NODE) - xml.push(''); - } - - var xml = []; - toXML(element); - return xml.join(""); -}; - - -// ************************************************************************************************ -// CSS classes - -this.hasClass = function(node, name) // className, className, ... -{ - // TODO: xxxpedro when lib.hasClass is called with more than 2 arguments? - // this function can be optimized a lot if assumed 2 arguments only, - // which seems to be what happens 99% of the time - if (arguments.length == 2) - return (' '+node.className+' ').indexOf(' '+name+' ') != -1; - - if (!node || node.nodeType != 1) - return false; - else - { - for (var i=1; i= 0) - { - var size = name.length; - node.className = node.className.substr(0,index-1) + node.className.substr(index+size); - } - } -}; - -this.toggleClass = function(elt, name) -{ - if ((' '+elt.className+' ').indexOf(' '+name+' ') != -1) - ///if (this.hasClass(elt, name)) - this.removeClass(elt, name); - else - this.setClass(elt, name); -}; - -this.setClassTimed = function(elt, name, context, timeout) -{ - if (!timeout) - timeout = 1300; - - if (elt.__setClassTimeout) - context.clearTimeout(elt.__setClassTimeout); - else - this.setClass(elt, name); - - elt.__setClassTimeout = context.setTimeout(function() - { - delete elt.__setClassTimeout; - - FBL.removeClass(elt, name); - }, timeout); -}; - -this.cancelClassTimed = function(elt, name, context) -{ - if (elt.__setClassTimeout) - { - FBL.removeClass(elt, name); - context.clearTimeout(elt.__setClassTimeout); - delete elt.__setClassTimeout; - } -}; - - -// ************************************************************************************************ -// DOM queries - -this.$ = function(id, doc) -{ - if (doc) - return doc.getElementById(id); - else - { - return FBL.Firebug.chrome.document.getElementById(id); - } -}; - -this.$$ = function(selector, doc) -{ - if (doc || !FBL.Firebug.chrome) - return FBL.Firebug.Selector(selector, doc); - else - { - return FBL.Firebug.Selector(selector, FBL.Firebug.chrome.document); - } -}; - -this.getChildByClass = function(node) // ,classname, classname, classname... -{ - for (var i = 1; i < arguments.length; ++i) - { - var className = arguments[i]; - var child = node.firstChild; - node = null; - for (; child; child = child.nextSibling) - { - if (this.hasClass(child, className)) - { - node = child; - break; - } - } - } - - return node; -}; - -this.getAncestorByClass = function(node, className) -{ - for (var parent = node; parent; parent = parent.parentNode) - { - if (this.hasClass(parent, className)) - return parent; - } - - return null; -}; - - -this.getElementsByClass = function(node, className) -{ - var result = []; - - for (var child = node.firstChild; child; child = child.nextSibling) - { - if (this.hasClass(child, className)) - result.push(child); - } - - return result; -}; - -this.getElementByClass = function(node, className) // className, className, ... -{ - var args = cloneArray(arguments); args.splice(0, 1); - for (var child = node.firstChild; child; child = child.nextSibling) - { - var args1 = cloneArray(args); args1.unshift(child); - if (FBL.hasClass.apply(null, args1)) - return child; - else - { - var found = FBL.getElementByClass.apply(null, args1); - if (found) - return found; - } - } - - return null; -}; - -this.isAncestor = function(node, potentialAncestor) -{ - for (var parent = node; parent; parent = parent.parentNode) - { - if (parent == potentialAncestor) - return true; - } - - return false; -}; - -this.getNextElement = function(node) -{ - while (node && node.nodeType != 1) - node = node.nextSibling; - - return node; -}; - -this.getPreviousElement = function(node) -{ - while (node && node.nodeType != 1) - node = node.previousSibling; - - return node; -}; - -this.getBody = function(doc) -{ - if (doc.body) - return doc.body; - - var body = doc.getElementsByTagName("body")[0]; - if (body) - return body; - - return doc.firstChild; // For non-HTML docs -}; - -this.findNextDown = function(node, criteria) -{ - if (!node) - return null; - - for (var child = node.firstChild; child; child = child.nextSibling) - { - if (criteria(child)) - return child; - - var next = this.findNextDown(child, criteria); - if (next) - return next; - } -}; - -this.findPreviousUp = function(node, criteria) -{ - if (!node) - return null; - - for (var child = node.lastChild; child; child = child.previousSibling) - { - var next = this.findPreviousUp(child, criteria); - if (next) - return next; - - if (criteria(child)) - return child; - } -}; - -this.findNext = function(node, criteria, upOnly, maxRoot) -{ - if (!node) - return null; - - if (!upOnly) - { - var next = this.findNextDown(node, criteria); - if (next) - return next; - } - - for (var sib = node.nextSibling; sib; sib = sib.nextSibling) - { - if (criteria(sib)) - return sib; - - var next = this.findNextDown(sib, criteria); - if (next) - return next; - } - - if (node.parentNode && node.parentNode != maxRoot) - return this.findNext(node.parentNode, criteria, true); -}; - -this.findPrevious = function(node, criteria, downOnly, maxRoot) -{ - if (!node) - return null; - - for (var sib = node.previousSibling; sib; sib = sib.previousSibling) - { - var prev = this.findPreviousUp(sib, criteria); - if (prev) - return prev; - - if (criteria(sib)) - return sib; - } - - if (!downOnly) - { - var next = this.findPreviousUp(node, criteria); - if (next) - return next; - } - - if (node.parentNode && node.parentNode != maxRoot) - { - if (criteria(node.parentNode)) - return node.parentNode; - - return this.findPrevious(node.parentNode, criteria, true); - } -}; - -this.getNextByClass = function(root, state) -{ - var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; - return this.findNext(root, iter); -}; - -this.getPreviousByClass = function(root, state) -{ - var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); }; - return this.findPrevious(root, iter); -}; - -this.isElement = function(o) -{ - try { - return o && this.instanceOf(o, "Element"); - } - catch (ex) { - return false; - } -}; - - -// ************************************************************************************************ -// DOM Modification - -// TODO: xxxpedro use doc fragments in Context API -var appendFragment = null; - -this.appendInnerHTML = function(element, html, referenceElement) -{ - // if undefined, we must convert it to null otherwise it will throw an error in IE - // when executing element.insertBefore(firstChild, referenceElement) - referenceElement = referenceElement || null; - - var doc = element.ownerDocument; - - // doc.createRange not available in IE - if (doc.createRange) - { - var range = doc.createRange(); // a helper object - range.selectNodeContents(element); // the environment to interpret the html - - var fragment = range.createContextualFragment(html); // parse - var firstChild = fragment.firstChild; - element.insertBefore(fragment, referenceElement); - } - else - { - if (!appendFragment || appendFragment.ownerDocument != doc) - appendFragment = doc.createDocumentFragment(); - - var div = doc.createElement("div"); - div.innerHTML = html; - - var firstChild = div.firstChild; - while (div.firstChild) - appendFragment.appendChild(div.firstChild); - - element.insertBefore(appendFragment, referenceElement); - - div = null; - } - - return firstChild; -}; - - -// ************************************************************************************************ -// DOM creation - -this.createElement = function(tagName, properties) -{ - properties = properties || {}; - var doc = properties.document || FBL.Firebug.chrome.document; - - var element = doc.createElement(tagName); - - for(var name in properties) - { - if (name != "document") - { - element[name] = properties[name]; - } - } - - return element; -}; - -this.createGlobalElement = function(tagName, properties) -{ - properties = properties || {}; - var doc = FBL.Env.browser.document; - - var element = this.NS && doc.createElementNS ? - doc.createElementNS(FBL.NS, tagName) : - doc.createElement(tagName); - - for(var name in properties) - { - var propname = name; - if (FBL.isIE && name == "class") propname = "className"; - - if (name != "document") - { - element.setAttribute(propname, properties[name]); - } - } - - return element; -}; - -//************************************************************************************************ - -this.safeGetWindowLocation = function(window) -{ - try - { - if (window) - { - if (window.closed) - return "(window.closed)"; - if ("location" in window) - return window.location+""; - else - return "(no window.location)"; - } - else - return "(no context.window)"; - } - catch(exc) - { - if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ERRORS) - FBTrace.sysout("TabContext.getWindowLocation failed "+exc, exc); - FBTrace.sysout("TabContext.getWindowLocation failed window:", window); - return "(getWindowLocation: "+exc+")"; - } -}; - -// ************************************************************************************************ -// Events - -this.isLeftClick = function(event) -{ - return (this.isIE && event.type != "click" && event.type != "dblclick" ? - event.button == 1 : // IE "click" and "dblclick" button model - event.button == 0) && // others - this.noKeyModifiers(event); -}; - -this.isMiddleClick = function(event) -{ - return (this.isIE && event.type != "click" && event.type != "dblclick" ? - event.button == 4 : // IE "click" and "dblclick" button model - event.button == 1) && - this.noKeyModifiers(event); -}; - -this.isRightClick = function(event) -{ - return (this.isIE && event.type != "click" && event.type != "dblclick" ? - event.button == 2 : // IE "click" and "dblclick" button model - event.button == 2) && - this.noKeyModifiers(event); -}; - -this.noKeyModifiers = function(event) -{ - return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey; -}; - -this.isControlClick = function(event) -{ - return (this.isIE && event.type != "click" && event.type != "dblclick" ? - event.button == 1 : // IE "click" and "dblclick" button model - event.button == 0) && - this.isControl(event); -}; - -this.isShiftClick = function(event) -{ - return (this.isIE && event.type != "click" && event.type != "dblclick" ? - event.button == 1 : // IE "click" and "dblclick" button model - event.button == 0) && - this.isShift(event); -}; - -this.isControl = function(event) -{ - return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey; -}; - -this.isAlt = function(event) -{ - return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey; -}; - -this.isAltClick = function(event) -{ - return (this.isIE && event.type != "click" && event.type != "dblclick" ? - event.button == 1 : // IE "click" and "dblclick" button model - event.button == 0) && - this.isAlt(event); -}; - -this.isControlShift = function(event) -{ - return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey; -}; - -this.isShift = function(event) -{ - return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey; -}; - -this.addEvent = function(object, name, handler, useCapture) -{ - if (object.addEventListener) - object.addEventListener(name, handler, useCapture); - else - object.attachEvent("on"+name, handler); -}; - -this.removeEvent = function(object, name, handler, useCapture) -{ - try - { - if (object.removeEventListener) - object.removeEventListener(name, handler, useCapture); - else - object.detachEvent("on"+name, handler); - } - catch(e) - { - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("FBL.removeEvent error: ", object, name); - } -}; - -this.cancelEvent = function(e, preventDefault) -{ - if (!e) return; - - if (preventDefault) - { - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - } - - if (e.stopPropagation) - e.stopPropagation(); - else - e.cancelBubble = true; -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.addGlobalEvent = function(name, handler) -{ - var doc = this.Firebug.browser.document; - var frames = this.Firebug.browser.window.frames; - - this.addEvent(doc, name, handler); - - if (this.Firebug.chrome.type == "popup") - this.addEvent(this.Firebug.chrome.document, name, handler); - - for (var i = 0, frame; frame = frames[i]; i++) - { - try - { - this.addEvent(frame.document, name, handler); - } - catch(E) - { - // Avoid acess denied - } - } -}; - -this.removeGlobalEvent = function(name, handler) -{ - var doc = this.Firebug.browser.document; - var frames = this.Firebug.browser.window.frames; - - this.removeEvent(doc, name, handler); - - if (this.Firebug.chrome.type == "popup") - this.removeEvent(this.Firebug.chrome.document, name, handler); - - for (var i = 0, frame; frame = frames[i]; i++) - { - try - { - this.removeEvent(frame.document, name, handler); - } - catch(E) - { - // Avoid acess denied - } - } -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.dispatch = function(listeners, name, args) -{ - if (!listeners) return; - - try - {/**/ - if (typeof listeners.length != "undefined") - { - if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners"); - - for (var i = 0; i < listeners.length; ++i) - { - var listener = listeners[i]; - if ( listener[name] ) - listener[name].apply(listener, args); - } - } - else - { - if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to listeners of an object"); - - for (var prop in listeners) - { - var listener = listeners[prop]; - if ( listener[name] ) - listener[name].apply(listener, args); - } - } - } - catch (exc) - { - if (FBTrace.DBG_ERRORS) - { - FBTrace.sysout(" Exception in lib.dispatch "+ name, exc); - //FBTrace.dumpProperties(" Exception in lib.dispatch listener", listener); - } - } - /**/ -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var disableTextSelectionHandler = function(event) -{ - FBL.cancelEvent(event, true); - - return false; -}; - -this.disableTextSelection = function(e) -{ - if (typeof e.onselectstart != "undefined") // IE - this.addEvent(e, "selectstart", disableTextSelectionHandler); - - else // others - { - e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;"; - - // canceling the event in FF will prevent the menu popups to close when clicking over - // text-disabled elements - if (!this.isFirefox) - this.addEvent(e, "mousedown", disableTextSelectionHandler); - } - - e.style.cursor = "default"; -}; - -this.restoreTextSelection = function(e) -{ - if (typeof e.onselectstart != "undefined") // IE - this.removeEvent(e, "selectstart", disableTextSelectionHandler); - - else // others - { - e.style.cssText = "cursor: default;"; - - // canceling the event in FF will prevent the menu popups to close when clicking over - // text-disabled elements - if (!this.isFirefox) - this.removeEvent(e, "mousedown", disableTextSelectionHandler); - } -}; - -// ************************************************************************************************ -// DOM Events - -var eventTypes = -{ - composition: [ - "composition", - "compositionstart", - "compositionend" ], - contextmenu: [ - "contextmenu" ], - drag: [ - "dragenter", - "dragover", - "dragexit", - "dragdrop", - "draggesture" ], - focus: [ - "focus", - "blur" ], - form: [ - "submit", - "reset", - "change", - "select", - "input" ], - key: [ - "keydown", - "keyup", - "keypress" ], - load: [ - "load", - "beforeunload", - "unload", - "abort", - "error" ], - mouse: [ - "mousedown", - "mouseup", - "click", - "dblclick", - "mouseover", - "mouseout", - "mousemove" ], - mutation: [ - "DOMSubtreeModified", - "DOMNodeInserted", - "DOMNodeRemoved", - "DOMNodeRemovedFromDocument", - "DOMNodeInsertedIntoDocument", - "DOMAttrModified", - "DOMCharacterDataModified" ], - paint: [ - "paint", - "resize", - "scroll" ], - scroll: [ - "overflow", - "underflow", - "overflowchanged" ], - text: [ - "text" ], - ui: [ - "DOMActivate", - "DOMFocusIn", - "DOMFocusOut" ], - xul: [ - "popupshowing", - "popupshown", - "popuphiding", - "popuphidden", - "close", - "command", - "broadcast", - "commandupdate" ] -}; - -this.getEventFamily = function(eventType) -{ - if (!this.families) - { - this.families = {}; - - for (var family in eventTypes) - { - var types = eventTypes[family]; - for (var i = 0; i < types.length; ++i) - this.families[types[i]] = family; - } - } - - return this.families[eventType]; -}; - - -// ************************************************************************************************ -// URLs - -this.getFileName = function(url) -{ - var split = this.splitURLBase(url); - return split.name; -}; - -this.splitURLBase = function(url) -{ - if (this.isDataURL(url)) - return this.splitDataURL(url); - return this.splitURLTrue(url); -}; - -this.splitDataURL = function(url) -{ - var mark = url.indexOf(':', 3); - if (mark != 4) - return false; // the first 5 chars must be 'data:' - - var point = url.indexOf(',', mark+1); - if (point < mark) - return false; // syntax error - - var props = { encodedContent: url.substr(point+1) }; - - var metadataBuffer = url.substr(mark+1, point); - var metadata = metadataBuffer.split(';'); - for (var i = 0; i < metadata.length; i++) - { - var nv = metadata[i].split('='); - if (nv.length == 2) - props[nv[0]] = nv[1]; - } - - // Additional Firebug-specific properties - if (props.hasOwnProperty('fileName')) - { - var caller_URL = decodeURIComponent(props['fileName']); - var caller_split = this.splitURLTrue(caller_URL); - - if (props.hasOwnProperty('baseLineNumber')) // this means it's probably an eval() - { - props['path'] = caller_split.path; - props['line'] = props['baseLineNumber']; - var hint = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); - props['name'] = 'eval->'+hint; - } - else - { - props['name'] = caller_split.name; - props['path'] = caller_split.path; - } - } - else - { - if (!props.hasOwnProperty('path')) - props['path'] = "data:"; - if (!props.hasOwnProperty('name')) - props['name'] = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, ""); - } - - return props; -}; - -this.splitURLTrue = function(url) -{ - var m = reSplitFile.exec(url); - if (!m) - return {name: url, path: url}; - else if (!m[2]) - return {path: m[1], name: m[1]}; - else - return {path: m[1], name: m[2]+m[3]}; -}; - -this.getFileExtension = function(url) -{ - if (!url) - return null; - - // Remove query string from the URL if any. - var queryString = url.indexOf("?"); - if (queryString != -1) - url = url.substr(0, queryString); - - // Now get the file extension. - var lastDot = url.lastIndexOf("."); - return url.substr(lastDot+1); -}; - -this.isSystemURL = function(url) -{ - if (!url) return true; - if (url.length == 0) return true; - if (url[0] == 'h') return false; - if (url.substr(0, 9) == "resource:") - return true; - else if (url.substr(0, 16) == "chrome://firebug") - return true; - else if (url == "XPCSafeJSObjectWrapper.cpp") - return true; - else if (url.substr(0, 6) == "about:") - return true; - else if (url.indexOf("firebug-service.js") != -1) - return true; - else - return false; -}; - -this.isSystemPage = function(win) -{ - try - { - var doc = win.document; - if (!doc) - return false; - - // Detect pages for pretty printed XML - if ((doc.styleSheets.length && doc.styleSheets[0].href - == "chrome://global/content/xml/XMLPrettyPrint.css") - || (doc.styleSheets.length > 1 && doc.styleSheets[1].href - == "chrome://browser/skin/feeds/subscribe.css")) - return true; - - return FBL.isSystemURL(win.location.href); - } - catch (exc) - { - // Sometimes documents just aren't ready to be manipulated here, but don't let that - // gum up the works - ERROR("tabWatcher.isSystemPage document not ready:"+ exc); - return false; - } -}; - -this.isSystemStyleSheet = function(sheet) -{ - var href = sheet && sheet.href; - return href && FBL.isSystemURL(href); -}; - -this.getURIHost = function(uri) -{ - try - { - if (uri) - return uri.host; - else - return ""; - } - catch (exc) - { - return ""; - } -}; - -this.isLocalURL = function(url) -{ - if (url.substr(0, 5) == "file:") - return true; - else if (url.substr(0, 8) == "wyciwyg:") - return true; - else - return false; -}; - -this.isDataURL = function(url) -{ - return (url && url.substr(0,5) == "data:"); -}; - -this.getLocalPath = function(url) -{ - if (this.isLocalURL(url)) - { - var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); - var file = fileHandler.getFileFromURLSpec(url); - return file.path; - } -}; - -this.getURLFromLocalFile = function(file) -{ - var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler); - var URL = fileHandler.getURLSpecFromFile(file); - return URL; -}; - -this.getDataURLForContent = function(content, url) -{ - // data:text/javascript;fileName=x%2Cy.js;baseLineNumber=10, - var uri = "data:text/html;"; - uri += "fileName="+encodeURIComponent(url)+ ","; - uri += encodeURIComponent(content); - return uri; -}, - -this.getDomain = function(url) -{ - var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url); - return m ? m[1] : ""; -}; - -this.getURLPath = function(url) -{ - var m = /[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url); - return m ? m[1] : ""; -}; - -this.getPrettyDomain = function(url) -{ - var m = /[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url); - return m ? m[2] : ""; -}; - -this.absoluteURL = function(url, baseURL) -{ - return this.absoluteURLWithDots(url, baseURL).replace("/./", "/", "g"); -}; - -this.absoluteURLWithDots = function(url, baseURL) -{ - if (url[0] == "?") - return baseURL + url; - - var reURL = /(([^:]+:)\/{1,2}[^\/]*)(.*?)$/; - var m = reURL.exec(url); - if (m) - return url; - - var m = reURL.exec(baseURL); - if (!m) - return ""; - - var head = m[1]; - var tail = m[3]; - if (url.substr(0, 2) == "//") - return m[2] + url; - else if (url[0] == "/") - { - return head + url; - } - else if (tail[tail.length-1] == "/") - return baseURL + url; - else - { - var parts = tail.split("/"); - return head + parts.slice(0, parts.length-1).join("/") + "/" + url; - } -}; - -this.normalizeURL = function(url) // this gets called a lot, any performance improvement welcome -{ - if (!url) - return ""; - // Replace one or more characters that are not forward-slash followed by /.., by space. - if (url.length < 255) // guard against monsters. - { - // Replace one or more characters that are not forward-slash followed by /.., by space. - url = url.replace(/[^\/]+\/\.\.\//, "", "g"); - // Issue 1496, avoid # - url = url.replace(/#.*/,""); - // For some reason, JSDS reports file URLs like "file:/" instead of "file:///", so they - // don't match up with the URLs we get back from the DOM - url = url.replace(/file:\/([^\/])/g, "file:///$1"); - if (url.indexOf('chrome:')==0) - { - var m = reChromeCase.exec(url); // 1 is package name, 2 is path - if (m) - { - url = "chrome://"+m[1].toLowerCase()+"/"+m[2]; - } - } - } - return url; -}; - -this.denormalizeURL = function(url) -{ - return url.replace(/file:\/\/\//g, "file:/"); -}; - -this.parseURLParams = function(url) -{ - var q = url ? url.indexOf("?") : -1; - if (q == -1) - return []; - - var search = url.substr(q+1); - var h = search.lastIndexOf("#"); - if (h != -1) - search = search.substr(0, h); - - if (!search) - return []; - - return this.parseURLEncodedText(search); -}; - -this.parseURLEncodedText = function(text) -{ - var maxValueLength = 25000; - - var params = []; - - // Unescape '+' characters that are used to encode a space. - // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt - text = text.replace(/\+/g, " "); - - var args = text.split("&"); - for (var i = 0; i < args.length; ++i) - { - try { - var parts = args[i].split("="); - if (parts.length == 2) - { - if (parts[1].length > maxValueLength) - parts[1] = this.$STR("LargeData"); - - params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])}); - } - else - params.push({name: decodeURIComponent(parts[0]), value: ""}); - } - catch (e) - { - if (FBTrace.DBG_ERRORS) - { - FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); - FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); - } - } - } - - params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); - - return params; -}; - -// TODO: xxxpedro lib. why loops in domplate are requiring array in parameters -// as in response/request headers and get/post parameters in Net module? -this.parseURLParamsArray = function(url) -{ - var q = url ? url.indexOf("?") : -1; - if (q == -1) - return []; - - var search = url.substr(q+1); - var h = search.lastIndexOf("#"); - if (h != -1) - search = search.substr(0, h); - - if (!search) - return []; - - return this.parseURLEncodedTextArray(search); -}; - -this.parseURLEncodedTextArray = function(text) -{ - var maxValueLength = 25000; - - var params = []; - - // Unescape '+' characters that are used to encode a space. - // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt - text = text.replace(/\+/g, " "); - - var args = text.split("&"); - for (var i = 0; i < args.length; ++i) - { - try { - var parts = args[i].split("="); - if (parts.length == 2) - { - if (parts[1].length > maxValueLength) - parts[1] = this.$STR("LargeData"); - - params.push({name: decodeURIComponent(parts[0]), value: [decodeURIComponent(parts[1])]}); - } - else - params.push({name: decodeURIComponent(parts[0]), value: [""]}); - } - catch (e) - { - if (FBTrace.DBG_ERRORS) - { - FBTrace.sysout("parseURLEncodedText EXCEPTION ", e); - FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]); - } - } - } - - params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; }); - - return params; -}; - -this.reEncodeURL = function(file, text) -{ - var lines = text.split("\n"); - var params = this.parseURLEncodedText(lines[lines.length-1]); - - var args = []; - for (var i = 0; i < params.length; ++i) - args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value)); - - var url = file.href; - url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&"); - - return url; -}; - -this.getResource = function(aURL) -{ - try - { - var channel=ioService.newChannel(aURL,null,null); - var input=channel.open(); - return FBL.readFromStream(input); - } - catch (e) - { - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("lib.getResource FAILS for "+aURL, e); - } -}; - -this.parseJSONString = function(jsonString, originURL) -{ - // See if this is a Prototype style *-secure request. - var regex = new RegExp(/^\/\*-secure-([\s\S]*)\*\/\s*$/); - var matches = regex.exec(jsonString); - - if (matches) - { - jsonString = matches[1]; - - if (jsonString[0] == "\\" && jsonString[1] == "n") - jsonString = jsonString.substr(2); - - if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n") - jsonString = jsonString.substr(0, jsonString.length-2); - } - - if (jsonString.indexOf("&&&START&&&")) - { - regex = new RegExp(/&&&START&&& (.+) &&&END&&&/); - matches = regex.exec(jsonString); - if (matches) - jsonString = matches[1]; - } - - // throw on the extra parentheses - jsonString = "(" + jsonString + ")"; - - ///var s = Components.utils.Sandbox(originURL); - var jsonObject = null; - - try - { - ///jsonObject = Components.utils.evalInSandbox(jsonString, s); - - //jsonObject = Firebug.context.eval(jsonString); - jsonObject = Firebug.context.evaluate(jsonString, null, null, function(){return null;}); - } - catch(e) - { - /*** - if (e.message.indexOf("is not defined")) - { - var parts = e.message.split(" "); - s[parts[0]] = function(str){ return str; }; - try { - jsonObject = Components.utils.evalInSandbox(jsonString, s); - } catch(ex) { - if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) - FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); - return null; - } - } - else - {/**/ - if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER) - FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e); - return null; - ///} - } - - return jsonObject; -}; - -// ************************************************************************************************ - -this.objectToString = function(object) -{ - try - { - return object+""; - } - catch (exc) - { - return null; - } -}; - -// ************************************************************************************************ -// Input Caret Position - -this.setSelectionRange = function(input, start, length) -{ - if (input.createTextRange) - { - var range = input.createTextRange(); - range.moveStart("character", start); - range.moveEnd("character", length - input.value.length); - range.select(); - } - else if (input.setSelectionRange) - { - input.setSelectionRange(start, length); - input.focus(); - } -}; - -// ************************************************************************************************ -// Input Selection Start / Caret Position - -this.getInputSelectionStart = function(input) -{ - if (document.selection) - { - var range = input.ownerDocument.selection.createRange(); - var text = range.text; - - //console.log("range", range.text); - - // if there is a selection, find the start position - if (text) - { - return input.value.indexOf(text); - } - // if there is no selection, find the caret position - else - { - range.moveStart("character", -input.value.length); - - return range.text.length; - } - } - else if (typeof input.selectionStart != "undefined") - return input.selectionStart; - - return 0; -}; - -// ************************************************************************************************ -// Opera Tab Fix - -function onOperaTabBlur(e) -{ - if (this.lastKey == 9) - this.focus(); -}; - -function onOperaTabKeyDown(e) -{ - this.lastKey = e.keyCode; -}; - -function onOperaTabFocus(e) -{ - this.lastKey = null; -}; - -this.fixOperaTabKey = function(el) -{ - el.onfocus = onOperaTabFocus; - el.onblur = onOperaTabBlur; - el.onkeydown = onOperaTabKeyDown; -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.Property = function(object, name) -{ - this.object = object; - this.name = name; - - this.getObject = function() - { - return object[name]; - }; -}; - -this.ErrorCopy = function(message) -{ - this.message = message; -}; - -function EventCopy(event) -{ - // Because event objects are destroyed arbitrarily by Gecko, we must make a copy of them to - // represent them long term in the inspector. - for (var name in event) - { - try { - this[name] = event[name]; - } catch (exc) { } - } -} - -this.EventCopy = EventCopy; - - -// ************************************************************************************************ -// Type Checking - -var toString = Object.prototype.toString; -var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/; - -this.isArray = function(object) { - return toString.call(object) === '[object Array]'; -}; - -this.isFunction = function(object) { - if (!object) return false; - - try - { - // FIXME: xxxpedro this is failing in IE for the global "external" object - return toString.call(object) === "[object Function]" || - this.isIE && typeof object != "string" && reFunction.test(""+object); - } - catch (E) - { - FBTrace.sysout("Lib.isFunction() failed for ", object); - return false; - } -}; - - -// ************************************************************************************************ -// Instance Checking - -this.instanceOf = function(object, className) -{ - if (!object || typeof object != "object") - return false; - - // Try to use the native instanceof operator. We can only use it when we know - // exactly the window where the object is located at - if (object.ownerDocument) - { - // find the correct window of the object - var win = object.ownerDocument.defaultView || object.ownerDocument.parentWindow; - - // if the class is accessible in the window, uses the native instanceof operator - // if the instanceof evaluates to "true" we can assume it is a instance, but if it - // evaluates to "false" we must continue with the duck type detection below because - // the native object may be extended, thus breaking the instanceof result - // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended - if (className in win && object instanceof win[className]) - return true; - } - // If the object doesn't have the ownerDocument property, we'll try to look at - // the current context's window - else - { - // TODO: xxxpedro context - // Since we're not using yet a Firebug.context, we'll just use the top window - // (browser) as a reference - var win = Firebug.browser.window; - if (className in win) - return object instanceof win[className]; - } - - // get the duck type model from the cache - var cache = instanceCheckMap[className]; - if (!cache) - return false; - - // starts the hacky duck type detection - for(var n in cache) - { - var obj = cache[n]; - var type = typeof obj; - obj = type == "object" ? obj : [obj]; - - for(var name in obj) - { - // avoid problems with extended native objects - // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended - if (!obj.hasOwnProperty(name)) - continue; - - var value = obj[name]; - - if( n == "property" && !(value in object) || - n == "method" && !this.isFunction(object[value]) || - n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() ) - return false; - } - } - - return true; -}; - -var instanceCheckMap = -{ - // DuckTypeCheck: - // { - // property: ["window", "document"], - // method: "setTimeout", - // value: {nodeType: 1} - // }, - - Window: - { - property: ["window", "document"], - method: "setTimeout" - }, - - Document: - { - property: ["body", "cookie"], - method: "getElementById" - }, - - Node: - { - property: "ownerDocument", - method: "appendChild" - }, - - Element: - { - property: "tagName", - value: {nodeType: 1} - }, - - Location: - { - property: ["hostname", "protocol"], - method: "assign" - }, - - HTMLImageElement: - { - property: "useMap", - value: - { - nodeType: 1, - tagName: "img" - } - }, - - HTMLAnchorElement: - { - property: "hreflang", - value: - { - nodeType: 1, - tagName: "a" - } - }, - - HTMLInputElement: - { - property: "form", - value: - { - nodeType: 1, - tagName: "input" - } - }, - - HTMLButtonElement: - { - // ? - }, - - HTMLFormElement: - { - method: "submit", - value: - { - nodeType: 1, - tagName: "form" - } - }, - - HTMLBodyElement: - { - - }, - - HTMLHtmlElement: - { - - }, - - CSSStyleRule: - { - property: ["selectorText", "style"] - } - -}; - - -// ************************************************************************************************ -// DOM Constants - -/* - -Problems: - - - IE does not have window.Node, window.Element, etc - - for (var name in Node.prototype) return nothing on FF - -*/ - - -var domMemberMap2 = {}; - -var domMemberMap2Sandbox = null; - -var getDomMemberMap2 = function(name) -{ - if (!domMemberMap2Sandbox) - { - var doc = Firebug.chrome.document; - var frame = doc.createElement("iframe"); - - frame.id = "FirebugSandbox"; - frame.style.display = "none"; - frame.src = "about:blank"; - - doc.body.appendChild(frame); - - domMemberMap2Sandbox = frame.window || frame.contentWindow; - } - - var props = []; - - //var object = domMemberMap2Sandbox[name]; - //object = object.prototype || object; - - var object = null; - - if (name == "Window") - object = domMemberMap2Sandbox.window; - - else if (name == "Document") - object = domMemberMap2Sandbox.document; - - else if (name == "HTMLScriptElement") - object = domMemberMap2Sandbox.document.createElement("script"); - - else if (name == "HTMLAnchorElement") - object = domMemberMap2Sandbox.document.createElement("a"); - - else if (name.indexOf("Element") != -1) - { - object = domMemberMap2Sandbox.document.createElement("div"); - } - - if (object) - { - //object = object.prototype || object; - - //props = 'addEventListener,document,location,navigator,window'.split(','); - - for (var n in object) - props.push(n); - } - /**/ - - return props; - return extendArray(props, domMemberMap[name]); -}; - -// xxxpedro experimental get DOM members -this.getDOMMembers = function(object) -{ - if (!domMemberCache) - { - FBL.domMemberCache = domMemberCache = {}; - - for (var name in domMemberMap) - { - var builtins = getDomMemberMap2(name); - var cache = domMemberCache[name] = {}; - - /* - if (name.indexOf("Element") != -1) - { - this.append(cache, this.getDOMMembers("Node")); - this.append(cache, this.getDOMMembers("Element")); - } - /**/ - - for (var i = 0; i < builtins.length; ++i) - cache[builtins[i]] = i; - } - } - - try - { - if (this.instanceOf(object, "Window")) - { return domMemberCache.Window; } - else if (this.instanceOf(object, "Document") || this.instanceOf(object, "XMLDocument")) - { return domMemberCache.Document; } - else if (this.instanceOf(object, "Location")) - { return domMemberCache.Location; } - else if (this.instanceOf(object, "HTMLImageElement")) - { return domMemberCache.HTMLImageElement; } - else if (this.instanceOf(object, "HTMLAnchorElement")) - { return domMemberCache.HTMLAnchorElement; } - else if (this.instanceOf(object, "HTMLInputElement")) - { return domMemberCache.HTMLInputElement; } - else if (this.instanceOf(object, "HTMLButtonElement")) - { return domMemberCache.HTMLButtonElement; } - else if (this.instanceOf(object, "HTMLFormElement")) - { return domMemberCache.HTMLFormElement; } - else if (this.instanceOf(object, "HTMLBodyElement")) - { return domMemberCache.HTMLBodyElement; } - else if (this.instanceOf(object, "HTMLHtmlElement")) - { return domMemberCache.HTMLHtmlElement; } - else if (this.instanceOf(object, "HTMLScriptElement")) - { return domMemberCache.HTMLScriptElement; } - else if (this.instanceOf(object, "HTMLTableElement")) - { return domMemberCache.HTMLTableElement; } - else if (this.instanceOf(object, "HTMLTableRowElement")) - { return domMemberCache.HTMLTableRowElement; } - else if (this.instanceOf(object, "HTMLTableCellElement")) - { return domMemberCache.HTMLTableCellElement; } - else if (this.instanceOf(object, "HTMLIFrameElement")) - { return domMemberCache.HTMLIFrameElement; } - else if (this.instanceOf(object, "SVGSVGElement")) - { return domMemberCache.SVGSVGElement; } - else if (this.instanceOf(object, "SVGElement")) - { return domMemberCache.SVGElement; } - else if (this.instanceOf(object, "Element")) - { return domMemberCache.Element; } - else if (this.instanceOf(object, "Text") || this.instanceOf(object, "CDATASection")) - { return domMemberCache.Text; } - else if (this.instanceOf(object, "Attr")) - { return domMemberCache.Attr; } - else if (this.instanceOf(object, "Node")) - { return domMemberCache.Node; } - else if (this.instanceOf(object, "Event") || this.instanceOf(object, "EventCopy")) - { return domMemberCache.Event; } - else - return {}; - } - catch(E) - { - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("lib.getDOMMembers FAILED ", E); - - return {}; - } -}; - - -/* -this.getDOMMembers = function(object) -{ - if (!domMemberCache) - { - domMemberCache = {}; - - for (var name in domMemberMap) - { - var builtins = domMemberMap[name]; - var cache = domMemberCache[name] = {}; - - for (var i = 0; i < builtins.length; ++i) - cache[builtins[i]] = i; - } - } - - try - { - if (this.instanceOf(object, "Window")) - { return domMemberCache.Window; } - else if (object instanceof Document || object instanceof XMLDocument) - { return domMemberCache.Document; } - else if (object instanceof Location) - { return domMemberCache.Location; } - else if (object instanceof HTMLImageElement) - { return domMemberCache.HTMLImageElement; } - else if (object instanceof HTMLAnchorElement) - { return domMemberCache.HTMLAnchorElement; } - else if (object instanceof HTMLInputElement) - { return domMemberCache.HTMLInputElement; } - else if (object instanceof HTMLButtonElement) - { return domMemberCache.HTMLButtonElement; } - else if (object instanceof HTMLFormElement) - { return domMemberCache.HTMLFormElement; } - else if (object instanceof HTMLBodyElement) - { return domMemberCache.HTMLBodyElement; } - else if (object instanceof HTMLHtmlElement) - { return domMemberCache.HTMLHtmlElement; } - else if (object instanceof HTMLScriptElement) - { return domMemberCache.HTMLScriptElement; } - else if (object instanceof HTMLTableElement) - { return domMemberCache.HTMLTableElement; } - else if (object instanceof HTMLTableRowElement) - { return domMemberCache.HTMLTableRowElement; } - else if (object instanceof HTMLTableCellElement) - { return domMemberCache.HTMLTableCellElement; } - else if (object instanceof HTMLIFrameElement) - { return domMemberCache.HTMLIFrameElement; } - else if (object instanceof SVGSVGElement) - { return domMemberCache.SVGSVGElement; } - else if (object instanceof SVGElement) - { return domMemberCache.SVGElement; } - else if (object instanceof Element) - { return domMemberCache.Element; } - else if (object instanceof Text || object instanceof CDATASection) - { return domMemberCache.Text; } - else if (object instanceof Attr) - { return domMemberCache.Attr; } - else if (object instanceof Node) - { return domMemberCache.Node; } - else if (object instanceof Event || object instanceof EventCopy) - { return domMemberCache.Event; } - else - return {}; - } - catch(E) - { - return {}; - } -}; -/**/ - -this.isDOMMember = function(object, propName) -{ - var members = this.getDOMMembers(object); - return members && propName in members; -}; - -var domMemberCache = null; -var domMemberMap = {}; - -domMemberMap.Window = -[ - "document", - "frameElement", - - "innerWidth", - "innerHeight", - "outerWidth", - "outerHeight", - "screenX", - "screenY", - "pageXOffset", - "pageYOffset", - "scrollX", - "scrollY", - "scrollMaxX", - "scrollMaxY", - - "status", - "defaultStatus", - - "parent", - "opener", - "top", - "window", - "content", - "self", - - "location", - "history", - "frames", - "navigator", - "screen", - "menubar", - "toolbar", - "locationbar", - "personalbar", - "statusbar", - "directories", - "scrollbars", - "fullScreen", - "netscape", - "java", - "console", - "Components", - "controllers", - "closed", - "crypto", - "pkcs11", - - "name", - "property", - "length", - - "sessionStorage", - "globalStorage", - - "setTimeout", - "setInterval", - "clearTimeout", - "clearInterval", - "addEventListener", - "removeEventListener", - "dispatchEvent", - "getComputedStyle", - "captureEvents", - "releaseEvents", - "routeEvent", - "enableExternalCapture", - "disableExternalCapture", - "moveTo", - "moveBy", - "resizeTo", - "resizeBy", - "scroll", - "scrollTo", - "scrollBy", - "scrollByLines", - "scrollByPages", - "sizeToContent", - "setResizable", - "getSelection", - "open", - "openDialog", - "close", - "alert", - "confirm", - "prompt", - "dump", - "focus", - "blur", - "find", - "back", - "forward", - "home", - "stop", - "print", - "atob", - "btoa", - "updateCommands", - "XPCNativeWrapper", - "GeckoActiveXObject", - "applicationCache" // FF3 -]; - -domMemberMap.Location = -[ - "href", - "protocol", - "host", - "hostname", - "port", - "pathname", - "search", - "hash", - - "assign", - "reload", - "replace" -]; - -domMemberMap.Node = -[ - "id", - "className", - - "nodeType", - "tagName", - "nodeName", - "localName", - "prefix", - "namespaceURI", - "nodeValue", - - "ownerDocument", - "parentNode", - "offsetParent", - "nextSibling", - "previousSibling", - "firstChild", - "lastChild", - "childNodes", - "attributes", - - "dir", - "baseURI", - "textContent", - "innerHTML", - - "addEventListener", - "removeEventListener", - "dispatchEvent", - "cloneNode", - "appendChild", - "insertBefore", - "replaceChild", - "removeChild", - "compareDocumentPosition", - "hasAttributes", - "hasChildNodes", - "lookupNamespaceURI", - "lookupPrefix", - "normalize", - "isDefaultNamespace", - "isEqualNode", - "isSameNode", - "isSupported", - "getFeature", - "getUserData", - "setUserData" -]; - -domMemberMap.Document = extendArray(domMemberMap.Node, -[ - "documentElement", - "body", - "title", - "location", - "referrer", - "cookie", - "contentType", - "lastModified", - "characterSet", - "inputEncoding", - "xmlEncoding", - "xmlStandalone", - "xmlVersion", - "strictErrorChecking", - "documentURI", - "URL", - - "defaultView", - "doctype", - "implementation", - "styleSheets", - "images", - "links", - "forms", - "anchors", - "embeds", - "plugins", - "applets", - - "width", - "height", - - "designMode", - "compatMode", - "async", - "preferredStylesheetSet", - - "alinkColor", - "linkColor", - "vlinkColor", - "bgColor", - "fgColor", - "domain", - - "addEventListener", - "removeEventListener", - "dispatchEvent", - "captureEvents", - "releaseEvents", - "routeEvent", - "clear", - "open", - "close", - "execCommand", - "execCommandShowHelp", - "getElementsByName", - "getSelection", - "queryCommandEnabled", - "queryCommandIndeterm", - "queryCommandState", - "queryCommandSupported", - "queryCommandText", - "queryCommandValue", - "write", - "writeln", - "adoptNode", - "appendChild", - "removeChild", - "renameNode", - "cloneNode", - "compareDocumentPosition", - "createAttribute", - "createAttributeNS", - "createCDATASection", - "createComment", - "createDocumentFragment", - "createElement", - "createElementNS", - "createEntityReference", - "createEvent", - "createExpression", - "createNSResolver", - "createNodeIterator", - "createProcessingInstruction", - "createRange", - "createTextNode", - "createTreeWalker", - "domConfig", - "evaluate", - "evaluateFIXptr", - "evaluateXPointer", - "getAnonymousElementByAttribute", - "getAnonymousNodes", - "addBinding", - "removeBinding", - "getBindingParent", - "getBoxObjectFor", - "setBoxObjectFor", - "getElementById", - "getElementsByTagName", - "getElementsByTagNameNS", - "hasAttributes", - "hasChildNodes", - "importNode", - "insertBefore", - "isDefaultNamespace", - "isEqualNode", - "isSameNode", - "isSupported", - "load", - "loadBindingDocument", - "lookupNamespaceURI", - "lookupPrefix", - "normalize", - "normalizeDocument", - "getFeature", - "getUserData", - "setUserData" -]); - -domMemberMap.Element = extendArray(domMemberMap.Node, -[ - "clientWidth", - "clientHeight", - "offsetLeft", - "offsetTop", - "offsetWidth", - "offsetHeight", - "scrollLeft", - "scrollTop", - "scrollWidth", - "scrollHeight", - - "style", - - "tabIndex", - "title", - "lang", - "align", - "spellcheck", - - "addEventListener", - "removeEventListener", - "dispatchEvent", - "focus", - "blur", - "cloneNode", - "appendChild", - "insertBefore", - "replaceChild", - "removeChild", - "compareDocumentPosition", - "getElementsByTagName", - "getElementsByTagNameNS", - "getAttribute", - "getAttributeNS", - "getAttributeNode", - "getAttributeNodeNS", - "setAttribute", - "setAttributeNS", - "setAttributeNode", - "setAttributeNodeNS", - "removeAttribute", - "removeAttributeNS", - "removeAttributeNode", - "hasAttribute", - "hasAttributeNS", - "hasAttributes", - "hasChildNodes", - "lookupNamespaceURI", - "lookupPrefix", - "normalize", - "isDefaultNamespace", - "isEqualNode", - "isSameNode", - "isSupported", - "getFeature", - "getUserData", - "setUserData" -]); - -domMemberMap.SVGElement = extendArray(domMemberMap.Element, -[ - "x", - "y", - "width", - "height", - "rx", - "ry", - "transform", - "href", - - "ownerSVGElement", - "viewportElement", - "farthestViewportElement", - "nearestViewportElement", - - "getBBox", - "getCTM", - "getScreenCTM", - "getTransformToElement", - "getPresentationAttribute", - "preserveAspectRatio" -]); - -domMemberMap.SVGSVGElement = extendArray(domMemberMap.Element, -[ - "x", - "y", - "width", - "height", - "rx", - "ry", - "transform", - - "viewBox", - "viewport", - "currentView", - "useCurrentView", - "pixelUnitToMillimeterX", - "pixelUnitToMillimeterY", - "screenPixelToMillimeterX", - "screenPixelToMillimeterY", - "currentScale", - "currentTranslate", - "zoomAndPan", - - "ownerSVGElement", - "viewportElement", - "farthestViewportElement", - "nearestViewportElement", - "contentScriptType", - "contentStyleType", - - "getBBox", - "getCTM", - "getScreenCTM", - "getTransformToElement", - "getEnclosureList", - "getIntersectionList", - "getViewboxToViewportTransform", - "getPresentationAttribute", - "getElementById", - "checkEnclosure", - "checkIntersection", - "createSVGAngle", - "createSVGLength", - "createSVGMatrix", - "createSVGNumber", - "createSVGPoint", - "createSVGRect", - "createSVGString", - "createSVGTransform", - "createSVGTransformFromMatrix", - "deSelectAll", - "preserveAspectRatio", - "forceRedraw", - "suspendRedraw", - "unsuspendRedraw", - "unsuspendRedrawAll", - "getCurrentTime", - "setCurrentTime", - "animationsPaused", - "pauseAnimations", - "unpauseAnimations" -]); - -domMemberMap.HTMLImageElement = extendArray(domMemberMap.Element, -[ - "src", - "naturalWidth", - "naturalHeight", - "width", - "height", - "x", - "y", - "name", - "alt", - "longDesc", - "lowsrc", - "border", - "complete", - "hspace", - "vspace", - "isMap", - "useMap" -]); - -domMemberMap.HTMLAnchorElement = extendArray(domMemberMap.Element, -[ - "name", - "target", - "accessKey", - "href", - "protocol", - "host", - "hostname", - "port", - "pathname", - "search", - "hash", - "hreflang", - "coords", - "shape", - "text", - "type", - "rel", - "rev", - "charset" -]); - -domMemberMap.HTMLIFrameElement = extendArray(domMemberMap.Element, -[ - "contentDocument", - "contentWindow", - "frameBorder", - "height", - "longDesc", - "marginHeight", - "marginWidth", - "name", - "scrolling", - "src", - "width" -]); - -domMemberMap.HTMLTableElement = extendArray(domMemberMap.Element, -[ - "bgColor", - "border", - "caption", - "cellPadding", - "cellSpacing", - "frame", - "rows", - "rules", - "summary", - "tBodies", - "tFoot", - "tHead", - "width", - - "createCaption", - "createTFoot", - "createTHead", - "deleteCaption", - "deleteRow", - "deleteTFoot", - "deleteTHead", - "insertRow" -]); - -domMemberMap.HTMLTableRowElement = extendArray(domMemberMap.Element, -[ - "bgColor", - "cells", - "ch", - "chOff", - "rowIndex", - "sectionRowIndex", - "vAlign", - - "deleteCell", - "insertCell" -]); - -domMemberMap.HTMLTableCellElement = extendArray(domMemberMap.Element, -[ - "abbr", - "axis", - "bgColor", - "cellIndex", - "ch", - "chOff", - "colSpan", - "headers", - "height", - "noWrap", - "rowSpan", - "scope", - "vAlign", - "width" - -]); - -domMemberMap.HTMLScriptElement = extendArray(domMemberMap.Element, -[ - "src" -]); - -domMemberMap.HTMLButtonElement = extendArray(domMemberMap.Element, -[ - "accessKey", - "disabled", - "form", - "name", - "type", - "value", - - "click" -]); - -domMemberMap.HTMLInputElement = extendArray(domMemberMap.Element, -[ - "type", - "value", - "checked", - "accept", - "accessKey", - "alt", - "controllers", - "defaultChecked", - "defaultValue", - "disabled", - "form", - "maxLength", - "name", - "readOnly", - "selectionEnd", - "selectionStart", - "size", - "src", - "textLength", - "useMap", - - "click", - "select", - "setSelectionRange" -]); - -domMemberMap.HTMLFormElement = extendArray(domMemberMap.Element, -[ - "acceptCharset", - "action", - "author", - "elements", - "encoding", - "enctype", - "entry_id", - "length", - "method", - "name", - "post", - "target", - "text", - "url", - - "reset", - "submit" -]); - -domMemberMap.HTMLBodyElement = extendArray(domMemberMap.Element, -[ - "aLink", - "background", - "bgColor", - "link", - "text", - "vLink" -]); - -domMemberMap.HTMLHtmlElement = extendArray(domMemberMap.Element, -[ - "version" -]); - -domMemberMap.Text = extendArray(domMemberMap.Node, -[ - "data", - "length", - - "appendData", - "deleteData", - "insertData", - "replaceData", - "splitText", - "substringData" -]); - -domMemberMap.Attr = extendArray(domMemberMap.Node, -[ - "name", - "value", - "specified", - "ownerElement" -]); - -domMemberMap.Event = -[ - "type", - "target", - "currentTarget", - "originalTarget", - "explicitOriginalTarget", - "relatedTarget", - "rangeParent", - "rangeOffset", - "view", - - "keyCode", - "charCode", - "screenX", - "screenY", - "clientX", - "clientY", - "layerX", - "layerY", - "pageX", - "pageY", - - "detail", - "button", - "which", - "ctrlKey", - "shiftKey", - "altKey", - "metaKey", - - "eventPhase", - "timeStamp", - "bubbles", - "cancelable", - "cancelBubble", - - "isTrusted", - "isChar", - - "getPreventDefault", - "initEvent", - "initMouseEvent", - "initKeyEvent", - "initUIEvent", - "preventBubble", - "preventCapture", - "preventDefault", - "stopPropagation" -]; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.domConstantMap = -{ - "ELEMENT_NODE": 1, - "ATTRIBUTE_NODE": 1, - "TEXT_NODE": 1, - "CDATA_SECTION_NODE": 1, - "ENTITY_REFERENCE_NODE": 1, - "ENTITY_NODE": 1, - "PROCESSING_INSTRUCTION_NODE": 1, - "COMMENT_NODE": 1, - "DOCUMENT_NODE": 1, - "DOCUMENT_TYPE_NODE": 1, - "DOCUMENT_FRAGMENT_NODE": 1, - "NOTATION_NODE": 1, - - "DOCUMENT_POSITION_DISCONNECTED": 1, - "DOCUMENT_POSITION_PRECEDING": 1, - "DOCUMENT_POSITION_FOLLOWING": 1, - "DOCUMENT_POSITION_CONTAINS": 1, - "DOCUMENT_POSITION_CONTAINED_BY": 1, - "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC": 1, - - "UNKNOWN_RULE": 1, - "STYLE_RULE": 1, - "CHARSET_RULE": 1, - "IMPORT_RULE": 1, - "MEDIA_RULE": 1, - "FONT_FACE_RULE": 1, - "PAGE_RULE": 1, - - "CAPTURING_PHASE": 1, - "AT_TARGET": 1, - "BUBBLING_PHASE": 1, - - "SCROLL_PAGE_UP": 1, - "SCROLL_PAGE_DOWN": 1, - - "MOUSEUP": 1, - "MOUSEDOWN": 1, - "MOUSEOVER": 1, - "MOUSEOUT": 1, - "MOUSEMOVE": 1, - "MOUSEDRAG": 1, - "CLICK": 1, - "DBLCLICK": 1, - "KEYDOWN": 1, - "KEYUP": 1, - "KEYPRESS": 1, - "DRAGDROP": 1, - "FOCUS": 1, - "BLUR": 1, - "SELECT": 1, - "CHANGE": 1, - "RESET": 1, - "SUBMIT": 1, - "SCROLL": 1, - "LOAD": 1, - "UNLOAD": 1, - "XFER_DONE": 1, - "ABORT": 1, - "ERROR": 1, - "LOCATE": 1, - "MOVE": 1, - "RESIZE": 1, - "FORWARD": 1, - "HELP": 1, - "BACK": 1, - "TEXT": 1, - - "ALT_MASK": 1, - "CONTROL_MASK": 1, - "SHIFT_MASK": 1, - "META_MASK": 1, - - "DOM_VK_TAB": 1, - "DOM_VK_PAGE_UP": 1, - "DOM_VK_PAGE_DOWN": 1, - "DOM_VK_UP": 1, - "DOM_VK_DOWN": 1, - "DOM_VK_LEFT": 1, - "DOM_VK_RIGHT": 1, - "DOM_VK_CANCEL": 1, - "DOM_VK_HELP": 1, - "DOM_VK_BACK_SPACE": 1, - "DOM_VK_CLEAR": 1, - "DOM_VK_RETURN": 1, - "DOM_VK_ENTER": 1, - "DOM_VK_SHIFT": 1, - "DOM_VK_CONTROL": 1, - "DOM_VK_ALT": 1, - "DOM_VK_PAUSE": 1, - "DOM_VK_CAPS_LOCK": 1, - "DOM_VK_ESCAPE": 1, - "DOM_VK_SPACE": 1, - "DOM_VK_END": 1, - "DOM_VK_HOME": 1, - "DOM_VK_PRINTSCREEN": 1, - "DOM_VK_INSERT": 1, - "DOM_VK_DELETE": 1, - "DOM_VK_0": 1, - "DOM_VK_1": 1, - "DOM_VK_2": 1, - "DOM_VK_3": 1, - "DOM_VK_4": 1, - "DOM_VK_5": 1, - "DOM_VK_6": 1, - "DOM_VK_7": 1, - "DOM_VK_8": 1, - "DOM_VK_9": 1, - "DOM_VK_SEMICOLON": 1, - "DOM_VK_EQUALS": 1, - "DOM_VK_A": 1, - "DOM_VK_B": 1, - "DOM_VK_C": 1, - "DOM_VK_D": 1, - "DOM_VK_E": 1, - "DOM_VK_F": 1, - "DOM_VK_G": 1, - "DOM_VK_H": 1, - "DOM_VK_I": 1, - "DOM_VK_J": 1, - "DOM_VK_K": 1, - "DOM_VK_L": 1, - "DOM_VK_M": 1, - "DOM_VK_N": 1, - "DOM_VK_O": 1, - "DOM_VK_P": 1, - "DOM_VK_Q": 1, - "DOM_VK_R": 1, - "DOM_VK_S": 1, - "DOM_VK_T": 1, - "DOM_VK_U": 1, - "DOM_VK_V": 1, - "DOM_VK_W": 1, - "DOM_VK_X": 1, - "DOM_VK_Y": 1, - "DOM_VK_Z": 1, - "DOM_VK_CONTEXT_MENU": 1, - "DOM_VK_NUMPAD0": 1, - "DOM_VK_NUMPAD1": 1, - "DOM_VK_NUMPAD2": 1, - "DOM_VK_NUMPAD3": 1, - "DOM_VK_NUMPAD4": 1, - "DOM_VK_NUMPAD5": 1, - "DOM_VK_NUMPAD6": 1, - "DOM_VK_NUMPAD7": 1, - "DOM_VK_NUMPAD8": 1, - "DOM_VK_NUMPAD9": 1, - "DOM_VK_MULTIPLY": 1, - "DOM_VK_ADD": 1, - "DOM_VK_SEPARATOR": 1, - "DOM_VK_SUBTRACT": 1, - "DOM_VK_DECIMAL": 1, - "DOM_VK_DIVIDE": 1, - "DOM_VK_F1": 1, - "DOM_VK_F2": 1, - "DOM_VK_F3": 1, - "DOM_VK_F4": 1, - "DOM_VK_F5": 1, - "DOM_VK_F6": 1, - "DOM_VK_F7": 1, - "DOM_VK_F8": 1, - "DOM_VK_F9": 1, - "DOM_VK_F10": 1, - "DOM_VK_F11": 1, - "DOM_VK_F12": 1, - "DOM_VK_F13": 1, - "DOM_VK_F14": 1, - "DOM_VK_F15": 1, - "DOM_VK_F16": 1, - "DOM_VK_F17": 1, - "DOM_VK_F18": 1, - "DOM_VK_F19": 1, - "DOM_VK_F20": 1, - "DOM_VK_F21": 1, - "DOM_VK_F22": 1, - "DOM_VK_F23": 1, - "DOM_VK_F24": 1, - "DOM_VK_NUM_LOCK": 1, - "DOM_VK_SCROLL_LOCK": 1, - "DOM_VK_COMMA": 1, - "DOM_VK_PERIOD": 1, - "DOM_VK_SLASH": 1, - "DOM_VK_BACK_QUOTE": 1, - "DOM_VK_OPEN_BRACKET": 1, - "DOM_VK_BACK_SLASH": 1, - "DOM_VK_CLOSE_BRACKET": 1, - "DOM_VK_QUOTE": 1, - "DOM_VK_META": 1, - - "SVG_ZOOMANDPAN_DISABLE": 1, - "SVG_ZOOMANDPAN_MAGNIFY": 1, - "SVG_ZOOMANDPAN_UNKNOWN": 1 -}; - -this.cssInfo = -{ - "background": ["bgRepeat", "bgAttachment", "bgPosition", "color", "systemColor", "none"], - "background-attachment": ["bgAttachment"], - "background-color": ["color", "systemColor"], - "background-image": ["none"], - "background-position": ["bgPosition"], - "background-repeat": ["bgRepeat"], - - "border": ["borderStyle", "thickness", "color", "systemColor", "none"], - "border-top": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], - "border-right": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], - "border-bottom": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], - "border-left": ["borderStyle", "borderCollapse", "color", "systemColor", "none"], - "border-collapse": ["borderCollapse"], - "border-color": ["color", "systemColor"], - "border-top-color": ["color", "systemColor"], - "border-right-color": ["color", "systemColor"], - "border-bottom-color": ["color", "systemColor"], - "border-left-color": ["color", "systemColor"], - "border-spacing": [], - "border-style": ["borderStyle"], - "border-top-style": ["borderStyle"], - "border-right-style": ["borderStyle"], - "border-bottom-style": ["borderStyle"], - "border-left-style": ["borderStyle"], - "border-width": ["thickness"], - "border-top-width": ["thickness"], - "border-right-width": ["thickness"], - "border-bottom-width": ["thickness"], - "border-left-width": ["thickness"], - - "bottom": ["auto"], - "caption-side": ["captionSide"], - "clear": ["clear", "none"], - "clip": ["auto"], - "color": ["color", "systemColor"], - "content": ["content"], - "counter-increment": ["none"], - "counter-reset": ["none"], - "cursor": ["cursor", "none"], - "direction": ["direction"], - "display": ["display", "none"], - "empty-cells": [], - "float": ["float", "none"], - "font": ["fontStyle", "fontVariant", "fontWeight", "fontFamily"], - - "font-family": ["fontFamily"], - "font-size": ["fontSize"], - "font-size-adjust": [], - "font-stretch": [], - "font-style": ["fontStyle"], - "font-variant": ["fontVariant"], - "font-weight": ["fontWeight"], - - "height": ["auto"], - "left": ["auto"], - "letter-spacing": [], - "line-height": [], - - "list-style": ["listStyleType", "listStylePosition", "none"], - "list-style-image": ["none"], - "list-style-position": ["listStylePosition"], - "list-style-type": ["listStyleType", "none"], - - "margin": [], - "margin-top": [], - "margin-right": [], - "margin-bottom": [], - "margin-left": [], - - "marker-offset": ["auto"], - "min-height": ["none"], - "max-height": ["none"], - "min-width": ["none"], - "max-width": ["none"], - - "outline": ["borderStyle", "color", "systemColor", "none"], - "outline-color": ["color", "systemColor"], - "outline-style": ["borderStyle"], - "outline-width": [], - - "overflow": ["overflow", "auto"], - "overflow-x": ["overflow", "auto"], - "overflow-y": ["overflow", "auto"], - - "padding": [], - "padding-top": [], - "padding-right": [], - "padding-bottom": [], - "padding-left": [], - - "position": ["position"], - "quotes": ["none"], - "right": ["auto"], - "table-layout": ["tableLayout", "auto"], - "text-align": ["textAlign"], - "text-decoration": ["textDecoration", "none"], - "text-indent": [], - "text-shadow": [], - "text-transform": ["textTransform", "none"], - "top": ["auto"], - "unicode-bidi": [], - "vertical-align": ["verticalAlign"], - "white-space": ["whiteSpace"], - "width": ["auto"], - "word-spacing": [], - "z-index": [], - - "-moz-appearance": ["mozAppearance"], - "-moz-border-radius": [], - "-moz-border-radius-bottomleft": [], - "-moz-border-radius-bottomright": [], - "-moz-border-radius-topleft": [], - "-moz-border-radius-topright": [], - "-moz-border-top-colors": ["color", "systemColor"], - "-moz-border-right-colors": ["color", "systemColor"], - "-moz-border-bottom-colors": ["color", "systemColor"], - "-moz-border-left-colors": ["color", "systemColor"], - "-moz-box-align": ["mozBoxAlign"], - "-moz-box-direction": ["mozBoxDirection"], - "-moz-box-flex": [], - "-moz-box-ordinal-group": [], - "-moz-box-orient": ["mozBoxOrient"], - "-moz-box-pack": ["mozBoxPack"], - "-moz-box-sizing": ["mozBoxSizing"], - "-moz-opacity": [], - "-moz-user-focus": ["userFocus", "none"], - "-moz-user-input": ["userInput"], - "-moz-user-modify": [], - "-moz-user-select": ["userSelect", "none"], - "-moz-background-clip": [], - "-moz-background-inline-policy": [], - "-moz-background-origin": [], - "-moz-binding": [], - "-moz-column-count": [], - "-moz-column-gap": [], - "-moz-column-width": [], - "-moz-image-region": [] -}; - -this.inheritedStyleNames = -{ - "border-collapse": 1, - "border-spacing": 1, - "border-style": 1, - "caption-side": 1, - "color": 1, - "cursor": 1, - "direction": 1, - "empty-cells": 1, - "font": 1, - "font-family": 1, - "font-size-adjust": 1, - "font-size": 1, - "font-style": 1, - "font-variant": 1, - "font-weight": 1, - "letter-spacing": 1, - "line-height": 1, - "list-style": 1, - "list-style-image": 1, - "list-style-position": 1, - "list-style-type": 1, - "quotes": 1, - "text-align": 1, - "text-decoration": 1, - "text-indent": 1, - "text-shadow": 1, - "text-transform": 1, - "white-space": 1, - "word-spacing": 1 -}; - -this.cssKeywords = -{ - "appearance": - [ - "button", - "button-small", - "checkbox", - "checkbox-container", - "checkbox-small", - "dialog", - "listbox", - "menuitem", - "menulist", - "menulist-button", - "menulist-textfield", - "menupopup", - "progressbar", - "radio", - "radio-container", - "radio-small", - "resizer", - "scrollbar", - "scrollbarbutton-down", - "scrollbarbutton-left", - "scrollbarbutton-right", - "scrollbarbutton-up", - "scrollbartrack-horizontal", - "scrollbartrack-vertical", - "separator", - "statusbar", - "tab", - "tab-left-edge", - "tabpanels", - "textfield", - "toolbar", - "toolbarbutton", - "toolbox", - "tooltip", - "treeheadercell", - "treeheadersortarrow", - "treeitem", - "treetwisty", - "treetwistyopen", - "treeview", - "window" - ], - - "systemColor": - [ - "ActiveBorder", - "ActiveCaption", - "AppWorkspace", - "Background", - "ButtonFace", - "ButtonHighlight", - "ButtonShadow", - "ButtonText", - "CaptionText", - "GrayText", - "Highlight", - "HighlightText", - "InactiveBorder", - "InactiveCaption", - "InactiveCaptionText", - "InfoBackground", - "InfoText", - "Menu", - "MenuText", - "Scrollbar", - "ThreeDDarkShadow", - "ThreeDFace", - "ThreeDHighlight", - "ThreeDLightShadow", - "ThreeDShadow", - "Window", - "WindowFrame", - "WindowText", - "-moz-field", - "-moz-fieldtext", - "-moz-workspace", - "-moz-visitedhyperlinktext", - "-moz-use-text-color" - ], - - "color": - [ - "AliceBlue", - "AntiqueWhite", - "Aqua", - "Aquamarine", - "Azure", - "Beige", - "Bisque", - "Black", - "BlanchedAlmond", - "Blue", - "BlueViolet", - "Brown", - "BurlyWood", - "CadetBlue", - "Chartreuse", - "Chocolate", - "Coral", - "CornflowerBlue", - "Cornsilk", - "Crimson", - "Cyan", - "DarkBlue", - "DarkCyan", - "DarkGoldenRod", - "DarkGray", - "DarkGreen", - "DarkKhaki", - "DarkMagenta", - "DarkOliveGreen", - "DarkOrange", - "DarkOrchid", - "DarkRed", - "DarkSalmon", - "DarkSeaGreen", - "DarkSlateBlue", - "DarkSlateGray", - "DarkTurquoise", - "DarkViolet", - "DeepPink", - "DarkSkyBlue", - "DimGray", - "DodgerBlue", - "Feldspar", - "FireBrick", - "FloralWhite", - "ForestGreen", - "Fuchsia", - "Gainsboro", - "GhostWhite", - "Gold", - "GoldenRod", - "Gray", - "Green", - "GreenYellow", - "HoneyDew", - "HotPink", - "IndianRed", - "Indigo", - "Ivory", - "Khaki", - "Lavender", - "LavenderBlush", - "LawnGreen", - "LemonChiffon", - "LightBlue", - "LightCoral", - "LightCyan", - "LightGoldenRodYellow", - "LightGrey", - "LightGreen", - "LightPink", - "LightSalmon", - "LightSeaGreen", - "LightSkyBlue", - "LightSlateBlue", - "LightSlateGray", - "LightSteelBlue", - "LightYellow", - "Lime", - "LimeGreen", - "Linen", - "Magenta", - "Maroon", - "MediumAquaMarine", - "MediumBlue", - "MediumOrchid", - "MediumPurple", - "MediumSeaGreen", - "MediumSlateBlue", - "MediumSpringGreen", - "MediumTurquoise", - "MediumVioletRed", - "MidnightBlue", - "MintCream", - "MistyRose", - "Moccasin", - "NavajoWhite", - "Navy", - "OldLace", - "Olive", - "OliveDrab", - "Orange", - "OrangeRed", - "Orchid", - "PaleGoldenRod", - "PaleGreen", - "PaleTurquoise", - "PaleVioletRed", - "PapayaWhip", - "PeachPuff", - "Peru", - "Pink", - "Plum", - "PowderBlue", - "Purple", - "Red", - "RosyBrown", - "RoyalBlue", - "SaddleBrown", - "Salmon", - "SandyBrown", - "SeaGreen", - "SeaShell", - "Sienna", - "Silver", - "SkyBlue", - "SlateBlue", - "SlateGray", - "Snow", - "SpringGreen", - "SteelBlue", - "Tan", - "Teal", - "Thistle", - "Tomato", - "Turquoise", - "Violet", - "VioletRed", - "Wheat", - "White", - "WhiteSmoke", - "Yellow", - "YellowGreen", - "transparent", - "invert" - ], - - "auto": - [ - "auto" - ], - - "none": - [ - "none" - ], - - "captionSide": - [ - "top", - "bottom", - "left", - "right" - ], - - "clear": - [ - "left", - "right", - "both" - ], - - "cursor": - [ - "auto", - "cell", - "context-menu", - "crosshair", - "default", - "help", - "pointer", - "progress", - "move", - "e-resize", - "all-scroll", - "ne-resize", - "nw-resize", - "n-resize", - "se-resize", - "sw-resize", - "s-resize", - "w-resize", - "ew-resize", - "ns-resize", - "nesw-resize", - "nwse-resize", - "col-resize", - "row-resize", - "text", - "vertical-text", - "wait", - "alias", - "copy", - "move", - "no-drop", - "not-allowed", - "-moz-alias", - "-moz-cell", - "-moz-copy", - "-moz-grab", - "-moz-grabbing", - "-moz-contextmenu", - "-moz-zoom-in", - "-moz-zoom-out", - "-moz-spinning" - ], - - "direction": - [ - "ltr", - "rtl" - ], - - "bgAttachment": - [ - "scroll", - "fixed" - ], - - "bgPosition": - [ - "top", - "center", - "bottom", - "left", - "right" - ], - - "bgRepeat": - [ - "repeat", - "repeat-x", - "repeat-y", - "no-repeat" - ], - - "borderStyle": - [ - "hidden", - "dotted", - "dashed", - "solid", - "double", - "groove", - "ridge", - "inset", - "outset", - "-moz-bg-inset", - "-moz-bg-outset", - "-moz-bg-solid" - ], - - "borderCollapse": - [ - "collapse", - "separate" - ], - - "overflow": - [ - "visible", - "hidden", - "scroll", - "-moz-scrollbars-horizontal", - "-moz-scrollbars-none", - "-moz-scrollbars-vertical" - ], - - "listStyleType": - [ - "disc", - "circle", - "square", - "decimal", - "decimal-leading-zero", - "lower-roman", - "upper-roman", - "lower-greek", - "lower-alpha", - "lower-latin", - "upper-alpha", - "upper-latin", - "hebrew", - "armenian", - "georgian", - "cjk-ideographic", - "hiragana", - "katakana", - "hiragana-iroha", - "katakana-iroha", - "inherit" - ], - - "listStylePosition": - [ - "inside", - "outside" - ], - - "content": - [ - "open-quote", - "close-quote", - "no-open-quote", - "no-close-quote", - "inherit" - ], - - "fontStyle": - [ - "normal", - "italic", - "oblique", - "inherit" - ], - - "fontVariant": - [ - "normal", - "small-caps", - "inherit" - ], - - "fontWeight": - [ - "normal", - "bold", - "bolder", - "lighter", - "inherit" - ], - - "fontSize": - [ - "xx-small", - "x-small", - "small", - "medium", - "large", - "x-large", - "xx-large", - "smaller", - "larger" - ], - - "fontFamily": - [ - "Arial", - "Comic Sans MS", - "Georgia", - "Tahoma", - "Verdana", - "Times New Roman", - "Trebuchet MS", - "Lucida Grande", - "Helvetica", - "serif", - "sans-serif", - "cursive", - "fantasy", - "monospace", - "caption", - "icon", - "menu", - "message-box", - "small-caption", - "status-bar", - "inherit" - ], - - "display": - [ - "block", - "inline", - "inline-block", - "list-item", - "marker", - "run-in", - "compact", - "table", - "inline-table", - "table-row-group", - "table-column", - "table-column-group", - "table-header-group", - "table-footer-group", - "table-row", - "table-cell", - "table-caption", - "-moz-box", - "-moz-compact", - "-moz-deck", - "-moz-grid", - "-moz-grid-group", - "-moz-grid-line", - "-moz-groupbox", - "-moz-inline-block", - "-moz-inline-box", - "-moz-inline-grid", - "-moz-inline-stack", - "-moz-inline-table", - "-moz-marker", - "-moz-popup", - "-moz-runin", - "-moz-stack" - ], - - "position": - [ - "static", - "relative", - "absolute", - "fixed", - "inherit" - ], - - "float": - [ - "left", - "right" - ], - - "textAlign": - [ - "left", - "right", - "center", - "justify" - ], - - "tableLayout": - [ - "fixed" - ], - - "textDecoration": - [ - "underline", - "overline", - "line-through", - "blink" - ], - - "textTransform": - [ - "capitalize", - "lowercase", - "uppercase", - "inherit" - ], - - "unicodeBidi": - [ - "normal", - "embed", - "bidi-override" - ], - - "whiteSpace": - [ - "normal", - "pre", - "nowrap" - ], - - "verticalAlign": - [ - "baseline", - "sub", - "super", - "top", - "text-top", - "middle", - "bottom", - "text-bottom", - "inherit" - ], - - "thickness": - [ - "thin", - "medium", - "thick" - ], - - "userFocus": - [ - "ignore", - "normal" - ], - - "userInput": - [ - "disabled", - "enabled" - ], - - "userSelect": - [ - "normal" - ], - - "mozBoxSizing": - [ - "content-box", - "padding-box", - "border-box" - ], - - "mozBoxAlign": - [ - "start", - "center", - "end", - "baseline", - "stretch" - ], - - "mozBoxDirection": - [ - "normal", - "reverse" - ], - - "mozBoxOrient": - [ - "horizontal", - "vertical" - ], - - "mozBoxPack": - [ - "start", - "center", - "end" - ] -}; - -this.nonEditableTags = -{ - "HTML": 1, - "HEAD": 1, - "html": 1, - "head": 1 -}; - -this.innerEditableTags = -{ - "BODY": 1, - "body": 1 -}; - -this.selfClosingTags = -{ // End tags for void elements are forbidden http://wiki.whatwg.org/wiki/HTML_vs._XHTML - "meta": 1, - "link": 1, - "area": 1, - "base": 1, - "col": 1, - "input": 1, - "img": 1, - "br": 1, - "hr": 1, - "param":1, - "embed":1 -}; - -var invisibleTags = this.invisibleTags = -{ - "HTML": 1, - "HEAD": 1, - "TITLE": 1, - "META": 1, - "LINK": 1, - "STYLE": 1, - "SCRIPT": 1, - "NOSCRIPT": 1, - "BR": 1, - "PARAM": 1, - "COL": 1, - - "html": 1, - "head": 1, - "title": 1, - "meta": 1, - "link": 1, - "style": 1, - "script": 1, - "noscript": 1, - "br": 1, - "param": 1, - "col": 1 - /* - "window": 1, - "browser": 1, - "frame": 1, - "tabbrowser": 1, - "WINDOW": 1, - "BROWSER": 1, - "FRAME": 1, - "TABBROWSER": 1, - */ -}; - - -if (typeof KeyEvent == "undefined") { - this.KeyEvent = { - DOM_VK_CANCEL: 3, - DOM_VK_HELP: 6, - DOM_VK_BACK_SPACE: 8, - DOM_VK_TAB: 9, - DOM_VK_CLEAR: 12, - DOM_VK_RETURN: 13, - DOM_VK_ENTER: 14, - DOM_VK_SHIFT: 16, - DOM_VK_CONTROL: 17, - DOM_VK_ALT: 18, - DOM_VK_PAUSE: 19, - DOM_VK_CAPS_LOCK: 20, - DOM_VK_ESCAPE: 27, - DOM_VK_SPACE: 32, - DOM_VK_PAGE_UP: 33, - DOM_VK_PAGE_DOWN: 34, - DOM_VK_END: 35, - DOM_VK_HOME: 36, - DOM_VK_LEFT: 37, - DOM_VK_UP: 38, - DOM_VK_RIGHT: 39, - DOM_VK_DOWN: 40, - DOM_VK_PRINTSCREEN: 44, - DOM_VK_INSERT: 45, - DOM_VK_DELETE: 46, - DOM_VK_0: 48, - DOM_VK_1: 49, - DOM_VK_2: 50, - DOM_VK_3: 51, - DOM_VK_4: 52, - DOM_VK_5: 53, - DOM_VK_6: 54, - DOM_VK_7: 55, - DOM_VK_8: 56, - DOM_VK_9: 57, - DOM_VK_SEMICOLON: 59, - DOM_VK_EQUALS: 61, - DOM_VK_A: 65, - DOM_VK_B: 66, - DOM_VK_C: 67, - DOM_VK_D: 68, - DOM_VK_E: 69, - DOM_VK_F: 70, - DOM_VK_G: 71, - DOM_VK_H: 72, - DOM_VK_I: 73, - DOM_VK_J: 74, - DOM_VK_K: 75, - DOM_VK_L: 76, - DOM_VK_M: 77, - DOM_VK_N: 78, - DOM_VK_O: 79, - DOM_VK_P: 80, - DOM_VK_Q: 81, - DOM_VK_R: 82, - DOM_VK_S: 83, - DOM_VK_T: 84, - DOM_VK_U: 85, - DOM_VK_V: 86, - DOM_VK_W: 87, - DOM_VK_X: 88, - DOM_VK_Y: 89, - DOM_VK_Z: 90, - DOM_VK_CONTEXT_MENU: 93, - DOM_VK_NUMPAD0: 96, - DOM_VK_NUMPAD1: 97, - DOM_VK_NUMPAD2: 98, - DOM_VK_NUMPAD3: 99, - DOM_VK_NUMPAD4: 100, - DOM_VK_NUMPAD5: 101, - DOM_VK_NUMPAD6: 102, - DOM_VK_NUMPAD7: 103, - DOM_VK_NUMPAD8: 104, - DOM_VK_NUMPAD9: 105, - DOM_VK_MULTIPLY: 106, - DOM_VK_ADD: 107, - DOM_VK_SEPARATOR: 108, - DOM_VK_SUBTRACT: 109, - DOM_VK_DECIMAL: 110, - DOM_VK_DIVIDE: 111, - DOM_VK_F1: 112, - DOM_VK_F2: 113, - DOM_VK_F3: 114, - DOM_VK_F4: 115, - DOM_VK_F5: 116, - DOM_VK_F6: 117, - DOM_VK_F7: 118, - DOM_VK_F8: 119, - DOM_VK_F9: 120, - DOM_VK_F10: 121, - DOM_VK_F11: 122, - DOM_VK_F12: 123, - DOM_VK_F13: 124, - DOM_VK_F14: 125, - DOM_VK_F15: 126, - DOM_VK_F16: 127, - DOM_VK_F17: 128, - DOM_VK_F18: 129, - DOM_VK_F19: 130, - DOM_VK_F20: 131, - DOM_VK_F21: 132, - DOM_VK_F22: 133, - DOM_VK_F23: 134, - DOM_VK_F24: 135, - DOM_VK_NUM_LOCK: 144, - DOM_VK_SCROLL_LOCK: 145, - DOM_VK_COMMA: 188, - DOM_VK_PERIOD: 190, - DOM_VK_SLASH: 191, - DOM_VK_BACK_QUOTE: 192, - DOM_VK_OPEN_BRACKET: 219, - DOM_VK_BACK_SLASH: 220, - DOM_VK_CLOSE_BRACKET: 221, - DOM_VK_QUOTE: 222, - DOM_VK_META: 224 - }; -} - - -// ************************************************************************************************ -// Ajax - -/** - * @namespace - */ -this.Ajax = -{ - - requests: [], - transport: null, - states: ["Uninitialized","Loading","Loaded","Interactive","Complete"], - - initialize: function() - { - this.transport = FBL.getNativeXHRObject(); - }, - - getXHRObject: function() - { - var xhrObj = false; - try - { - xhrObj = new XMLHttpRequest(); - } - catch(e) - { - var progid = [ - "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", - "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" - ]; - - for ( var i=0; i < progid.length; ++i ) { - try - { - xhrObj = new ActiveXObject(progid[i]); - } - catch(e) - { - continue; - } - break; - } - } - finally - { - return xhrObj; - } - }, - - - /** - * Create a AJAX request. - * - * @name request - * @param {Object} options request options - * @param {String} options.url URL to be requested - * @param {String} options.type Request type ("get" ou "post"). Default is "get". - * @param {Boolean} options.async Asynchronous flag. Default is "true". - * @param {String} options.dataType Data type ("text", "html", "xml" or "json"). Default is "text". - * @param {String} options.contentType Content-type of the data being sent. Default is "application/x-www-form-urlencoded". - * @param {Function} options.onLoading onLoading callback - * @param {Function} options.onLoaded onLoaded callback - * @param {Function} options.onInteractive onInteractive callback - * @param {Function} options.onComplete onComplete callback - * @param {Function} options.onUpdate onUpdate callback - * @param {Function} options.onSuccess onSuccess callback - * @param {Function} options.onFailure onFailure callback - */ - request: function(options) - { - // process options - var o = FBL.extend( - { - // default values - type: "get", - async: true, - dataType: "text", - contentType: "application/x-www-form-urlencoded" - }, - options || {} - ); - - this.requests.push(o); - - var s = this.getState(); - if (s == "Uninitialized" || s == "Complete" || s == "Loaded") - this.sendRequest(); - }, - - serialize: function(data) - { - var r = [""], rl = 0; - if (data) { - if (typeof data == "string") r[rl++] = data; - - else if (data.innerHTML && data.elements) { - for (var i=0,el,l=(el=data.elements).length; i < l; i++) - if (el[i].name) { - r[rl++] = encodeURIComponent(el[i].name); - r[rl++] = "="; - r[rl++] = encodeURIComponent(el[i].value); - r[rl++] = "&"; - } - - } else - for(var param in data) { - r[rl++] = encodeURIComponent(param); - r[rl++] = "="; - r[rl++] = encodeURIComponent(data[param]); - r[rl++] = "&"; - } - } - return r.join("").replace(/&$/, ""); - }, - - sendRequest: function() - { - var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data; - - // open XHR object - t.open(r.type, r.url, r.async); - - //setRequestHeaders(); - - // indicates that it is a XHR request to the server - t.setRequestHeader("X-Requested-With", "XMLHttpRequest"); - - // if data is being sent, sets the appropriate content-type - if (data = FBL.Ajax.serialize(r.data)) - t.setRequestHeader("Content-Type", r.contentType); - - /** @ignore */ - // onreadystatechange handler - t.onreadystatechange = function() - { - FBL.Ajax.onStateChange(r); - }; - - // send the request - t.send(data); - }, - - /** - * Handles the state change - */ - onStateChange: function(options) - { - var fn, o = options, t = this.transport; - var state = this.getState(t); - - if (fn = o["on" + state]) fn(this.getResponse(o), o); - - if (state == "Complete") - { - var success = t.status == 200, response = this.getResponse(o); - - if (fn = o["onUpdate"]) - fn(response, o); - - if (fn = o["on" + (success ? "Success" : "Failure")]) - fn(response, o); - - t.onreadystatechange = FBL.emptyFn; - - if (this.requests.length > 0) - setTimeout(this.sendRequest, 10); - } - }, - - /** - * gets the appropriate response value according the type - */ - getResponse: function(options) - { - var t = this.transport, type = options.dataType; - - if (t.status != 200) return t.statusText; - else if (type == "text") return t.responseText; - else if (type == "html") return t.responseText; - else if (type == "xml") return t.responseXML; - else if (type == "json") return eval("(" + t.responseText + ")"); - }, - - /** - * returns the current state of the XHR object - */ - getState: function() - { - return this.states[this.transport.readyState]; - } - -}; - - -// ************************************************************************************************ -// Cookie, from http://www.quirksmode.org/js/cookies.html - -this.createCookie = function(name,value,days) -{ - if ('cookie' in document) - { - if (days) - { - var date = new Date(); - date.setTime(date.getTime()+(days*24*60*60*1000)); - var expires = "; expires="+date.toGMTString(); - } - else - var expires = ""; - - document.cookie = name+"="+value+expires+"; path=/"; - } -}; - -this.readCookie = function (name) -{ - if ('cookie' in document) - { - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - - for(var i=0; i < ca.length; i++) - { - var c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1,c.length); - if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); - } - } - - return null; -}; - -this.removeCookie = function(name) -{ - this.createCookie(name, "", -1); -}; - - -// ************************************************************************************************ -// http://www.mister-pixel.com/#Content__state=is_that_simple -var fixIE6BackgroundImageCache = function(doc) -{ - doc = doc || document; - try - { - doc.execCommand("BackgroundImageCache", false, true); - } - catch(E) - { - - } -}; - -// ************************************************************************************************ -// calculatePixelsPerInch - -var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; - -var calculatePixelsPerInch = function calculatePixelsPerInch(doc, body) -{ - var inch = FBL.createGlobalElement("div"); - inch.style.cssText = resetStyle + "width:1in; height:1in; position:absolute; top:-1234px; left:-1234px;"; - body.appendChild(inch); - - FBL.pixelsPerInch = { - x: inch.offsetWidth, - y: inch.offsetHeight - }; - - body.removeChild(inch); -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.SourceLink = function(url, line, type, object, instance) -{ - this.href = url; - this.instance = instance; - this.line = line; - this.type = type; - this.object = object; -}; - -this.SourceLink.prototype = -{ - toString: function() - { - return this.href; - }, - toJSON: function() // until 3.1... - { - return "{\"href\":\""+this.href+"\", "+ - (this.line?("\"line\":"+this.line+","):"")+ - (this.type?(" \"type\":\""+this.type+"\","):"")+ - "}"; - } - -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -this.SourceText = function(lines, owner) -{ - this.lines = lines; - this.owner = owner; -}; - -this.SourceText.getLineAsHTML = function(lineNo) -{ - return escapeForSourceLine(this.lines[lineNo-1]); -}; - - -// ************************************************************************************************ -}).apply(FBL); - -/* See license.txt for terms of usage */ - -FBL.ns( /** @scope s_i18n */ function() { with (FBL) { -// ************************************************************************************************ - -// TODO: xxxpedro localization -var oSTR = -{ - "NoMembersWarning": "There are no properties to show for this object.", - - "EmptyStyleSheet": "There are no rules in this stylesheet.", - "EmptyElementCSS": "This element has no style rules.", - "AccessRestricted": "Access to restricted URI denied.", - - "net.label.Parameters": "Parameters", - "net.label.Source": "Source", - "URLParameters": "Params", - - "EditStyle": "Edit Element Style...", - "NewRule": "New Rule...", - - "NewProp": "New Property...", - "EditProp": 'Edit "%s"', - "DeleteProp": 'Delete "%s"', - "DisableProp": 'Disable "%s"' -}; - -// ************************************************************************************************ - -FBL.$STR = function(name) -{ - return oSTR.hasOwnProperty(name) ? oSTR[name] : name; -}; - -FBL.$STRF = function(name, args) -{ - if (!oSTR.hasOwnProperty(name)) return name; - - var format = oSTR[name]; - var objIndex = 0; - - var parts = parseFormat(format); - var trialIndex = objIndex; - var objects = args; - - for (var i= 0; i < parts.length; i++) - { - var part = parts[i]; - if (part && typeof(part) == "object") - { - if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted. - { - format = ""; - objIndex = -1; - parts.length = 0; - break; - } - } - - } - - var result = []; - for (var i = 0; i < parts.length; ++i) - { - var part = parts[i]; - if (part && typeof(part) == "object") - { - result.push(""+args.shift()); - } - else - result.push(part); - } - - return result.join(""); -}; - -// ************************************************************************************************ - -var parseFormat = function parseFormat(format) -{ - var parts = []; - if (format.length <= 0) - return parts; - - var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/; - for (var m = reg.exec(format); m; m = reg.exec(format)) - { - if (m[0].substr(0, 2) == "%%") - { - parts.push(format.substr(0, m.index)); - parts.push(m[0].substr(1)); - } - else - { - var type = m[8] ? m[8] : m[5]; - var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0); - - var rep = null; - switch (type) - { - case "s": - rep = FirebugReps.Text; - break; - case "f": - case "i": - case "d": - rep = FirebugReps.Number; - break; - case "o": - rep = null; - break; - } - - parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1)); - parts.push({rep: rep, precision: precision, type: ("%" + type)}); - } - - format = format.substr(m.index+m[0].length); - } - - parts.push(format); - return parts; -}; - -// ************************************************************************************************ -}}); - -/* See license.txt for terms of usage */ - -FBL.ns( /** @scope s_firebug */ function() { with (FBL) { -// ************************************************************************************************ - -// ************************************************************************************************ -// Globals - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Internals - -var modules = []; -var panelTypes = []; -var panelTypeMap = {}; -var reps = []; - -var parentPanelMap = {}; - - -// ************************************************************************************************ -// Firebug - -/** - * @namespace describe Firebug - * @exports FBL.Firebug as Firebug - */ -FBL.Firebug = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - version: "Firebug Lite 1.4.0", - revision: "$Revision$", - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - modules: modules, - panelTypes: panelTypes, - panelTypeMap: panelTypeMap, - reps: reps, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Initialization - - initialize: function() - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application"); - - Firebug.browser = new Context(Env.browser); - Firebug.context = Firebug.browser; - - Firebug.loadPrefs(); - Firebug.context.persistedState.isOpen = false; - - // Document must be cached before chrome initialization - cacheDocument(); - - if (Firebug.Inspector && Firebug.Inspector.create) - Firebug.Inspector.create(); - - if (FBL.CssAnalyzer && FBL.CssAnalyzer.processAllStyleSheets) - FBL.CssAnalyzer.processAllStyleSheets(Firebug.browser.document); - - FirebugChrome.initialize(); - - dispatch(modules, "initialize", []); - - if (Firebug.disableResourceFetching) - Firebug.Console.logFormatted(["Some Firebug Lite features are not working because " + - "resource fetching is disabled. To enabled it set the Firebug Lite option " + - "\"disableResourceFetching\" to \"false\". More info at " + - "http://getfirebug.com/firebuglite#Options"], - Firebug.context, "warn"); - - if (Env.onLoad) - { - var onLoad = Env.onLoad; - delete Env.onLoad; - - setTimeout(onLoad, 200); - } - }, - - shutdown: function() - { - if (Firebug.saveCookies) - Firebug.savePrefs(); - - if (Firebug.Inspector) - Firebug.Inspector.destroy(); - - dispatch(modules, "shutdown", []); - - var chromeMap = FirebugChrome.chromeMap; - - for (var name in chromeMap) - { - if (chromeMap.hasOwnProperty(name)) - { - try - { - chromeMap[name].destroy(); - } - catch(E) - { - if (FBTrace.DBG_ERRORS) FBTrace.sysout("chrome.destroy() failed to: " + name); - } - } - } - - Firebug.Lite.Cache.Element.clear(); - Firebug.Lite.Cache.StyleSheet.clear(); - - Firebug.browser = null; - Firebug.context = null; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Registration - - registerModule: function() - { - modules.push.apply(modules, arguments); - - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule"); - }, - - registerPanel: function() - { - panelTypes.push.apply(panelTypes, arguments); - - for (var i = 0, panelType; panelType = arguments[i]; ++i) - { - panelTypeMap[panelType.prototype.name] = arguments[i]; - - if (panelType.prototype.parentPanel) - parentPanelMap[panelType.prototype.parentPanel] = 1; - } - - if (FBTrace.DBG_INITIALIZE) - for (var i = 0; i < arguments.length; ++i) - FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name); - }, - - registerRep: function() - { - reps.push.apply(reps, arguments); - }, - - unregisterRep: function() - { - for (var i = 0; i < arguments.length; ++i) - remove(reps, arguments[i]); - }, - - setDefaultReps: function(funcRep, rep) - { - FBL.defaultRep = rep; - FBL.defaultFuncRep = funcRep; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Reps - - getRep: function(object) - { - var type = typeof object; - if (isIE && isFunction(object)) - type = "function"; - - for (var i = 0; i < reps.length; ++i) - { - var rep = reps[i]; - try - { - if (rep.supportsObject(object, type)) - { - if (FBTrace.DBG_DOM) - FBTrace.sysout("getRep type: "+type+" object: "+object, rep); - return rep; - } - } - catch (exc) - { - if (FBTrace.DBG_ERRORS) - { - FBTrace.sysout("firebug.getRep FAILS: ", exc.message || exc); - FBTrace.sysout("firebug.getRep reps["+i+"/"+reps.length+"]: Rep="+reps[i].className); - // TODO: xxxpedro add trace to FBTrace logs like in Firebug - //firebug.trace(); - } - } - } - - return (type == 'function') ? defaultFuncRep : defaultRep; - }, - - getRepObject: function(node) - { - var target = null; - for (var child = node; child; child = child.parentNode) - { - if (hasClass(child, "repTarget")) - target = child; - - if (child.repObject) - { - if (!target && hasClass(child, "repIgnore")) - break; - else - return child.repObject; - } - } - }, - - getRepNode: function(node) - { - for (var child = node; child; child = child.parentNode) - { - if (child.repObject) - return child; - } - }, - - getElementByRepObject: function(element, object) - { - for (var child = element.firstChild; child; child = child.nextSibling) - { - if (child.repObject == object) - return child; - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Preferences - - getPref: function(name) - { - return Firebug[name]; - }, - - setPref: function(name, value) - { - Firebug[name] = value; - - Firebug.savePrefs(); - }, - - setPrefs: function(prefs) - { - for (var name in prefs) - { - if (prefs.hasOwnProperty(name)) - Firebug[name] = prefs[name]; - } - - Firebug.savePrefs(); - }, - - restorePrefs: function() - { - var Options = Env.DefaultOptions; - - for (var name in Options) - { - Firebug[name] = Options[name]; - } - }, - - loadPrefs: function() - { - this.restorePrefs(); - - var prefs = Store.get("FirebugLite") || {}; - var options = prefs.options; - var persistedState = prefs.persistedState || FBL.defaultPersistedState; - - for (var name in options) - { - if (options.hasOwnProperty(name)) - Firebug[name] = options[name]; - } - - if (Firebug.context && persistedState) - Firebug.context.persistedState = persistedState; - }, - - savePrefs: function() - { - var prefs = { - options: {} - }; - - var EnvOptions = Env.Options; - var options = prefs.options; - for (var name in EnvOptions) - { - if (EnvOptions.hasOwnProperty(name)) - { - options[name] = Firebug[name]; - } - } - - var persistedState = Firebug.context.persistedState; - if (!persistedState) - { - persistedState = Firebug.context.persistedState = FBL.defaultPersistedState; - } - - prefs.persistedState = persistedState; - - Store.set("FirebugLite", prefs); - }, - - erasePrefs: function() - { - Store.remove("FirebugLite"); - this.restorePrefs(); - } -}; - -Firebug.restorePrefs(); - -// xxxpedro should we remove this? -window.Firebug = FBL.Firebug; - -if (!Env.Options.enablePersistent || - Env.Options.enablePersistent && Env.isChromeContext || - Env.isDebugMode) - Env.browser.window.Firebug = FBL.Firebug; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Other methods - -FBL.cacheDocument = function cacheDocument() -{ - var ElementCache = Firebug.Lite.Cache.Element; - var els = Firebug.browser.document.getElementsByTagName("*"); - for (var i=0, l=els.length, el; iFirebug.registerModule method. There is always one instance of a module object - * per browser window. - * @extends Firebug.Listener - */ -Firebug.Module = extend(new Firebug.Listener(), -/** @extend Firebug.Module */ -{ - /** - * Called when the window is opened. - */ - initialize: function() - { - }, - - /** - * Called when the window is closed. - */ - shutdown: function() - { - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - /** - * Called when a new context is created but before the page is loaded. - */ - initContext: function(context) - { - }, - - /** - * Called after a context is detached to a separate window; - */ - reattachContext: function(browser, context) - { - }, - - /** - * Called when a context is destroyed. Module may store info on persistedState for reloaded pages. - */ - destroyContext: function(context, persistedState) - { - }, - - // Called when a FF tab is create or activated (user changes FF tab) - // Called after context is created or with context == null (to abort?) - showContext: function(browser, context) - { - }, - - /** - * Called after a context's page gets DOMContentLoaded - */ - loadedContext: function(context) - { - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - showPanel: function(browser, panel) - { - }, - - showSidePanel: function(browser, panel) - { - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - updateOption: function(name, value) - { - }, - - getObjectByURL: function(context, url) - { - } -}); - -// ************************************************************************************************ -// Panel - -/** - * @panel Base class for all panels. Every derived panel must define a constructor and - * register with "Firebug.registerPanel" method. An instance of the panel - * object is created by the framework for each browser tab where Firebug is activated. - */ -Firebug.Panel = -{ - name: "HelloWorld", - title: "Hello World!", - - parentPanel: null, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - options: { - hasCommandLine: false, - hasStatusBar: false, - hasToolButtons: false, - - // Pre-rendered panels are those included in the skin file (firebug.html) - isPreRendered: false, - innerHTMLSync: false - - /* - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // To be used by external extensions - panelHTML: "", - panelCSS: "", - - toolButtonsHTML: "" - /**/ - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - tabNode: null, - panelNode: null, - sidePanelNode: null, - statusBarNode: null, - toolButtonsNode: null, - - panelBarNode: null, - - sidePanelBarBoxNode: null, - sidePanelBarNode: null, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - sidePanelBar: null, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - searchable: false, - editable: true, - order: 2147483647, - statusSeparator: "<", - - create: function(context, doc) - { - this.hasSidePanel = parentPanelMap.hasOwnProperty(this.name); - - this.panelBarNode = $("fbPanelBar1"); - this.sidePanelBarBoxNode = $("fbPanelBar2"); - - if (this.hasSidePanel) - { - this.sidePanelBar = extend({}, PanelBar); - this.sidePanelBar.create(this); - } - - var options = this.options = extend(Firebug.Panel.options, this.options); - var panelId = "fb" + this.name; - - if (options.isPreRendered) - { - this.panelNode = $(panelId); - - this.tabNode = $(panelId + "Tab"); - this.tabNode.style.display = "block"; - - if (options.hasToolButtons) - { - this.toolButtonsNode = $(panelId + "Buttons"); - } - - if (options.hasStatusBar) - { - this.statusBarBox = $("fbStatusBarBox"); - this.statusBarNode = $(panelId + "StatusBar"); - } - } - else - { - var containerSufix = this.parentPanel ? "2" : "1"; - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Create Panel - var panelNode = this.panelNode = createElement("div", { - id: panelId, - className: "fbPanel" - }); - - $("fbPanel" + containerSufix).appendChild(panelNode); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Create Panel Tab - var tabHTML = '' + - this.title + ''; - - var tabNode = this.tabNode = createElement("a", { - id: panelId + "Tab", - className: "fbTab fbHover", - innerHTML: tabHTML - }); - - if (isIE6) - { - tabNode.href = "javascript:void(0)"; - } - - var panelBarNode = this.parentPanel ? - Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode : - this.panelBarNode; - - panelBarNode.appendChild(tabNode); - tabNode.style.display = "block"; - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create ToolButtons - if (options.hasToolButtons) - { - this.toolButtonsNode = createElement("span", { - id: panelId + "Buttons", - className: "fbToolbarButtons" - }); - - $("fbToolbarButtons").appendChild(this.toolButtonsNode); - } - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create StatusBar - if (options.hasStatusBar) - { - this.statusBarBox = $("fbStatusBarBox"); - - this.statusBarNode = createElement("span", { - id: panelId + "StatusBar", - className: "fbToolbarButtons fbStatusBar" - }); - - this.statusBarBox.appendChild(this.statusBarNode); - } - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create SidePanel - } - - this.containerNode = this.panelNode.parentNode; - - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.create", this.name); - - // xxxpedro contextMenu - this.onContextMenu = bind(this.onContextMenu, this); - - /* - this.context = context; - this.document = doc; - - this.panelNode = doc.createElement("div"); - this.panelNode.ownerPanel = this; - - setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid); - doc.body.appendChild(this.panelNode); - - if (FBTrace.DBG_INITIALIZE) - FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n"); - - this.initializeNode(this.panelNode); - /**/ - }, - - destroy: function(state) // Panel may store info on state - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.destroy", this.name); - - if (this.hasSidePanel) - { - this.sidePanelBar.destroy(); - this.sidePanelBar = null; - } - - this.options = null; - this.name = null; - this.parentPanel = null; - - this.tabNode = null; - this.panelNode = null; - this.containerNode = null; - - this.toolButtonsNode = null; - this.statusBarBox = null; - this.statusBarNode = null; - - //if (this.panelNode) - // delete this.panelNode.ownerPanel; - - //this.destroyNode(); - }, - - initialize: function() - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.initialize", this.name); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (this.hasSidePanel) - { - this.sidePanelBar.initialize(); - } - - var options = this.options = extend(Firebug.Panel.options, this.options); - var panelId = "fb" + this.name; - - this.panelNode = $(panelId); - - this.tabNode = $(panelId + "Tab"); - this.tabNode.style.display = "block"; - - if (options.hasStatusBar) - { - this.statusBarBox = $("fbStatusBarBox"); - this.statusBarNode = $(panelId + "StatusBar"); - } - - if (options.hasToolButtons) - { - this.toolButtonsNode = $(panelId + "Buttons"); - } - - this.containerNode = this.panelNode.parentNode; - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // restore persistent state - this.containerNode.scrollTop = this.lastScrollTop; - - // xxxpedro contextMenu - addEvent(this.containerNode, "contextmenu", this.onContextMenu); - - - /// TODO: xxxpedro infoTip Hack - Firebug.chrome.currentPanel = - Firebug.chrome.selectedPanel && Firebug.chrome.selectedPanel.sidePanelBar ? - Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel : - Firebug.chrome.selectedPanel; - - Firebug.showInfoTips = true; - if (Firebug.InfoTip) - Firebug.InfoTip.initializeBrowser(Firebug.chrome); - }, - - shutdown: function() - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name); - - /// TODO: xxxpedro infoTip Hack - if (Firebug.InfoTip) - Firebug.InfoTip.uninitializeBrowser(Firebug.chrome); - - if (Firebug.chrome.largeCommandLineVisible) - Firebug.chrome.hideLargeCommandLine(); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (this.hasSidePanel) - { - // TODO: xxxpedro firebug1.3a6 - // new PanelBar mechanism will need to call shutdown to hide the panels (so it - // doesn't appears in other panel's sidePanelBar. Therefore, we need to implement - // a "remember selected panel" feature in the sidePanelBar - //this.sidePanelBar.shutdown(); - } - - // store persistent state - this.lastScrollTop = this.containerNode.scrollTop; - - // xxxpedro contextMenu - removeEvent(this.containerNode, "contextmenu", this.onContextMenu); - }, - - detach: function(oldChrome, newChrome) - { - if (oldChrome && oldChrome.selectedPanel && oldChrome.selectedPanel.name == this.name) - this.lastScrollTop = oldChrome.selectedPanel.containerNode.scrollTop; - }, - - reattach: function(doc) - { - if (this.options.innerHTMLSync) - this.synchronizeUI(); - }, - - synchronizeUI: function() - { - this.containerNode.scrollTop = this.lastScrollTop || 0; - }, - - show: function(state) - { - var options = this.options; - - if (options.hasStatusBar) - { - this.statusBarBox.style.display = "inline"; - this.statusBarNode.style.display = "inline"; - } - - if (options.hasToolButtons) - { - this.toolButtonsNode.style.display = "inline"; - } - - this.panelNode.style.display = "block"; - - this.visible = true; - - if (!this.parentPanel) - Firebug.chrome.layout(this); - }, - - hide: function(state) - { - var options = this.options; - - if (options.hasStatusBar) - { - this.statusBarBox.style.display = "none"; - this.statusBarNode.style.display = "none"; - } - - if (options.hasToolButtons) - { - this.toolButtonsNode.style.display = "none"; - } - - this.panelNode.style.display = "none"; - - this.visible = false; - }, - - watchWindow: function(win) - { - }, - - unwatchWindow: function(win) - { - }, - - updateOption: function(name, value) - { - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - /** - * Toolbar helpers - */ - showToolbarButtons: function(buttonsId, show) - { - try - { - if (!this.context.browser) // XXXjjb this is bug. Somehow the panel context is not FirebugContext. - { - if (FBTrace.DBG_ERRORS) - FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:", this); - - return; - } - var buttons = this.context.browser.chrome.$(buttonsId); - if (buttons) - collapse(buttons, show ? "false" : "true"); - } - catch (exc) - { - if (FBTrace.DBG_ERRORS) - { - FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS", exc); - if (!this.context.browser)FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser"); - } - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - /** - * Returns a number indicating the view's ability to inspect the object. - * - * Zero means not supported, and higher numbers indicate specificity. - */ - supportsObject: function(object) - { - return 0; - }, - - hasObject: function(object) // beyond type testing, is this object selectable? - { - return false; - }, - - select: function(object, forceUpdate) - { - if (!object) - object = this.getDefaultSelection(this.context); - - if(FBTrace.DBG_PANELS) - FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection); - - if (forceUpdate || object != this.selection) - { - this.selection = object; - this.updateSelection(object); - - // TODO: xxxpedro - // XXXjoe This is kind of cheating, but, feh. - //Firebug.chrome.onPanelSelect(object, this); - //if (uiListeners.length > 0) - // dispatch(uiListeners, "onPanelSelect", [object, this]); // TODO: make Firebug.chrome a uiListener - } - }, - - updateSelection: function(object) - { - }, - - markChange: function(skipSelf) - { - if (this.dependents) - { - if (skipSelf) - { - for (var i = 0; i < this.dependents.length; ++i) - { - var panelName = this.dependents[i]; - if (panelName != this.name) - this.context.invalidatePanels(panelName); - } - } - else - this.context.invalidatePanels.apply(this.context, this.dependents); - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - startInspecting: function() - { - }, - - stopInspecting: function(object, cancelled) - { - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - search: function(text, reverse) - { - }, - - /** - * Retrieves the search options that this modules supports. - * This is used by the search UI to present the proper options. - */ - getSearchOptionsMenuItems: function() - { - return [ - Firebug.Search.searchOptionMenu("search.Case Sensitive", "searchCaseSensitive") - ]; - }, - - /** - * Navigates to the next document whose match parameter returns true. - */ - navigateToNextDocument: function(match, reverse) - { - // This is an approximation of the UI that is displayed by the location - // selector. This should be close enough, although it may be better - // to simply generate the sorted list within the module, rather than - // sorting within the UI. - var self = this; - function compare(a, b) { - var locA = self.getObjectDescription(a); - var locB = self.getObjectDescription(b); - if(locA.path > locB.path) - return 1; - if(locA.path < locB.path) - return -1; - if(locA.name > locB.name) - return 1; - if(locA.name < locB.name) - return -1; - return 0; - } - var allLocs = this.getLocationList().sort(compare); - for (var curPos = 0; curPos < allLocs.length && allLocs[curPos] != this.location; curPos++); - - function transformIndex(index) { - if (reverse) { - // For the reverse case we need to implement wrap around. - var intermediate = curPos - index - 1; - return (intermediate < 0 ? allLocs.length : 0) + intermediate; - } else { - return (curPos + index + 1) % allLocs.length; - } - }; - - for (var next = 0; next < allLocs.length - 1; next++) - { - var object = allLocs[transformIndex(next)]; - - if (match(object)) - { - this.navigate(object); - return object; - } - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - // Called when "Options" clicked. Return array of - // {label: 'name', nol10n: true, type: "checkbox", checked: , command:function to set } - getOptionsMenuItems: function() - { - return null; - }, - - /* - * Called by chrome.onContextMenu to build the context menu when this panel has focus. - * See also FirebugRep for a similar function also called by onContextMenu - * Extensions may monkey patch and chain off this call - * @param object: the 'realObject', a model value, eg a DOM property - * @param target: the HTML element clicked on. - * @return an array of menu items. - */ - getContextMenuItems: function(object, target) - { - return []; - }, - - getBreakOnMenuItems: function() - { - return []; - }, - - getEditor: function(target, value) - { - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - getDefaultSelection: function() - { - return null; - }, - - browseObject: function(object) - { - }, - - getPopupObject: function(target) - { - return Firebug.getRepObject(target); - }, - - getTooltipObject: function(target) - { - return Firebug.getRepObject(target); - }, - - showInfoTip: function(infoTip, x, y) - { - - }, - - getObjectPath: function(object) - { - return null; - }, - - // An array of objects that can be passed to getObjectLocation. - // The list of things a panel can show, eg sourceFiles. - // Only shown if panel.location defined and supportsObject true - getLocationList: function() - { - return null; - }, - - getDefaultLocation: function() - { - return null; - }, - - getObjectLocation: function(object) - { - return ""; - }, - - // Text for the location list menu eg script panel source file list - // return.path: group/category label, return.name: item label - getObjectDescription: function(object) - { - var url = this.getObjectLocation(object); - return FBL.splitURLBase(url); - }, - - /* - * UI signal that a tab needs attention, eg Script panel is currently stopped on a breakpoint - * @param: show boolean, true turns on. - */ - highlight: function(show) - { - var tab = this.getTab(); - if (!tab) - return; - - if (show) - tab.setAttribute("highlight", "true"); - else - tab.removeAttribute("highlight"); - }, - - getTab: function() - { - var chrome = Firebug.chrome; - - var tab = chrome.$("fbPanelBar2").getTab(this.name); - if (!tab) - tab = chrome.$("fbPanelBar1").getTab(this.name); - return tab; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Support for Break On Next - - /** - * Called by the framework when the user clicks on the Break On Next button. - * @param {Boolean} armed Set to true if the Break On Next feature is - * to be armed for action and set to false if the Break On Next should be disarmed. - * If 'armed' is true, then the next call to shouldBreakOnNext should be |true|. - */ - breakOnNext: function(armed) - { - }, - - /** - * Called when a panel is selected/displayed. The method should return true - * if the Break On Next feature is currently armed for this panel. - */ - shouldBreakOnNext: function() - { - return false; - }, - - /** - * Returns labels for Break On Next tooltip (one for enabled and one for disabled state). - * @param {Boolean} enabled Set to true if the Break On Next feature is - * currently activated for this panel. - */ - getBreakOnNextTooltip: function(enabled) - { - return null; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - // xxxpedro contextMenu - onContextMenu: function(event) - { - if (!this.getContextMenuItems) - return; - - cancelEvent(event, true); - - var target = event.target || event.srcElement; - - var menu = this.getContextMenuItems(this.selection, target); - if (!menu) - return; - - var contextMenu = new Menu( - { - id: "fbPanelContextMenu", - - items: menu - }); - - contextMenu.show(event.clientX, event.clientY); - - return true; - - /* - // TODO: xxxpedro move code to somewhere. code to get cross-browser - // window to screen coordinates - var box = Firebug.browser.getElementPosition(Firebug.chrome.node); - - var screenY = 0; - - // Firefox - if (typeof window.mozInnerScreenY != "undefined") - { - screenY = window.mozInnerScreenY; - } - // Chrome - else if (typeof window.innerHeight != "undefined") - { - screenY = window.outerHeight - window.innerHeight; - } - // IE - else if (typeof window.screenTop != "undefined") - { - screenY = window.screenTop; - } - - contextMenu.show(event.screenX-box.left, event.screenY-screenY-box.top); - /**/ - } - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -/** - * MeasureBox - * To get pixels size.width and size.height: - *
  • this.startMeasuring(view);
  • - *
  • var size = this.measureText(lineNoCharsSpacer);
  • - *
  • this.stopMeasuring();
  • - *
- * - * @namespace - */ -Firebug.MeasureBox = -{ - startMeasuring: function(target) - { - if (!this.measureBox) - { - this.measureBox = target.ownerDocument.createElement("span"); - this.measureBox.className = "measureBox"; - } - - copyTextStyles(target, this.measureBox); - target.ownerDocument.body.appendChild(this.measureBox); - }, - - getMeasuringElement: function() - { - return this.measureBox; - }, - - measureText: function(value) - { - this.measureBox.innerHTML = value ? escapeForSourceLine(value) : "m"; - return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; - }, - - measureInputText: function(value) - { - value = value ? escapeForTextNode(value) : "m"; - if (!Firebug.showTextNodesWithWhitespace) - value = value.replace(/\t/g,'mmmmmm').replace(/\ /g,'m'); - this.measureBox.innerHTML = value; - return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1}; - }, - - getBox: function(target) - { - var style = this.measureBox.ownerDocument.defaultView.getComputedStyle(this.measureBox, ""); - var box = getBoxFromStyles(style, this.measureBox); - return box; - }, - - stopMeasuring: function() - { - this.measureBox.parentNode.removeChild(this.measureBox); - } -}; - - -// ************************************************************************************************ -if (FBL.domplate) Firebug.Rep = domplate( -{ - className: "", - inspectable: true, - - supportsObject: function(object, type) - { - return false; - }, - - inspectObject: function(object, context) - { - Firebug.chrome.select(object); - }, - - browseObject: function(object, context) - { - }, - - persistObject: function(object, context) - { - }, - - getRealObject: function(object, context) - { - return object; - }, - - getTitle: function(object) - { - var label = safeToString(object); - - var re = /\[object (.*?)\]/; - var m = re.exec(label); - - ///return m ? m[1] : label; - - // if the label is in the "[object TYPE]" format return its type - if (m) - { - return m[1]; - } - // if it is IE we need to handle some special cases - else if ( - // safeToString() fails to recognize some objects in IE - isIE && - // safeToString() returns "[object]" for some objects like window.Image - (label == "[object]" || - // safeToString() returns undefined for some objects like window.clientInformation - typeof object == "object" && typeof label == "undefined") - ) - { - return "Object"; - } - else - { - return label; - } - }, - - getTooltip: function(object) - { - return null; - }, - - getContextMenuItems: function(object, target, context) - { - return []; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Convenience for domplates - - STR: function(name) - { - return $STR(name); - }, - - cropString: function(text) - { - return cropString(text); - }, - - cropMultipleLines: function(text, limit) - { - return cropMultipleLines(text, limit); - }, - - toLowerCase: function(text) - { - return text ? text.toLowerCase() : text; - }, - - plural: function(n) - { - return n == 1 ? "" : "s"; - } -}); - -// ************************************************************************************************ - - -// ************************************************************************************************ -}}); - -/* See license.txt for terms of usage */ - -FBL.ns( /** @scope s_gui */ function() { with (FBL) { -// ************************************************************************************************ - -// ************************************************************************************************ -// Controller - -/**@namespace*/ -FBL.Controller = { - - controllers: null, - controllerContext: null, - - initialize: function(context) - { - this.controllers = []; - this.controllerContext = context || Firebug.chrome; - }, - - shutdown: function() - { - this.removeControllers(); - - //this.controllers = null; - //this.controllerContext = null; - }, - - addController: function() - { - for (var i=0, arg; arg=arguments[i]; i++) - { - // If the first argument is a string, make a selector query - // within the controller node context - if (typeof arg[0] == "string") - { - arg[0] = $$(arg[0], this.controllerContext); - } - - // bind the handler to the proper context - var handler = arg[2]; - arg[2] = bind(handler, this); - // save the original handler as an extra-argument, so we can - // look for it later, when removing a particular controller - arg[3] = handler; - - this.controllers.push(arg); - addEvent.apply(this, arg); - } - }, - - removeController: function() - { - for (var i=0, arg; arg=arguments[i]; i++) - { - for (var j=0, c; c=this.controllers[j]; j++) - { - if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3]) - removeEvent.apply(this, c); - } - } - }, - - removeControllers: function() - { - for (var i=0, c; c=this.controllers[i]; i++) - { - removeEvent.apply(this, c); - } - } -}; - - -// ************************************************************************************************ -// PanelBar - -/**@namespace*/ -FBL.PanelBar = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - panelMap: null, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - selectedPanel: null, - parentPanelName: null, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - create: function(ownerPanel) - { - this.panelMap = {}; - this.ownerPanel = ownerPanel; - - if (ownerPanel) - { - ownerPanel.sidePanelBarNode = createElement("span"); - ownerPanel.sidePanelBarNode.style.display = "none"; - ownerPanel.sidePanelBarBoxNode.appendChild(ownerPanel.sidePanelBarNode); - } - - var panels = Firebug.panelTypes; - for (var i=0, p; p=panels[i]; i++) - { - if ( // normal Panel of the Chrome's PanelBar - !ownerPanel && !p.prototype.parentPanel || - // Child Panel of the current Panel's SidePanelBar - ownerPanel && p.prototype.parentPanel && - ownerPanel.name == p.prototype.parentPanel) - { - this.addPanel(p.prototype.name); - } - } - }, - - destroy: function() - { - PanelBar.shutdown.call(this); - - for (var name in this.panelMap) - { - this.removePanel(name); - - var panel = this.panelMap[name]; - panel.destroy(); - - this.panelMap[name] = null; - delete this.panelMap[name]; - } - - this.panelMap = null; - this.ownerPanel = null; - }, - - initialize: function() - { - if (this.ownerPanel) - this.ownerPanel.sidePanelBarNode.style.display = "inline"; - - for(var name in this.panelMap) - { - (function(self, name){ - - // tab click handler - var onTabClick = function onTabClick() - { - self.selectPanel(name); - return false; - }; - - Firebug.chrome.addController([self.panelMap[name].tabNode, "mousedown", onTabClick]); - - })(this, name); - } - }, - - shutdown: function() - { - var selectedPanel = this.selectedPanel; - - if (selectedPanel) - { - removeClass(selectedPanel.tabNode, "fbSelectedTab"); - selectedPanel.hide(); - selectedPanel.shutdown(); - } - - if (this.ownerPanel) - this.ownerPanel.sidePanelBarNode.style.display = "none"; - - this.selectedPanel = null; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - addPanel: function(panelName, parentPanel) - { - var PanelType = Firebug.panelTypeMap[panelName]; - var panel = this.panelMap[panelName] = new PanelType(); - - panel.create(); - }, - - removePanel: function(panelName) - { - var panel = this.panelMap[panelName]; - if (panel.hasOwnProperty(panelName)) - panel.destroy(); - }, - - selectPanel: function(panelName) - { - var selectedPanel = this.selectedPanel; - var panel = this.panelMap[panelName]; - - if (panel && selectedPanel != panel) - { - if (selectedPanel) - { - removeClass(selectedPanel.tabNode, "fbSelectedTab"); - selectedPanel.shutdown(); - selectedPanel.hide(); - } - - if (!panel.parentPanel) - Firebug.context.persistedState.selectedPanelName = panelName; - - this.selectedPanel = panel; - - setClass(panel.tabNode, "fbSelectedTab"); - panel.show(); - panel.initialize(); - } - }, - - getPanel: function(panelName) - { - var panel = this.panelMap[panelName]; - - return panel; - } - -}; - -//************************************************************************************************ -// Button - -/** - * options.element - * options.caption - * options.title - * - * options.owner - * options.className - * options.pressedClassName - * - * options.onPress - * options.onUnpress - * options.onClick - * - * @class - * @extends FBL.Controller - * - */ - -FBL.Button = function(options) -{ - options = options || {}; - - append(this, options); - - this.state = "unpressed"; - this.display = "unpressed"; - - if (this.element) - { - this.container = this.element.parentNode; - } - else - { - this.shouldDestroy = true; - - this.container = this.owner.getPanel().toolButtonsNode; - - this.element = createElement("a", { - className: this.baseClassName + " " + this.className + " fbHover", - innerHTML: this.caption - }); - - if (this.title) - this.element.title = this.title; - - this.container.appendChild(this.element); - } -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -Button.prototype = extend(Controller, -/**@extend FBL.Button.prototype*/ -{ - type: "normal", - caption: "caption", - title: null, - - className: "", // custom class - baseClassName: "fbButton", // control class - pressedClassName: "fbBtnPressed", // control pressed class - - element: null, - container: null, - owner: null, - - state: null, - display: null, - - destroy: function() - { - this.shutdown(); - - // only remove if it is a dynamically generated button (not pre-rendered) - if (this.shouldDestroy) - this.container.removeChild(this.element); - - this.element = null; - this.container = null; - this.owner = null; - }, - - initialize: function() - { - Controller.initialize.apply(this); - - var element = this.element; - - this.addController([element, "mousedown", this.handlePress]); - - if (this.type == "normal") - this.addController( - [element, "mouseup", this.handleUnpress], - [element, "mouseout", this.handleUnpress], - [element, "click", this.handleClick] - ); - }, - - shutdown: function() - { - Controller.shutdown.apply(this); - }, - - restore: function() - { - this.changeState("unpressed"); - }, - - changeState: function(state) - { - this.state = state; - this.changeDisplay(state); - }, - - changeDisplay: function(display) - { - if (display != this.display) - { - if (display == "pressed") - { - setClass(this.element, this.pressedClassName); - } - else if (display == "unpressed") - { - removeClass(this.element, this.pressedClassName); - } - this.display = display; - } - }, - - handlePress: function(event) - { - cancelEvent(event, true); - - if (this.type == "normal") - { - this.changeDisplay("pressed"); - this.beforeClick = true; - } - else if (this.type == "toggle") - { - if (this.state == "pressed") - { - this.changeState("unpressed"); - - if (this.onUnpress) - this.onUnpress.apply(this.owner, arguments); - } - else - { - this.changeState("pressed"); - - if (this.onPress) - this.onPress.apply(this.owner, arguments); - } - - if (this.onClick) - this.onClick.apply(this.owner, arguments); - } - - return false; - }, - - handleUnpress: function(event) - { - cancelEvent(event, true); - - if (this.beforeClick) - this.changeDisplay("unpressed"); - - return false; - }, - - handleClick: function(event) - { - cancelEvent(event, true); - - if (this.type == "normal") - { - if (this.onClick) - this.onClick.apply(this.owner); - - this.changeState("unpressed"); - } - - this.beforeClick = false; - - return false; - } -}); - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -/** - * @class - * @extends FBL.Button - */ -FBL.IconButton = function() -{ - Button.apply(this, arguments); -}; - -IconButton.prototype = extend(Button.prototype, -/**@extend FBL.IconButton.prototype*/ -{ - baseClassName: "fbIconButton", - pressedClassName: "fbIconPressed" -}); - - -//************************************************************************************************ -// Menu - -var menuItemProps = {"class": "$item.className", type: "$item.type", value: "$item.value", - _command: "$item.command"}; - -if (isIE6) - menuItemProps.href = "javascript:void(0)"; - -// Allow GUI to be loaded even when Domplate module is not installed. -if (FBL.domplate) -var MenuPlate = domplate(Firebug.Rep, -{ - tag: - DIV({"class": "fbMenu fbShadow"}, - DIV({"class": "fbMenuContent fbShadowContent"}, - FOR("item", "$object.items|memberIterator", - TAG("$item.tag", {item: "$item"}) - ) - ) - ), - - itemTag: - A(menuItemProps, - "$item.label" - ), - - checkBoxTag: - A(extend(menuItemProps, {checked : "$item.checked"}), - - "$item.label" - ), - - radioButtonTag: - A(extend(menuItemProps, {selected : "$item.selected"}), - - "$item.label" - ), - - groupTag: - A(extend(menuItemProps, {child: "$item.child"}), - "$item.label" - ), - - shortcutTag: - A(menuItemProps, - "$item.label", - SPAN({"class": "fbMenuShortcutKey"}, - "$item.key" - ) - ), - - separatorTag: - SPAN({"class": "fbMenuSeparator"}), - - memberIterator: function(items) - { - var result = []; - - for (var i=0, length=items.length; i width || el.scrollHeight > height)) - { - width = el.scrollWidth; - height = el.scrollHeight; - } - - return {width: width, height: height}; - }, - - getWindowScrollPosition: function() - { - var top=0, left=0, el; - - if(typeof this.window.pageYOffset == "number") - { - top = this.window.pageYOffset; - left = this.window.pageXOffset; - } - else if((el=this.document.body) && (el.scrollTop || el.scrollLeft)) - { - top = el.scrollTop; - left = el.scrollLeft; - } - else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft)) - { - top = el.scrollTop; - left = el.scrollLeft; - } - - return {top:top, left:left}; - }, - - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Element Methods - - getElementFromPoint: function(x, y) - { - if (shouldFixElementFromPoint) - { - var scroll = this.getWindowScrollPosition(); - return this.document.elementFromPoint(x + scroll.left, y + scroll.top); - } - else - return this.document.elementFromPoint(x, y); - }, - - getElementPosition: function(el) - { - var left = 0; - var top = 0; - - do - { - left += el.offsetLeft; - top += el.offsetTop; - } - while (el = el.offsetParent); - - return {left:left, top:top}; - }, - - getElementBox: function(el) - { - var result = {}; - - if (el.getBoundingClientRect) - { - var rect = el.getBoundingClientRect(); - - // fix IE problem with offset when not in fullscreen mode - var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0; - - var scroll = this.getWindowScrollPosition(); - - result.top = Math.round(rect.top - offset + scroll.top); - result.left = Math.round(rect.left - offset + scroll.left); - result.height = Math.round(rect.bottom - rect.top); - result.width = Math.round(rect.right - rect.left); - } - else - { - var position = this.getElementPosition(el); - - result.top = position.top; - result.left = position.left; - result.height = el.offsetHeight; - result.width = el.offsetWidth; - } - - return result; - }, - - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Measurement Methods - - getMeasurement: function(el, name) - { - var result = {value: 0, unit: "px"}; - - var cssValue = this.getStyle(el, name); - - if (!cssValue) return result; - if (cssValue.toLowerCase() == "auto") return result; - - var reMeasure = /(\d+\.?\d*)(.*)/; - var m = cssValue.match(reMeasure); - - if (m) - { - result.value = m[1]-0; - result.unit = m[2].toLowerCase(); - } - - return result; - }, - - getMeasurementInPixels: function(el, name) - { - if (!el) return null; - - var m = this.getMeasurement(el, name); - var value = m.value; - var unit = m.unit; - - if (unit == "px") - return value; - - else if (unit == "pt") - return this.pointsToPixels(name, value); - - else if (unit == "em") - return this.emToPixels(el, value); - - else if (unit == "%") - return this.percentToPixels(el, value); - - else if (unit == "ex") - return this.exToPixels(el, value); - - // TODO: add other units. Maybe create a better general way - // to calculate measurements in different units. - }, - - getMeasurementBox1: function(el, name) - { - var sufixes = ["Top", "Left", "Bottom", "Right"]; - var result = []; - - for(var i=0, sufix; sufix=sufixes[i]; i++) - result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix)); - - return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; - }, - - getMeasurementBox: function(el, name) - { - var result = []; - var sufixes = name == "border" ? - ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] : - ["Top", "Left", "Bottom", "Right"]; - - if (isIE) - { - var propName, cssValue; - var autoMargin = null; - - for(var i=0, sufix; sufix=sufixes[i]; i++) - { - propName = name + sufix; - - cssValue = el.currentStyle[propName] || el.style[propName]; - - if (cssValue == "auto") - { - if (!autoMargin) - autoMargin = this.getCSSAutoMarginBox(el); - - result[i] = autoMargin[sufix.toLowerCase()]; - } - else - result[i] = this.getMeasurementInPixels(el, propName); - - } - - } - else - { - for(var i=0, sufix; sufix=sufixes[i]; i++) - result[i] = this.getMeasurementInPixels(el, name + sufix); - } - - return {top:result[0], left:result[1], bottom:result[2], right:result[3]}; - }, - - getCSSAutoMarginBox: function(el) - { - if (isIE && " meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ") != -1) - return {top:0, left:0, bottom:0, right:0}; - /**/ - - if (isIE && " h1 h2 h3 h4 h5 h6 h7 ul p ".indexOf(" "+el.nodeName.toLowerCase()+" ") == -1) - return {top:0, left:0, bottom:0, right:0}; - /**/ - - var offsetTop = 0; - if (false && isIEStantandMode) - { - var scrollSize = Firebug.browser.getWindowScrollSize(); - offsetTop = scrollSize.height; - } - - var box = this.document.createElement("div"); - //box.style.cssText = "margin:0; padding:1px; border: 0; position:static; overflow:hidden; visibility: hidden;"; - box.style.cssText = "margin:0; padding:1px; border: 0; visibility: hidden;"; - - var clone = el.cloneNode(false); - var text = this.document.createTextNode(" "); - clone.appendChild(text); - - box.appendChild(clone); - - this.document.body.appendChild(box); - - var marginTop = clone.offsetTop - box.offsetTop - 1; - var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop; - - var marginLeft = clone.offsetLeft - box.offsetLeft - 1; - var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft; - - this.document.body.removeChild(box); - - return {top:marginTop+offsetTop, left:marginLeft, bottom:marginBottom-offsetTop, right:marginRight}; - }, - - getFontSizeInPixels: function(el) - { - var size = this.getMeasurement(el, "fontSize"); - - if (size.unit == "px") return size.value; - - // get font size, the dirty way - var computeDirtyFontSize = function(el, calibration) - { - var div = this.document.createElement("div"); - var divStyle = offscreenStyle; - - if (calibration) - divStyle += " font-size:"+calibration+"px;"; - - div.style.cssText = divStyle; - div.innerHTML = "A"; - el.appendChild(div); - - var value = div.offsetHeight; - el.removeChild(div); - return value; - }; - - /* - var calibrationBase = 200; - var calibrationValue = computeDirtyFontSize(el, calibrationBase); - var rate = calibrationBase / calibrationValue; - /**/ - - // the "dirty technique" fails in some environments, so we're using a static value - // based in some tests. - var rate = 200 / 225; - - var value = computeDirtyFontSize(el); - - return value * rate; - }, - - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Unit Funtions - - pointsToPixels: function(name, value, returnFloat) - { - var axis = /Top$|Bottom$/.test(name) ? "y" : "x"; - - var result = value * pixelsPerInch[axis] / 72; - - return returnFloat ? result : Math.round(result); - }, - - emToPixels: function(el, value) - { - if (!el) return null; - - var fontSize = this.getFontSizeInPixels(el); - - return Math.round(value * fontSize); - }, - - exToPixels: function(el, value) - { - if (!el) return null; - - // get ex value, the dirty way - var div = this.document.createElement("div"); - div.style.cssText = offscreenStyle + "width:"+value + "ex;"; - - el.appendChild(div); - var value = div.offsetWidth; - el.removeChild(div); - - return value; - }, - - percentToPixels: function(el, value) - { - if (!el) return null; - - // get % value, the dirty way - var div = this.document.createElement("div"); - div.style.cssText = offscreenStyle + "width:"+value + "%;"; - - el.appendChild(div); - var value = div.offsetWidth; - el.removeChild(div); - - return value; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - getStyle: isIE ? function(el, name) - { - return el.currentStyle[name] || el.style[name] || undefined; - } - : function(el, name) - { - return this.document.defaultView.getComputedStyle(el,null)[name] - || el.style[name] || undefined; - } - -}; - - -// ************************************************************************************************ -}}); - -/* See license.txt for terms of usage */ - -FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) { -// ************************************************************************************************ - -// ************************************************************************************************ -// Globals - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Window Options - -var WindowDefaultOptions = - { - type: "frame", - id: "FirebugUI" - //height: 350 // obsolete - }, - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Instantiated objects - - commandLine, - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Interface Elements Cache - - fbTop, - fbContent, - fbContentStyle, - fbBottom, - fbBtnInspect, - - fbToolbar, - - fbPanelBox1, - fbPanelBox1Style, - fbPanelBox2, - fbPanelBox2Style, - fbPanelBar2Box, - fbPanelBar2BoxStyle, - - fbHSplitter, - fbVSplitter, - fbVSplitterStyle, - - fbPanel1, - fbPanel1Style, - fbPanel2, - fbPanel2Style, - - fbConsole, - fbConsoleStyle, - fbHTML, - - fbCommandLine, - fbLargeCommandLine, - fbLargeCommandButtons, - -//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Cached size values - - topHeight, - topPartialHeight, - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75, - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - lastSelectedPanelName, - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - focusCommandLineState = 0, - lastFocusedPanelName, - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - lastHSplitterMouseMove = 0, - onHSplitterMouseMoveBuffer = null, - onHSplitterMouseMoveTimer = null, - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - lastVSplitterMouseMove = 0; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - -// ************************************************************************************************ -// FirebugChrome - -FBL.defaultPersistedState = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - isOpen: false, - height: 300, - sidePanelWidth: 350, - - selectedPanelName: "Console", - selectedHTMLElementId: null, - - htmlSelectionStack: [] - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -}; - -/**@namespace*/ -FBL.FirebugChrome = -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - //isOpen: false, - //height: 300, - //sidePanelWidth: 350, - - //selectedPanelName: "Console", - //selectedHTMLElementId: null, - - chromeMap: {}, - - htmlSelectionStack: [], - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - create: function() - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window"); - - createChromeWindow(); - }, - - initialize: function() - { - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window"); - - if (Env.chrome.type == "frame" || Env.chrome.type == "div") - ChromeMini.create(Env.chrome); - - var chrome = Firebug.chrome = new Chrome(Env.chrome); - FirebugChrome.chromeMap[chrome.type] = chrome; - - addGlobalEvent("keydown", onGlobalKeyDown); - - if (Env.Options.enablePersistent && chrome.type == "popup") - { - // TODO: xxxpedro persist - revise chrome synchronization when in persistent mode - var frame = FirebugChrome.chromeMap.frame; - if (frame) - frame.close(); - - //chrome.reattach(frame, chrome); - //TODO: xxxpedro persist synchronize? - chrome.initialize(); - } - }, - - clone: function(FBChrome) - { - for (var name in FBChrome) - { - var prop = FBChrome[name]; - if (FBChrome.hasOwnProperty(name) && !isFunction(prop)) - { - this[name] = prop; - } - } - } -}; - - - -// ************************************************************************************************ -// Chrome Window Creation - -var createChromeWindow = function(options) -{ - options = extend(WindowDefaultOptions, options || {}); - - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Locals - - var browserWin = Env.browser.window; - var browserContext = new Context(browserWin); - var prefs = Store.get("FirebugLite"); - var persistedState = prefs && prefs.persistedState || defaultPersistedState; - - var chrome = {}, - - context = options.context || Env.browser, - - type = chrome.type = Env.Options.enablePersistent ? - "popup" : - options.type, - - isChromeFrame = type == "frame", - - useLocalSkin = Env.useLocalSkin, - - url = useLocalSkin ? - Env.Location.skin : - "about:blank", - - // document.body not available in XML+XSL documents in Firefox - body = context.document.getElementsByTagName("body")[0], - - formatNode = function(node) - { - if (!Env.isDebugMode) - { - node.firebugIgnore = true; - } - - var browserWinSize = browserContext.getWindowSize(); - var height = persistedState.height || 300; - - height = Math.min(browserWinSize.height, height); - height = Math.max(200, height); - - node.style.border = "0"; - node.style.visibility = "hidden"; - node.style.zIndex = "2147483647"; // MAX z-index = 2147483647 - node.style.position = noFixedPosition ? "absolute" : "fixed"; - node.style.width = "100%"; // "102%"; IE auto margin bug - node.style.left = "0"; - node.style.bottom = noFixedPosition ? "-1px" : "0"; - node.style.height = height + "px"; - - // avoid flickering during chrome rendering - //if (isFirefox) - // node.style.display = "none"; - }, - - createChromeDiv = function() - { - //Firebug.Console.warn("Firebug Lite GUI is working in 'windowless mode'. It may behave slower and receive interferences from the page in which it is installed."); - - var node = chrome.node = createGlobalElement("div"), - style = createGlobalElement("style"), - - css = FirebugChrome.Skin.CSS - /* - .replace(/;/g, " !important;") - .replace(/!important\s!important/g, "!important") - .replace(/display\s*:\s*(\w+)\s*!important;/g, "display:$1;")*/, - - // reset some styles to minimize interference from the main page's style - rules = ".fbBody *{margin:0;padding:0;font-size:11px;line-height:13px;color:inherit;}" + - // load the chrome styles - css + - // adjust some remaining styles - ".fbBody #fbHSplitter{position:absolute !important;} .fbBody #fbHTML span{line-height:14px;} .fbBody .lineNo div{line-height:inherit !important;}"; - /* - if (isIE) - { - // IE7 CSS bug (FbChrome table bigger than its parent div) - rules += ".fbBody table.fbChrome{position: static !important;}"; - }/**/ - - style.type = "text/css"; - - if (style.styleSheet) - style.styleSheet.cssText = rules; - else - style.appendChild(context.document.createTextNode(rules)); - - document.getElementsByTagName("head")[0].appendChild(style); - - node.className = "fbBody"; - node.style.overflow = "hidden"; - node.innerHTML = getChromeDivTemplate(); - - if (isIE) - { - // IE7 CSS bug (FbChrome table bigger than its parent div) - setTimeout(function(){ - node.firstChild.style.height = "1px"; - node.firstChild.style.position = "static"; - },0); - /**/ - } - - formatNode(node); - - body.appendChild(node); - - chrome.window = window; - chrome.document = document; - onChromeLoad(chrome); - }; - - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - try - { - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create the Chrome as a "div" (windowless mode) - if (type == "div") - { - createChromeDiv(); - return; - } - - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // cretate the Chrome as an "iframe" - else if (isChromeFrame) - { - // Create the Chrome Frame - var node = chrome.node = createGlobalElement("iframe"); - node.setAttribute("src", url); - node.setAttribute("frameBorder", "0"); - - formatNode(node); - - body.appendChild(node); - - // must set the id after appending to the document, otherwise will cause an - // strange error in IE, making the iframe load the page in which the bookmarklet - // was created (like getfirebug.com), before loading the injected UI HTML, - // generating an "Access Denied" error. - node.id = options.id; - } - - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create the Chrome as a "popup" - else - { - var height = persistedState.popupHeight || 300; - var browserWinSize = browserContext.getWindowSize(); - - var browserWinLeft = typeof browserWin.screenX == "number" ? - browserWin.screenX : browserWin.screenLeft; - - var popupLeft = typeof persistedState.popupLeft == "number" ? - persistedState.popupLeft : browserWinLeft; - - var browserWinTop = typeof browserWin.screenY == "number" ? - browserWin.screenY : browserWin.screenTop; - - var popupTop = typeof persistedState.popupTop == "number" ? - persistedState.popupTop : - Math.max( - 0, - Math.min( - browserWinTop + browserWinSize.height - height, - // Google Chrome bug - screen.availHeight - height - 61 - ) - ); - - var popupWidth = typeof persistedState.popupWidth == "number" ? - persistedState.popupWidth : - Math.max( - 0, - Math.min( - browserWinSize.width, - // Opera opens popup in a new tab if it's too big! - screen.availWidth-10 - ) - ); - - var popupHeight = typeof persistedState.popupHeight == "number" ? - persistedState.popupHeight : 300; - - var options = [ - "true,top=", popupTop, - ",left=", popupLeft, - ",height=", popupHeight, - ",width=", popupWidth, - ",resizable" - ].join(""), - - node = chrome.node = context.window.open( - url, - "popup", - options - ); - - if (node) - { - try - { - node.focus(); - } - catch(E) - { - alert("Firebug Error: Firebug popup was blocked."); - return; - } - } - else - { - alert("Firebug Error: Firebug popup was blocked."); - return; - } - } - - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Inject the interface HTML if it is not using the local skin - - if (!useLocalSkin) - { - var tpl = getChromeTemplate(!isChromeFrame), - doc = isChromeFrame ? node.contentWindow.document : node.document; - - doc.write(tpl); - doc.close(); - } - - //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Wait the Window to be loaded - - var win, - - waitDelay = useLocalSkin ? isChromeFrame ? 200 : 300 : 100, - - waitForWindow = function() - { - if ( // Frame loaded... OR - isChromeFrame && (win=node.contentWindow) && - node.contentWindow.document.getElementById("fbCommandLine") || - - // Popup loaded - !isChromeFrame && (win=node.window) && node.document && - node.document.getElementById("fbCommandLine") ) - { - chrome.window = win.window; - chrome.document = win.document; - - // Prevent getting the wrong chrome height in FF when opening a popup - setTimeout(function(){ - onChromeLoad(chrome); - }, useLocalSkin ? 200 : 0); - } - else - setTimeout(waitForWindow, waitDelay); - }; - - waitForWindow(); - } - catch(e) - { - var msg = e.message || e; - - if (/access/i.test(msg)) - { - // Firebug Lite could not create a window for its Graphical User Interface due to - // a access restriction. This happens in some pages, when loading via bookmarklet. - // In such cases, the only way is to load the GUI in a "windowless mode". - - if (isChromeFrame) - body.removeChild(node); - else if(type == "popup") - node.close(); - - // Load the GUI in a "windowless mode" - createChromeDiv(); - } - else - { - alert("Firebug Error: Firebug GUI could not be created."); - } - } -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var onChromeLoad = function onChromeLoad(chrome) -{ - Env.chrome = chrome; - - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Chrome onChromeLoad", "chrome window loaded"); - - if (Env.Options.enablePersistent) - { - // TODO: xxxpedro persist - make better chrome synchronization when in persistent mode - Env.FirebugChrome = FirebugChrome; - - chrome.window.Firebug = chrome.window.Firebug || {}; - chrome.window.Firebug.SharedEnv = Env; - - if (Env.isDevelopmentMode) - { - Env.browser.window.FBDev.loadChromeApplication(chrome); - } - else - { - var doc = chrome.document; - var script = doc.createElement("script"); - script.src = Env.Location.app + "#remote,persist"; - doc.getElementsByTagName("head")[0].appendChild(script); - } - } - else - { - if (chrome.type == "frame" || chrome.type == "div") - { - // initialize the chrome application - setTimeout(function(){ - FBL.Firebug.initialize(); - },0); - } - else if (chrome.type == "popup") - { - var oldChrome = FirebugChrome.chromeMap.frame; - - var newChrome = new Chrome(chrome); - - // TODO: xxxpedro sync detach reattach attach - dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]); - - newChrome.reattach(oldChrome, newChrome); - } - } -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var getChromeDivTemplate = function() -{ - return FirebugChrome.Skin.HTML; -}; - -var getChromeTemplate = function(isPopup) -{ - var tpl = FirebugChrome.Skin; - var r = [], i = -1; - - r[++i] = ''; - r[++i] = ''; - r[++i] = Firebug.version; - - /* - r[++i] = ''; - /**/ - - r[++i] = ''; - /**/ - - r[++i] = ''; - r[++i] = tpl.HTML; - r[++i] = ''; - - return r.join(""); -}; - - -// ************************************************************************************************ -// Chrome Class - -/**@class*/ -var Chrome = function Chrome(chrome) -{ - var type = chrome.type; - var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase; - - append(this, Base); // inherit from base class (ChromeFrameBase or ChromePopupBase) - append(this, chrome); // inherit chrome window properties - append(this, new Context(chrome.window)); // inherit from Context class - - FirebugChrome.chromeMap[type] = this; - Firebug.chrome = this; - Env.chrome = chrome.window; - - this.commandLineVisible = false; - this.sidePanelVisible = false; - - this.create(); - - return this; -}; - -// ************************************************************************************************ -// ChromeBase - -/** - * @namespace - * @extends FBL.Controller - * @extends FBL.PanelBar - **/ -var ChromeBase = {}; -append(ChromeBase, Controller); -append(ChromeBase, PanelBar); -append(ChromeBase, -/**@extend ns-chrome-ChromeBase*/ -{ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // inherited properties - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // inherited from createChrome function - - node: null, - type: null, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // inherited from Context.prototype - - document: null, - window: null, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // value properties - - sidePanelVisible: false, - commandLineVisible: false, - largeCommandLineVisible: false, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // object properties - - inspectButton: null, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - create: function() - { - PanelBar.create.call(this); - - if (Firebug.Inspector) - this.inspectButton = new Button({ - type: "toggle", - element: $("fbChrome_btInspect"), - owner: Firebug.Inspector, - - onPress: Firebug.Inspector.startInspecting, - onUnpress: Firebug.Inspector.stopInspecting - }); - }, - - destroy: function() - { - if(Firebug.Inspector) - this.inspectButton.destroy(); - - PanelBar.destroy.call(this); - - this.shutdown(); - }, - - testMenu: function() - { - var firebugMenu = new Menu( - { - id: "fbFirebugMenu", - - items: - [ - { - label: "Open Firebug", - type: "shortcut", - key: isFirefox ? "Shift+F12" : "F12", - checked: true, - command: "toggleChrome" - }, - { - label: "Open Firebug in New Window", - type: "shortcut", - key: isFirefox ? "Ctrl+Shift+F12" : "Ctrl+F12", - command: "openPopup" - }, - { - label: "Inspect Element", - type: "shortcut", - key: "Ctrl+Shift+C", - command: "toggleInspect" - }, - { - label: "Command Line", - type: "shortcut", - key: "Ctrl+Shift+L", - command: "focusCommandLine" - }, - "-", - { - label: "Options", - type: "group", - child: "fbFirebugOptionsMenu" - }, - "-", - { - label: "Firebug Lite Website...", - command: "visitWebsite" - }, - { - label: "Discussion Group...", - command: "visitDiscussionGroup" - }, - { - label: "Issue Tracker...", - command: "visitIssueTracker" - } - ], - - onHide: function() - { - iconButton.restore(); - }, - - toggleChrome: function() - { - Firebug.chrome.toggle(); - }, - - openPopup: function() - { - Firebug.chrome.toggle(true, true); - }, - - toggleInspect: function() - { - Firebug.Inspector.toggleInspect(); - }, - - focusCommandLine: function() - { - Firebug.chrome.focusCommandLine(); - }, - - visitWebsite: function() - { - this.visit("http://getfirebug.com/lite.html"); - }, - - visitDiscussionGroup: function() - { - this.visit("http://groups.google.com/group/firebug"); - }, - - visitIssueTracker: function() - { - this.visit("http://code.google.com/p/fbug/issues/list"); - }, - - visit: function(url) - { - window.open(url); - } - - }); - - /**@private*/ - var firebugOptionsMenu = - { - id: "fbFirebugOptionsMenu", - - getItems: function() - { - var cookiesDisabled = !Firebug.saveCookies; - - return [ - { - label: "Start Opened", - type: "checkbox", - value: "startOpened", - checked: Firebug.startOpened, - disabled: cookiesDisabled - }, - { - label: "Start in New Window", - type: "checkbox", - value: "startInNewWindow", - checked: Firebug.startInNewWindow, - disabled: cookiesDisabled - }, - { - label: "Show Icon When Hidden", - type: "checkbox", - value: "showIconWhenHidden", - checked: Firebug.showIconWhenHidden, - disabled: cookiesDisabled - }, - { - label: "Override Console Object", - type: "checkbox", - value: "overrideConsole", - checked: Firebug.overrideConsole, - disabled: cookiesDisabled - }, - { - label: "Ignore Firebug Elements", - type: "checkbox", - value: "ignoreFirebugElements", - checked: Firebug.ignoreFirebugElements, - disabled: cookiesDisabled - }, - { - label: "Disable When Firebug Active", - type: "checkbox", - value: "disableWhenFirebugActive", - checked: Firebug.disableWhenFirebugActive, - disabled: cookiesDisabled - }, - { - label: "Disable XHR Listener", - type: "checkbox", - value: "disableXHRListener", - checked: Firebug.disableXHRListener, - disabled: cookiesDisabled - }, - { - label: "Disable Resource Fetching", - type: "checkbox", - value: "disableResourceFetching", - checked: Firebug.disableResourceFetching, - disabled: cookiesDisabled - }, - { - label: "Enable Trace Mode", - type: "checkbox", - value: "enableTrace", - checked: Firebug.enableTrace, - disabled: cookiesDisabled - }, - { - label: "Enable Persistent Mode (experimental)", - type: "checkbox", - value: "enablePersistent", - checked: Firebug.enablePersistent, - disabled: cookiesDisabled - }, - "-", - { - label: "Reset All Firebug Options", - command: "restorePrefs", - disabled: cookiesDisabled - } - ]; - }, - - onCheck: function(target, value, checked) - { - Firebug.setPref(value, checked); - }, - - restorePrefs: function(target) - { - Firebug.erasePrefs(); - - if (target) - this.updateMenu(target); - }, - - updateMenu: function(target) - { - var options = getElementsByClass(target.parentNode, "fbMenuOption"); - - var firstOption = options[0]; - var enabled = Firebug.saveCookies; - if (enabled) - Menu.check(firstOption); - else - Menu.uncheck(firstOption); - - if (enabled) - Menu.check(options[0]); - else - Menu.uncheck(options[0]); - - for (var i = 1, length = options.length; i < length; i++) - { - var option = options[i]; - - var value = option.getAttribute("value"); - var pref = Firebug[value]; - - if (pref) - Menu.check(option); - else - Menu.uncheck(option); - - if (enabled) - Menu.enable(option); - else - Menu.disable(option); - } - } - }; - - Menu.register(firebugOptionsMenu); - - var menu = firebugMenu; - - var testMenuClick = function(event) - { - //console.log("testMenuClick"); - cancelEvent(event, true); - - var target = event.target || event.srcElement; - - if (menu.isVisible) - menu.hide(); - else - { - var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position - - chrome = Firebug.chrome, - - box = chrome.getElementBox(target), - - offset = chrome.type == "div" ? - chrome.getElementPosition(chrome.node) : - {top: 0, left: 0}; - - menu.show( - box.left + offsetLeft - offset.left, - box.top + box.height -5 - offset.top - ); - } - - return false; - }; - - var iconButton = new IconButton({ - type: "toggle", - element: $("fbFirebugButton"), - - onClick: testMenuClick - }); - - iconButton.initialize(); - - //addEvent($("fbToolbarIcon"), "click", testMenuClick); - }, - - initialize: function() - { - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (Env.bookmarkletOutdated) - Firebug.Console.logFormatted([ - "A new bookmarklet version is available. " + - "Please visit http://getfirebug.com/firebuglite#Install and update it." - ], Firebug.context, "warn"); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (Firebug.Console) - Firebug.Console.flush(); - - if (Firebug.Trace) - FBTrace.flush(Firebug.Trace); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application"); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // initialize inherited classes - Controller.initialize.call(this); - PanelBar.initialize.call(this); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // create the interface elements cache - - fbTop = $("fbTop"); - fbContent = $("fbContent"); - fbContentStyle = fbContent.style; - fbBottom = $("fbBottom"); - fbBtnInspect = $("fbBtnInspect"); - - fbToolbar = $("fbToolbar"); - - fbPanelBox1 = $("fbPanelBox1"); - fbPanelBox1Style = fbPanelBox1.style; - fbPanelBox2 = $("fbPanelBox2"); - fbPanelBox2Style = fbPanelBox2.style; - fbPanelBar2Box = $("fbPanelBar2Box"); - fbPanelBar2BoxStyle = fbPanelBar2Box.style; - - fbHSplitter = $("fbHSplitter"); - fbVSplitter = $("fbVSplitter"); - fbVSplitterStyle = fbVSplitter.style; - - fbPanel1 = $("fbPanel1"); - fbPanel1Style = fbPanel1.style; - fbPanel2 = $("fbPanel2"); - fbPanel2Style = fbPanel2.style; - - fbConsole = $("fbConsole"); - fbConsoleStyle = fbConsole.style; - fbHTML = $("fbHTML"); - - fbCommandLine = $("fbCommandLine"); - fbLargeCommandLine = $("fbLargeCommandLine"); - fbLargeCommandButtons = $("fbLargeCommandButtons"); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // static values cache - topHeight = fbTop.offsetHeight; - topPartialHeight = fbToolbar.offsetHeight; - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - disableTextSelection($("fbToolbar")); - disableTextSelection($("fbPanelBarBox")); - disableTextSelection($("fbPanelBar1")); - disableTextSelection($("fbPanelBar2")); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Add the "javascript:void(0)" href attributes used to make the hover effect in IE6 - if (isIE6 && Firebug.Selector) - { - // TODO: xxxpedro change to getElementsByClass - var as = $$(".fbHover"); - for (var i=0, a; a=as[i]; i++) - { - a.setAttribute("href", "javascript:void(0)"); - } - } - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // initialize all panels - /* - var panelMap = Firebug.panelTypes; - for (var i=0, p; p=panelMap[i]; i++) - { - if (!p.parentPanel) - { - this.addPanel(p.prototype.name); - } - } - /**/ - - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - - if(Firebug.Inspector) - this.inspectButton.initialize(); - - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - - this.addController( - [$("fbLargeCommandLineIcon"), "click", this.showLargeCommandLine] - ); - - // ************************************************************************************************ - - // Select the first registered panel - // TODO: BUG IE7 - var self = this; - setTimeout(function(){ - self.selectPanel(Firebug.context.persistedState.selectedPanelName); - - if (Firebug.context.persistedState.selectedPanelName == "Console" && Firebug.CommandLine) - Firebug.chrome.focusCommandLine(); - },0); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - //this.draw(); - - - - - - - - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - var onPanelMouseDown = function onPanelMouseDown(event) - { - //console.log("onPanelMouseDown", event.target || event.srcElement, event); - - var target = event.target || event.srcElement; - - if (FBL.isLeftClick(event)) - { - var editable = FBL.getAncestorByClass(target, "editable"); - - // if an editable element has been clicked then start editing - if (editable) - { - Firebug.Editor.startEditing(editable); - FBL.cancelEvent(event); - } - // if any other element has been clicked then stop editing - else - { - if (!hasClass(target, "textEditorInner")) - Firebug.Editor.stopEditing(); - } - } - else if (FBL.isMiddleClick(event) && Firebug.getRepNode(target)) - { - // Prevent auto-scroll when middle-clicking a rep object - FBL.cancelEvent(event); - } - }; - - Firebug.getElementPanel = function(element) - { - var panelNode = getAncestorByClass(element, "fbPanel"); - var id = panelNode.id.substr(2); - - var panel = Firebug.chrome.panelMap[id]; - - if (!panel) - { - if (Firebug.chrome.selectedPanel.sidePanelBar) - panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id]; - } - - return panel; - }; - - - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - // TODO: xxxpedro port to Firebug - - // Improved window key code event listener. Only one "keydown" event will be attached - // to the window, and the onKeyCodeListen() function will delegate which listeners - // should be called according to the event.keyCode fired. - var onKeyCodeListenersMap = []; - var onKeyCodeListen = function(event) - { - for (var keyCode in onKeyCodeListenersMap) - { - var listeners = onKeyCodeListenersMap[keyCode]; - - for (var i = 0, listener; listener = listeners[i]; i++) - { - var filter = listener.filter || FBL.noKeyModifiers; - - if (event.keyCode == keyCode && (!filter || filter(event))) - { - listener.listener(); - FBL.cancelEvent(event, true); - return false; - } - } - } - }; - - addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen); - - /** - * @name keyCodeListen - * @memberOf FBL.FirebugChrome - */ - Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) - { - var keyCode = KeyEvent["DOM_VK_"+key]; - - if (!onKeyCodeListenersMap[keyCode]) - onKeyCodeListenersMap[keyCode] = []; - - onKeyCodeListenersMap[keyCode].push({ - filter: filter, - listener: listener - }); - - return keyCode; - }; - - /** - * @name keyIgnore - * @memberOf FBL.FirebugChrome - */ - Firebug.chrome.keyIgnore = function(keyCode) - { - onKeyCodeListenersMap[keyCode] = null; - delete onKeyCodeListenersMap[keyCode]; - }; - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - /**/ - // move to shutdown - //removeEvent(Firebug.chrome.document, "keydown", listener[0]); - - - /* - Firebug.chrome.keyCodeListen = function(key, filter, listener, capture) - { - if (!filter) - filter = FBL.noKeyModifiers; - - var keyCode = KeyEvent["DOM_VK_"+key]; - - var fn = function fn(event) - { - if (event.keyCode == keyCode && (!filter || filter(event))) - { - listener(); - FBL.cancelEvent(event, true); - return false; - } - } - - addEvent(Firebug.chrome.document, "keydown", fn); - - return [fn, capture]; - }; - - Firebug.chrome.keyIgnore = function(listener) - { - removeEvent(Firebug.chrome.document, "keydown", listener[0]); - }; - /**/ - - - this.addController( - [fbPanel1, "mousedown", onPanelMouseDown], - [fbPanel2, "mousedown", onPanelMouseDown] - ); -/**/ - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - - // menus can be used without domplate - if (FBL.domplate) - this.testMenu(); - /**/ - - //test XHR - /* - setTimeout(function(){ - - FBL.Ajax.request({url: "../content/firebug/boot.js"}); - FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"}); - - },1000); - /**/ - }, - - shutdown: function() - { - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - - if(Firebug.Inspector) - this.inspectButton.shutdown(); - - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - // ************************************************************************************************ - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - // remove disableTextSelection event handlers - restoreTextSelection($("fbToolbar")); - restoreTextSelection($("fbPanelBarBox")); - restoreTextSelection($("fbPanelBar1")); - restoreTextSelection($("fbPanelBar2")); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // shutdown inherited classes - Controller.shutdown.call(this); - PanelBar.shutdown.call(this); - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Remove the interface elements cache (this must happen after calling - // the shutdown method of all dependent components to avoid errors) - - fbTop = null; - fbContent = null; - fbContentStyle = null; - fbBottom = null; - fbBtnInspect = null; - - fbToolbar = null; - - fbPanelBox1 = null; - fbPanelBox1Style = null; - fbPanelBox2 = null; - fbPanelBox2Style = null; - fbPanelBar2Box = null; - fbPanelBar2BoxStyle = null; - - fbHSplitter = null; - fbVSplitter = null; - fbVSplitterStyle = null; - - fbPanel1 = null; - fbPanel1Style = null; - fbPanel2 = null; - - fbConsole = null; - fbConsoleStyle = null; - fbHTML = null; - - fbCommandLine = null; - fbLargeCommandLine = null; - fbLargeCommandButtons = null; - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // static values cache - - topHeight = null; - topPartialHeight = null; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - toggle: function(forceOpen, popup) - { - if(popup) - { - this.detach(); - } - else - { - if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed) - { - var frame = FirebugChrome.chromeMap.frame; - frame.reattach(); - - FirebugChrome.chromeMap.popup = null; - - frame.open(); - - return; - } - - // If the context is a popup, ignores the toggle process - if (Firebug.chrome.type == "popup") return; - - var shouldOpen = forceOpen || !Firebug.context.persistedState.isOpen; - - if(shouldOpen) - this.open(); - else - this.close(); - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - detach: function() - { - if(!FirebugChrome.chromeMap.popup) - { - this.close(); - createChromeWindow({type: "popup"}); - } - }, - - reattach: function(oldChrome, newChrome) - { - Firebug.browser.window.Firebug = Firebug; - - // chrome synchronization - var newPanelMap = newChrome.panelMap; - var oldPanelMap = oldChrome.panelMap; - - var panel; - for(var name in newPanelMap) - { - // TODO: xxxpedro innerHTML - panel = newPanelMap[name]; - if (panel.options.innerHTMLSync) - panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML; - } - - Firebug.chrome = newChrome; - - // TODO: xxxpedro sync detach reattach attach - //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]); - - if (newChrome.type == "popup") - { - newChrome.initialize(); - //dispatch(Firebug.modules, "initialize", []); - } - else - { - // TODO: xxxpedro only needed in persistent - // should use FirebugChrome.clone, but popup FBChrome - // isn't acessible - Firebug.context.persistedState.selectedPanelName = oldChrome.selectedPanel.name; - } - - dispatch(newPanelMap, "reattach", [oldChrome, newChrome]); - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - draw: function() - { - var size = this.getSize(); - - // Height related values - var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0, - - y = Math.max(size.height /* chrome height */, topHeight), - - heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0), - - height = heightValue + "px", - - // Width related values - sideWidthValue = Firebug.chrome.sidePanelVisible ? Firebug.context.persistedState.sidePanelWidth : 0, - - width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px"; - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Height related rendering - fbPanelBox1Style.height = height; - fbPanel1Style.height = height; - - if (isIE || isOpera) - { - // Fix IE and Opera problems with auto resizing the verticall splitter - fbVSplitterStyle.height = Math.max(y - topPartialHeight - commandLineHeight, 0) + "px"; - } - //xxxpedro FF2 only? - /* - else if (isFirefox) - { - // Fix Firefox problem with table rows with 100% height (fit height) - fbContentStyle.maxHeight = Math.max(y - fixedHeight, 0)+ "px"; - }/**/ - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Width related rendering - fbPanelBox1Style.width = width; - fbPanel1Style.width = width; - - // SidePanel rendering - if (Firebug.chrome.sidePanelVisible) - { - sideWidthValue = Math.max(sideWidthValue - 6, 0); - - var sideWidth = sideWidthValue + "px"; - - fbPanelBox2Style.width = sideWidth; - - fbVSplitterStyle.right = sideWidth; - - if (Firebug.chrome.largeCommandLineVisible) - { - fbLargeCommandLine = $("fbLargeCommandLine"); - - fbLargeCommandLine.style.height = heightValue - 4 + "px"; - fbLargeCommandLine.style.width = sideWidthValue - 2 + "px"; - - fbLargeCommandButtons = $("fbLargeCommandButtons"); - fbLargeCommandButtons.style.width = sideWidth; - } - else - { - fbPanel2Style.height = height; - fbPanel2Style.width = sideWidth; - - fbPanelBar2BoxStyle.width = sideWidth; - } - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - getSize: function() - { - return this.type == "div" ? - { - height: this.node.offsetHeight, - width: this.node.offsetWidth - } - : - this.getWindowSize(); - }, - - resize: function() - { - var self = this; - - // avoid partial resize when maximizing window - setTimeout(function(){ - self.draw(); - - if (noFixedPosition && (self.type == "frame" || self.type == "div")) - self.fixIEPosition(); - }, 0); - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - layout: function(panel) - { - if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", ""); - - var options = panel.options; - - changeCommandLineVisibility(options.hasCommandLine); - changeSidePanelVisibility(panel.hasSidePanel); - - Firebug.chrome.draw(); - }, - - showLargeCommandLine: function(hideToggleIcon) - { - var chrome = Firebug.chrome; - - if (!chrome.largeCommandLineVisible) - { - chrome.largeCommandLineVisible = true; - - if (chrome.selectedPanel.options.hasCommandLine) - { - if (Firebug.CommandLine) - Firebug.CommandLine.blur(); - - changeCommandLineVisibility(false); - } - - changeSidePanelVisibility(true); - - fbLargeCommandLine.style.display = "block"; - fbLargeCommandButtons.style.display = "block"; - - fbPanel2Style.display = "none"; - fbPanelBar2BoxStyle.display = "none"; - - chrome.draw(); - - fbLargeCommandLine.focus(); - - if (Firebug.CommandLine) - Firebug.CommandLine.setMultiLine(true); - } - }, - - hideLargeCommandLine: function() - { - if (Firebug.chrome.largeCommandLineVisible) - { - Firebug.chrome.largeCommandLineVisible = false; - - if (Firebug.CommandLine) - Firebug.CommandLine.setMultiLine(false); - - fbLargeCommandLine.blur(); - - fbPanel2Style.display = "block"; - fbPanelBar2BoxStyle.display = "block"; - - fbLargeCommandLine.style.display = "none"; - fbLargeCommandButtons.style.display = "none"; - - changeSidePanelVisibility(false); - - if (Firebug.chrome.selectedPanel.options.hasCommandLine) - changeCommandLineVisibility(true); - - Firebug.chrome.draw(); - - } - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - focusCommandLine: function() - { - var selectedPanelName = this.selectedPanel.name, panelToSelect; - - if (focusCommandLineState == 0 || selectedPanelName != "Console") - { - focusCommandLineState = 0; - lastFocusedPanelName = selectedPanelName; - - panelToSelect = "Console"; - } - if (focusCommandLineState == 1) - { - panelToSelect = lastFocusedPanelName; - } - - this.selectPanel(panelToSelect); - - try - { - if (Firebug.CommandLine) - { - if (panelToSelect == "Console") - Firebug.CommandLine.focus(); - else - Firebug.CommandLine.blur(); - } - } - catch(e) - { - //TODO: xxxpedro trace error - } - - focusCommandLineState = ++focusCommandLineState % 2; - } - -}); - -// ************************************************************************************************ -// ChromeFrameBase - -/** - * @namespace - * @extends ns-chrome-ChromeBase - */ -var ChromeFrameBase = extend(ChromeBase, -/**@extend ns-chrome-ChromeFrameBase*/ -{ - create: function() - { - ChromeBase.create.call(this); - - // restore display for the anti-flicker trick - if (isFirefox) - this.node.style.display = "block"; - - if (Env.Options.startInNewWindow) - { - this.close(); - this.toggle(true, true); - return; - } - - if (Env.Options.startOpened) - this.open(); - else - this.close(); - }, - - destroy: function() - { - var size = Firebug.chrome.getWindowSize(); - - Firebug.context.persistedState.height = size.height; - - if (Firebug.saveCookies) - Firebug.savePrefs(); - - removeGlobalEvent("keydown", onGlobalKeyDown); - - ChromeBase.destroy.call(this); - - this.document = null; - delete this.document; - - this.window = null; - delete this.window; - - this.node.parentNode.removeChild(this.node); - this.node = null; - delete this.node; - }, - - initialize: function() - { - //FBTrace.sysout("Frame", "initialize();") - ChromeBase.initialize.call(this); - - this.addController( - [Firebug.browser.window, "resize", this.resize], - [$("fbWindow_btClose"), "click", this.close], - [$("fbWindow_btDetach"), "click", this.detach], - [$("fbWindow_btDeactivate"), "click", this.deactivate] - ); - - if (!Env.Options.enablePersistent) - this.addController([Firebug.browser.window, "unload", Firebug.shutdown]); - - if (noFixedPosition) - { - this.addController( - [Firebug.browser.window, "scroll", this.fixIEPosition] - ); - } - - fbVSplitter.onmousedown = onVSplitterMouseDown; - fbHSplitter.onmousedown = onHSplitterMouseDown; - - this.isInitialized = true; - }, - - shutdown: function() - { - fbVSplitter.onmousedown = null; - fbHSplitter.onmousedown = null; - - ChromeBase.shutdown.apply(this); - - this.isInitialized = false; - }, - - reattach: function() - { - var frame = FirebugChrome.chromeMap.frame; - - ChromeBase.reattach(FirebugChrome.chromeMap.popup, this); - }, - - open: function() - { - if (!Firebug.context.persistedState.isOpen) - { - Firebug.context.persistedState.isOpen = true; - - if (Env.isChromeExtension) - localStorage.setItem("Firebug", "1,1"); - - var node = this.node; - - node.style.visibility = "hidden"; // Avoid flickering - - if (Firebug.showIconWhenHidden) - { - if (ChromeMini.isInitialized) - { - ChromeMini.shutdown(); - } - - } - else - node.style.display = "block"; - - var main = $("fbChrome"); - - // IE6 throws an error when setting this property! why? - //main.style.display = "table"; - main.style.display = ""; - - var self = this; - /// TODO: xxxpedro FOUC - node.style.visibility = "visible"; - setTimeout(function(){ - ///node.style.visibility = "visible"; - - //dispatch(Firebug.modules, "initialize", []); - self.initialize(); - - if (noFixedPosition) - self.fixIEPosition(); - - self.draw(); - - }, 10); - } - }, - - close: function() - { - if (Firebug.context.persistedState.isOpen) - { - if (this.isInitialized) - { - //dispatch(Firebug.modules, "shutdown", []); - this.shutdown(); - } - - Firebug.context.persistedState.isOpen = false; - - if (Env.isChromeExtension) - localStorage.setItem("Firebug", "1,0"); - - var node = this.node; - - if (Firebug.showIconWhenHidden) - { - node.style.visibility = "hidden"; // Avoid flickering - - // TODO: xxxpedro - persist IE fixed? - var main = $("fbChrome", FirebugChrome.chromeMap.frame.document); - main.style.display = "none"; - - ChromeMini.initialize(); - - node.style.visibility = "visible"; - } - else - node.style.display = "none"; - } - }, - - deactivate: function() - { - // if it is running as a Chrome extension, dispatch a message to the extension signaling - // that Firebug should be deactivated for the current tab - if (Env.isChromeExtension) - { - localStorage.removeItem("Firebug"); - Firebug.GoogleChrome.dispatch("FB_deactivate"); - - // xxxpedro problem here regarding Chrome extension. We can't deactivate the whole - // app, otherwise it won't be able to be reactivated without reloading the page. - // but we need to stop listening global keys, otherwise the key activation won't work. - Firebug.chrome.close(); - } - else - { - Firebug.shutdown(); - } - }, - - fixIEPosition: function() - { - // fix IE problem with offset when not in fullscreen mode - var doc = this.document; - var offset = isIE ? doc.body.clientTop || doc.documentElement.clientTop: 0; - - var size = Firebug.browser.getWindowSize(); - var scroll = Firebug.browser.getWindowScrollPosition(); - var maxHeight = size.height; - var height = this.node.offsetHeight; - - var bodyStyle = doc.body.currentStyle; - - this.node.style.top = maxHeight - height + scroll.top + "px"; - - if ((this.type == "frame" || this.type == "div") && - (bodyStyle.marginLeft || bodyStyle.marginRight)) - { - this.node.style.width = size.width + "px"; - } - - if (fbVSplitterStyle) - fbVSplitterStyle.right = Firebug.context.persistedState.sidePanelWidth + "px"; - - this.draw(); - } - -}); - - -// ************************************************************************************************ -// ChromeMini - -/** - * @namespace - * @extends FBL.Controller - */ -var ChromeMini = extend(Controller, -/**@extend ns-chrome-ChromeMini*/ -{ - create: function(chrome) - { - append(this, chrome); - this.type = "mini"; - }, - - initialize: function() - { - Controller.initialize.apply(this); - - var doc = FirebugChrome.chromeMap.frame.document; - - var mini = $("fbMiniChrome", doc); - mini.style.display = "block"; - - var miniIcon = $("fbMiniIcon", doc); - var width = miniIcon.offsetWidth + 10; - miniIcon.title = "Open " + Firebug.version; - - var errors = $("fbMiniErrors", doc); - if (errors.offsetWidth) - width += errors.offsetWidth + 10; - - var node = this.node; - node.style.height = "27px"; - node.style.width = width + "px"; - node.style.left = ""; - node.style.right = 0; - - if (this.node.nodeName.toLowerCase() == "iframe") - { - node.setAttribute("allowTransparency", "true"); - this.document.body.style.backgroundColor = "transparent"; - } - else - node.style.background = "transparent"; - - if (noFixedPosition) - this.fixIEPosition(); - - this.addController( - [$("fbMiniIcon", doc), "click", onMiniIconClick] - ); - - if (noFixedPosition) - { - this.addController( - [Firebug.browser.window, "scroll", this.fixIEPosition] - ); - } - - this.isInitialized = true; - }, - - shutdown: function() - { - var node = this.node; - node.style.height = Firebug.context.persistedState.height + "px"; - node.style.width = "100%"; - node.style.left = 0; - node.style.right = ""; - - if (this.node.nodeName.toLowerCase() == "iframe") - { - node.setAttribute("allowTransparency", "false"); - this.document.body.style.backgroundColor = "#fff"; - } - else - node.style.background = "#fff"; - - if (noFixedPosition) - this.fixIEPosition(); - - var doc = FirebugChrome.chromeMap.frame.document; - - var mini = $("fbMiniChrome", doc); - mini.style.display = "none"; - - Controller.shutdown.apply(this); - - this.isInitialized = false; - }, - - draw: function() - { - - }, - - fixIEPosition: ChromeFrameBase.fixIEPosition - -}); - - -// ************************************************************************************************ -// ChromePopupBase - -/** - * @namespace - * @extends ns-chrome-ChromeBase - */ -var ChromePopupBase = extend(ChromeBase, -/**@extend ns-chrome-ChromePopupBase*/ -{ - - initialize: function() - { - setClass(this.document.body, "FirebugPopup"); - - ChromeBase.initialize.call(this); - - this.addController( - [Firebug.chrome.window, "resize", this.resize], - [Firebug.chrome.window, "unload", this.destroy] - //[Firebug.chrome.window, "beforeunload", this.destroy] - ); - - if (Env.Options.enablePersistent) - { - this.persist = bind(this.persist, this); - addEvent(Firebug.browser.window, "unload", this.persist); - } - else - this.addController( - [Firebug.browser.window, "unload", this.close] - ); - - fbVSplitter.onmousedown = onVSplitterMouseDown; - }, - - destroy: function() - { - var chromeWin = Firebug.chrome.window; - var left = chromeWin.screenX || chromeWin.screenLeft; - var top = chromeWin.screenY || chromeWin.screenTop; - var size = Firebug.chrome.getWindowSize(); - - Firebug.context.persistedState.popupTop = top; - Firebug.context.persistedState.popupLeft = left; - Firebug.context.persistedState.popupWidth = size.width; - Firebug.context.persistedState.popupHeight = size.height; - - if (Firebug.saveCookies) - Firebug.savePrefs(); - - // TODO: xxxpedro sync detach reattach attach - var frame = FirebugChrome.chromeMap.frame; - - if(frame) - { - dispatch(frame.panelMap, "detach", [this, frame]); - - frame.reattach(this, frame); - } - - if (Env.Options.enablePersistent) - { - removeEvent(Firebug.browser.window, "unload", this.persist); - } - - ChromeBase.destroy.apply(this); - - FirebugChrome.chromeMap.popup = null; - - this.node.close(); - }, - - persist: function() - { - persistTimeStart = new Date().getTime(); - - removeEvent(Firebug.browser.window, "unload", this.persist); - - Firebug.Inspector.destroy(); - Firebug.browser.window.FirebugOldBrowser = true; - - var persistTimeStart = new Date().getTime(); - - var waitMainWindow = function() - { - var doc, head; - - try - { - if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* && - doc.documentElement && (head = doc.documentElement.firstChild)*/) - { - - try - { - // exposes the FBL to the global namespace when in debug mode - if (Env.isDebugMode) - { - window.FBL = FBL; - } - - window.Firebug = Firebug; - window.opener.Firebug = Firebug; - - Env.browser = window.opener; - Firebug.browser = Firebug.context = new Context(Env.browser); - Firebug.loadPrefs(); - - registerConsole(); - - // the delay time should be calculated right after registering the - // console, once right after the console registration, call log messages - // will be properly handled - var persistDelay = new Date().getTime() - persistTimeStart; - - var chrome = Firebug.chrome; - addEvent(Firebug.browser.window, "unload", chrome.persist); - - FBL.cacheDocument(); - Firebug.Inspector.create(); - - Firebug.Console.logFormatted( - ["Firebug could not capture console calls during " + - persistDelay + "ms"], - Firebug.context, - "info" - ); - - setTimeout(function(){ - var htmlPanel = chrome.getPanel("HTML"); - htmlPanel.createUI(); - },50); - - } - catch(pE) - { - alert("persist error: " + (pE.message || pE)); - } - - } - else - { - window.setTimeout(waitMainWindow, 0); - } - - } catch (E) { - window.close(); - } - }; - - waitMainWindow(); - }, - - close: function() - { - this.destroy(); - } - -}); - - -//************************************************************************************************ -// UI helpers - -var changeCommandLineVisibility = function changeCommandLineVisibility(visibility) -{ - var last = Firebug.chrome.commandLineVisible; - var visible = Firebug.chrome.commandLineVisible = - typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible; - - if (visible != last) - { - if (visible) - { - fbBottom.className = ""; - - if (Firebug.CommandLine) - Firebug.CommandLine.activate(); - } - else - { - if (Firebug.CommandLine) - Firebug.CommandLine.deactivate(); - - fbBottom.className = "hide"; - } - } -}; - -var changeSidePanelVisibility = function changeSidePanelVisibility(visibility) -{ - var last = Firebug.chrome.sidePanelVisible; - Firebug.chrome.sidePanelVisible = - typeof visibility == "boolean" ? visibility : !Firebug.chrome.sidePanelVisible; - - if (Firebug.chrome.sidePanelVisible != last) - { - fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; - fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide"; - } -}; - - -// ************************************************************************************************ -// F12 Handler - -var onGlobalKeyDown = function onGlobalKeyDown(event) -{ - var keyCode = event.keyCode; - var shiftKey = event.shiftKey; - var ctrlKey = event.ctrlKey; - - if (keyCode == 123 /* F12 */ && (!isFirefox && !shiftKey || shiftKey && isFirefox)) - { - Firebug.chrome.toggle(false, ctrlKey); - cancelEvent(event, true); - - // TODO: xxxpedro replace with a better solution. we're doing this - // to allow reactivating with the F12 key after being deactivated - if (Env.isChromeExtension) - { - Firebug.GoogleChrome.dispatch("FB_enableIcon"); - } - } - else if (keyCode == 67 /* C */ && ctrlKey && shiftKey) - { - Firebug.Inspector.toggleInspect(); - cancelEvent(event, true); - } - else if (keyCode == 76 /* L */ && ctrlKey && shiftKey) - { - Firebug.chrome.focusCommandLine(); - cancelEvent(event, true); - } -}; - -var onMiniIconClick = function onMiniIconClick(event) -{ - Firebug.chrome.toggle(false, event.ctrlKey); - cancelEvent(event, true); -}; - - -// ************************************************************************************************ -// Horizontal Splitter Handling - -var onHSplitterMouseDown = function onHSplitterMouseDown(event) -{ - addGlobalEvent("mousemove", onHSplitterMouseMove); - addGlobalEvent("mouseup", onHSplitterMouseUp); - - if (isIE) - addEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); - - fbHSplitter.className = "fbOnMovingHSplitter"; - - return false; -}; - -var onHSplitterMouseMove = function onHSplitterMouseMove(event) -{ - cancelEvent(event, true); - - var clientY = event.clientY; - var win = isIE - ? event.srcElement.ownerDocument.parentWindow - : event.target.defaultView || event.target.ownerDocument && event.target.ownerDocument.defaultView; - - if (!win) - return; - - if (win != win.parent) - { - var frameElement = win.frameElement; - if (frameElement) - { - var framePos = Firebug.browser.getElementPosition(frameElement).top; - clientY += framePos; - - if (frameElement.style.position != "fixed") - clientY -= Firebug.browser.getWindowScrollPosition().top; - } - } - - if (isOpera && isQuiksMode && win.frameElement.id == "FirebugUI") - { - clientY = Firebug.browser.getWindowSize().height - win.frameElement.offsetHeight + clientY; - } - - /* - console.log( - typeof win.FBL != "undefined" ? "no-Chrome" : "Chrome", - //win.frameElement.id, - event.target, - clientY - );/**/ - - onHSplitterMouseMoveBuffer = clientY; // buffer - - if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping - { - lastHSplitterMouseMove = new Date().getTime(); - handleHSplitterMouseMove(); - } - else - if (!onHSplitterMouseMoveTimer) - onHSplitterMouseMoveTimer = setTimeout(handleHSplitterMouseMove, chromeRedrawSkipRate); - - // improving the resizing performance by canceling the mouse event. - // canceling events will prevent the page to receive such events, which would imply - // in more processing being expended. - cancelEvent(event, true); - return false; -}; - -var handleHSplitterMouseMove = function() -{ - if (onHSplitterMouseMoveTimer) - { - clearTimeout(onHSplitterMouseMoveTimer); - onHSplitterMouseMoveTimer = null; - } - - var clientY = onHSplitterMouseMoveBuffer; - - var windowSize = Firebug.browser.getWindowSize(); - var scrollSize = Firebug.browser.getWindowScrollSize(); - - // compute chrome fixed size (top bar and command line) - var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0; - var fixedHeight = topHeight + commandLineHeight; - var chromeNode = Firebug.chrome.node; - - var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0; - - //var height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height; - var height = windowSize.height; - - // compute the min and max size of the chrome - var chromeHeight = Math.max(height - clientY + 5 - scrollbarSize, fixedHeight); - chromeHeight = Math.min(chromeHeight, windowSize.height - scrollbarSize); - - Firebug.context.persistedState.height = chromeHeight; - chromeNode.style.height = chromeHeight + "px"; - - if (noFixedPosition) - Firebug.chrome.fixIEPosition(); - - Firebug.chrome.draw(); -}; - -var onHSplitterMouseUp = function onHSplitterMouseUp(event) -{ - removeGlobalEvent("mousemove", onHSplitterMouseMove); - removeGlobalEvent("mouseup", onHSplitterMouseUp); - - if (isIE) - removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp); - - fbHSplitter.className = ""; - - Firebug.chrome.draw(); - - // avoid text selection in IE when returning to the document - // after the mouse leaves the document during the resizing - return false; -}; - - -// ************************************************************************************************ -// Vertical Splitter Handling - -var onVSplitterMouseDown = function onVSplitterMouseDown(event) -{ - addGlobalEvent("mousemove", onVSplitterMouseMove); - addGlobalEvent("mouseup", onVSplitterMouseUp); - - return false; -}; - -var onVSplitterMouseMove = function onVSplitterMouseMove(event) -{ - if (new Date().getTime() - lastVSplitterMouseMove > chromeRedrawSkipRate) // frame skipping - { - var target = event.target || event.srcElement; - if (target && target.ownerDocument) // avoid error when cursor reaches out of the chrome - { - var clientX = event.clientX; - var win = document.all - ? event.srcElement.ownerDocument.parentWindow - : event.target.ownerDocument.defaultView; - - if (win != win.parent) - clientX += win.frameElement ? win.frameElement.offsetLeft : 0; - - var size = Firebug.chrome.getSize(); - var x = Math.max(size.width - clientX + 3, 6); - - Firebug.context.persistedState.sidePanelWidth = x; - Firebug.chrome.draw(); - } - - lastVSplitterMouseMove = new Date().getTime(); - } - - cancelEvent(event, true); - return false; -}; - -var onVSplitterMouseUp = function onVSplitterMouseUp(event) -{ - removeGlobalEvent("mousemove", onVSplitterMouseMove); - removeGlobalEvent("mouseup", onVSplitterMouseUp); - - Firebug.chrome.draw(); -}; - - -// ************************************************************************************************ -}}); - -/* See license.txt for terms of usage */ - -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ - -Firebug.Lite = -{ -}; - -// ************************************************************************************************ -}}); - - -/* See license.txt for terms of usage */ - -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ - -Firebug.Lite.Cache = -{ - ID: "firebug-" + new Date().getTime() -}; - -// ************************************************************************************************ - -/** - * TODO: if a cached element is cloned, the expando property will be cloned too in IE - * which will result in a bug. Firebug Lite will think the new cloned node is the old - * one. - * - * TODO: Investigate a possibility of cache validation, to be customized by each - * kind of cache. For ElementCache it should validate if the element still is - * inserted at the DOM. - */ -var cacheUID = 0; -var createCache = function() -{ - var map = {}; - var data = {}; - - var CID = Firebug.Lite.Cache.ID; - - // better detection - var supportsDeleteExpando = !document.all; - - var cacheFunction = function(element) - { - return cacheAPI.set(element); - }; - - var cacheAPI = - { - get: function(key) - { - return map.hasOwnProperty(key) ? - map[key] : - null; - }, - - set: function(element) - { - var id = getValidatedKey(element); - - if (!id) - { - id = ++cacheUID; - element[CID] = id; - } - - if (!map.hasOwnProperty(id)) - { - map[id] = element; - data[id] = {}; - } - - return id; - }, - - unset: function(element) - { - var id = getValidatedKey(element); - - if (!id) return; - - if (supportsDeleteExpando) - { - delete element[CID]; - } - else if (element.removeAttribute) - { - element.removeAttribute(CID); - } - - delete map[id]; - delete data[id]; - - }, - - key: function(element) - { - return getValidatedKey(element); - }, - - has: function(element) - { - var id = getValidatedKey(element); - return id && map.hasOwnProperty(id); - }, - - each: function(callback) - { - for (var key in map) - { - if (map.hasOwnProperty(key)) - { - callback(key, map[key]); - } - } - }, - - data: function(element, name, value) - { - // set data - if (value) - { - if (!name) return null; - - var id = cacheAPI.set(element); - - return data[id][name] = value; - } - // get data - else - { - var id = cacheAPI.key(element); - - return data.hasOwnProperty(id) && data[id].hasOwnProperty(name) ? - data[id][name] : - null; - } - }, - - clear: function() - { - for (var id in map) - { - var element = map[id]; - cacheAPI.unset(element); - } - } - }; - - var getValidatedKey = function(element) - { - var id = element[CID]; - - // If a cached element is cloned in IE, the expando property CID will be also - // cloned (differently than other browsers) resulting in a bug: Firebug Lite - // will think the new cloned node is the old one. To prevent this problem we're - // checking if the cached element matches the given element. - if ( - !supportsDeleteExpando && // the problem happens when supportsDeleteExpando is false - id && // the element has the expando property - map.hasOwnProperty(id) && // there is a cached element with the same id - map[id] != element // but it is a different element than the current one - ) - { - // remove the problematic property - element.removeAttribute(CID); - - id = null; - } - - return id; - }; - - FBL.append(cacheFunction, cacheAPI); - - return cacheFunction; -}; - -// ************************************************************************************************ - -// TODO: xxxpedro : check if we need really this on FBL scope -Firebug.Lite.Cache.StyleSheet = createCache(); -Firebug.Lite.Cache.Element = createCache(); - -// TODO: xxxpedro -Firebug.Lite.Cache.Event = createCache(); - - -// ************************************************************************************************ -}}); - - -/* See license.txt for terms of usage */ - -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ - -// ************************************************************************************************ -var sourceMap = {}; - -// ************************************************************************************************ -Firebug.Lite.Proxy = -{ - // jsonp callbacks - _callbacks: {}, - - /** - * Load a resource, either locally (directly) or externally (via proxy) using - * synchronous XHR calls. Loading external resources requires the proxy plugin to - * be installed and configured (see /plugin/proxy/proxy.php). - */ - load: function(url) - { - var resourceDomain = getDomain(url); - var isLocalResource = - // empty domain means local URL - !resourceDomain || - // same domain means local too - resourceDomain == Firebug.context.window.location.host; // TODO: xxxpedro context - - return isLocalResource ? fetchResource(url) : fetchProxyResource(url); - }, - - /** - * Load a resource using JSONP technique. - */ - loadJSONP: function(url, callback) - { - var script = createGlobalElement("script"), - doc = Firebug.context.document, - - uid = "" + new Date().getTime(), - callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid, - - jsonpURL = url.indexOf("?") != -1 ? - url + "&" + callbackName : - url + "?" + callbackName; - - Firebug.Lite.Proxy._callbacks[uid] = function(data) - { - if (callback) - callback(data); - - script.parentNode.removeChild(script); - delete Firebug.Lite.Proxy._callbacks[uid]; - }; - - script.src = jsonpURL; - - if (doc.documentElement) - doc.documentElement.appendChild(script); - }, - - /** - * Load a resource using YQL (not reliable). - */ - YQL: function(url, callback) - { - var yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" + - encodeURIComponent(url) + "%22&format=xml"; - - this.loadJSONP(yql, function(data) - { - var source = data.results[0]; - - // clean up YQL bogus elements - var match = /\s+

([\s\S]+)<\/p>\s+<\/body>$/.exec(source); - if (match) - source = match[1]; - - console.log(source); - }); - } -}; - -// ************************************************************************************************ - -Firebug.Lite.Proxy.fetchResourceDisabledMessage = - "/* Firebug Lite resource fetching is disabled.\n" + - "To enabled it set the Firebug Lite option \"disableResourceFetching\" to \"false\".\n" + - "More info at http://getfirebug.com/firebuglite#Options */"; - -var fetchResource = function(url) -{ - if (Firebug.disableResourceFetching) - { - var source = sourceMap[url] = Firebug.Lite.Proxy.fetchResourceDisabledMessage; - return source; - } - - if (sourceMap.hasOwnProperty(url)) - return sourceMap[url]; - - // Getting the native XHR object so our calls won't be logged in the Console Panel - var xhr = FBL.getNativeXHRObject(); - xhr.open("get", url, false); - xhr.send(); - - var source = sourceMap[url] = xhr.responseText; - return source; -}; - -var fetchProxyResource = function(url) -{ - if (sourceMap.hasOwnProperty(url)) - return sourceMap[url]; - - var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url); - var response = fetchResource(proxyURL); - - try - { - var data = eval("(" + response + ")"); - } - catch(E) - { - return "ERROR: Firebug Lite Proxy plugin returned an invalid response."; - } - - var source = data ? data.contents : ""; - return source; -}; - - -// ************************************************************************************************ -}}); - - -/* See license.txt for terms of usage */ - -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ - -Firebug.Lite.Style = -{ -}; - -// ************************************************************************************************ -}}); - - -/* See license.txt for terms of usage */ - -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ - -Firebug.Lite.Script = function(window) -{ - this.fileName = null; - this.isValid = null; - this.baseLineNumber = null; - this.lineExtent = null; - this.tag = null; - - this.functionName = null; - this.functionSource = null; -}; - -Firebug.Lite.Script.prototype = -{ - isLineExecutable: function(){}, - pcToLine: function(){}, - lineToPc: function(){}, - - toString: function() - { - return "Firebug.Lite.Script"; - } -}; - -// ************************************************************************************************ -}}); - - -/* See license.txt for terms of usage */ - -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ - - -Firebug.Lite.Browser = function(window) -{ - this.contentWindow = window; - this.contentDocument = window.document; - this.currentURI = - { - spec: window.location.href - }; -}; - -Firebug.Lite.Browser.prototype = -{ - toString: function() - { - return "Firebug.Lite.Browser"; - } -}; - - -// ************************************************************************************************ -}}); - - -/* See license.txt for terms of usage */ - -/* - http://www.JSON.org/json2.js - 2010-03-20 - - Public Domain. - - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - - See http://www.JSON.org/js.html - - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. - - - This file creates a global JSON object containing two methods: stringify - and parse. - - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. - - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. - - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. - - This method produces a JSON text from a JavaScript value. - - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value - - For example, this would serialize Dates as ISO strings. - - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. - - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. - - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. - - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. - - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. - - Example: - - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' - - - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' - - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' - - - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. - - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. - - Example: - - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. - - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); - - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); - - - This is a reference implementation. You are free to copy, modify, or - redistribute. -*/ - -/*jslint evil: true, strict: false */ - -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ - - -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. - -// ************************************************************************************************ - -var JSON = window.JSON || {}; - -// ************************************************************************************************ - -(function () { - - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - if (typeof Date.prototype.toJSON !== 'function') { - - Date.prototype.toJSON = function (key) { - - return isFinite(this.valueOf()) ? - this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z' : null; - }; - - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function (key) { - return this.valueOf(); - }; - } - - var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - gap, - indent, - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }, - rep; - - - function quote(string) { - -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0; - return escapable.test(string) ? - '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' ? c : - '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : - '"' + string + '"'; - } - - - function str(key, holder) { - -// Produce a string from holder[key]. - - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; - -// If the value has a toJSON method, call it to obtain a replacement value. - - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } - -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. - - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } - -// What happens next depends on the value's type. - - switch (typeof value) { - case 'string': - return quote(value); - - case 'number': - -// JSON numbers must be finite. Encode non-finite numbers as null. - - return isFinite(value) ? String(value) : 'null'; - - case 'boolean': - case 'null': - -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - - return String(value); - -// If the type is 'object', we might be dealing with an object or an array or -// null. - - case 'object': - -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. - - if (!value) { - return 'null'; - } - -// Make an array to hold the partial results of stringifying this object value. - - gap += indent; - partial = []; - -// Is the value an array? - - if (Object.prototype.toString.apply(value) === '[object Array]') { - -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. - - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } - -// Join all of the elements together, separated with commas, and wrap them in -// brackets. - - v = partial.length === 0 ? '[]' : - gap ? '[\n' + gap + - partial.join(',\n' + gap) + '\n' + - mind + ']' : - '[' + partial.join(',') + ']'; - gap = mind; - return v; - } - -// If the replacer is an array, use it to select the members to be stringified. - - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - k = rep[i]; - if (typeof k === 'string') { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { - -// Otherwise, iterate through all of the keys in the object. - - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } - -// Join all of the member texts together, separated with commas, -// and wrap them in braces. - - v = partial.length === 0 ? '{}' : - gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + - mind + '}' : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } - -// If the JSON object does not yet have a stringify method, give it one. - - if (typeof JSON.stringify !== 'function') { - JSON.stringify = function (value, replacer, space) { - -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - text = String(text); - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - if (/^[\],:{}\s]*$/. -test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). -replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). -replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - - j = eval('(' + text + ')'); - -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. - - return typeof reviver === 'function' ? - walk({'': j}, '') : j; - } - -// If the text is not JSON parseable, then a SyntaxError is thrown. - - throw new SyntaxError('JSON.parse'); - }; - } - -// ************************************************************************************************ -// registration - -FBL.JSON = JSON; - -// ************************************************************************************************ -}()); - -/* See license.txt for terms of usage */ - -(function(){ -// ************************************************************************************************ - -/* Copyright (c) 2010-2011 Marcus Westin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -var store = (function(){ - var api = {}, - win = window, - doc = win.document, - localStorageName = 'localStorage', - globalStorageName = 'globalStorage', - namespace = '__firebug__storejs__', - storage - - api.disabled = false - api.set = function(key, value) {} - api.get = function(key) {} - api.remove = function(key) {} - api.clear = function() {} - api.transact = function(key, transactionFn) { - var val = api.get(key) - if (typeof val == 'undefined') { val = {} } - transactionFn(val) - api.set(key, val) - } - - api.serialize = function(value) { - return JSON.stringify(value) - } - api.deserialize = function(value) { - if (typeof value != 'string') { return undefined } - return JSON.parse(value) - } - - // Functions to encapsulate questionable FireFox 3.6.13 behavior - // when about.config::dom.storage.enabled === false - // See https://github.com/marcuswestin/store.js/issues#issue/13 - function isLocalStorageNameSupported() { - try { return (localStorageName in win && win[localStorageName]) } - catch(err) { return false } - } - - function isGlobalStorageNameSupported() { - try { return (globalStorageName in win && win[globalStorageName] && win[globalStorageName][win.location.hostname]) } - catch(err) { return false } - } - - if (isLocalStorageNameSupported()) { - storage = win[localStorageName] - api.set = function(key, val) { storage.setItem(key, api.serialize(val)) } - api.get = function(key) { return api.deserialize(storage.getItem(key)) } - api.remove = function(key) { storage.removeItem(key) } - api.clear = function() { storage.clear() } - - } else if (isGlobalStorageNameSupported()) { - storage = win[globalStorageName][win.location.hostname] - api.set = function(key, val) { storage[key] = api.serialize(val) } - api.get = function(key) { return api.deserialize(storage[key] && storage[key].value) } - api.remove = function(key) { delete storage[key] } - api.clear = function() { for (var key in storage ) { delete storage[key] } } - - } else if (doc.documentElement.addBehavior) { - var storage = doc.createElement('div') - function withIEStorage(storeFunction) { - return function() { - var args = Array.prototype.slice.call(arguments, 0) - args.unshift(storage) - // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx - // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx - // TODO: xxxpedro doc.body is not always available so we must use doc.documentElement. - // We need to make sure this change won't affect the behavior of this library. - doc.documentElement.appendChild(storage) - storage.addBehavior('#default#userData') - storage.load(localStorageName) - var result = storeFunction.apply(api, args) - doc.documentElement.removeChild(storage) - return result - } - } - api.set = withIEStorage(function(storage, key, val) { - storage.setAttribute(key, api.serialize(val)) - storage.save(localStorageName) - }) - api.get = withIEStorage(function(storage, key) { - return api.deserialize(storage.getAttribute(key)) - }) - api.remove = withIEStorage(function(storage, key) { - storage.removeAttribute(key) - storage.save(localStorageName) - }) - api.clear = withIEStorage(function(storage) { - var attributes = storage.XMLDocument.documentElement.attributes - storage.load(localStorageName) - for (var i=0, attr; attr = attributes[i]; i++) { - storage.removeAttribute(attr.name) - } - storage.save(localStorageName) - }) - } - - try { - api.set(namespace, namespace) - if (api.get(namespace) != namespace) { api.disabled = true } - api.remove(namespace) - } catch(e) { - api.disabled = true - } - - return api -})(); - -if (typeof module != 'undefined') { module.exports = store } - - -// ************************************************************************************************ -// registration - -FBL.Store = store; - -// ************************************************************************************************ -})(); - -/* See license.txt for terms of usage */ - -FBL.ns( /**@scope s_selector*/ function() { with (FBL) { -// ************************************************************************************************ - -/* - * Sizzle CSS Selector Engine - v1.0 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function(){ - baseHasDuplicate = false; - return 0; -}); - -/** - * @name Firebug.Selector - * @namespace - */ - -/** - * @exports Sizzle as Firebug.Selector - */ -var Sizzle = function(selector, context, results, seed) { - results = results || []; - var origContext = context = context || document; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) - selector += parts.shift(); - - set = posProcess( selector, set ); - } - } - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - var ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; - } - - if ( context ) { - var ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray(set); - } else { - prune = false; - } - - while ( parts.length ) { - var cur = parts.pop(), pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - throw "Syntax error, unrecognized expression: " + (cur || selector); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - } else if ( context && context.nodeType === 1 ) { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - } else { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function(results){ - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort(sortOrder); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[i-1] ) { - results.splice(i--, 1); - } - } - } - } - - return results; -}; - -Sizzle.matches = function(expr, set){ - return Sizzle(expr, null, null, set); -}; - -Sizzle.find = function(expr, context, isXML){ - var set, match; - - if ( !expr ) { - return []; - } - - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var type = Expr.order[i], match; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; - match.splice(1,1); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace(/\\/g, ""); - set = Expr.find[ type ]( match, context, isXML ); - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = context.getElementsByTagName("*"); - } - - return {set: set, expr: expr}; -}; - -Sizzle.filter = function(expr, set, inplace, not){ - var old = expr, result = [], curLoop = set, match, anyFound, - isXMLFilter = set && set[0] && isXML(set[0]); - - while ( expr && set.length ) { - for ( var type in Expr.filter ) { - if ( (match = Expr.match[ type ].exec( expr )) != null ) { - var filter = Expr.filter[ type ], found, item; - anyFound = false; - - if ( curLoop == result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - } else { - curLoop[i] = false; - } - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr == old ) { - if ( anyFound == null ) { - throw "Syntax error, unrecognized expression: " + expr; - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -/**#@+ @ignore */ -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - match: { - ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ - }, - leftMatch: {}, - attrMap: { - "class": "className", - "for": "htmlFor" - }, - attrHandle: { - href: function(elem){ - return elem.getAttribute("href"); - } - }, - relative: { - "+": function(checkSet, part, isXML){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !/\W/.test(part), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag && !isXML ) { - part = part.toUpperCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - ">": function(checkSet, part, isXML){ - var isPartStr = typeof part === "string"; - - if ( isPartStr && !/\W/.test(part) ) { - part = isXML ? part : part.toUpperCase(); - - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName === part ? parent : false; - } - } - } else { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - "": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; - - if ( !/\W/.test(part) ) { - var nodeCheck = part = isXML ? part : part.toUpperCase(); - checkFn = dirNodeCheck; - } - - checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); - }, - "~": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; - - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = isXML ? part : part.toUpperCase(); - checkFn = dirNodeCheck; - } - - checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); - } - }, - find: { - ID: function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? [m] : []; - } - }, - NAME: function(match, context, isXML){ - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], results = context.getElementsByName(match[1]); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - TAG: function(match, context){ - return context.getElementsByTagName(match[1]); - } - }, - preFilter: { - CLASS: function(match, curLoop, inplace, result, not, isXML){ - match = " " + match[1].replace(/\\/g, "") + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { - if ( !inplace ) - result.push( elem ); - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - ID: function(match){ - return match[1].replace(/\\/g, ""); - }, - TAG: function(match, curLoop){ - for ( var i = 0; curLoop[i] === false; i++ ){} - return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); - }, - CHILD: function(match){ - if ( match[1] == "nth" ) { - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( - match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - ATTR: function(match, curLoop, inplace, result, not, isXML){ - var name = match[1].replace(/\\/g, ""); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - PSEUDO: function(match, curLoop, inplace, result, not){ - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - if ( !inplace ) { - result.push.apply( result, ret ); - } - return false; - } - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - POS: function(match){ - match.unshift( true ); - return match; - } - }, - filters: { - enabled: function(elem){ - return elem.disabled === false && elem.type !== "hidden"; - }, - disabled: function(elem){ - return elem.disabled === true; - }, - checked: function(elem){ - return elem.checked === true; - }, - selected: function(elem){ - // Accessing this property makes selected-by-default - // options in Safari work properly - elem.parentNode.selectedIndex; - return elem.selected === true; - }, - parent: function(elem){ - return !!elem.firstChild; - }, - empty: function(elem){ - return !elem.firstChild; - }, - has: function(elem, i, match){ - return !!Sizzle( match[3], elem ).length; - }, - header: function(elem){ - return /h\d/i.test( elem.nodeName ); - }, - text: function(elem){ - return "text" === elem.type; - }, - radio: function(elem){ - return "radio" === elem.type; - }, - checkbox: function(elem){ - return "checkbox" === elem.type; - }, - file: function(elem){ - return "file" === elem.type; - }, - password: function(elem){ - return "password" === elem.type; - }, - submit: function(elem){ - return "submit" === elem.type; - }, - image: function(elem){ - return "image" === elem.type; - }, - reset: function(elem){ - return "reset" === elem.type; - }, - button: function(elem){ - return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; - }, - input: function(elem){ - return /input|select|textarea|button/i.test(elem.nodeName); - } - }, - setFilters: { - first: function(elem, i){ - return i === 0; - }, - last: function(elem, i, match, array){ - return i === array.length - 1; - }, - even: function(elem, i){ - return i % 2 === 0; - }, - odd: function(elem, i){ - return i % 2 === 1; - }, - lt: function(elem, i, match){ - return i < match[3] - 0; - }, - gt: function(elem, i, match){ - return i > match[3] - 0; - }, - nth: function(elem, i, match){ - return match[3] - 0 == i; - }, - eq: function(elem, i, match){ - return match[3] - 0 == i; - } - }, - filter: { - PSEUDO: function(elem, match, i, array){ - var name = match[1], filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; - } else if ( name === "not" ) { - var not = match[3]; - - for ( var i = 0, l = not.length; i < l; i++ ) { - if ( not[i] === elem ) { - return false; - } - } - - return true; - } - }, - CHILD: function(elem, match){ - var type = match[1], node = elem; - switch (type) { - case 'only': - case 'first': - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) return false; - } - if ( type == 'first') return true; - node = elem; - case 'last': - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) return false; - } - return true; - case 'nth': - var first = match[2], last = match[3]; - - if ( first == 1 && last == 0 ) { - return true; - } - - var doneName = match[0], - parent = elem.parentNode; - - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - parent.sizcache = doneName; - } - - var diff = elem.nodeIndex - last; - if ( first == 0 ) { - return diff == 0; - } else { - return ( diff % first == 0 && diff / first >= 0 ); - } - } - }, - ID: function(elem, match){ - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - TAG: function(elem, match){ - return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; - }, - CLASS: function(elem, match){ - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - ATTR: function(elem, match){ - var name = match[1], - result = Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value != check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - POS: function(elem, match, i, array){ - var name = match[2], filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); -} - -var makeArray = function(array, results) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 ); - -// Provide a fallback method if it does not work -} catch(e){ - makeArray = function(array, results) { - var ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - } else { - if ( typeof array.length === "number" ) { - for ( var i = 0, l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - } else { - for ( var i = 0; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - if ( a == b ) { - hasDuplicate = true; - } - return 0; - } - - var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( "sourceIndex" in document.documentElement ) { - sortOrder = function( a, b ) { - if ( !a.sourceIndex || !b.sourceIndex ) { - if ( a == b ) { - hasDuplicate = true; - } - return 0; - } - - var ret = a.sourceIndex - b.sourceIndex; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( document.createRange ) { - sortOrder = function( a, b ) { - if ( !a.ownerDocument || !b.ownerDocument ) { - if ( a == b ) { - hasDuplicate = true; - } - return 0; - } - - var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); - aRange.setStart(a, 0); - aRange.setEnd(a, 0); - bRange.setStart(b, 0); - bRange.setEnd(b, 0); - var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} - -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - var form = document.createElement("div"), - id = "script" + (new Date).getTime(); - form.innerHTML = ""; - - // Inject it into the root element, check its status, and remove it quickly - var root = document.documentElement; - root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - if ( !!document.getElementById( id ) ) { - Expr.find.ID = function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; - } - }; - - Expr.filter.ID = function(elem, match){ - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } - - root.removeChild( form ); - root = form = null; // release memory in IE -})(); - -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); - - // Make sure no comments are found - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function(match, context){ - var results = context.getElementsByTagName(match[1]); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - } - - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - Expr.attrHandle.href = function(elem){ - return elem.getAttribute("href", 2); - }; - } - - div = null; // release memory in IE -})(); - -if ( document.querySelectorAll ) (function(){ - var oldSizzle = Sizzle, div = document.createElement("div"); - div.innerHTML = "

"; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function(query, context, extra, seed){ - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && context.nodeType === 9 && !isXML(context) ) { - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(e){} - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - div = null; // release memory in IE -})(); - -if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ - var div = document.createElement("div"); - div.innerHTML = "
"; - - // Opera can't find a second classname (in 9.6) - if ( div.getElementsByClassName("e").length === 0 ) - return; - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) - return; - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function(match, context, isXML) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - div = null; // release memory in IE -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - var sibDir = dir == "previousSibling" && !isXML; - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - if ( sibDir && elem.nodeType === 1 ){ - elem.sizcache = doneName; - elem.sizset = i; - } - elem = elem[dir]; - var match = false; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; - elem.sizset = i; - } - - if ( elem.nodeName === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - var sibDir = dir == "previousSibling" && !isXML; - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - if ( sibDir && elem.nodeType === 1 ) { - elem.sizcache = doneName; - elem.sizset = i; - } - elem = elem[dir]; - var match = false; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem.sizcache = doneName; - elem.sizset = i; - } - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -var contains = document.compareDocumentPosition ? function(a, b){ - return a.compareDocumentPosition(b) & 16; -} : function(a, b){ - return a !== b && (a.contains ? a.contains(b) : true); -}; - -var isXML = function(elem){ - return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || - !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; -}; - -var posProcess = function(selector, context){ - var tmpSet = [], later = "", match, - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE - -Firebug.Selector = Sizzle; - -/**#@-*/ - -// ************************************************************************************************ -}}); - -/* See license.txt for terms of usage */ - -FBL.ns(function() { with (FBL) { -// ************************************************************************************************ - -// ************************************************************************************************ -// Inspector Module - -var ElementCache = Firebug.Lite.Cache.Element; - -var inspectorTS, inspectorTimer, isInspecting; - -Firebug.Inspector = -{ - create: function() - { - offlineFragment = Env.browser.document.createDocumentFragment(); - - createBoxModelInspector(); - createOutlineInspector(); - }, - - destroy: function() - { - destroyBoxModelInspector(); - destroyOutlineInspector(); - - offlineFragment = null; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Inspect functions - - toggleInspect: function() - { - if (isInspecting) - { - this.stopInspecting(); - } - else - { - Firebug.chrome.inspectButton.changeState("pressed"); - this.startInspecting(); - } - }, - - startInspecting: function() - { - isInspecting = true; - - Firebug.chrome.selectPanel("HTML"); - - createInspectorFrame(); - - var size = Firebug.browser.getWindowScrollSize(); - - fbInspectFrame.style.width = size.width + "px"; - fbInspectFrame.style.height = size.height + "px"; - - //addEvent(Firebug.browser.document.documentElement, "mousemove", Firebug.Inspector.onInspectingBody); - - addEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); - addEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); - }, - - stopInspecting: function() - { - isInspecting = false; - - if (outlineVisible) this.hideOutline(); - removeEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting); - removeEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick); - - destroyInspectorFrame(); - - Firebug.chrome.inspectButton.restore(); - - if (Firebug.chrome.type == "popup") - Firebug.chrome.node.focus(); - }, - - onInspectingClick: function(e) - { - fbInspectFrame.style.display = "none"; - var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); - fbInspectFrame.style.display = "block"; - - // Avoid inspecting the outline, and the FirebugUI - var id = targ.id; - if (id && /^fbOutline\w$/.test(id)) return; - if (id == "FirebugUI") return; - - // Avoid looking at text nodes in Opera - while (targ.nodeType != 1) targ = targ.parentNode; - - //Firebug.Console.log(targ); - Firebug.Inspector.stopInspecting(); - }, - - onInspecting: function(e) - { - if (new Date().getTime() - lastInspecting > 30) - { - fbInspectFrame.style.display = "none"; - var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY); - fbInspectFrame.style.display = "block"; - - // Avoid inspecting the outline, and the FirebugUI - var id = targ.id; - if (id && /^fbOutline\w$/.test(id)) return; - if (id == "FirebugUI") return; - - // Avoid looking at text nodes in Opera - while (targ.nodeType != 1) targ = targ.parentNode; - - if (targ.nodeName.toLowerCase() == "body") return; - - //Firebug.Console.log(e.clientX, e.clientY, targ); - Firebug.Inspector.drawOutline(targ); - - if (ElementCache(targ)) - { - var target = ""+ElementCache.key(targ); - var lazySelect = function() - { - inspectorTS = new Date().getTime(); - - if (Firebug.HTML) - Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)); - }; - - if (inspectorTimer) - { - clearTimeout(inspectorTimer); - inspectorTimer = null; - } - - if (new Date().getTime() - inspectorTS > 200) - setTimeout(lazySelect, 0); - else - inspectorTimer = setTimeout(lazySelect, 300); - } - - lastInspecting = new Date().getTime(); - } - }, - - // TODO: xxxpedro remove this? - onInspectingBody: function(e) - { - if (new Date().getTime() - lastInspecting > 30) - { - var targ = e.target; - - // Avoid inspecting the outline, and the FirebugUI - var id = targ.id; - if (id && /^fbOutline\w$/.test(id)) return; - if (id == "FirebugUI") return; - - // Avoid looking at text nodes in Opera - while (targ.nodeType != 1) targ = targ.parentNode; - - if (targ.nodeName.toLowerCase() == "body") return; - - //Firebug.Console.log(e.clientX, e.clientY, targ); - Firebug.Inspector.drawOutline(targ); - - if (ElementCache.has(targ)) - FBL.Firebug.HTML.selectTreeNode(""+ElementCache.key(targ)); - - lastInspecting = new Date().getTime(); - } - }, - - /** - * - * llttttttrr - * llttttttrr - * ll rr - * ll rr - * llbbbbbbrr - * llbbbbbbrr - */ - drawOutline: function(el) - { - var border = 2; - var scrollbarSize = 17; - - var windowSize = Firebug.browser.getWindowSize(); - var scrollSize = Firebug.browser.getWindowScrollSize(); - var scrollPosition = Firebug.browser.getWindowScrollPosition(); - - var box = Firebug.browser.getElementBox(el); - - var top = box.top; - var left = box.left; - var height = box.height; - var width = box.width; - - var freeHorizontalSpace = scrollPosition.left + windowSize.width - left - width - - (!isIE && scrollSize.height > windowSize.height ? // is *vertical* scrollbar visible - scrollbarSize : 0); - - var freeVerticalSpace = scrollPosition.top + windowSize.height - top - height - - (!isIE && scrollSize.width > windowSize.width ? // is *horizontal* scrollbar visible - scrollbarSize : 0); - - var numVerticalBorders = freeVerticalSpace > 0 ? 2 : 1; - - var o = outlineElements; - var style; - - style = o.fbOutlineT.style; - style.top = top-border + "px"; - style.left = left + "px"; - style.height = border + "px"; // TODO: on initialize() - style.width = width + "px"; - - style = o.fbOutlineL.style; - style.top = top-border + "px"; - style.left = left-border + "px"; - style.height = height+ numVerticalBorders*border + "px"; - style.width = border + "px"; // TODO: on initialize() - - style = o.fbOutlineB.style; - if (freeVerticalSpace > 0) - { - style.top = top+height + "px"; - style.left = left + "px"; - style.width = width + "px"; - //style.height = border + "px"; // TODO: on initialize() or worst case? - } - else - { - style.top = -2*border + "px"; - style.left = -2*border + "px"; - style.width = border + "px"; - //style.height = border + "px"; - } - - style = o.fbOutlineR.style; - if (freeHorizontalSpace > 0) - { - style.top = top-border + "px"; - style.left = left+width + "px"; - style.height = height + numVerticalBorders*border + "px"; - style.width = (freeHorizontalSpace < border ? freeHorizontalSpace : border) + "px"; - } - else - { - style.top = -2*border + "px"; - style.left = -2*border + "px"; - style.height = border + "px"; - style.width = border + "px"; - } - - if (!outlineVisible) this.showOutline(); - }, - - hideOutline: function() - { - if (!outlineVisible) return; - - for (var name in outline) - offlineFragment.appendChild(outlineElements[name]); - - outlineVisible = false; - }, - - showOutline: function() - { - if (outlineVisible) return; - - if (boxModelVisible) this.hideBoxModel(); - - for (var name in outline) - Firebug.browser.document.getElementsByTagName("body")[0].appendChild(outlineElements[name]); - - outlineVisible = true; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - // Box Model - - drawBoxModel: function(el) - { - // avoid error when the element is not attached a document - if (!el || !el.parentNode) - return; - - var box = Firebug.browser.getElementBox(el); - - var windowSize = Firebug.browser.getWindowSize(); - var scrollPosition = Firebug.browser.getWindowScrollPosition(); - - // element may be occluded by the chrome, when in frame mode - var offsetHeight = Firebug.chrome.type == "frame" ? Firebug.context.persistedState.height : 0; - - // if element box is not inside the viewport, don't draw the box model - if (box.top > scrollPosition.top + windowSize.height - offsetHeight || - box.left > scrollPosition.left + windowSize.width || - scrollPosition.top > box.top + box.height || - scrollPosition.left > box.left + box.width ) - return; - - var top = box.top; - var left = box.left; - var height = box.height; - var width = box.width; - - var margin = Firebug.browser.getMeasurementBox(el, "margin"); - var padding = Firebug.browser.getMeasurementBox(el, "padding"); - var border = Firebug.browser.getMeasurementBox(el, "border"); - - boxModelStyle.top = top - margin.top + "px"; - boxModelStyle.left = left - margin.left + "px"; - boxModelStyle.height = height + margin.top + margin.bottom + "px"; - boxModelStyle.width = width + margin.left + margin.right + "px"; - - boxBorderStyle.top = margin.top + "px"; - boxBorderStyle.left = margin.left + "px"; - boxBorderStyle.height = height + "px"; - boxBorderStyle.width = width + "px"; - - boxPaddingStyle.top = margin.top + border.top + "px"; - boxPaddingStyle.left = margin.left + border.left + "px"; - boxPaddingStyle.height = height - border.top - border.bottom + "px"; - boxPaddingStyle.width = width - border.left - border.right + "px"; - - boxContentStyle.top = margin.top + border.top + padding.top + "px"; - boxContentStyle.left = margin.left + border.left + padding.left + "px"; - boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px"; - boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px"; - - if (!boxModelVisible) this.showBoxModel(); - }, - - hideBoxModel: function() - { - if (!boxModelVisible) return; - - offlineFragment.appendChild(boxModel); - boxModelVisible = false; - }, - - showBoxModel: function() - { - if (boxModelVisible) return; - - if (outlineVisible) this.hideOutline(); - - Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel); - boxModelVisible = true; - } - -}; - -// ************************************************************************************************ -// Inspector Internals - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Shared variables - - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// Internal variables - -var offlineFragment = null; - -var boxModelVisible = false; - -var boxModel, boxModelStyle, - boxMargin, boxMarginStyle, - boxBorder, boxBorderStyle, - boxPadding, boxPaddingStyle, - boxContent, boxContentStyle; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;"; -var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;"; - -var inspectStyle = resetStyle + "z-index: 2147483500;"; -var inspectFrameStyle = resetStyle + "z-index: 2147483550; top:0; left:0; background:url(" + - Env.Location.skinDir + "pixel_transparent.gif);"; - -//if (Env.Options.enableTrace) inspectFrameStyle = resetStyle + "z-index: 2147483550; top: 0; left: 0; background: #ff0; opacity: 0.05; _filter: alpha(opacity=5);"; - -var inspectModelOpacity = isIE ? "filter:alpha(opacity=80);" : "opacity:0.8;"; -var inspectModelStyle = inspectStyle + inspectModelOpacity; -var inspectMarginStyle = inspectStyle + "background: #EDFF64; height:100%; width:100%;"; -var inspectBorderStyle = inspectStyle + "background: #666;"; -var inspectPaddingStyle = inspectStyle + "background: SlateBlue;"; -var inspectContentStyle = inspectStyle + "background: SkyBlue;"; - - -var outlineStyle = { - fbHorizontalLine: "background: #3875D7;height: 2px;", - fbVerticalLine: "background: #3875D7;width: 2px;" -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var lastInspecting = 0; -var fbInspectFrame = null; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var outlineVisible = false; -var outlineElements = {}; -var outline = { - "fbOutlineT": "fbHorizontalLine", - "fbOutlineL": "fbVerticalLine", - "fbOutlineB": "fbHorizontalLine", - "fbOutlineR": "fbVerticalLine" -}; - - -var getInspectingTarget = function() -{ - -}; - -// ************************************************************************************************ -// Section - -var createInspectorFrame = function createInspectorFrame() -{ - fbInspectFrame = createGlobalElement("div"); - fbInspectFrame.id = "fbInspectFrame"; - fbInspectFrame.firebugIgnore = true; - fbInspectFrame.style.cssText = inspectFrameStyle; - Firebug.browser.document.getElementsByTagName("body")[0].appendChild(fbInspectFrame); -}; - -var destroyInspectorFrame = function destroyInspectorFrame() -{ - if (fbInspectFrame) - { - Firebug.browser.document.getElementsByTagName("body")[0].removeChild(fbInspectFrame); - fbInspectFrame = null; - } -}; - -var createOutlineInspector = function createOutlineInspector() -{ - for (var name in outline) - { - var el = outlineElements[name] = createGlobalElement("div"); - el.id = name; - el.firebugIgnore = true; - el.style.cssText = inspectStyle + outlineStyle[outline[name]]; - offlineFragment.appendChild(el); - } -}; - -var destroyOutlineInspector = function destroyOutlineInspector() -{ - for (var name in outline) - { - var el = outlineElements[name]; - el.parentNode.removeChild(el); - } -}; - -var createBoxModelInspector = function createBoxModelInspector() -{ - boxModel = createGlobalElement("div"); - boxModel.id = "fbBoxModel"; - boxModel.firebugIgnore = true; - boxModelStyle = boxModel.style; - boxModelStyle.cssText = inspectModelStyle; - - boxMargin = createGlobalElement("div"); - boxMargin.id = "fbBoxMargin"; - boxMarginStyle = boxMargin.style; - boxMarginStyle.cssText = inspectMarginStyle; - boxModel.appendChild(boxMargin); - - boxBorder = createGlobalElement("div"); - boxBorder.id = "fbBoxBorder"; - boxBorderStyle = boxBorder.style; - boxBorderStyle.cssText = inspectBorderStyle; - boxModel.appendChild(boxBorder); - - boxPadding = createGlobalElement("div"); - boxPadding.id = "fbBoxPadding"; - boxPaddingStyle = boxPadding.style; - boxPaddingStyle.cssText = inspectPaddingStyle; - boxModel.appendChild(boxPadding); - - boxContent = createGlobalElement("div"); - boxContent.id = "fbBoxContent"; - boxContentStyle = boxContent.style; - boxContentStyle.cssText = inspectContentStyle; - boxModel.appendChild(boxContent); - - offlineFragment.appendChild(boxModel); -}; - -var destroyBoxModelInspector = function destroyBoxModelInspector() -{ - boxModel.parentNode.removeChild(boxModel); -}; - -// ************************************************************************************************ -// Section - - - - -// ************************************************************************************************ -}}); - -// Problems in IE -// FIXED - eval return -// FIXED - addEventListener problem in IE -// FIXED doc.createRange? -// -// class reserved word -// test all honza examples in IE6 and IE7 - - -/* See license.txt for terms of usage */ - -( /** @scope s_domplate */ function() { - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -/** @class */ -FBL.DomplateTag = function DomplateTag(tagName) -{ - this.tagName = tagName; -}; - -/** - * @class - * @extends FBL.DomplateTag - */ -FBL.DomplateEmbed = function DomplateEmbed() -{ -}; - -/** - * @class - * @extends FBL.DomplateTag - */ -FBL.DomplateLoop = function DomplateLoop() -{ -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var DomplateTag = FBL.DomplateTag; -var DomplateEmbed = FBL.DomplateEmbed; -var DomplateLoop = FBL.DomplateLoop; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -var womb = null; - -FBL.domplate = function() -{ - var lastSubject; - for (var i = 0; i < arguments.length; ++i) - lastSubject = lastSubject ? copyObject(lastSubject, arguments[i]) : arguments[i]; - - for (var name in lastSubject) - { - var val = lastSubject[name]; - if (isTag(val)) - val.tag.subject = lastSubject; - } - - return lastSubject; -}; - -var domplate = FBL.domplate; - -FBL.domplate.context = function(context, fn) -{ - var lastContext = domplate.lastContext; - domplate.topContext = context; - fn.apply(context); - domplate.topContext = lastContext; -}; - -FBL.TAG = function() -{ - var embed = new DomplateEmbed(); - return embed.merge(arguments); -}; - -FBL.FOR = function() -{ - var loop = new DomplateLoop(); - return loop.merge(arguments); -}; - -FBL.DomplateTag.prototype = -{ - merge: function(args, oldTag) - { - if (oldTag) - this.tagName = oldTag.tagName; - - this.context = oldTag ? oldTag.context : null; - this.subject = oldTag ? oldTag.subject : null; - this.attrs = oldTag ? copyObject(oldTag.attrs) : {}; - this.classes = oldTag ? copyObject(oldTag.classes) : {}; - this.props = oldTag ? copyObject(oldTag.props) : null; - this.listeners = oldTag ? copyArray(oldTag.listeners) : null; - this.children = oldTag ? copyArray(oldTag.children) : []; - this.vars = oldTag ? copyArray(oldTag.vars) : []; - - var attrs = args.length ? args[0] : null; - var hasAttrs = typeof(attrs) == "object" && !isTag(attrs); - - this.children = []; - - if (domplate.topContext) - this.context = domplate.topContext; - - if (args.length) - parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children); - - if (hasAttrs) - this.parseAttrs(attrs); - - return creator(this, DomplateTag); - }, - - parseAttrs: function(args) - { - for (var name in args) - { - var val = parseValue(args[name]); - readPartNames(val, this.vars); - - if (name.indexOf("on") == 0) - { - var eventName = name.substr(2); - if (!this.listeners) - this.listeners = []; - this.listeners.push(eventName, val); - } - else if (name.indexOf("_") == 0) - { - var propName = name.substr(1); - if (!this.props) - this.props = {}; - this.props[propName] = val; - } - else if (name.indexOf("$") == 0) - { - var className = name.substr(1); - if (!this.classes) - this.classes = {}; - this.classes[className] = val; - } - else - { - if (name == "class" && this.attrs.hasOwnProperty(name) ) - this.attrs[name] += " " + val; - else - this.attrs[name] = val; - } - } - }, - - compile: function() - { - if (this.renderMarkup) - return; - - this.compileMarkup(); - this.compileDOM(); - - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderMarkup: ", this.renderMarkup); - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderDOM:", this.renderDOM); - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate domArgs:", this.domArgs); - }, - - compileMarkup: function() - { - this.markupArgs = []; - var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0}; - - this.generateMarkup(topBlock, topOuts, blocks, info); - this.addCode(topBlock, topOuts, blocks); - - var fnBlock = ['r=(function (__code__, __context__, __in__, __out__']; - for (var i = 0; i < info.argIndex; ++i) - fnBlock.push(', s', i); - fnBlock.push(') {'); - - if (this.subject) - fnBlock.push('with (this) {'); - if (this.context) - fnBlock.push('with (__context__) {'); - fnBlock.push('with (__in__) {'); - - fnBlock.push.apply(fnBlock, blocks); - - if (this.subject) - fnBlock.push('}'); - if (this.context) - fnBlock.push('}'); - - fnBlock.push('}})'); - - function __link__(tag, code, outputs, args) - { - if (!tag || !tag.tag) - return; - - tag.tag.compile(); - - var tagOutputs = []; - var markupArgs = [code, tag.tag.context, args, tagOutputs]; - markupArgs.push.apply(markupArgs, tag.tag.markupArgs); - tag.tag.renderMarkup.apply(tag.tag.subject, markupArgs); - - outputs.push(tag); - outputs.push(tagOutputs); - } - - function __escape__(value) - { - function replaceChars(ch) - { - switch (ch) - { - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - case "'": - return "'"; - case '"': - return """; - } - return "?"; - }; - return String(value).replace(/[<>&"']/g, replaceChars); - } - - function __loop__(iter, outputs, fn) - { - var iterOuts = []; - outputs.push(iterOuts); - - if (iter instanceof Array) - iter = new ArrayIterator(iter); - - try - { - while (1) - { - var value = iter.next(); - var itemOuts = [0,0]; - iterOuts.push(itemOuts); - fn.apply(this, [value, itemOuts]); - } - } - catch (exc) - { - if (exc != StopIteration) - throw exc; - } - } - - var js = fnBlock.join(""); - var r = null; - eval(js); - this.renderMarkup = r; - }, - - getVarNames: function(args) - { - if (this.vars) - args.push.apply(args, this.vars); - - for (var i = 0; i < this.children.length; ++i) - { - var child = this.children[i]; - if (isTag(child)) - child.tag.getVarNames(args); - else if (child instanceof Parts) - { - for (var i = 0; i < child.parts.length; ++i) - { - if (child.parts[i] instanceof Variable) - { - var name = child.parts[i].name; - var names = name.split("."); - args.push(names[0]); - } - } - } - } - }, - - generateMarkup: function(topBlock, topOuts, blocks, info) - { - topBlock.push(',"<', this.tagName, '"'); - - for (var name in this.attrs) - { - if (name != "class") - { - var val = this.attrs[name]; - topBlock.push(', " ', name, '=\\""'); - addParts(val, ',', topBlock, info, true); - topBlock.push(', "\\""'); - } - } - - if (this.listeners) - { - for (var i = 0; i < this.listeners.length; i += 2) - readPartNames(this.listeners[i+1], topOuts); - } - - if (this.props) - { - for (var name in this.props) - readPartNames(this.props[name], topOuts); - } - - if ( this.attrs.hasOwnProperty("class") || this.classes) - { - topBlock.push(', " class=\\""'); - if (this.attrs.hasOwnProperty("class")) - addParts(this.attrs["class"], ',', topBlock, info, true); - topBlock.push(', " "'); - for (var name in this.classes) - { - topBlock.push(', ('); - addParts(this.classes[name], '', topBlock, info); - topBlock.push(' ? "', name, '" + " " : "")'); - } - topBlock.push(', "\\""'); - } - topBlock.push(',">"'); - - this.generateChildMarkup(topBlock, topOuts, blocks, info); - topBlock.push(',""'); - }, - - generateChildMarkup: function(topBlock, topOuts, blocks, info) - { - for (var i = 0; i < this.children.length; ++i) - { - var child = this.children[i]; - if (isTag(child)) - child.tag.generateMarkup(topBlock, topOuts, blocks, info); - else - addParts(child, ',', topBlock, info, true); - } - }, - - addCode: function(topBlock, topOuts, blocks) - { - if (topBlock.length) - blocks.push('__code__.push(""', topBlock.join(""), ');'); - if (topOuts.length) - blocks.push('__out__.push(', topOuts.join(","), ');'); - topBlock.splice(0, topBlock.length); - topOuts.splice(0, topOuts.length); - }, - - addLocals: function(blocks) - { - var varNames = []; - this.getVarNames(varNames); - - var map = {}; - for (var i = 0; i < varNames.length; ++i) - { - var name = varNames[i]; - if ( map.hasOwnProperty(name) ) - continue; - - map[name] = 1; - var names = name.split("."); - blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';'); - } - }, - - compileDOM: function() - { - var path = []; - var blocks = []; - this.domArgs = []; - path.embedIndex = 0; - path.loopIndex = 0; - path.staticIndex = 0; - path.renderIndex = 0; - var nodeCount = this.generateDOM(path, blocks, this.domArgs); - - var fnBlock = ['r=(function (root, context, o']; - - for (var i = 0; i < path.staticIndex; ++i) - fnBlock.push(', ', 's'+i); - - for (var i = 0; i < path.renderIndex; ++i) - fnBlock.push(', ', 'd'+i); - - fnBlock.push(') {'); - for (var i = 0; i < path.loopIndex; ++i) - fnBlock.push('var l', i, ' = 0;'); - for (var i = 0; i < path.embedIndex; ++i) - fnBlock.push('var e', i, ' = 0;'); - - if (this.subject) - fnBlock.push('with (this) {'); - if (this.context) - fnBlock.push('with (context) {'); - - fnBlock.push(blocks.join("")); - - if (this.subject) - fnBlock.push('}'); - if (this.context) - fnBlock.push('}'); - - fnBlock.push('return ', nodeCount, ';'); - fnBlock.push('})'); - - function __bind__(object, fn) - { - return function(event) { return fn.apply(object, [event]); }; - } - - function __link__(node, tag, args) - { - if (!tag || !tag.tag) - return; - - tag.tag.compile(); - - var domArgs = [node, tag.tag.context, 0]; - domArgs.push.apply(domArgs, tag.tag.domArgs); - domArgs.push.apply(domArgs, args); - //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate__link__ domArgs:", domArgs); - return tag.tag.renderDOM.apply(tag.tag.subject, domArgs); - } - - var self = this; - function __loop__(iter, fn) - { - var nodeCount = 0; - for (var i = 0; i < iter.length; ++i) - { - iter[i][0] = i; - iter[i][1] = nodeCount; - nodeCount += fn.apply(this, iter[i]); - //if (FBTrace.DBG_DOM) FBTrace.sysout("nodeCount", nodeCount); - } - return nodeCount; - } - - function __path__(parent, offset) - { - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n"); - var root = parent; - - for (var i = 2; i < arguments.length; ++i) - { - var index = arguments[i]; - if (i == 3) - index += offset; - - if (index == -1) - parent = parent.parentNode; - else - parent = parent.childNodes[index]; - } - - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n"); - return parent; - } - - var js = fnBlock.join(""); - //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n")); - var r = null; - eval(js); - this.renderDOM = r; - }, - - generateDOM: function(path, blocks, args) - { - if (this.listeners || this.props) - this.generateNodePath(path, blocks); - - if (this.listeners) - { - for (var i = 0; i < this.listeners.length; i += 2) - { - var val = this.listeners[i+1]; - var arg = generateArg(val, path, args); - //blocks.push('node.addEventListener("', this.listeners[i], '", __bind__(this, ', arg, '), false);'); - blocks.push('addEvent(node, "', this.listeners[i], '", __bind__(this, ', arg, '), false);'); - } - } - - if (this.props) - { - for (var name in this.props) - { - var val = this.props[name]; - var arg = generateArg(val, path, args); - blocks.push('node.', name, ' = ', arg, ';'); - } - } - - this.generateChildDOM(path, blocks, args); - return 1; - }, - - generateNodePath: function(path, blocks) - { - blocks.push("var node = __path__(root, o"); - for (var i = 0; i < path.length; ++i) - blocks.push(",", path[i]); - blocks.push(");"); - }, - - generateChildDOM: function(path, blocks, args) - { - path.push(0); - for (var i = 0; i < this.children.length; ++i) - { - var child = this.children[i]; - if (isTag(child)) - path[path.length-1] += '+' + child.tag.generateDOM(path, blocks, args); - else - path[path.length-1] += '+1'; - } - path.pop(); - } -}; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -FBL.DomplateEmbed.prototype = copyObject(FBL.DomplateTag.prototype, -/** @lends FBL.DomplateEmbed.prototype */ -{ - merge: function(args, oldTag) - { - this.value = oldTag ? oldTag.value : parseValue(args[0]); - this.attrs = oldTag ? oldTag.attrs : {}; - this.vars = oldTag ? copyArray(oldTag.vars) : []; - - var attrs = args[1]; - for (var name in attrs) - { - var val = parseValue(attrs[name]); - this.attrs[name] = val; - readPartNames(val, this.vars); - } - - return creator(this, DomplateEmbed); - }, - - getVarNames: function(names) - { - if (this.value instanceof Parts) - names.push(this.value.parts[0].name); - - if (this.vars) - names.push.apply(names, this.vars); - }, - - generateMarkup: function(topBlock, topOuts, blocks, info) - { - this.addCode(topBlock, topOuts, blocks); - - blocks.push('__link__('); - addParts(this.value, '', blocks, info); - blocks.push(', __code__, __out__, {'); - - var lastName = null; - for (var name in this.attrs) - { - if (lastName) - blocks.push(','); - lastName = name; - - var val = this.attrs[name]; - blocks.push('"', name, '":'); - addParts(val, '', blocks, info); - } - - blocks.push('});'); - //this.generateChildMarkup(topBlock, topOuts, blocks, info); - }, - - generateDOM: function(path, blocks, args) - { - var embedName = 'e'+path.embedIndex++; - - this.generateNodePath(path, blocks); - - var valueName = 'd' + path.renderIndex++; - var argsName = 'd' + path.renderIndex++; - blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');'); - - return embedName; - } -}); - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -FBL.DomplateLoop.prototype = copyObject(FBL.DomplateTag.prototype, -/** @lends FBL.DomplateLoop.prototype */ -{ - merge: function(args, oldTag) - { - this.varName = oldTag ? oldTag.varName : args[0]; - this.iter = oldTag ? oldTag.iter : parseValue(args[1]); - this.vars = []; - - this.children = oldTag ? copyArray(oldTag.children) : []; - - var offset = Math.min(args.length, 2); - parseChildren(args, offset, this.vars, this.children); - - return creator(this, DomplateLoop); - }, - - getVarNames: function(names) - { - if (this.iter instanceof Parts) - names.push(this.iter.parts[0].name); - - DomplateTag.prototype.getVarNames.apply(this, [names]); - }, - - generateMarkup: function(topBlock, topOuts, blocks, info) - { - this.addCode(topBlock, topOuts, blocks); - - var iterName; - if (this.iter instanceof Parts) - { - var part = this.iter.parts[0]; - iterName = part.name; - - if (part.format) - { - for (var i = 0; i < part.format.length; ++i) - iterName = part.format[i] + "(" + iterName + ")"; - } - } - else - iterName = this.iter; - - blocks.push('__loop__.apply(this, [', iterName, ', __out__, function(', this.varName, ', __out__) {'); - this.generateChildMarkup(topBlock, topOuts, blocks, info); - this.addCode(topBlock, topOuts, blocks); - blocks.push('}]);'); - }, - - generateDOM: function(path, blocks, args) - { - var iterName = 'd'+path.renderIndex++; - var counterName = 'i'+path.loopIndex; - var loopName = 'l'+path.loopIndex++; - - if (!path.length) - path.push(-1, 0); - - var preIndex = path.renderIndex; - path.renderIndex = 0; - - var nodeCount = 0; - - var subBlocks = []; - var basePath = path[path.length-1]; - for (var i = 0; i < this.children.length; ++i) - { - path[path.length-1] = basePath+'+'+loopName+'+'+nodeCount; - - var child = this.children[i]; - if (isTag(child)) - nodeCount += '+' + child.tag.generateDOM(path, subBlocks, args); - else - nodeCount += '+1'; - } - - path[path.length-1] = basePath+'+'+loopName; - - blocks.push(loopName,' = __loop__.apply(this, [', iterName, ', function(', counterName,',',loopName); - for (var i = 0; i < path.renderIndex; ++i) - blocks.push(',d'+i); - blocks.push(') {'); - blocks.push(subBlocks.join("")); - blocks.push('return ', nodeCount, ';'); - blocks.push('}]);'); - - path.renderIndex = preIndex; - - return loopName; - } -}); - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -/** @class */ -function Variable(name, format) -{ - this.name = name; - this.format = format; -} - -/** @class */ -function Parts(parts) -{ - this.parts = parts; -} - -// ************************************************************************************************ - -function parseParts(str) -{ - var re = /\$([_A-Za-z][_A-Za-z0-9.|]*)/g; - var index = 0; - var parts = []; - - var m; - while (m = re.exec(str)) - { - var pre = str.substr(index, (re.lastIndex-m[0].length)-index); - if (pre) - parts.push(pre); - - var expr = m[1].split("|"); - parts.push(new Variable(expr[0], expr.slice(1))); - index = re.lastIndex; - } - - if (!index) - return str; - - var post = str.substr(index); - if (post) - parts.push(post); - - return new Parts(parts); -} - -function parseValue(val) -{ - return typeof(val) == 'string' ? parseParts(val) : val; -} - -function parseChildren(args, offset, vars, children) -{ - for (var i = offset; i < args.length; ++i) - { - var val = parseValue(args[i]); - children.push(val); - readPartNames(val, vars); - } -} - -function readPartNames(val, vars) -{ - if (val instanceof Parts) - { - for (var i = 0; i < val.parts.length; ++i) - { - var part = val.parts[i]; - if (part instanceof Variable) - vars.push(part.name); - } - } -} - -function generateArg(val, path, args) -{ - if (val instanceof Parts) - { - var vals = []; - for (var i = 0; i < val.parts.length; ++i) - { - var part = val.parts[i]; - if (part instanceof Variable) - { - var varName = 'd'+path.renderIndex++; - if (part.format) - { - for (var j = 0; j < part.format.length; ++j) - varName = part.format[j] + '(' + varName + ')'; - } - - vals.push(varName); - } - else - vals.push('"'+part.replace(/"/g, '\\"')+'"'); - } - - return vals.join('+'); - } - else - { - args.push(val); - return 's' + path.staticIndex++; - } -} - -function addParts(val, delim, block, info, escapeIt) -{ - var vals = []; - if (val instanceof Parts) - { - for (var i = 0; i < val.parts.length; ++i) - { - var part = val.parts[i]; - if (part instanceof Variable) - { - var partName = part.name; - if (part.format) - { - for (var j = 0; j < part.format.length; ++j) - partName = part.format[j] + "(" + partName + ")"; - } - - if (escapeIt) - vals.push("__escape__(" + partName + ")"); - else - vals.push(partName); - } - else - vals.push('"'+ part + '"'); - } - } - else if (isTag(val)) - { - info.args.push(val); - vals.push('s'+info.argIndex++); - } - else - vals.push('"'+ val + '"'); - - var parts = vals.join(delim); - if (parts) - block.push(delim, parts); -} - -function isTag(obj) -{ - return (typeof(obj) == "function" || obj instanceof Function) && !!obj.tag; -} - -function creator(tag, cons) -{ - var fn = new Function( - "var tag = arguments.callee.tag;" + - "var cons = arguments.callee.cons;" + - "var newTag = new cons();" + - "return newTag.merge(arguments, tag);"); - - fn.tag = tag; - fn.cons = cons; - extend(fn, Renderer); - - return fn; -} - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -function copyArray(oldArray) -{ - var ary = []; - if (oldArray) - for (var i = 0; i < oldArray.length; ++i) - ary.push(oldArray[i]); - return ary; -} - -function copyObject(l, r) -{ - var m = {}; - extend(m, l); - extend(m, r); - return m; -} - -function extend(l, r) -{ - for (var n in r) - l[n] = r[n]; -} - -function addEvent(object, name, handler) -{ - if (document.all) - object.attachEvent("on"+name, handler); - else - object.addEventListener(name, handler, false); -} - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - -/** @class */ -function ArrayIterator(array) -{ - var index = -1; - - this.next = function() - { - if (++index >= array.length) - throw StopIteration; - - return array[index]; - }; -} - -/** @class */ -function StopIteration() {} - -FBL.$break = function() -{ - throw StopIteration; -}; - -// ************************************************************************************************ - -/** @namespace */ -var Renderer = -{ - renderHTML: function(args, outputs, self) - { - var code = []; - var markupArgs = [code, this.tag.context, args, outputs]; - markupArgs.push.apply(markupArgs, this.tag.markupArgs); - this.tag.renderMarkup.apply(self ? self : this.tag.subject, markupArgs); - return code.join(""); - }, - - insertRows: function(args, before, self) - { - this.tag.compile(); - - var outputs = []; - var html = this.renderHTML(args, outputs, self); - - var doc = before.ownerDocument; - var div = doc.createElement("div"); - div.innerHTML = ""+html+"
"; - - var tbody = div.firstChild.firstChild; - var parent = before.tagName == "TR" ? before.parentNode : before; - var after = before.tagName == "TR" ? before.nextSibling : null; - - var firstRow = tbody.firstChild, lastRow; - while (tbody.firstChild) - { - lastRow = tbody.firstChild; - if (after) - parent.insertBefore(lastRow, after); - else - parent.appendChild(lastRow); - } - - var offset = 0; - if (before.tagName == "TR") - { - var node = firstRow.parentNode.firstChild; - for (; node && node != firstRow; node = node.nextSibling) - ++offset; - } - - var domArgs = [firstRow, this.tag.context, offset]; - domArgs.push.apply(domArgs, this.tag.domArgs); - domArgs.push.apply(domArgs, outputs); - - this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); - return [firstRow, lastRow]; - }, - - insertBefore: function(args, before, self) - { - return this.insertNode(args, before.ownerDocument, before, false, self); - }, - - insertAfter: function(args, after, self) - { - return this.insertNode(args, after.ownerDocument, after, true, self); - }, - - insertNode: function(args, doc, element, isAfter, self) - { - if (!args) - args = {}; - - this.tag.compile(); - - var outputs = []; - var html = this.renderHTML(args, outputs, self); - - //if (FBTrace.DBG_DOM) - // FBTrace.sysout("domplate.insertNode html: "+html+"\n"); - - var doc = element.ownerDocument; - if (!womb || womb.ownerDocument != doc) - womb = doc.createElement("div"); - - womb.innerHTML = html; - - var root = womb.firstChild; - if (isAfter) - { - while (womb.firstChild) - if (element.nextSibling) - element.parentNode.insertBefore(womb.firstChild, element.nextSibling); - else - element.parentNode.appendChild(womb.firstChild); - } - else - { - while (womb.lastChild) - element.parentNode.insertBefore(womb.lastChild, element); - } - - var domArgs = [root, this.tag.context, 0]; - domArgs.push.apply(domArgs, this.tag.domArgs); - domArgs.push.apply(domArgs, outputs); - - //if (FBTrace.DBG_DOM) - // FBTrace.sysout("domplate.insertNode domArgs:", domArgs); - this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); - - return root; - }, - /**/ - - /* - insertAfter: function(args, before, self) - { - this.tag.compile(); - - var outputs = []; - var html = this.renderHTML(args, outputs, self); - - var doc = before.ownerDocument; - if (!womb || womb.ownerDocument != doc) - womb = doc.createElement("div"); - - womb.innerHTML = html; - - var root = womb.firstChild; - while (womb.firstChild) - if (before.nextSibling) - before.parentNode.insertBefore(womb.firstChild, before.nextSibling); - else - before.parentNode.appendChild(womb.firstChild); - - var domArgs = [root, this.tag.context, 0]; - domArgs.push.apply(domArgs, this.tag.domArgs); - domArgs.push.apply(domArgs, outputs); - - this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null), - domArgs); - - return root; - }, - /**/ - - replace: function(args, parent, self) - { - this.tag.compile(); - - var outputs = []; - var html = this.renderHTML(args, outputs, self); - - var root; - if (parent.nodeType == 1) - { - parent.innerHTML = html; - root = parent.firstChild; - } - else - { - if (!parent || parent.nodeType != 9) - parent = document; - - if (!womb || womb.ownerDocument != parent) - womb = parent.createElement("div"); - womb.innerHTML = html; - - root = womb.firstChild; - //womb.removeChild(root); - } - - var domArgs = [root, this.tag.context, 0]; - domArgs.push.apply(domArgs, this.tag.domArgs); - domArgs.push.apply(domArgs, outputs); - this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); - - return root; - }, - - append: function(args, parent, self) - { - this.tag.compile(); - - var outputs = []; - var html = this.renderHTML(args, outputs, self); - //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate.append html: "+html+"\n"); - - if (!womb || womb.ownerDocument != parent.ownerDocument) - womb = parent.ownerDocument.createElement("div"); - womb.innerHTML = html; - - // TODO: xxxpedro domplate port to Firebug - var root = womb.firstChild; - while (womb.firstChild) - parent.appendChild(womb.firstChild); - - // clearing element reference to avoid reference error in IE8 when switching contexts - womb = null; - - var domArgs = [root, this.tag.context, 0]; - domArgs.push.apply(domArgs, this.tag.domArgs); - domArgs.push.apply(domArgs, outputs); - - //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate append domArgs:", domArgs); - this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs); - - return root; - } -}; - -// ************************************************************************************************ - -function defineTags() -{ - for (var i = 0; i < arguments.length; ++i) - { - var tagName = arguments[i]; - var fn = new Function("var newTag = new arguments.callee.DomplateTag('"+tagName+"'); return newTag.merge(arguments);"); - fn.DomplateTag = DomplateTag; - - var fnName = tagName.toUpperCase(); - FBL[fnName] = fn; - } -} - -defineTags( - "a", "button", "br", "canvas", "code", "col", "colgroup", "div", "fieldset", "form", "h1", "h2", "h3", "hr", - "img", "input", "label", "legend", "li", "ol", "optgroup", "option", "p", "pre", "select", - "span", "strong", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul", "iframe" -); - -})(); - - -/* See license.txt for terms of usage */ - -var FirebugReps = FBL.ns(function() { with (FBL) { - - -// ************************************************************************************************ -// Common Tags - -var OBJECTBOX = this.OBJECTBOX = - SPAN({"class": "objectBox objectBox-$className"}); - -var OBJECTBLOCK = this.OBJECTBLOCK = - DIV({"class": "objectBox objectBox-$className"}); - -var OBJECTLINK = this.OBJECTLINK = isIE6 ? // IE6 object link representation - A({ - "class": "objectLink objectLink-$className a11yFocus", - href: "javascript:void(0)", - // workaround to show XPath (a better approach would use the tooltip on mouseover, - // so the XPath information would be calculated dynamically, but we need to create - // a tooltip class/wrapper around Menu or InfoTip) - title: "$object|FBL.getElementXPath", - _repObject: "$object" - }) - : // Other browsers - A({ - "class": "objectLink objectLink-$className a11yFocus", - // workaround to show XPath (a better approach would use the tooltip on mouseover, - // so the XPath information would be calculated dynamically, but we need to create - // a tooltip class/wrapper around Menu or InfoTip) - title: "$object|FBL.getElementXPath", - _repObject: "$object" - }); - - -// ************************************************************************************************ - -this.Undefined = domplate(Firebug.Rep, -{ - tag: OBJECTBOX("undefined"), - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "undefined", - - supportsObject: function(object, type) - { - return type == "undefined"; - } -}); - -// ************************************************************************************************ - -this.Null = domplate(Firebug.Rep, -{ - tag: OBJECTBOX("null"), - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "null", - - supportsObject: function(object, type) - { - return object == null; - } -}); - -// ************************************************************************************************ - -this.Nada = domplate(Firebug.Rep, -{ - tag: SPAN(""), - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "nada" -}); - -// ************************************************************************************************ - -this.Number = domplate(Firebug.Rep, -{ - tag: OBJECTBOX("$object"), - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "number", - - supportsObject: function(object, type) - { - return type == "boolean" || type == "number"; - } -}); - -// ************************************************************************************************ - -this.String = domplate(Firebug.Rep, -{ - tag: OBJECTBOX(""$object""), - - shortTag: OBJECTBOX(""$object|cropString""), - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "string", - - supportsObject: function(object, type) - { - return type == "string"; - } -}); - -// ************************************************************************************************ - -this.Text = domplate(Firebug.Rep, -{ - tag: OBJECTBOX("$object"), - - shortTag: OBJECTBOX("$object|cropString"), - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "text" -}); - -// ************************************************************************************************ - -this.Caption = domplate(Firebug.Rep, -{ - tag: SPAN({"class": "caption"}, "$object") -}); - -// ************************************************************************************************ - -this.Warning = domplate(Firebug.Rep, -{ - tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR") -}); - -// ************************************************************************************************ - -this.Func = domplate(Firebug.Rep, -{ - tag: - OBJECTLINK("$object|summarizeFunction"), - - summarizeFunction: function(fn) - { - var fnRegex = /function ([^(]+\([^)]*\)) \{/; - var fnText = safeToString(fn); - - var m = fnRegex.exec(fnText); - return m ? m[1] : "function()"; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - copySource: function(fn) - { - copyToClipboard(safeToString(fn)); - }, - - monitor: function(fn, script, monitored) - { - if (monitored) - Firebug.Debugger.unmonitorScript(fn, script, "monitor"); - else - Firebug.Debugger.monitorScript(fn, script, "monitor"); - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "function", - - supportsObject: function(object, type) - { - return isFunction(object); - }, - - inspectObject: function(fn, context) - { - var sourceLink = findSourceForFunction(fn, context); - if (sourceLink) - Firebug.chrome.select(sourceLink); - if (FBTrace.DBG_FUNCTION_NAME) - FBTrace.sysout("reps.function.inspectObject selected sourceLink is ", sourceLink); - }, - - getTooltip: function(fn, context) - { - var script = findScriptForFunctionInContext(context, fn); - if (script) - return $STRF("Line", [normalizeURL(script.fileName), script.baseLineNumber]); - else - if (fn.toString) - return fn.toString(); - }, - - getTitle: function(fn, context) - { - var name = fn.name ? fn.name : "function"; - return name + "()"; - }, - - getContextMenuItems: function(fn, target, context, script) - { - if (!script) - script = findScriptForFunctionInContext(context, fn); - if (!script) - return; - - var scriptInfo = getSourceFileAndLineByScript(context, script); - var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; - - var name = script ? getFunctionName(script, context) : fn.name; - return [ - {label: "CopySource", command: bindFixed(this.copySource, this, fn) }, - "-", - {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, - type: "checkbox", checked: monitored, - command: bindFixed(this.monitor, this, fn, script, monitored) } - ]; - } -}); - -// ************************************************************************************************ -/* -this.jsdScript = domplate(Firebug.Rep, -{ - copySource: function(script) - { - var fn = script.functionObject.getWrappedValue(); - return FirebugReps.Func.copySource(fn); - }, - - monitor: function(fn, script, monitored) - { - fn = script.functionObject.getWrappedValue(); - return FirebugReps.Func.monitor(fn, script, monitored); - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "jsdScript", - inspectable: false, - - supportsObject: function(object, type) - { - return object instanceof jsdIScript; - }, - - inspectObject: function(script, context) - { - var sourceLink = getSourceLinkForScript(script, context); - if (sourceLink) - Firebug.chrome.select(sourceLink); - }, - - getRealObject: function(script, context) - { - return script; - }, - - getTooltip: function(script) - { - return $STRF("jsdIScript", [script.tag]); - }, - - getTitle: function(script, context) - { - var fn = script.functionObject.getWrappedValue(); - return FirebugReps.Func.getTitle(fn, context); - }, - - getContextMenuItems: function(script, target, context) - { - var fn = script.functionObject.getWrappedValue(); - - var scriptInfo = getSourceFileAndLineByScript(context, script); - var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false; - - var name = getFunctionName(script, context); - - return [ - {label: "CopySource", command: bindFixed(this.copySource, this, script) }, - "-", - {label: $STRF("ShowCallsInConsole", [name]), nol10n: true, - type: "checkbox", checked: monitored, - command: bindFixed(this.monitor, this, fn, script, monitored) } - ]; - } -}); -/**/ -//************************************************************************************************ - -this.Obj = domplate(Firebug.Rep, -{ - tag: - OBJECTLINK( - SPAN({"class": "objectTitle"}, "$object|getTitle "), - - SPAN({"class": "objectProps"}, - SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"), - FOR("prop", "$object|propIterator", - SPAN({"class": "objectPropName", role: "presentation"}, "$prop.name"), - SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"), - TAG("$prop.tag", {object: "$prop.object"}), - SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim") - ), - SPAN({"class": "objectRightBrace"}, "}") - ) - ), - - propNumberTag: - SPAN({"class": "objectProp-number"}, "$object"), - - propStringTag: - SPAN({"class": "objectProp-string"}, ""$object""), - - propObjectTag: - SPAN({"class": "objectProp-object"}, "$object"), - - propIterator: function (object) - { - ///Firebug.ObjectShortIteratorMax; - var maxLength = 55; // default max length for long representation - - if (!object) - return []; - - var props = []; - var length = 0; - - var numProperties = 0; - var numPropertiesShown = 0; - var maxLengthReached = false; - - var lib = this; - - var propRepsMap = - { - "boolean": this.propNumberTag, - "number": this.propNumberTag, - "string": this.propStringTag, - "object": this.propObjectTag - }; - - try - { - var title = Firebug.Rep.getTitle(object); - length += title.length; - - for (var name in object) - { - var value; - try - { - value = object[name]; - } - catch (exc) - { - continue; - } - - var type = typeof(value); - if (type == "boolean" || - type == "number" || - (type == "string" && value) || - (type == "object" && value && value.toString)) - { - var tag = propRepsMap[type]; - - var value = (type == "object") ? - Firebug.getRep(value).getTitle(value) : - value + ""; - - length += name.length + value.length + 4; - - if (length <= maxLength) - { - props.push({ - tag: tag, - name: name, - object: value, - equal: "=", - delim: ", " - }); - - numPropertiesShown++; - } - else - maxLengthReached = true; - - } - - numProperties++; - - if (maxLengthReached && numProperties > numPropertiesShown) - break; - } - - if (numProperties > numPropertiesShown) - { - props.push({ - object: "...", //xxxHonza localization - tag: FirebugReps.Caption.tag, - name: "", - equal:"", - delim:"" - }); - } - else if (props.length > 0) - { - props[props.length-1].delim = ''; - } - } - catch (exc) - { - // Sometimes we get exceptions when trying to read from certain objects, like - // StorageList, but don't let that gum up the works - // XXXjjb also History.previous fails because object is a web-page object which does not have - // permission to read the history - } - return props; - }, - - fb_1_6_propIterator: function (object, max) - { - max = max || 3; - if (!object) - return []; - - var props = []; - var len = 0, count = 0; - - try - { - for (var name in object) - { - var value; - try - { - value = object[name]; - } - catch (exc) - { - continue; - } - - var t = typeof(value); - if (t == "boolean" || t == "number" || (t == "string" && value) - || (t == "object" && value && value.toString)) - { - var rep = Firebug.getRep(value); - var tag = rep.shortTag || rep.tag; - if (t == "object") - { - value = rep.getTitle(value); - tag = rep.titleTag; - } - count++; - if (count <= max) - props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "}); - else - break; - } - } - if (count > max) - { - props[Math.max(1,max-1)] = { - object: "more...", //xxxHonza localization - tag: FirebugReps.Caption.tag, - name: "", - equal:"", - delim:"" - }; - } - else if (props.length > 0) - { - props[props.length-1].delim = ''; - } - } - catch (exc) - { - // Sometimes we get exceptions when trying to read from certain objects, like - // StorageList, but don't let that gum up the works - // XXXjjb also History.previous fails because object is a web-page object which does not have - // permission to read the history - } - return props; - }, - - /* - propIterator: function (object) - { - if (!object) - return []; - - var props = []; - var len = 0; - - try - { - for (var name in object) - { - var val; - try - { - val = object[name]; - } - catch (exc) - { - continue; - } - - var t = typeof val; - if (t == "boolean" || t == "number" || (t == "string" && val) - || (t == "object" && !isFunction(val) && val && val.toString)) - { - var title = (t == "object") - ? Firebug.getRep(val).getTitle(val) - : val+""; - - len += name.length + title.length + 1; - if (len < 50) - props.push({name: name, value: title}); - else - break; - } - } - } - catch (exc) - { - // Sometimes we get exceptions when trying to read from certain objects, like - // StorageList, but don't let that gum up the works - // XXXjjb also History.previous fails because object is a web-page object which does not have - // permission to read the history - } - - return props; - }, - /**/ - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "object", - - supportsObject: function(object, type) - { - return true; - } -}); - - -// ************************************************************************************************ - -this.Arr = domplate(Firebug.Rep, -{ - tag: - OBJECTBOX({_repObject: "$object"}, - SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), - FOR("item", "$object|arrayIterator", - TAG("$item.tag", {object: "$item.object"}), - SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") - ), - SPAN({"class": "arrayRightBracket", role : "presentation"}, "]") - ), - - shortTag: - OBJECTBOX({_repObject: "$object"}, - SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["), - FOR("item", "$object|shortArrayIterator", - TAG("$item.tag", {object: "$item.object"}), - SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim") - ), - // TODO: xxxpedro - confirm this on Firebug - //FOR("prop", "$object|shortPropIterator", - // " $prop.name=", - // SPAN({"class": "objectPropValue"}, "$prop.value|cropString") - //), - SPAN({"class": "arrayRightBracket"}, "]") - ), - - arrayIterator: function(array) - { - var items = []; - for (var i = 0; i < array.length; ++i) - { - var value = array[i]; - var rep = Firebug.getRep(value); - var tag = rep.shortTag ? rep.shortTag : rep.tag; - var delim = (i == array.length-1 ? "" : ", "); - - items.push({object: value, tag: tag, delim: delim}); - } - - return items; - }, - - shortArrayIterator: function(array) - { - var items = []; - for (var i = 0; i < array.length && i < 3; ++i) - { - var value = array[i]; - var rep = Firebug.getRep(value); - var tag = rep.shortTag ? rep.shortTag : rep.tag; - var delim = (i == array.length-1 ? "" : ", "); - - items.push({object: value, tag: tag, delim: delim}); - } - - if (array.length > 3) - items.push({object: (array.length-3) + " more...", tag: FirebugReps.Caption.tag, delim: ""}); - - return items; - }, - - shortPropIterator: this.Obj.propIterator, - - getItemIndex: function(child) - { - var arrayIndex = 0; - for (child = child.previousSibling; child; child = child.previousSibling) - { - if (child.repObject) - ++arrayIndex; - } - return arrayIndex; - }, - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "array", - - supportsObject: function(object) - { - return this.isArray(object); - }, - - // http://code.google.com/p/fbug/issues/detail?id=874 - // BEGIN Yahoo BSD Source (modified here) YAHOO.lang.isArray, YUI 2.2.2 June 2007 - isArray: function(obj) { - try { - if (!obj) - return false; - else if (isIE && !isFunction(obj) && typeof obj == "object" && isFinite(obj.length) && obj.nodeType != 8) - return true; - else if (isFinite(obj.length) && isFunction(obj.splice)) - return true; - else if (isFinite(obj.length) && isFunction(obj.callee)) // arguments - return true; - else if (instanceOf(obj, "HTMLCollection")) - return true; - else if (instanceOf(obj, "NodeList")) - return true; - else - return false; - } - catch(exc) - { - if (FBTrace.DBG_ERRORS) - { - FBTrace.sysout("isArray FAILS:", exc); /* Something weird: without the try/catch, OOM, with no exception?? */ - FBTrace.sysout("isArray Fails on obj", obj); - } - } - - return false; - }, - // END Yahoo BSD SOURCE See license below. - - getTitle: function(object, context) - { - return "[" + object.length + "]"; - } -}); - -// ************************************************************************************************ - -this.Property = domplate(Firebug.Rep, -{ - supportsObject: function(object) - { - return object instanceof Property; - }, - - getRealObject: function(prop, context) - { - return prop.object[prop.name]; - }, - - getTitle: function(prop, context) - { - return prop.name; - } -}); - -// ************************************************************************************************ - -this.NetFile = domplate(this.Obj, -{ - supportsObject: function(object) - { - return object instanceof Firebug.NetFile; - }, - - browseObject: function(file, context) - { - openNewTab(file.href); - return true; - }, - - getRealObject: function(file, context) - { - return null; - } -}); - -// ************************************************************************************************ - -this.Except = domplate(Firebug.Rep, -{ - tag: - OBJECTBOX({_repObject: "$object"}, "$object.message"), - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - - className: "exception", - - supportsObject: function(object) - { - return object instanceof ErrorCopy; - } -}); - - -// ************************************************************************************************ - -this.Element = domplate(Firebug.Rep, -{ - tag: - OBJECTLINK( - "<", - SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"), - FOR("attr", "$object|attrIterator", - " $attr.nodeName="", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), """ - ), - ">" - ), - - shortTag: - OBJECTLINK( - SPAN({"class": "$object|getVisible"}, - SPAN({"class": "selectorTag"}, "$object|getSelectorTag"), - SPAN({"class": "selectorId"}, "$object|getSelectorId"), - SPAN({"class": "selectorClass"}, "$object|getSelectorClass"), - SPAN({"class": "selectorValue"}, "$object|getValue") - ) - ), - - getVisible: function(elt) - { - return isVisible(elt) ? "" : "selectorHidden"; - }, - - getSelectorTag: function(elt) - { - return elt.nodeName.toLowerCase(); - }, - - getSelectorId: function(elt) - { - return elt.id ? "#" + elt.id : ""; - }, - - getSelectorClass: function(elt) - { - return elt.className ? "." + elt.className.split(" ")[0] : ""; - }, - - getValue: function(elt) - { - // TODO: xxxpedro - return ""; - var value; - if (elt instanceof HTMLImageElement) - value = getFileName(elt.src); - else if (elt instanceof HTMLAnchorElement) - value = getFileName(elt.href); - else if (elt instanceof HTMLInputElement) - value = elt.value; - else if (elt instanceof HTMLFormElement) - value = getFileName(elt.action); - else if (elt instanceof HTMLScriptElement) - value = getFileName(elt.src); - - return value ? " " + cropString(value, 20) : ""; - }, - - attrIterator: function(elt) - { - var attrs = []; - var idAttr, classAttr; - if (elt.attributes) - { - for (var i = 0; i < elt.attributes.length; ++i) - { - var attr = elt.attributes[i]; - - // we must check if the attribute is specified otherwise IE will show them - if (!attr.specified || attr.nodeName && attr.nodeName.indexOf("firebug-") != -1) - continue; - else if (attr.nodeName == "id") - idAttr = attr; - else if (attr.nodeName == "class") - classAttr = attr; - else if (attr.nodeName == "style") - attrs.push({ - nodeName: attr.nodeName, - nodeValue: attr.nodeValue || - // IE won't recognize the attr.nodeValue of