diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..349ba98e4 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +tidelift: "npm/underscore" +patreon: juliangonggrijp +github: [jgonggrijp] diff --git a/.github/config/codeql.yml b/.github/config/codeql.yml new file mode 100644 index 000000000..05e73fcf8 --- /dev/null +++ b/.github/config/codeql.yml @@ -0,0 +1,6 @@ +paths: + - 'modules/**' + - 'test/**' + - 'test-treeshake/**' + - 'rollup*.js' + - 'index.html' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000..3158b12ee --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,78 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + paths: + - 'modules/**' + - 'test/**' + - 'test-treeshake/**' + - 'rollup*.js' + - 'index.html' + schedule: + - cron: '16 8 * * 3' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at + # https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/ + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + config-file: ./.github/config/codeql.yml + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.gitignore b/.gitignore index 250659f2f..744003c44 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ node_modules nyc_output coverage test-treeshake/*-umd.js -docs/underscore.js +amd +cjs +/underscore-node-*-pre* diff --git a/.travis.yml b/.travis.yml index 835b954fb..87b67d7d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,25 +1,34 @@ language: node_js sudo: false -node_js: - - "4.9.1" - - "6.14.1" - - "8.11.1" - - "9.11.1" -matrix: +jobs: include: - - node_js: "4.0" - env: BROWSER=true + - node_js: 8 + env: + - DOWNGRADE=true + - EXTRA=false + - node_js: 12 + env: + - DOWNGRADE=false + - EXTRA=false + - node_js: 16 + env: + - DOWNGRADE=false + - EXTRA=true before_install: - - npm install -g npm@2.6 - - npm install -g karma-cli + - "[ $EXTRA = false ] || npm install -g karma-cli" before_script: - - npm install karma-sauce-launcher - - export DISPLAY=:99.0 - - sh -e /etc/init.d/xvfb start + - "[ $EXTRA = false ] || npm install karma-sauce-launcher" + - "[ $DOWNGRADE = false ] || npm install rollup@1" script: - - npm test - - "[ $BROWSER == false ] || npm run test-browser" - - "[ $BROWSER == false ] || karma start karma.conf-sauce.js" + - "[ $EXTRA = false ] || npm run lint" + - npm run prepare-tests + - "[ $EXTRA = false ] || npm run build-umd" + - "[ $EXTRA = false ] || npm run build-esm" + - "[ $EXTRA = false ] || npm run doc" + - "[ $EXTRA = true ] || npm run test-node" + - "[ $EXTRA = false ] || npm run coveralls" + - "[ $EXTRA = false ] || npm run test-browser" + - "[ $EXTRA = false ] || karma start karma.conf-sauce.js" notifications: email: false env: @@ -27,5 +36,3 @@ env: - NPM_CONFIG_PROGRESS="false" - secure: bDZSBQfqr21hCayjcZ20IxrV6+XGhxQPFIfwWqEKLrF93Gu8LLVjZRxXE/mE8I8N4Z5WtDNb4ZHrm/TTzmcPa5MuHgIxEdknQCncobH8oimwc83SHwEPk6okeNKl39VlCjvvnmoe/V/KpnknuYn3Rqghtl/Uv9KLpCwskwjTtcw= - secure: SRECgXuwcZTcD3GVxTS2bYNgRyye4vq6BLrV2PH9FyNenowsKQR2EwlC/dppc1Q8NWMgv79J/R96q9JOFh+mEH9L5dlBb2yhnGH8amVeM/ChAJHT/F8YktKM453uVpz5fR00QcCQDDUOx6Pvx374ID0OKNpWKAkQBWA9mPTsLnE= - # matrix: BROWSER=false -after_success: npm run coveralls diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b8fb76fd7..b55e1765d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,12 +2,19 @@ * This project adheres to a [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. +* Please do not open a ticket to report a security issue. Consult the [security policy](SECURITY.md) on what to do instead. + * Before you open a ticket or send a pull request, [search](https://github.com/jashkenas/underscore/issues) for previous discussions about the same feature or issue. Add to the earlier ticket if you find one. * If you're proposing a new feature, make sure it isn't already implemented in [Underscore-Contrib](https://github.com/documentcloud/underscore-contrib). +* When contributing code, make sure that you edit the source code in the `modules/` directory. Also, run `npm install` before committing any changes to ensure that our commit hooks can do their work. + * Before sending a pull request for a feature, be sure to have [tests](https://underscorejs.org/test/). * Use the same coding style as the rest of the [codebase](https://github.com/jashkenas/underscore/blob/master/modules/index.js). -* In your pull request, do not add documentation or re-build the minified `underscore-min.js` file. We'll do those things before cutting a new release. +* In your pull request, do not add documentation or re-build the minified `underscore-umd-min.js` file. We'll do those things before cutting a new release. + +### "Help, cloning fails with `fatal: fsck error in packed object`" +This error is caused by zero-padded file modes in the commit history. As fixing this is highly destructive, we suggest ignoring these warnings. The simplest way is to instruct git to do so when cloning. For example, to clone from `jashkenas/underscore`, run the following command: `git clone --config transfer.fsckobjects=false git@github.com:jashkenas/underscore.git`. If cloning from a different user or organization, replace `jashkenas` with their name in the previous command. \ No newline at end of file diff --git a/LICENSE b/LICENSE index 8c2236251..12a7f05a2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,4 @@ -Copyright (c) 2009-2020 Jeremy Ashkenas, DocumentCloud and Investigative -Reporters & Editors +Copyright (c) 2009-2022 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/README.md b/README.md index 890269cd4..9beae5059 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ without extending any core JavaScript objects. For Docs, License, Tests, and pre-packed downloads, see: https://underscorejs.org -For support and questions, please use +For support and questions, please consult +our [security policy](SECURITY.md), [the gitter channel](https://gitter.im/jashkenas/underscore) or [stackoverflow](https://stackoverflow.com/search?q=underscore.js) @@ -25,4 +26,9 @@ https://github.com/documentcloud Many thanks to our contributors: https://github.com/jashkenas/underscore/contributors +You can support the project by donating on +[Patreon](https://patreon.com/juliangonggrijp). +Enterprise coverage is available as part of the +[Tidelift Subscription](https://tidelift.com/subscription/pkg/npm-underscore?utm_source=npm-underscore&utm_medium=referral&utm_campaign=enterprise). + This project adheres to a [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..9d564f97d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,38 @@ +# Security Policy + +## Supported Versions + +We currently support the following versions of Underscore with security updates: + +- the latest commit on the `master` branch (published as "edge" on the + [project website][website]); +- the 1.x release tagged as [latest][npm-latest] on npm; +- any release tagged as [preview][npm-preview] on npm, if present. + +[website]: https://underscorejs.org +[npm-latest]: https://www.npmjs.com/package/underscore/v/latest +[npm-preview]: https://www.npmjs.com/package/underscore/v/preview + +## Reporting a Vulnerability + +Please report security issues by sending an email to +dev@juliangonggrijp.com and jashkenas@gmail.com. + +Do __not__ submit an issue ticket or pull request or otherwise publicly +disclose the issue. + +After receiving your email, we will respond as soon as possible and indicate +what we plan to do. + +## Disclosure policy + +After confirming a vulnerability, we will generally release a security update +as soon as possible, including the minimum amount of information required for +software maintainers and system administrators to assess the urgency of the +update for their particular situation. + +We postpone the publication of any further details such as code comments, +tests, commit history and diffs, in order to enable a substantial share of the +users to install the security fix before this time. + +Upon publication of full details, we will credit the reporter if the reporter wishes to be publicly identified. diff --git a/bower.json b/bower.json index d5e1d7852..03260df70 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "underscore", - "main": "underscore.js", + "main": "underscore-umd.js", "keywords": ["util", "functional", "server", "client", "browser"], "ignore" : ["docs", "test", "*.yml", "CNAME", "index.html", "favicon.ico", "CONTRIBUTING.md", ".*", "package.json", "karma.*"] } diff --git a/docs/linked-esm.jst b/docs/linked-esm.jst new file mode 100644 index 000000000..bdeb4cd23 --- /dev/null +++ b/docs/linked-esm.jst @@ -0,0 +1,108 @@ +<% /* + This is an extended version of the resources/parallel/docco.jst that is + bundled with Docco 0.8.0. + The license of the original file is available over here: + https://github.com/jashkenas/docco/blob/master/LICENSE. + The extension adds hyperlinking to javascript import statements. +*/ %> + + + +
+import isObject from './isObject.js';
+import { nativeCreate } from './_setup.js';Create a naked function reference for surrogate-prototype-swapping.
+ +function ctor() {
+ return function(){};
+}An internal function for creating a new object that inherits from another.
+ +export default function baseCreate(prototype) {
+ if (!isObject(prototype)) return {};
+ if (nativeCreate) return nativeCreate(prototype);
+ var Ctor = ctor();
+ Ctor.prototype = prototype;
+ var result = new Ctor;
+ Ctor.prototype = null;
+ return result;
+}import identity from './identity.js';
+import isFunction from './isFunction.js';
+import isObject from './isObject.js';
+import isArray from './isArray.js';
+import matcher from './matcher.js';
+import property from './property.js';
+import optimizeCb from './_optimizeCb.js';An internal function to generate callbacks that can be applied to each
+element in a collection, returning the desired result — either _.identity,
+an arbitrary callback, a property matcher, or a property accessor.
export default function baseIteratee(value, context, argCount) {
+ if (value == null) return identity;
+ if (isFunction(value)) return optimizeCb(value, context, argCount);
+ if (isObject(value) && !isArray(value)) return matcher(value);
+ return property(value);
+}import _ from './underscore.js';
+import baseIteratee from './_baseIteratee.js';
+import iteratee from './iteratee.js';The function we call internally to generate a callback. It invokes
+_.iteratee if overridden, otherwise baseIteratee.
export default function cb(value, context, argCount) {
+ if (_.iteratee !== iteratee) return _.iteratee(value, context);
+ return baseIteratee(value, context, argCount);
+}import { nonEnumerableProps, ObjProto } from './_setup.js';
+import isFunction from './isFunction.js';
+import has from './_has.js';Internal helper to create a simple lookup structure.
+collectNonEnumProps used to depend on _.contains, but this led to
+circular imports. emulatedSet is a one-off solution that only works for
+arrays of strings.
function emulatedSet(keys) {
+ var hash = {};
+ for (var l = keys.length, i = 0; i < l; ++i) hash[keys[i]] = true;
+ return {
+ contains: function(key) { return hash[key] === true; },
+ push: function(key) {
+ hash[key] = true;
+ return keys.push(key);
+ }
+ };
+}Internal helper. Checks keys for the presence of keys in IE < 9 that won’t
+be iterated by for key in ... and thus missed. Extends keys in place if
+needed.
export default function collectNonEnumProps(obj, keys) {
+ keys = emulatedSet(keys);
+ var nonEnumIdx = nonEnumerableProps.length;
+ var constructor = obj.constructor;
+ var proto = (isFunction(constructor) && constructor.prototype) || ObjProto;Constructor is a special case.
+ + var prop = 'constructor';
+ if (has(obj, prop) && !keys.contains(prop)) keys.push(prop);
+
+ while (nonEnumIdx--) {
+ prop = nonEnumerableProps[nonEnumIdx];
+ if (prop in obj && obj[prop] !== proto[prop] && !keys.contains(prop)) {
+ keys.push(prop);
+ }
+ }
+}An internal function for creating assigner functions.
+ +export default function createAssigner(keysFunc, defaults) {
+ return function(obj) {
+ var length = arguments.length;
+ if (defaults) obj = Object(obj);
+ if (length < 2 || obj == null) return obj;
+ for (var index = 1; index < length; index++) {
+ var source = arguments[index],
+ keys = keysFunc(source),
+ l = keys.length;
+ for (var i = 0; i < l; i++) {
+ var key = keys[i];
+ if (!defaults || obj[key] === void 0) obj[key] = source[key];
+ }
+ }
+ return obj;
+ };
+}import keys from './keys.js';Internal helper to generate functions for escaping and unescaping strings +to/from HTML interpolation.
+ +export default function createEscaper(map) {
+ var escaper = function(match) {
+ return map[match];
+ };Regexes for identifying a key that needs to be escaped.
+ + var source = '(?:' + keys(map).join('|') + ')';
+ var testRegexp = RegExp(source);
+ var replaceRegexp = RegExp(source, 'g');
+ return function(string) {
+ string = string == null ? '' : '' + string;
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+ };
+}import getLength from './_getLength.js';
+import { slice } from './_setup.js';
+import isNaN from './isNaN.js';Internal function to generate the _.indexOf and _.lastIndexOf functions.
export default function createIndexFinder(dir, predicateFind, sortedIndex) {
+ return function(array, item, idx) {
+ var i = 0, length = getLength(array);
+ if (typeof idx == 'number') {
+ if (dir > 0) {
+ i = idx >= 0 ? idx : Math.max(idx + length, i);
+ } else {
+ length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
+ }
+ } else if (sortedIndex && idx && length) {
+ idx = sortedIndex(array, item);
+ return array[idx] === item ? idx : -1;
+ }
+ if (item !== item) {
+ idx = predicateFind(slice.call(array, i, length), isNaN);
+ return idx >= 0 ? idx + i : -1;
+ }
+ for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
+ if (array[idx] === item) return idx;
+ }
+ return -1;
+ };
+}import cb from './_cb.js';
+import getLength from './_getLength.js';Internal function to generate _.findIndex and _.findLastIndex.
export default function createPredicateIndexFinder(dir) {
+ return function(array, predicate, context) {
+ predicate = cb(predicate, context);
+ var length = getLength(array);
+ var index = dir > 0 ? 0 : length - 1;
+ for (; index >= 0 && index < length; index += dir) {
+ if (predicate(array[index], index, array)) return index;
+ }
+ return -1;
+ };
+}import isArrayLike from './_isArrayLike.js';
+import keys from './keys.js';
+import optimizeCb from './_optimizeCb.js';Internal helper to create a reducing function, iterating left or right.
+ +export default function createReduce(dir) {Wrap code that reassigns argument variables in a separate function than
+the one that accesses arguments.length to avoid a perf hit. (#1991)
var reducer = function(obj, iteratee, memo, initial) {
+ var _keys = !isArrayLike(obj) && keys(obj),
+ length = (_keys || obj).length,
+ index = dir > 0 ? 0 : length - 1;
+ if (!initial) {
+ memo = obj[_keys ? _keys[index] : index];
+ index += dir;
+ }
+ for (; index >= 0 && index < length; index += dir) {
+ var currentKey = _keys ? _keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
+ }
+ return memo;
+ };
+
+ return function(obj, iteratee, memo, context) {
+ var initial = arguments.length >= 3;
+ return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
+ };
+}import { MAX_ARRAY_INDEX } from './_setup.js';Common internal logic for isArrayLike and isBufferLike.
export default function createSizePropertyCheck(getSizeProperty) {
+ return function(collection) {
+ var sizeProperty = getSizeProperty(collection);
+ return typeof sizeProperty == 'number' && sizeProperty >= 0 && sizeProperty <= MAX_ARRAY_INDEX;
+ }
+}Internal function to obtain a nested property in obj along path.
export default function deepGet(obj, path) {
+ var length = path.length;
+ for (var i = 0; i < length; i++) {
+ if (obj == null) return void 0;
+ obj = obj[path[i]];
+ }
+ return length ? obj : void 0;
+}Internal list of HTML entities for escaping.
+ +export default {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
+};import baseCreate from './_baseCreate.js';
+import isObject from './isObject.js';Internal function to execute sourceFunc bound to context with optional
+args. Determines whether to execute a function as a constructor or as a
+normal function.
export default function executeBound(sourceFunc, boundFunc, context, callingContext, args) {
+ if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
+ var self = baseCreate(sourceFunc.prototype);
+ var result = sourceFunc.apply(self, args);
+ if (isObject(result)) return result;
+ return self;
+}import getLength from './_getLength.js';
+import isArrayLike from './_isArrayLike.js';
+import isArray from './isArray.js';
+import isArguments from './isArguments.js';Internal implementation of a recursive flatten function.
export default function flatten(input, depth, strict, output) {
+ output = output || [];
+ if (!depth && depth !== 0) {
+ depth = Infinity;
+ } else if (depth <= 0) {
+ return output.concat(input);
+ }
+ var idx = output.length;
+ for (var i = 0, length = getLength(input); i < length; i++) {
+ var value = input[i];
+ if (isArrayLike(value) && (isArray(value) || isArguments(value))) {Flatten current level of array or arguments object.
+ + if (depth > 1) {
+ flatten(value, depth - 1, strict, output);
+ idx = output.length;
+ } else {
+ var j = 0, len = value.length;
+ while (j < len) output[idx++] = value[j++];
+ }
+ } else if (!strict) {
+ output[idx++] = value;
+ }
+ }
+ return output;
+}import cb from './_cb.js';
+import each from './each.js';An internal function used for aggregate “group by” operations.
+ +export default function group(behavior, partition) {
+ return function(obj, iteratee, context) {
+ var result = partition ? [[], []] : {};
+ iteratee = cb(iteratee, context);
+ each(obj, function(value, index) {
+ var key = iteratee(value, index, obj);
+ behavior(result, value, key);
+ });
+ return result;
+ };
+}import { hasOwnProperty } from './_setup.js';Internal function to check whether key is an own property name of obj.
export default function has(obj, key) {
+ return obj != null && hasOwnProperty.call(obj, key);
+}import tagTester from './_tagTester.js';
+
+export default tagTester('Object');import createSizePropertyCheck from './_createSizePropertyCheck.js';
+import getLength from './_getLength.js';Internal helper for collection methods to determine whether a collection +should be iterated as an array or as an object. +Related: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength +Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
+ +export default createSizePropertyCheck(getLength);import createSizePropertyCheck from './_createSizePropertyCheck.js';
+import getByteLength from './_getByteLength.js';Internal helper to determine whether we should spend extensive checks against
+ArrayBuffer et al.
export default createSizePropertyCheck(getByteLength);Internal _.pick helper function to determine whether key is an enumerable
+property name of obj.
export default function keyInObj(value, key, obj) {
+ return key in obj;
+}import getLength from './_getLength.js';
+import isFunction from './isFunction.js';
+import allKeys from './allKeys.js';Since the regular Object.prototype.toString type tests don’t work for
+some types in IE 11, we use a fingerprinting heuristic instead, based
+on the methods. It’s not great, but it’s the best we got.
+The fingerprint method lists are defined below.
export function ie11fingerprint(methods) {
+ var length = getLength(methods);
+ return function(obj) {
+ if (obj == null) return false;Map, WeakMap and Set have no enumerable keys.
var keys = allKeys(obj);
+ if (getLength(keys)) return false;
+ for (var i = 0; i < length; i++) {
+ if (!isFunction(obj[methods[i]])) return false;
+ }If we are testing against WeakMap, we need to ensure that
+obj doesn’t have a forEach method in order to distinguish
+it from a regular Map.
return methods !== weakMapMethods || !isFunction(obj[forEachName]);
+ };
+}In the interest of compact minification, we write +each string in the fingerprints only once.
+ +var forEachName = 'forEach',
+ hasName = 'has',
+ commonInit = ['clear', 'delete'],
+ mapTail = ['get', hasName, 'set'];Map, WeakMap and Set each have slightly different
+combinations of the above sublists.
export var mapMethods = commonInit.concat(forEachName, mapTail),
+ weakMapMethods = commonInit.concat(mapTail),
+ setMethods = ['add'].concat(commonInit, forEachName, hasName);Internal function that returns an efficient (for current engines) version +of the passed-in callback, to be repeatedly applied in other Underscore +functions.
+ +export default function optimizeCb(func, context, argCount) {
+ if (context === void 0) return func;
+ switch (argCount == null ? 3 : argCount) {
+ case 1: return function(value) {
+ return func.call(context, value);
+ };The 2-argument case is omitted because we’re not using it.
+ + case 3: return function(value, index, collection) {
+ return func.call(context, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(context, accumulator, value, index, collection);
+ };
+ }
+ return function() {
+ return func.apply(context, arguments);
+ };
+}Current version.
+ +export var VERSION = '1.13.7';Establish the root object, window (self) in the browser, global
+on the server, or this in some virtual machines. We use self
+instead of window for WebWorker support.
export var root = (typeof self == 'object' && self.self === self && self) ||
+ (typeof global == 'object' && global.global === global && global) ||
+ Function('return this')() ||
+ {};Save bytes in the minified (but not gzipped) version:
+ +export var ArrayProto = Array.prototype, ObjProto = Object.prototype;
+export var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;Create quick reference variables for speed access to core prototypes.
+ +export var push = ArrayProto.push,
+ slice = ArrayProto.slice,
+ toString = ObjProto.toString,
+ hasOwnProperty = ObjProto.hasOwnProperty;Modern feature detection.
+ +export var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined',
+ supportsDataView = typeof DataView !== 'undefined';All ECMAScript 5+ native function implementations that we hope to use +are declared here.
+ +export var nativeIsArray = Array.isArray,
+ nativeKeys = Object.keys,
+ nativeCreate = Object.create,
+ nativeIsView = supportsArrayBuffer && ArrayBuffer.isView;Create references to these builtin functions because we override them.
+ +export var _isNaN = isNaN,
+ _isFinite = isFinite;Keys in IE < 9 that won’t be iterated by for key in ... and thus missed.
export var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
+export var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
+ 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];The largest integer that can be represented exactly.
+ +export var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;Internal helper to generate a function to obtain property key from obj.
export default function shallowProperty(key) {
+ return function(obj) {
+ return obj == null ? void 0 : obj[key];
+ };
+}import { supportsDataView } from './_setup.js';
+import hasObjectTag from './_hasObjectTag.js';In IE 10 - Edge 13, DataView has string tag '[object Object]'.
+In IE 11, the most common among them, this problem also applies to
+Map, WeakMap and Set.
+Also, there are cases where an application can override the native
+DataView object, in cases like that we can’t use the constructor
+safely and should just rely on alternate DataView checks
export var hasDataViewBug = (
+ supportsDataView && (!/\[native code\]/.test(String(DataView)) || hasObjectTag(new DataView(new ArrayBuffer(8))))
+ ),
+ isIE11 = (typeof Map !== 'undefined' && hasObjectTag(new Map));import { toString } from './_setup.js';Internal function for creating a toString-based type tester.
export default function tagTester(name) {
+ var tag = '[object ' + name + ']';
+ return function(obj) {
+ return toString.call(obj) === tag;
+ };
+}import getByteLength from './_getByteLength.js';Internal function to wrap or shallow-copy an ArrayBuffer, +typed array or DataView to a new view, reusing the buffer.
+ +export default function toBufferView(bufferSource) {
+ return new Uint8Array(
+ bufferSource.buffer || bufferSource,
+ bufferSource.byteOffset || 0,
+ getByteLength(bufferSource)
+ );
+}Returns a function that will only be executed on and after the Nth call.
+ +export default function after(times, func) {
+ return function() {
+ if (--times < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+}import isObject from './isObject.js';
+import { hasEnumBug } from './_setup.js';
+import collectNonEnumProps from './_collectNonEnumProps.js';Retrieve all the enumerable property names of an object.
+ +export default function allKeys(obj) {
+ if (!isObject(obj)) return [];
+ var keys = [];
+ for (var key in obj) keys.push(key);Ahem, IE < 9.
+ + if (hasEnumBug) collectNonEnumProps(obj, keys);
+ return keys;
+}Returns a function that will only be executed up to (but not including) the +Nth call.
+ +export default function before(times, func) {
+ var memo;
+ return function() {
+ if (--times > 0) {
+ memo = func.apply(this, arguments);
+ }
+ if (times <= 1) func = null;
+ return memo;
+ };
+}import restArguments from './restArguments.js';
+import isFunction from './isFunction.js';
+import executeBound from './_executeBound.js';Create a function bound to a given object (assigning this, and arguments,
+optionally).
export default restArguments(function(func, context, args) {
+ if (!isFunction(func)) throw new TypeError('Bind must be called on a function');
+ var bound = restArguments(function(callArgs) {
+ return executeBound(func, bound, context, this, args.concat(callArgs));
+ });
+ return bound;
+});import restArguments from './restArguments.js';
+import flatten from './_flatten.js';
+import bind from './bind.js';Bind a number of an object’s methods to that object. Remaining arguments +are the method names to be bound. Useful for ensuring that all callbacks +defined on an object belong to it.
+ +export default restArguments(function(obj, keys) {
+ keys = flatten(keys, false, false);
+ var index = keys.length;
+ if (index < 1) throw new Error('bindAll must be passed function names');
+ while (index--) {
+ var key = keys[index];
+ obj[key] = bind(obj[key], obj);
+ }
+ return obj;
+});import { slice } from './_setup.js';Chunk a single array into multiple arrays, each containing count or fewer
+items.
export default function chunk(array, count) {
+ if (count == null || count < 1) return [];
+ var result = [];
+ var i = 0, length = array.length;
+ while (i < length) {
+ result.push(slice.call(array, i, i += count));
+ }
+ return result;
+}import isObject from './isObject.js';
+import isArray from './isArray.js';
+import extend from './extend.js';Create a (shallow-cloned) duplicate of an object.
+ +export default function clone(obj) {
+ if (!isObject(obj)) return obj;
+ return isArray(obj) ? obj.slice() : extend({}, obj);
+}Returns a function that is the composition of a list of functions, each +consuming the return value of the function that follows.
+ +export default function compose() {
+ var args = arguments;
+ var start = args.length - 1;
+ return function() {
+ var i = start;
+ var result = args[start].apply(this, arguments);
+ while (i--) result = args[i].call(this, result);
+ return result;
+ };
+}Predicate-generating function. Often useful outside of Underscore.
+ +export default function constant(value) {
+ return function() {
+ return value;
+ };
+}import isArrayLike from './_isArrayLike.js';
+import values from './values.js';
+import indexOf from './indexOf.js';Determine if the array or object contains a given item (using ===).
export default function contains(obj, item, fromIndex, guard) {
+ if (!isArrayLike(obj)) obj = values(obj);
+ if (typeof fromIndex != 'number' || guard) fromIndex = 0;
+ return indexOf(obj, item, fromIndex) >= 0;
+}import group from './_group.js';
+import has from './_has.js';Counts instances of an object that group by a certain criterion. Pass +either a string attribute to count by, or a function that returns the +criterion.
+ +export default group(function(result, value, key) {
+ if (has(result, key)) result[key]++; else result[key] = 1;
+});import baseCreate from './_baseCreate.js';
+import extendOwn from './extendOwn.js';Creates an object that inherits from the given prototype object. +If additional properties are provided then they will be added to the +created object.
+ +export default function create(prototype, props) {
+ var result = baseCreate(prototype);
+ if (props) extendOwn(result, props);
+ return result;
+}import restArguments from './restArguments.js';
+import now from './now.js';When a sequence of calls of the returned function ends, the argument
+function is triggered. The end of a sequence is defined by the wait
+parameter. If immediate is passed, the argument function will be
+triggered at the beginning of the sequence instead of at the end.
export default function debounce(func, wait, immediate) {
+ var timeout, previous, args, result, context;
+
+ var later = function() {
+ var passed = now() - previous;
+ if (wait > passed) {
+ timeout = setTimeout(later, wait - passed);
+ } else {
+ timeout = null;
+ if (!immediate) result = func.apply(context, args);This check is needed because func can recursively invoke debounced.
if (!timeout) args = context = null;
+ }
+ };
+
+ var debounced = restArguments(function(_args) {
+ context = this;
+ args = _args;
+ previous = now();
+ if (!timeout) {
+ timeout = setTimeout(later, wait);
+ if (immediate) result = func.apply(context, args);
+ }
+ return result;
+ });
+
+ debounced.cancel = function() {
+ clearTimeout(timeout);
+ timeout = args = context = null;
+ };
+
+ return debounced;
+}import partial from './partial.js';
+import delay from './delay.js';
+import _ from './underscore.js';Defers a function, scheduling it to run after the current call stack has +cleared.
+ +export default partial(delay, _, 1);import restArguments from './restArguments.js';Delays a function for the given number of milliseconds, and then calls +it with the arguments supplied.
+ +export default restArguments(function(func, wait, args) {
+ return setTimeout(function() {
+ return func.apply(null, args);
+ }, wait);
+});import restArguments from './restArguments.js';
+import flatten from './_flatten.js';
+import filter from './filter.js';
+import contains from './contains.js';Take the difference between one array and a number of other arrays. +Only the elements present in just the first array will remain.
+ +export default restArguments(function(array, rest) {
+ rest = flatten(rest, true, true);
+ return filter(array, function(value){
+ return !contains(rest, value);
+ });
+});import optimizeCb from './_optimizeCb.js';
+import isArrayLike from './_isArrayLike.js';
+import keys from './keys.js';The cornerstone for collection functions, an each
+implementation, aka forEach.
+Handles raw objects in addition to array-likes. Treats all
+sparse array-likes as if they were dense.
export default function each(obj, iteratee, context) {
+ iteratee = optimizeCb(iteratee, context);
+ var i, length;
+ if (isArrayLike(obj)) {
+ for (i = 0, length = obj.length; i < length; i++) {
+ iteratee(obj[i], i, obj);
+ }
+ } else {
+ var _keys = keys(obj);
+ for (i = 0, length = _keys.length; i < length; i++) {
+ iteratee(obj[_keys[i]], _keys[i], obj);
+ }
+ }
+ return obj;
+}import cb from './_cb.js';
+import isArrayLike from './_isArrayLike.js';
+import keys from './keys.js';Determine whether all of the elements pass a truth test.
+ +export default function every(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var _keys = !isArrayLike(obj) && keys(obj),
+ length = (_keys || obj).length;
+ for (var index = 0; index < length; index++) {
+ var currentKey = _keys ? _keys[index] : index;
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
+ }
+ return true;
+}import createAssigner from './_createAssigner.js';
+import keys from './keys.js';Assigns a given object with all the own properties in the passed-in +object(s). +(https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+ +export default createAssigner(keys);import cb from './_cb.js';
+import each from './each.js';Return all the elements that pass a truth test.
+ +export default function filter(obj, predicate, context) {
+ var results = [];
+ predicate = cb(predicate, context);
+ each(obj, function(value, index, list) {
+ if (predicate(value, index, list)) results.push(value);
+ });
+ return results;
+}import isArrayLike from './_isArrayLike.js';
+import findIndex from './findIndex.js';
+import findKey from './findKey.js';Return the first value which passes a truth test.
+ +export default function find(obj, predicate, context) {
+ var keyFinder = isArrayLike(obj) ? findIndex : findKey;
+ var key = keyFinder(obj, predicate, context);
+ if (key !== void 0 && key !== -1) return obj[key];
+}import cb from './_cb.js';
+import keys from './keys.js';Returns the first key on an object that passes a truth test.
+ +export default function findKey(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var _keys = keys(obj), key;
+ for (var i = 0, length = _keys.length; i < length; i++) {
+ key = _keys[i];
+ if (predicate(obj[key], key, obj)) return key;
+ }
+}import find from './find.js';
+import matcher from './matcher.js';Convenience version of a common use case of _.find: getting the first
+object containing specific key:value pairs.
export default function findWhere(obj, attrs) {
+ return find(obj, matcher(attrs));
+}import initial from './initial.js';Get the first element of an array. Passing n will return the first N
+values in the array. The guard check allows it to work with _.map.
export default function first(array, n, guard) {
+ if (array == null || array.length < 1) return n == null || guard ? void 0 : [];
+ if (n == null || guard) return array[0];
+ return initial(array, array.length - n);
+}import _flatten from './_flatten.js';Flatten out an array, either recursively (by default), or up to depth.
+Passing true or false as depth means 1 or Infinity, respectively.
export default function flatten(array, depth) {
+ return _flatten(array, depth, false);
+}import isFunction from './isFunction.js';Return a sorted list of the function names available on the object.
+ +export default function functions(obj) {
+ var names = [];
+ for (var key in obj) {
+ if (isFunction(obj[key])) names.push(key);
+ }
+ return names.sort();
+}import toPath from './_toPath.js';
+import deepGet from './_deepGet.js';
+import isUndefined from './isUndefined.js';Get the value of the (deep) property on path from object.
+If any property in path does not exist or if the value is
+undefined, return defaultValue instead.
+The path is normalized through _.toPath.
export default function get(object, path, defaultValue) {
+ var value = deepGet(object, toPath(path));
+ return isUndefined(value) ? defaultValue : value;
+}import group from './_group.js';
+import has from './_has.js';Groups the object’s values by a criterion. Pass either a string attribute +to group by, or a function that returns the criterion.
+ +export default group(function(result, value, key) {
+ if (has(result, key)) result[key].push(value); else result[key] = [value];
+});import _has from './_has.js';
+import toPath from './_toPath.js';Shortcut function for checking if an object has a given property directly on
+itself (in other words, not on a prototype). Unlike the internal has
+function, this public version can also traverse nested properties.
export default function has(obj, path) {
+ path = toPath(path);
+ var length = path.length;
+ for (var i = 0; i < length; i++) {
+ var key = path[i];
+ if (!_has(obj, key)) return false;
+ obj = obj[key];
+ }
+ return !!length;
+}Keep the identity function around for default iteratees.
+ +export default function identity(value) {
+ return value;
+}This module is the package entry point for ES module users. In other words, +it is the module they are interfacing with when they import from the whole +package instead of from a submodule, like this:
+import { map } from 'underscore';
+
+The difference with ./index-default, which is the package entry point for
+CommonJS, AMD and UMD users, is purely technical. In ES modules, named and
+default exports are considered to be siblings, so when you have a default
+export, its properties are not automatically available as named exports. For
+this reason, we re-export the named exports in addition to providing the same
+default export as in ./index-default.
export { default } from './index-default.js';
+export * from './index.js';In this module, we mix our bundled exports into the _ object and export
+the result. This is analogous to setting module.exports = _ in CommonJS.
+Hence, this module is also the entry point of our UMD bundle and the package
+entry point for CommonJS and AMD users. In other words, this is (the source
+of) the module you are interfacing with when you do any of the following:
// CommonJS
+var _ = require('underscore');
+
+// AMD
+define(['underscore'], function(_) {...});
+
+// UMD in the browser
+// _ is available as a global variable
+
+
+ import * as allExports from './index.js';
+import { mixin } from './index.js';Add all of the Underscore functions to the wrapper object.
+ +var _ = mixin(allExports);Legacy Node.js API.
+ +_._ = _;Export the Underscore API.
+ +export default _;Underscore.js 1.13.7
+https://underscorejs.org
+(c) 2009-2024 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors
+Underscore may be freely distributed under the MIT license.
+
+
+ Baseline setup.
+ +export { VERSION } from './_setup.js';
+export { default as restArguments } from './restArguments.js';Our most fundamental functions operate on any JavaScript object. +Most functions in Underscore depend on at least one function in this section.
+ +A group of functions that check the types of core JavaScript values. +These are often informally referred to as the “isType” functions.
+ +export { default as isObject } from './isObject.js';
+export { default as isNull } from './isNull.js';
+export { default as isUndefined } from './isUndefined.js';
+export { default as isBoolean } from './isBoolean.js';
+export { default as isElement } from './isElement.js';
+export { default as isString } from './isString.js';
+export { default as isNumber } from './isNumber.js';
+export { default as isDate } from './isDate.js';
+export { default as isRegExp } from './isRegExp.js';
+export { default as isError } from './isError.js';
+export { default as isSymbol } from './isSymbol.js';
+export { default as isArrayBuffer } from './isArrayBuffer.js';
+export { default as isDataView } from './isDataView.js';
+export { default as isArray } from './isArray.js';
+export { default as isFunction } from './isFunction.js';
+export { default as isArguments } from './isArguments.js';
+export { default as isFinite } from './isFinite.js';
+export { default as isNaN } from './isNaN.js';
+export { default as isTypedArray } from './isTypedArray.js';
+export { default as isEmpty } from './isEmpty.js';
+export { default as isMatch } from './isMatch.js';
+export { default as isEqual } from './isEqual.js';
+export { default as isMap } from './isMap.js';
+export { default as isWeakMap } from './isWeakMap.js';
+export { default as isSet } from './isSet.js';
+export { default as isWeakSet } from './isWeakSet.js';Functions that treat an object as a dictionary of key-value pairs.
+ +export { default as keys } from './keys.js';
+export { default as allKeys } from './allKeys.js';
+export { default as values } from './values.js';
+export { default as pairs } from './pairs.js';
+export { default as invert } from './invert.js';
+export { default as functions,
+ default as methods } from './functions.js';
+export { default as extend } from './extend.js';
+export { default as extendOwn,
+ default as assign } from './extendOwn.js';
+export { default as defaults } from './defaults.js';
+export { default as create } from './create.js';
+export { default as clone } from './clone.js';
+export { default as tap } from './tap.js';
+export { default as get } from './get.js';
+export { default as has } from './has.js';
+export { default as mapObject } from './mapObject.js';A bit of a grab bag: Predicate-generating functions for use with filters and +loops, string escaping and templating, create random numbers and unique ids, +and functions that facilitate Underscore’s chaining and iteration conventions.
+ +export { default as identity } from './identity.js';
+export { default as constant } from './constant.js';
+export { default as noop } from './noop.js';
+export { default as toPath } from './toPath.js';
+export { default as property } from './property.js';
+export { default as propertyOf } from './propertyOf.js';
+export { default as matcher,
+ default as matches } from './matcher.js';
+export { default as times } from './times.js';
+export { default as random } from './random.js';
+export { default as now } from './now.js';
+export { default as escape } from './escape.js';
+export { default as unescape } from './unescape.js';
+export { default as templateSettings } from './templateSettings.js';
+export { default as template } from './template.js';
+export { default as result } from './result.js';
+export { default as uniqueId } from './uniqueId.js';
+export { default as chain } from './chain.js';
+export { default as iteratee } from './iteratee.js';These functions take a function as an argument and return a new function +as the result. Also known as higher-order functions.
+ +export { default as partial } from './partial.js';
+export { default as bind } from './bind.js';
+export { default as bindAll } from './bindAll.js';
+export { default as memoize } from './memoize.js';
+export { default as delay } from './delay.js';
+export { default as defer } from './defer.js';
+export { default as throttle } from './throttle.js';
+export { default as debounce } from './debounce.js';
+export { default as wrap } from './wrap.js';
+export { default as negate } from './negate.js';
+export { default as compose } from './compose.js';
+export { default as after } from './after.js';
+export { default as before } from './before.js';
+export { default as once } from './once.js';Functions that extract (the position of) a single element from an object +or array based on some criterion.
+ +export { default as findKey } from './findKey.js';
+export { default as findIndex } from './findIndex.js';
+export { default as findLastIndex } from './findLastIndex.js';
+export { default as sortedIndex } from './sortedIndex.js';
+export { default as indexOf } from './indexOf.js';
+export { default as lastIndexOf } from './lastIndexOf.js';
+export { default as find,
+ default as detect } from './find.js';
+export { default as findWhere } from './findWhere.js';Functions that work on any collection of elements: either an array, or +an object of key-value pairs.
+ +export { default as each,
+ default as forEach } from './each.js';
+export { default as map,
+ default as collect } from './map.js';
+export { default as reduce,
+ default as foldl,
+ default as inject } from './reduce.js';
+export { default as reduceRight,
+ default as foldr } from './reduceRight.js';
+export { default as filter,
+ default as select } from './filter.js';
+export { default as reject } from './reject.js';
+export { default as every,
+ default as all } from './every.js';
+export { default as some,
+ default as any } from './some.js';
+export { default as contains,
+ default as includes,
+ default as include } from './contains.js';
+export { default as invoke } from './invoke.js';
+export { default as pluck } from './pluck.js';
+export { default as where } from './where.js';
+export { default as max } from './max.js';
+export { default as min } from './min.js';
+export { default as shuffle } from './shuffle.js';
+export { default as sample } from './sample.js';
+export { default as sortBy } from './sortBy.js';
+export { default as groupBy } from './groupBy.js';
+export { default as indexBy } from './indexBy.js';
+export { default as countBy } from './countBy.js';
+export { default as partition } from './partition.js';
+export { default as toArray } from './toArray.js';
+export { default as size } from './size.js';_.pick and _.omit are actually object functions, but we put
+them here in order to create a more natural reading order in the
+monolithic build as they depend on _.contains.
export { default as pick } from './pick.js';
+export { default as omit } from './omit.js';Functions that operate on arrays (and array-likes) only, because they’re +expressed in terms of operations on an ordered list of values.
+ +export { default as first,
+ default as head,
+ default as take } from './first.js';
+export { default as initial } from './initial.js';
+export { default as last } from './last.js';
+export { default as rest,
+ default as tail,
+ default as drop } from './rest.js';
+export { default as compact } from './compact.js';
+export { default as flatten } from './flatten.js';
+export { default as without } from './without.js';
+export { default as uniq,
+ default as unique } from './uniq.js';
+export { default as union } from './union.js';
+export { default as intersection } from './intersection.js';
+export { default as difference } from './difference.js';
+export { default as unzip,
+ default as transpose } from './unzip.js';
+export { default as zip } from './zip.js';
+export { default as object } from './object.js';
+export { default as range } from './range.js';
+export { default as chunk } from './chunk.js';These modules support the “object-oriented” calling style. See also
+underscore.js and index-default.js.
export { default as mixin } from './mixin.js';
+export { default } from './underscore-array-methods.js';import group from './_group.js';Indexes the object’s values by a criterion, similar to _.groupBy, but for
+when you know that your index values will be unique.
export default group(function(result, value, key) {
+ result[key] = value;
+});import sortedIndex from './sortedIndex.js';
+import findIndex from './findIndex.js';
+import createIndexFinder from './_createIndexFinder.js';Return the position of the first occurrence of an item in an array,
+or -1 if the item is not included in the array.
+If the array is large and already in sort order, pass true
+for isSorted to use binary search.
export default createIndexFinder(1, findIndex, sortedIndex);import { slice } from './_setup.js';Returns everything but the last entry of the array. Especially useful on +the arguments object. Passing n will return all the values in +the array, excluding the last N.
+ +export default function initial(array, n, guard) {
+ return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
+}import getLength from './_getLength.js';
+import contains from './contains.js';Produce an array that contains every item shared between all the +passed-in arrays.
+ +export default function intersection(array) {
+ var result = [];
+ var argsLength = arguments.length;
+ for (var i = 0, length = getLength(array); i < length; i++) {
+ var item = array[i];
+ if (contains(result, item)) continue;
+ var j;
+ for (j = 1; j < argsLength; j++) {
+ if (!contains(arguments[j], item)) break;
+ }
+ if (j === argsLength) result.push(item);
+ }
+ return result;
+}import keys from './keys.js';Invert the keys and values of an object. The values must be serializable.
+ +export default function invert(obj) {
+ var result = {};
+ var _keys = keys(obj);
+ for (var i = 0, length = _keys.length; i < length; i++) {
+ result[obj[_keys[i]]] = _keys[i];
+ }
+ return result;
+}import restArguments from './restArguments.js';
+import isFunction from './isFunction.js';
+import map from './map.js';
+import deepGet from './_deepGet.js';
+import toPath from './_toPath.js';Invoke a method (with arguments) on every item in a collection.
+ +export default restArguments(function(obj, path, args) {
+ var contextPath, func;
+ if (isFunction(path)) {
+ func = path;
+ } else {
+ path = toPath(path);
+ contextPath = path.slice(0, -1);
+ path = path[path.length - 1];
+ }
+ return map(obj, function(context) {
+ var method = func;
+ if (!method) {
+ if (contextPath && contextPath.length) {
+ context = deepGet(context, contextPath);
+ }
+ if (context == null) return void 0;
+ method = context[path];
+ }
+ return method == null ? method : method.apply(context, args);
+ });
+});import tagTester from './_tagTester.js';
+import has from './_has.js';
+
+var isArguments = tagTester('Arguments');Define a fallback version of the method in browsers (ahem, IE < 9), where +there isn’t any inspectable “Arguments” type.
+ +(function() {
+ if (!isArguments(arguments)) {
+ isArguments = function(obj) {
+ return has(obj, 'callee');
+ };
+ }
+}());
+
+export default isArguments;import { nativeIsArray } from './_setup.js';
+import tagTester from './_tagTester.js';Is a given value an array?
+Delegates to ECMA5’s native Array.isArray.
export default nativeIsArray || tagTester('Array');import tagTester from './_tagTester.js';
+
+export default tagTester('ArrayBuffer');