-// ♓🌟 Piscēs ∷ collection.js
-// ====================================================================
-//
-// Copyright © 2020–2023 Lady [@ Lady’s Computer].
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
-
-import { call, createCallableFunction } from "./function.js";
-import { isConcatSpreadableObject } from "./object.js";
-import { toIndex, type } from "./value.js";
-
-const { prototype: arrayPrototype } = Array;
-
-export const {
-  /** Returns an array of the provided values. */
-  of: array,
+// SPDX-FileCopyrightText: 2020, 2021, 2022, 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
+// SPDX-License-Identifier: MPL-2.0
+/**
+ * ⁌ ♓🧩 Piscēs ∷ collection.js
+ *
+ * Copyright © 2020–2023, 2025 Lady [@ Ladys Computer].
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+ */
 
-  /** Returns whether the provided value is an array. */
-  isArray,
+import {
+  call,
+  createArrowFunction,
+  createCallableFunction,
+  createProxyConstructor,
+  isCallable,
+  maybe,
+} from "./function.js";
+import {
+  defineOwnDataProperty,
+  defineOwnProperty,
+  getMethod,
+  hasOwnProperty,
+  isConcatSpreadableObject,
+  lengthOfArraylike,
+  objectCreate,
+  setPropertyValues,
+  toObject,
+  toPropertyDescriptorRecord,
+} from "./object.js";
+import {
+  canonicalNumericIndexString,
+  ITERATOR,
+  MAXIMUM_SAFE_INTEGRAL_NUMBER,
+  sameValue,
+  toFunctionName,
+  toIndex,
+  toLength,
+  type,
+  UNDEFINED,
+} from "./value.js";
 
-  /** Returns an array created from the provided arraylike. */
-  from: toArray,
-} = Array;
+const PISCĒS = "♓🧩 Piscēs";
 
-/**
- * Returns the result of catenating the provided arraylikes into a new
- * collection according to the algorithm of `Array::concat`.
- */
-export const catenate = createCallableFunction(
-  arrayPrototype.concat,
-  "catenate",
+/** Returns an array of the provided values. */
+export const array = createArrowFunction(
+  Array.of,
+  { name: "array" },
 );
 
+export const {
+  /**
+   * Returns the result of catenating the provided concat spreadable
+   * values into a new collection according to the algorithm of
+   * `Array::concat´.
+   *
+   * ※ If no arguments are given, this function returns an empty
+   * array. This is different behaviour than if an explicit undefined
+   * first argument is given, in which case the resulting array will
+   * have undefined as its first item.
+   *
+   * ※ Unlike `Array::concat´, this function ignores
+   * `.constructor[Symbol.species]´ and always returns an array.
+   */
+  concatSpreadableCatenate,
+} = (() => {
+  const { concat } = Array.prototype;
+  return {
+    concatSpreadableCatenate: Object.defineProperties(
+      (...args) => call(concat, [], args),
+      {
+        name: { value: "concatSpreadableCatenate" },
+        length: { value: 2 },
+      },
+    ),
+  };
+})();
+
 /**
  * Copies the items in the provided object to a new location according
- * to the algorithm of `Array::copyWithin`.
+ * to the algorithm of `Array::copyWithin´.
  */
 export const copyWithin = createCallableFunction(
-  arrayPrototype.copyWithin,
+  Array.prototype.copyWithin,
 );
 
+export const {
+  /**
+   * Returns a proxy of the provided arraylike value for which every
+   * integer index less than its length will appear to be present.
+   *
+   * ※ The returned proxy will have the original object as its
+   * prototype and will update with changes to the original.
+   *
+   * ※ The returned proxy only reflects ⹐own⹑ properties on the
+   * underlying object; if an index is set on the prototype chain, but
+   * not as an own property on the underlying object, it will appear as
+   * undefined on the proxy. Like·wise, if the length is not an own
+   * property, it will appear to be zero.
+   *
+   * ※ Both data values and accessors are supported for indices,
+   * provided they are defined directly on the underlying object.
+   *
+   * ※ A proxy can be made non·extensible if the `.length´ of the
+   * underlying object is read·only (i·e, not defined using a getter)
+   * and nonconfigurable.
+   *
+   * ※ Integer indices on the returned proxy, as well as `.length´,
+   * are read·only and start out formally (but not manually)
+   * configurable. They can only be made nonconfigurable if the
+   * underlying value is guaranteed not to change. As a change in
+   * `.length´ deletes any integer indices larger than the `.length´,
+   * the `.length´ of the underlying object must be fixed for any
+   * integer index to be made nonconfigurable.
+   *
+   * ※ When iterating, it is probably faster to just make a copy of
+   * the original value, for example :—
+   *
+   * | `setPropertyValues(´
+   * | `  fill(setPropertyValue([], "length", original.length)),´
+   * | `  original,´
+   * | `);´
+   *
+   * This function is rather intended for the use·case where both the
+   * proxy and the underlying array are longlived, and the latter may
+   * change unexpectedly after the formers creation.
+   */
+  denseProxy,
+
+  /**
+   * Returns whether the provided value is a dense proxy (created with
+   * `denseProxy´).
+   */
+  isDenseProxy,
+} = (() => {
+  const {
+    deleteProperty: reflectDeleteProperty,
+    defineProperty: reflectDefineProperty,
+    getOwnPropertyDescriptor: reflectGetOwnPropertyDescriptor,
+    getPrototypeOf: reflectGetPrototypeOf,
+    has: reflectHas,
+    isExtensible: reflectIsExtensible,
+    ownKeys: reflectOwnKeys,
+    preventExtensions: reflectPreventExtensions,
+    setPrototypeOf: reflectSetPrototypeOf,
+  } = Reflect;
+  const isReadOnlyNonconfigurable = (Desc) =>
+    Desc !== UNDEFINED
+    && !(Desc.configurable || "get" in Desc
+      || "writable" in Desc && Desc.writable);
+
+  const denseProxyHandler = Object.assign(Object.create(null), {
+    defineProperty(O, P, Desc) {
+      const k = P === "length"
+        ? UNDEFINED
+        : canonicalNumericIndexString(P);
+      if (
+        P === "length"
+        || k !== UNDEFINED
+          && (sameValue(k, 0) || k > 0 && k === toLength(k))
+      ) {
+        // The provided property is either `"length"´ or an integer
+        // index.
+        const desc = maybe(Desc, toPropertyDescriptorRecord);
+        if (
+          desc.set !== UNDEFINED
+          || "writable" in desc && desc.writable
+        ) {
+          // The provided descriptor defines a setter or is attempting
+          // to make the property writable; this is not permitted.
+          return false;
+        } else {
+          // The provided descriptor does not define a setter.
+          const Q = reflectGetPrototypeOf(O);
+          const current = maybe(
+            reflectGetOwnPropertyDescriptor(O, P),
+            toPropertyDescriptorRecord,
+          );
+          const lenDesc = maybe(
+            reflectGetOwnPropertyDescriptor(Q, "length"),
+            toPropertyDescriptorRecord,
+          );
+          const currentlyConfigurable = current?.configurable ?? true;
+          const willChangeConfigurable = "configurable" in desc
+            && (desc.configurable !== currentlyConfigurable);
+          if (
+            willChangeConfigurable
+            && (!currentlyConfigurable
+              || !isReadOnlyNonconfigurable(lenDesc))
+          ) {
+            // The provided descriptor either aims to make a property
+            // nonconfigurable when the underlying length is not
+            // readonly or else aims to make a property configurable
+            // when it currently isn¦t; neither is permitted.
+            return false;
+          } else if (P === "length") {
+            // The provided descriptor is attempting to modify the
+            // length.
+            //
+            // It is known at this point that either the property
+            // descriptor is not trying to make the length
+            // nonconfigurable, or else the underlying length is
+            // readonly.
+            const len = !currentlyConfigurable
+              ? current.value
+              : lenDesc === UNDEFINED
+              ? 0 // force zero if not an own property
+              : !("value" in desc)
+              ? null // not needed yet
+              : lengthOfArraylike(Q);
+            if (
+              "get" in desc
+              || "enumerable" in desc && desc.enumerable
+              || "value" in desc && desc.value !== len
+            ) {
+              // The provided descriptor is attempting to create a
+              // getter for the length, change the enumerability of the
+              // length, or change the value of the length; these are
+              // not permitted.
+              return false;
+            } else if (!willChangeConfigurable) {
+              // The provided descriptor is not attempting to change
+              // the value of the length or its configurablility; this
+              // succeeds with no effect.
+              return true;
+            } else {
+              // The provided descriptor is attempting to make a
+              // read·only, configurable length nonconfigurable.
+              return reflectDefineProperty(
+                O,
+                P,
+                setPropertyValues(objectCreate(null), {
+                  configurable: false,
+                  enumerable: false,
+                  value: len ?? lengthOfArraylike(Q),
+                  writable: false,
+                }),
+              );
+            }
+          } else {
+            // The provided property is an integral canonical numeric
+            // index string.
+            const len = lenDesc === UNDEFINED
+              ? 0
+              : lengthOfArraylike(Q);
+            if (k < len) {
+              // The provided property is smaller than the length; this
+              // property can potentially be modified.
+              const kDesc = maybe(
+                reflectGetOwnPropertyDescriptor(Q, P),
+                toPropertyDescriptorRecord,
+              );
+              const kGet = current?.get; // use current getter
+              const kValue = // use underlying value
+                kDesc === UNDEFINED
+                  ? UNDEFINED
+                  : kDesc.value ?? call(kDesc.get, Q, []);
+              if (
+                "get" in desc && desc.get !== kGet
+                || "enumerable" in desc && !desc.enumerable
+                || "value" in desc && desc.value !== kValue
+              ) {
+                // The provided descriptor is attempting to change the
+                // value or enumerability of the property away from
+                // their current values; this is not permitted.
+                return false;
+              } else if (!willChangeConfigurable) {
+                // The provided descriptor is not attempting to change
+                // the configurability of the property; in this case,
+                // no actual change is being requested.
+                return true;
+              } else {
+                // The provided descriptor is attempting to make the
+                // property nonconfigurable, but it is currently
+                // configurable (and maybe not even present on the
+                // proxy target); this is only permissible if the value
+                // of the underlying property is known not to be able
+                // to change.
+                //
+                // Providing the value is okay if the underlying
+                // property is readonly, but if the underlying property
+                // is a getter, then the value must not be provided
+                // (since the resulting property will be defined with a
+                // brand new getter).
+                //
+                // At this point, it is known that the provided
+                // descriptor does not provide a getter, because
+                // getters are only supported on index properties which
+                // are already nonconfigurable.
+                //
+                // At this point, we have already confirmed that the
+                // length of the underlying object is immutable.
+                const dynamic = kDesc !== UNDEFINED
+                  && !("writable" in kDesc);
+                const readonly =
+                  kDesc === UNDEFINED && !reflectIsExtensible(Q)
+                  || kDesc !== UNDEFINED && !kDesc.configurable && (
+                      dynamic || !kDesc.writable
+                    );
+                const noChange = !dynamic
+                  || dynamic && !("value" in desc);
+                return readonly && noChange && reflectDefineProperty(
+                  O,
+                  P,
+                  setPropertyValues(
+                    objectCreate(null),
+                    kDesc !== UNDEFINED && "get" in kDesc
+                      ? {
+                        configurable: false,
+                        enumerable: true,
+                        get: defineOwnProperty(
+                          () => call(kDesc.get, Q, []),
+                          "name",
+                          defineOwnDataProperty(
+                            objectCreate(null),
+                            "value",
+                            toFunctionName(P, "get"),
+                          ),
+                        ),
+                        set: UNDEFINED,
+                      }
+                      : {
+                        configurable: false,
+                        enumerable: true,
+                        value: kValue,
+                        writable: false,
+                      },
+                  ),
+                );
+              }
+            } else {
+              // The provided property is not smaller than the length;
+              // this is not permitted.
+              return false;
+            }
+          }
+        }
+      } else {
+        // The provided property is not `"length"´ or an integer index.
+        return reflectDefineProperty(O, P, Desc);
+      }
+    },
+    deleteProperty(O, P) {
+      const k = P === "length"
+        ? UNDEFINED
+        : canonicalNumericIndexString(P);
+      if (
+        P === "length"
+        || k !== UNDEFINED
+          && (sameValue(k, 0) || k > 0 && k === toLength(k))
+      ) {
+        // The property is an integer index or `"length"´.
+        if (!reflectIsExtensible(O) || P === "length") {
+          // The proxied object is not extensible or the provided
+          // property is `"length"´; this is not permitted.
+          return false;
+        } else {
+          // The provided property is an integer index; it can only
+          // be deleted if it is greater than the length (in which
+          // case, it is not present in the first place).
+          const Q = reflectGetPrototypeOf(O);
+          const len = hasOwnProperty(Q, "length")
+            ? lengthOfArraylike(Q)
+            : 0;
+          return k < len ? false : true;
+        }
+      } else {
+        // The provided property is not `"length"´ or an integer index.
+        return reflectDeleteProperty(O, P);
+      }
+    },
+    getOwnPropertyDescriptor(O, P) {
+      const k = P === "length"
+        ? UNDEFINED
+        : canonicalNumericIndexString(P);
+      if (
+        P === "length"
+        || k !== UNDEFINED
+          && (sameValue(k, 0) || k > 0 && k === toLength(k))
+      ) {
+        // The property is an integer index or `"length"´.
+        const Q = reflectGetPrototypeOf(O);
+        const current = maybe(
+          reflectGetOwnPropertyDescriptor(O, P),
+          toPropertyDescriptorRecord,
+        );
+        if (current !== UNDEFINED && !current.configurable) {
+          // The property is defined and nonconfigurable on the object.
+          //
+          // Return its descriptor.
+          return current;
+        } else if (P === "length") {
+          // The property is `"length"´.
+          //
+          // Return the length of the underlying object.
+          return setPropertyValues(objectCreate(null), {
+            configurable: true,
+            enumerable: false,
+            value: hasOwnProperty(Q, "length")
+              ? lengthOfArraylike(Q)
+              : 0,
+            writable: false,
+          });
+        } else {
+          // The property is an integer index.
+          //
+          // Return a data descriptor with its value or undefined as
+          // appropriate.
+          const len = hasOwnProperty(Q, "length")
+            ? lengthOfArraylike(Q)
+            : 0;
+          if (k < len) {
+            // The property is an integer index less than the length.
+            //
+            // Provide the current value of the own property.
+            const kDesc = maybe(
+              reflectGetOwnPropertyDescriptor(Q, P),
+              toPropertyDescriptorRecord,
+            );
+            return setPropertyValues(objectCreate(null), {
+              configurable: true,
+              enumerable: true,
+              value: !kDesc
+                ? UNDEFINED
+                : "get" in kDesc
+                ? call(kDesc.get, Q, [])
+                : kDesc.value,
+              writable: false,
+            });
+          } else {
+            // The property is an integer index, but not less than the
+            // length.
+            //
+            // Return undefined.
+            return UNDEFINED;
+          }
+        }
+      } else {
+        // The provided property is not `"length"´ or an integer index.
+        return reflectGetOwnPropertyDescriptor(O, P);
+      }
+    },
+    has(O, P) {
+      const k = P === "length"
+        ? UNDEFINED
+        : canonicalNumericIndexString(P);
+      if (P === "length") {
+        // The provided property is `"length"´; this is always present.
+        return true;
+      } else if (
+        k !== UNDEFINED
+        && (sameValue(k, 0) || k > 0 && k === toLength(k))
+      ) {
+        // The provided property is an integer index.
+        //
+        // Return whether it is less than the length.
+        const Q = reflectGetPrototypeOf(O);
+        const len = hasOwnProperty(Q, "length")
+          ? lengthOfArraylike(Q)
+          : 0;
+        return k < len ? true : reflectHas(O, P);
+      } else {
+        // The provided property is not `"length"´ or an integer index.
+        return reflectHas(O, P);
+      }
+    },
+    ownKeys(O) {
+      const keys = reflectOwnKeys(O);
+      const Q = reflectGetPrototypeOf(O);
+      const len = hasOwnProperty(Q, "length")
+        ? lengthOfArraylike(Q)
+        : 0;
+      const result = [];
+      let i;
+      let hasHitLength = false;
+      for (i = 0; i < len && i < -1 >>> 0; ++i) {
+        // Iterate over those array indices which are less than the
+        // length of the underlying object and collect them in the
+        // result.
+        //
+        // Array indices are handled specially by the Ecmascript
+        // specification. Other integer indices may also be present
+        // (if they are too big to be array indices but still smaller
+        // than the length), but these are added later with all of the
+        // other keys.
+        defineOwnDataProperty(result, i, `${i}`);
+      }
+      for (let j = 0; j < keys.length; ++j) {
+        // Iterate over the own keys of the object and collect them in
+        // the result if necessary.
+        const P = keys[j];
+        const k = P === "length"
+          ? UNDEFINED
+          : canonicalNumericIndexString(P);
+        const isIntegerIndex = k !== UNDEFINED
+          && (sameValue(k, 0) || k > 0 && k === toLength(k));
+        if (!hasHitLength && (!isIntegerIndex || k >= -1 >>> 0)) {
+          // The current key is the first key which is not an array
+          // index; add `"length"´ to the result, as well as any
+          // integer indices which are not array indices.
+          //
+          // This may never occur, in which case these properties are
+          // added after the end of the loop.
+          //
+          // `"length"´ is added first as it is conceptually the first
+          // property on the object.
+          defineOwnDataProperty(result, result.length, "length");
+          for (; i < len; ++i) {
+            // Iterate over those remaining integer indices which are
+            // less than the length of the underlying object and
+            // collect them in the result.
+            defineOwnDataProperty(result, result.length, `${i}`);
+          }
+          hasHitLength = true;
+        } else {
+          // The current key is not the first key which is not an array
+          // index.
+          /* do nothing */
+        }
+        if (P === "length" || isIntegerIndex && k < len) {
+          // The current key is either `"length"´ or an integer index
+          // less than the length; it has already been collected.
+          /* do nothing */
+        } else {
+          // The current key has not yet been collected into the
+          // result; add it.
+          defineOwnDataProperty(result, result.length, P);
+        }
+      }
+      if (!hasHitLength) {
+        // All of the collected keys were array indices; `"length"´ and
+        // any outstanding integer indices still need to be collected.
+        defineOwnDataProperty(result, result.length, "length");
+        for (; i < len; ++i) {
+          // Iterate over those remaining integer indices which are
+          // less than the length of the underlying object and collect
+          // them in the result.
+          defineOwnDataProperty(result, result.length, `${i}`);
+        }
+      } else {
+        // There was at least one key collected which was not an array
+        // index.
+        /* do nothing */
+      }
+      return result;
+    },
+    preventExtensions(O) {
+      if (!reflectIsExtensible(O)) {
+        // The object is already not extensible; this is an automatic
+        // success.
+        return true;
+      } else {
+        // The object is currently extensible; see if it can be made
+        // non·extensible and attempt to do so.
+        const Q = reflectGetPrototypeOf(O);
+        const lenDesc = maybe(
+          reflectGetOwnPropertyDescriptor(Q, "length"),
+          toPropertyDescriptorRecord,
+        );
+        if (!isReadOnlyNonconfigurable(lenDesc)) {
+          // The underlying length is not read·only; the object cannot
+          // be made non·extensible because the indices may change.
+          return false;
+        } else {
+          // The underlying length is read·only; define the needed
+          // indices on the object and then prevent extensions.
+          const len = lengthOfArraylike(Q); // definitely exists
+          for (let k = 0; k < len; ++k) {
+            // Iterate over each index and define a placeholder for it.
+            reflectDefineProperty(
+              O,
+              k,
+              setPropertyValues(objectCreate(null), {
+                configurable: true,
+                enumerable: true,
+                value: UNDEFINED,
+                writable: false,
+              }),
+            );
+          }
+          return reflectPreventExtensions(O);
+        }
+      }
+    },
+    setPrototypeOf(O, V) {
+      const Q = reflectGetPrototypeOf(O);
+      return Q === V ? reflectSetPrototypeOf(O, V) : false;
+    },
+  });
+
+  const DenseProxy = createProxyConstructor(
+    denseProxyHandler,
+    function Dense($) {
+      return objectCreate(toObject($)); // throws if nullish
+    },
+  );
+
+  return {
+    denseProxy: Object.defineProperty(
+      ($) => new DenseProxy($),
+      "name",
+      { value: "denseProxy" },
+    ),
+    isDenseProxy: DenseProxy.isDenseProxy,
+  };
+})();
+
 /**
  * Fills the provided object with the provided value according to the
- * algorithm of `Array::fill`.
+ * algorithm of `Array::fill´.
  */
-export const fill = createCallableFunction(arrayPrototype.fill);
+export const fill = createCallableFunction(Array.prototype.fill);
 
 /**
  * Returns the result of filtering the provided object with the
- * provided callback, according to the algorithm of `Array::filter`.
+ * provided callback, according to the algorithm of `Array::filter´.
+ *
+ * ※ Unlike `Array::filter´, this function ignores
+ * `.constructor[Symbol.species]´ and always returns an array.
  */
-export const filter = createCallableFunction(arrayPrototype.filter);
+export const filter = ($, callbackFn, thisArg = UNDEFINED) => {
+  const O = toObject($);
+  const len = lengthOfArraylike(O);
+  if (!isCallable(callbackFn)) {
+    throw new TypeError(
+      `${PISCĒS}: Filter callback must be callable.`,
+    );
+  } else {
+    const A = [];
+    for (let k = 0, to = 0; k < len; ++k) {
+      if (k in O) {
+        const kValue = O[k];
+        if (call(callbackFn, thisArg, [kValue, k, O])) {
+          defineOwnDataProperty(A, to++, kValue);
+        } else {
+          /* do nothing */
+        }
+      } else {
+        /* do nothing */
+      }
+    }
+    return A;
+  }
+};
 
 /**
  * Returns the first index in the provided object whose value satisfies
- * the provided callback according to the algorithm of
- * `Array::findIndex`.
+ * the provided callback.
+ *
+ * ※ This function differs from `Array::findIndex´ in that it returns
+ * undefined, not −1, if no match is found, and indices which aren¦t
+ * present are skipped, not treated as having values of undefined.
  */
-export const findIndex = createCallableFunction(
-  arrayPrototype.findIndex,
-);
+export const findFirstIndex = ($, callback, thisArg = UNDEFINED) =>
+  findFirstIndexedEntry($, callback, thisArg)?.[0];
+
+export const {
+  /**
+   * Returns the first indexed entry in the provided object whose value
+   * satisfies the provided callback.
+   *
+   * If a third argument is supplied, it will be used as the this value
+   * of the callback.
+   *
+   * ※ Unlike the builtin Ecmascript array searching methods, this
+   * function does not treat indices which are not present on a sparse
+   * array as though they were undefined.
+   */
+  findFirstIndexedEntry,
+
+  /**
+   * Returns the last indexed entry in the provided object whose value
+   * satisfies the provided callback.
+   *
+   * If a third argument is supplied, it will be used as the this value
+   * of the callback.
+   *
+   * ※ Unlike the builtin Ecmascript array searching methods, this
+   * function does not treat indices which are not present on a sparse
+   * array as though they were undefined.
+   */
+  findLastIndexedEntry,
+} = (() => {
+  const findViaPredicate = ($, direction, predicate, thisArg) => {
+    const O = toObject($);
+    const len = lengthOfArraylike(O);
+    if (!isCallable(predicate)) {
+      // The provided predicate is not callable; throw an error.
+      throw new TypeError(
+        `${PISCĒS}: Find predicate must be callable.`,
+      );
+    } else {
+      // The provided predicate is callable; do the search.
+      const ascending = direction === "ascending";
+      for (
+        let k = ascending ? 0 : len - 1;
+        ascending ? k < len : k >= 0;
+        ascending ? ++k : --k
+      ) {
+        // Iterate over each possible index between 0 and the length of
+        // the provided arraylike.
+        if (!(k in O)) {
+          // The current index is not present in the provided value.
+          /* do nothing */
+        } else {
+          // The current index is present in the provided value; test
+          // to see if it satisfies the predicate.
+          const kValue = O[k];
+          if (call(predicate, thisArg, [kValue, k, O])) {
+            // The value at the current index satisfies the predicate;
+            // return the entry.
+            return [k, kValue];
+          } else {
+            // The value at the current index does not satisfy the
+            // predicate.
+            /* do nothing */
+          }
+        }
+      }
+      return UNDEFINED;
+    }
+  };
+
+  return {
+    findFirstIndexedEntry: ($, predicate, thisArg = UNDEFINED) =>
+      findViaPredicate($, "ascending", predicate, thisArg),
+    findLastIndexedEntry: ($, predicate, thisArg = UNDEFINED) =>
+      findViaPredicate($, "descending", predicate, thisArg),
+  };
+})();
 
 /**
- * Returns the first indexed entry in the provided object whose value
+ * Returns the first indexed value in the provided object which
  * satisfies the provided callback.
  *
- * If a third argument is supplied, it will be used as the this value
- * of the callback.
+ * ※ Unlike `Array::find´, this function does not treat indices which
+ * are not present on a sparse array as though they were undefined.
  */
-export const findIndexedEntry = (
-  $,
-  callback,
-  thisArg = undefined,
-) => {
-  let result = undefined;
-  findItem($, (kValue, k, O) => {
-    if (call(callback, thisArg, [kValue, k, O])) {
-      // The callback succeeded.
-      result = [k, kValue];
-      return true;
-    } else {
-      // The callback failed.
-      return false;
-    }
-  });
-  return result;
-};
+export const findFirstItem = ($, callback, thisArg = UNDEFINED) =>
+  findFirstIndexedEntry($, callback, thisArg)?.[1];
 
 /**
- * Returns the first indexed value in the provided object which
- * satisfies the provided callback, according to the algorithm of
- * `Array::find`.
+ * Returns the last index in the provided object whose value satisfies
+ * the provided callback.
+ *
+ * ※ This function differs from `Array::findLastIndex´ in that it
+ * returns undefined, not −1, if no match is found, and indices which
+ * aren¦t present are skipped, not treated as having values of
+ * undefined.
  */
-export const findItem = createCallableFunction(
-  arrayPrototype.find,
-  "findItem",
-);
+export const findLastIndex = ($, callback, thisArg = UNDEFINED) =>
+  findLastIndexedEntry($, callback, thisArg)?.[0];
+
+/**
+ * Returns the last indexed value in the provided object which
+ * satisfies the provided callback.
+ *
+ * ※ Unlike `Array::findLast´, this function does not treat indices
+ * which are not present on a sparse array as though they were
+ * undefined.
+ */
+export const findLastItem = ($, callback, thisArg = UNDEFINED) =>
+  findLastIndexedEntry($, callback, thisArg)?.[1];
 
 /**
  * Returns the result of flatmapping the provided value with the
- * provided callback according to the algorithm of `Array::flatMap`.
+ * provided callback according to the algorithm of `Array::flatMap´.
+ *
+ * ※ Flattening always produces a dense array.
  */
 export const flatmap = createCallableFunction(
-  arrayPrototype.flatMap,
-  "flatmap",
+  Array.prototype.flatMap,
+  { name: "flatmap" },
 );
 
 /**
  * Returns the result of flattening the provided object according to
- * the algorithm of `Array::flat`.
+ * the algorithm of `Array::flat´.
+ *
+ * ※ Flattening always produces a dense array.
  */
 export const flatten = createCallableFunction(
-  arrayPrototype.flat,
-  "flatten",
+  Array.prototype.flat,
+  { name: "flatten" },
 );
 
 /**
  * Returns the first index of the provided object with a value
  * equivalent to the provided value according to the algorithm of
- * `Array::indexOf`.
+ * `Array::indexOf´.
  */
 export const getFirstIndex = createCallableFunction(
-  arrayPrototype.indexOf,
-  "getFirstIndex",
+  Array.prototype.indexOf,
+  { name: "getFirstIndex" },
 );
 
 /**
  * Returns the item on the provided object at the provided index
- * according to the algorithm of `Array::at`.
+ * according to the algorithm of `Array::at´.
  */
 export const getItem = createCallableFunction(
-  arrayPrototype.at,
-  "getItem",
+  Array.prototype.at,
+  { name: "getItem" },
 );
 
 /**
  * Returns the last index of the provided object with a value
  * equivalent to the provided value according to the algorithm of
- * `Array::lastIndexOf`.
+ * `Array::lastIndexOf´.
  */
 export const getLastIndex = createCallableFunction(
-  arrayPrototype.lastIndexOf,
-  "getLastIndex",
+  Array.prototype.lastIndexOf,
+  { name: "getLastIndex" },
 );
 
 /**
  * Returns whether every indexed value in the provided object satisfies
- * the provided function, according to the algorithm of `Array::every`.
+ * the provided function, according to the algorithm of `Array::every´.
  */
 export const hasEvery = createCallableFunction(
-  arrayPrototype.every,
-  "hasEvery",
+  Array.prototype.every,
+  { name: "hasEvery" },
 );
 
 /**
  * Returns whether the provided object has an indexed value which
  * satisfies the provided function, according to the algorithm of
- * `Array::some`.
+ * `Array::some´.
  */
 export const hasSome = createCallableFunction(
-  arrayPrototype.some,
-  "hasSome",
+  Array.prototype.some,
+  { name: "hasSome" },
 );
 
 /**
  * Returns whether the provided object has an indexed value equivalent
  * to the provided value according to the algorithm of
- * `Array::includes`.
+ * `Array::includes´.
  *
- * ※ This algorithm treats missing values as `undefined` rather than
+ * ※ This algorithm treats missing values as undefined rather than
  * skipping them.
  */
 export const includes = createCallableFunction(
-  arrayPrototype.includes,
+  Array.prototype.includes,
 );
 
 /**
  * Returns an iterator over the indexed entries in the provided value
- * according to the algorithm of `Array::entries`.
+ * according to the algorithm of `Array::entries´.
  */
 export const indexedEntries = createCallableFunction(
-  arrayPrototype.entries,
-  "indexedEntries",
+  Array.prototype.entries,
+  { name: "indexedEntries" },
 );
 
 /**
  * Returns an iterator over the indices in the provided value according
- * to the algorithm of `Array::keys`.
+ * to the algorithm of `Array::keys´.
  */
 export const indices = createCallableFunction(
-  arrayPrototype.keys,
-  "indices",
+  Array.prototype.keys,
+  { name: "indices" },
 );
 
+export const isArray = createArrowFunction(Array.isArray);
+
 /**
  * Returns whether the provided object is a collection.
  *
  * The definition of “collection” used by Piscēs is similar to
- * Ecmascript’s definition of an arraylike object, but it differs in
+ * Ecmascripts definition of an arraylike object, but it differs in
  * a few ways :—
  *
  * - It requires the provided value to be a proper object.
  *
- * - It requires the `length` property to be an integer index.
+ * - It requires the `length´ property to be an integer index.
  *
  * - It requires the object to be concat‐spreadable, meaning it must
- *   either be an array or have `.[Symbol.isConcatSpreadable]` be true.
+ *   either be an array or have `.[Symbol.isConcatSpreadable]´ be true.
  */
 export const isCollection = ($) => {
   if (!(type($) === "object" && "length" in $)) {
-    // The provided value is not an object or does not have a `length`.
+    // The provided value is not an object or does not have a `length´.
     return false;
   } else {
     try {
-      toIndex($.length); // will throw if `length` is not an index
+      toIndex($.length); // will throw if `length´ is not an index
       return isConcatSpreadableObject($);
     } catch {
       return false;
 
 /**
  * Returns an iterator over the items in the provided value according
- * to the algorithm of `Array::values`.
+ * to the algorithm of `Array::values´.
  */
 export const items = createCallableFunction(
-  arrayPrototype.values,
-  "items",
+  Array.prototype.values,
+  { name: "items" },
 );
 
 /**
  * Returns the result of mapping the provided value with the provided
- * callback according to the algorithm of `Array::map`.
+ * callback according to the algorithm of `Array::map´.
  */
-export const map = createCallableFunction(arrayPrototype.map);
+export const map = createCallableFunction(Array.prototype.map);
 
 /**
  * Pops from the provided value according to the algorithm of
- * `Array::pop`.
+ * `Array::pop´.
  */
-export const pop = createCallableFunction(arrayPrototype.pop);
+export const pop = createCallableFunction(Array.prototype.pop);
 
 /**
  * Pushes onto the provided value according to the algorithm of
- * `Array::push`.
+ * `Array::push´.
  */
-export const push = createCallableFunction(arrayPrototype.push);
+export const push = createCallableFunction(Array.prototype.push);
 
 /**
  * Returns the result of reducing the provided value with the provided
- * callback, according to the algorithm of `Array::reduce`.
+ * callback, according to the algorithm of `Array::reduce´.
  */
-export const reduce = createCallableFunction(arrayPrototype.reduce);
+export const reduce = createCallableFunction(Array.prototype.reduce);
 
 /**
  * Reverses the provided value according to the algorithm of
- * `Array::reverse`.
+ * `Array::reverse´.
  */
-export const reverse = createCallableFunction(arrayPrototype.reverse);
+export const reverse = createCallableFunction(Array.prototype.reverse);
 
 /**
  * Shifts the provided value according to the algorithm of
- * `Array::shift`.
+ * `Array::shift´.
  */
-export const shift = createCallableFunction(arrayPrototype.shift);
+export const shift = createCallableFunction(Array.prototype.shift);
 
 /**
  * Returns a slice of the provided value according to the algorithm of
- * `Array::slice`.
+ * `Array::slice´.
  */
-export const slice = createCallableFunction(arrayPrototype.slice);
+export const slice = createCallableFunction(Array.prototype.slice);
 
 /**
  * Sorts the provided value in‐place according to the algorithm of
- * `Array::sort`.
+ * `Array::sort´.
  */
-export const sort = createCallableFunction(arrayPrototype.sort);
+export const sort = createCallableFunction(Array.prototype.sort);
 
 /**
  * Splices into and out of the provided value according to the
- * algorithm of `Array::splice`.
+ * algorithm of `Array::splice´.
  */
-export const splice = createCallableFunction(arrayPrototype.splice);
+export const splice = createCallableFunction(Array.prototype.splice);
+
+export const {
+  /**
+   * Returns a potentially‐sparse array created from the provided
+   * arraylike or iterable.
+   *
+   * ※ This function differs from `Array.from´ in that it does not
+   * support subclassing and, in the case of a provided arraylike
+   * value, does not set properties on the result which are not present
+   * in the provided value. This can result in sparse arrays.
+   *
+   * ※ An iterator result which lacks a `value´ property also results
+   * in the corresponding index being missing in the resulting array.
+   */
+  toArray,
+
+  /**
+   * Returns a dense array created from the provided arraylike or
+   * iterable.
+   *
+   * ※ This function differs from `Array.from´ in that it does not
+   * support subclassing.
+   *
+   * ※ If indices are not present in a provided arraylike value, they
+   * will be treated exactly as tho they were present and set to
+   * undefined.
+   */
+  toDenseArray,
+} = (() => {
+  const makeArray = Array;
+
+  const arrayFrom = (items, mapFn, thisArg, allowSparse = false) => {
+    // This function re·implements the behaviour of `Array.from´, plus
+    // support for sparse arrays and minus the support for subclassing.
+    //
+    // It is actually only needed in the former case, as subclassing
+    // support can more easily be removed by wrapping it in an arrow
+    // function or binding it to `Array´ or undefined.
+    if (mapFn !== UNDEFINED && !isCallable(mapFn)) {
+      // A mapping function was provided but is not callable; this is
+      // an error.
+      throw new TypeError(`${PISCĒS}: Map function not callable.`);
+    } else {
+      // Attempt to get an iterator method for the provided items;
+      // further behaviour depends on whether this is successful.
+      const iteratorMethod = getMethod(items, ITERATOR);
+      if (iteratorMethod !== UNDEFINED) {
+        // An iterator method was found; attempt to create an array
+        // from its items.
+        const A = [];
+        const iterator = call(items, iteratorMethod, []);
+        if (type(iterator) !== "object") {
+          // The iterator method did not produce an object; this is an
+          // error.
+          throw new TypeError(
+            `${PISCĒS}: Iterators must be objects, but got: ${iterator}.`,
+          );
+        } else {
+          // The iterator method produced an iterator object; collect
+          // its values into the array.
+          const nextMethod = iterator.next;
+          for (let k = 0; true; ++k) {
+            // Loop until the iterator is exhausted.
+            if (k >= MAXIMUM_SAFE_INTEGRAL_NUMBER) {
+              // The current index has exceeded the maximum index
+              // allowable for arrays; close the iterator, then throw
+              // an error.
+              try {
+                // Attempt to close the iterator.
+                iterator.return();
+              } catch {
+                // Ignore any errors while closing the iterator.
+                /* do nothing */
+              }
+              throw new TypeError(`${PISCĒS}: Index out of range.`);
+            } else {
+              // The current index is a valid index; get the next value
+              // from the iterator and assign it, if one exists.
+              const result = call(nextMethod, iterator, []);
+              if (type(result) !== "object") {
+                // The next method did not produce an object; this is
+                // an error.
+                throw new TypeError(
+                  `${PISCĒS}: Iterator results must be objects, but got: ${result}.`,
+                );
+              } else {
+                // The next method produced an object; process it.
+                const { done } = result;
+                if (done) {
+                  // The iterator has exhausted itself; confirm the
+                  // length of the resulting array and return it.
+                  A.length = k;
+                  return A;
+                } else {
+                  const present = "value" in result;
+                  // The iterator has not exhausted itself; add its
+                  // value to the array.
+                  if (allowSparse && !present) {
+                    // The iterator has no value and creating sparse
+                    // arrays is allowed.
+                    /* do nothing */
+                  } else {
+                    // The iterator has a value or sparse arrays are
+                    // disallowed.
+                    const nextValue = present
+                      ? result.value
+                      : UNDEFINED;
+                    try {
+                      // Try to assign the value in the result array,
+                      // mapping if necessary.
+                      defineOwnDataProperty(
+                        A,
+                        k,
+                        mapFn !== UNDEFINED
+                          ? call(mapFn, thisArg, [nextValue, k])
+                          : nextValue,
+                      );
+                    } catch (error) {
+                      // There was an error when mapping or assigning
+                      // the value; close the iterator before
+                      // rethrowing the error.
+                      try {
+                        // Attempt to close the iterator.
+                        iterator.return();
+                      } catch {
+                        // Ignore any errors while closing the
+                        // iterator.
+                        /* do nothing */
+                      }
+                      throw error;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      } else {
+        // No iterator method was found; treat the provided items as an
+        // arraylike object.
+        const arraylike = toObject(items);
+        const len = lengthOfArraylike(arraylike);
+        const A = makeArray(len);
+        for (let k = 0; k < len; ++k) {
+          // Iterate over the values in the arraylike object and assign
+          // them to the result array as necessary.
+          const present = k in arraylike;
+          if (allowSparse && !present) {
+            // The current index is not present in the arraylike object
+            // and sparse arrays are allowed.
+            /* do nothing */
+          } else {
+            // The current index is present in the arraylike object or
+            // sparse arrays are not allowed; assign the value to the
+            // appropriate index in the result array, mapping if
+            // necessary.
+            const nextValue = present ? arraylike[k] : UNDEFINED;
+            defineOwnDataProperty(
+              A,
+              k,
+              mapFn !== UNDEFINED
+                ? call(mapFn, thisArg, [nextValue, k])
+                : nextValue,
+            );
+          }
+        }
+        A.length = len;
+        return A;
+      }
+    }
+  };
+
+  return {
+    toArray: (items, mapFn = UNDEFINED, thisArg = UNDEFINED) =>
+      arrayFrom(items, mapFn, thisArg, true),
+    toDenseArray: (items, mapFn = UNDEFINED, thisArg = UNDEFINED) =>
+      arrayFrom(items, mapFn, thisArg, false),
+  };
+})();
 
 /**
  * Unshifts the provided value according to the algorithm of
- * `Array::unshift`.
+ * `Array::unshift´.
  */
-export const unshift = createCallableFunction(arrayPrototype.unshift);
+export const unshift = createCallableFunction(Array.prototype.unshift);
 
-// ♓🌟 Piscēs ∷ collection.test.js
-// ====================================================================
-//
-// Copyright © 2022 Lady [@ Lady’s Computer].
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+// SPDX-FileCopyrightText: 2022, 2023, 2025 Lady <https://www.ladys.computer/about/#lady>
+// SPDX-License-Identifier: MPL-2.0
+/**
+ * ⁌ ♓🧩 Piscēs ∷ collection.js
+ *
+ * Copyright © 2022–2023, 2025 Lady [@ Ladys Computer].
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
+ */
 
 import {
   assertEquals,
   assertSpyCall,
   assertSpyCalls,
   assertStrictEquals,
+  assertThrows,
   describe,
   it,
   spy,
 } from "./dev-deps.js";
-import { findIndexedEntry, isCollection } from "./collection.js";
+import {
+  array,
+  concatSpreadableCatenate,
+  copyWithin,
+  denseProxy,
+  fill,
+  filter,
+  findFirstIndex,
+  findFirstIndexedEntry,
+  findFirstItem,
+  findLastIndex,
+  findLastIndexedEntry,
+  findLastItem,
+  flatmap,
+  flatten as _flatten /* TK */,
+  getFirstIndex as _getFirstIndex /* TK */,
+  getItem as _getItem /* TK */,
+  getLastIndex as _getLastIndex /* TK */,
+  hasEvery as _hasEvery /* TK */,
+  hasSome as _hasSome /* TK */,
+  includes as _includes /* TK */,
+  indexedEntries as _indexedEntries /* TK */,
+  indices as _indices /* TK */,
+  isArray as _isArray /* TK */,
+  isCollection,
+  isDenseProxy,
+  items as _items /* TK */,
+  map as _map /* TK */,
+  pop as _pop /* TK */,
+  push as _push /* TK */,
+  reduce as _reduce /* TK */,
+  reverse as _reverse /* TK */,
+  shift as _shift /* TK */,
+  slice as _slice /* TK */,
+  sort as _sort /* TK */,
+  splice as _splice /* TK */,
+  toArray,
+  toDenseArray,
+  unshift as _unshift /* TK */,
+} from "./collection.js";
+
+describe("array", () => {
+  it("[[Call]] returns an array of the provided values", () => {
+    assertEquals(array("etaoin", [], true), ["etaoin", [], true]);
+  });
+
+  it("[[Call]] returns an empty array with no arguments", () => {
+    assertEquals(array(), []);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new array());
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(array.length, 0);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(array.name, "array");
+    });
+  });
+});
+
+describe("concatSpreadableCatenate", () => {
+  it("[[Call]] catenates concat spreadable values", () => {
+    assertEquals(
+      concatSpreadableCatenate([1, 2], [2, [3]], {
+        length: 1,
+        [Symbol.isConcatSpreadable]: true,
+      }),
+      [1, 2, 2, [3], ,],
+    );
+  });
+
+  it("[[Call]] does not catenate other values", () => {
+    assertEquals(concatSpreadableCatenate({}, "etaoin"), [
+      {},
+      "etaoin",
+    ]);
+  });
+
+  it("[[Call]] allows a nullish first argument", () => {
+    assertEquals(concatSpreadableCatenate(null), [null]);
+    assertEquals(concatSpreadableCatenate(undefined), [undefined]);
+  });
+
+  it("[[Call]] returns an empty array with no arguments", () => {
+    assertEquals(concatSpreadableCatenate(), []);
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new concatSpreadableCatenate());
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(concatSpreadableCatenate.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        concatSpreadableCatenate.name,
+        "concatSpreadableCatenate",
+      );
+    });
+  });
+});
+
+describe("copyWithin", () => {
+  it("[[Call]] copies within", () => {
+    assertEquals(
+      copyWithin(["a", "b", "c", , "e"], 0, 3, 4),
+      [, "b", "c", , "e"],
+    );
+    assertEquals(
+      copyWithin(["a", "b", "c", , "e"], 1, 3),
+      ["a", , "e", , "e"],
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new copyWithin([], 0, 0));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(copyWithin.length, 3);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(copyWithin.name, "copyWithin");
+    });
+  });
+});
+
+describe("denseProxy", () => {
+  const makeUnderlying = () =>
+    Object.create({ 2: "inherited" }, {
+      // 0 is not present
+      1: { value: "static", configurable: true, writable: true },
+      // 2 is not an own property, but is present on the prototype
+      3: { configurable: true, get: () => "dynamic" },
+      length: { value: "4", configurable: true, writable: true },
+    });
+
+  it("[[Call]] returns an object which inherits from the provided object", () => {
+    const underlying = makeUnderlying();
+    const proxy = denseProxy(underlying);
+    assertStrictEquals(
+      Object.getPrototypeOf(proxy),
+      underlying,
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new denseProxy([]));
+  });
+
+  it("[[OwnPropertyKeys]] lists integer indices, then the length, then other keys", () => {
+    const underlying = makeUnderlying();
+    const proxy = denseProxy(underlying);
+    const sym = Symbol();
+    proxy[sym] = "shrdlu";
+    proxy["1.2.3"] = "etaion";
+    assertEquals(
+      Reflect.ownKeys(proxy),
+      ["0", "1", "2", "3", "length", "1.2.3", sym],
+    );
+  });
+
+  it("[[PreventExtensions]] fails if the underlying object is extensible", () => {
+    const underlying = makeUnderlying();
+    const proxy = denseProxy(underlying);
+    assertStrictEquals(
+      Reflect.preventExtensions(proxy),
+      false,
+    );
+  });
+
+  it("[[PreventExtensions]] fails if the underlying object has a nonconstant length", () => {
+    const underlying = makeUnderlying();
+    const proxy = denseProxy(underlying);
+    Object.defineProperty(underlying, "length", { get: () => 4 });
+    Object.freeze(underlying);
+    assertStrictEquals(
+      Reflect.preventExtensions(proxy),
+      false,
+    );
+  });
+
+  it("[[PreventExtensions]] succeeds if the underlying object is non·extensible and has a constant length", () => {
+    const underlying = makeUnderlying();
+    const proxy = denseProxy(underlying);
+    Object.defineProperty(underlying, "length", {
+      configurable: false,
+      writable: false,
+    });
+    Object.preventExtensions(underlying);
+    assertStrictEquals(
+      Reflect.preventExtensions(proxy),
+      true,
+    );
+  });
+
+  it("[[SetPrototypeOf]] fails to change the prototype", () => {
+    const underlying = makeUnderlying();
+    const proxy = denseProxy(underlying);
+    assertStrictEquals(
+      Reflect.setPrototypeOf(proxy, {}),
+      false,
+    );
+  });
+
+  it("[[SetPrototypeOf]] succeeds keeping the prototype the same", () => {
+    const underlying = makeUnderlying();
+    const proxy = denseProxy(underlying);
+    assertStrictEquals(
+      Reflect.setPrototypeOf(proxy, underlying),
+      true,
+    );
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(denseProxy.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(denseProxy.name, "denseProxy");
+    });
+  });
+
+  describe("~[]", () => {
+    it("[[DefineProperty]] allows changes when the property is not an index property or length", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      const newValue = Symbol();
+      proxy.etaoin = newValue;
+      assertStrictEquals(
+        proxy.etaoin,
+        newValue,
+      );
+    });
+
+    it("[[DefineProperty]] allows changing nothing when the property is not an own property", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "0",
+          {
+            configurable: true,
+            enumerable: true,
+            writable: false,
+            value: undefined,
+          },
+        ),
+        true,
+      );
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "2",
+          {
+            configurable: true,
+            enumerable: true,
+            writable: false,
+            value: undefined,
+          },
+        ),
+        true,
+      );
+      /* test nonconfigurable versions too */
+      Object.freeze(underlying);
+      Object.defineProperty(proxy, "0", { configurable: false });
+      Object.defineProperty(proxy, "2", { configurable: false });
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "0",
+          Object.getOwnPropertyDescriptor(proxy, "0"),
+        ),
+        true,
+      );
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "2",
+          Object.getOwnPropertyDescriptor(proxy, "2"),
+        ),
+        true,
+      );
+    });
+
+    it("[[DefineProperty]] allows changing nothing when the property is a data index property", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "1",
+          {
+            configurable: true,
+            enumerable: true,
+            writable: false,
+            value: underlying[1],
+          },
+        ),
+        true,
+      );
+      /* test nonconfigurable versions too */
+      Object.freeze(underlying);
+      Object.defineProperty(proxy, "1", { configurable: false });
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "1",
+          Object.getOwnPropertyDescriptor(proxy, "1"),
+        ),
+        true,
+      );
+    });
+
+    it("[[DefineProperty]] allows changing nothing when the property is an accessor index property", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "3",
+          {
+            configurable: true,
+            enumerable: true,
+            writable: false,
+            value: underlying[3],
+          },
+        ),
+        true,
+      );
+      /* test nonconfigurable versions too */
+      Object.freeze(underlying);
+      Object.defineProperty(proxy, "1", { configurable: false });
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "1",
+          Object.getOwnPropertyDescriptor(proxy, "1"),
+        ),
+        true,
+      );
+    });
+
+    it("[[DefineProperty]] does not allow a change in enumerablility on index properties", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.defineProperty(proxy, i, { enumerable: false }),
+          false,
+        );
+      }
+    });
+
+    it("[[DefineProperty]] does not allow a change in value on index properties", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.defineProperty(proxy, i, { value: "new value" })
+            && (() => {
+              throw i;
+            })(),
+          false,
+        );
+      }
+    });
+
+    it("[[DefineProperty]] does not allow a change in getter on index properties", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.defineProperty(proxy, i, {
+            get: () => underlying[i],
+          }) && (() => {
+            throw i;
+          })(),
+          false,
+        );
+      }
+    });
+
+    it("[[DefineProperty]] does not allow a change in setter on index properties", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.defineProperty(proxy, i, { set: () => undefined }),
+          false,
+        );
+      }
+    });
+
+    it("[[DefineProperty]] does not allow a change in configurability on index properties if the property in the underlying object may change", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      Object.defineProperty(underlying, "length", {
+        configurable: false,
+        writable: false,
+      });
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.defineProperty(proxy, i, { configurable: false }),
+          false,
+        );
+      }
+    });
+
+    it("[[DefineProperty]] does not allow a change in configurability on index properties if the length of the underlying object may change", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      Object.seal(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.defineProperty(proxy, i, { configurable: false }),
+          false,
+        );
+      }
+    });
+
+    it("[[DefineProperty]] allows a change in configurability on index properties when it is safe to do so", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      Object.defineProperty(underlying, "length", {
+        configurable: false,
+        writable: false,
+      });
+      Object.defineProperty(underlying, "1", {
+        configurable: false,
+        writable: false,
+      });
+      Object.defineProperty(underlying, "3", { configurable: false });
+      Object.preventExtensions(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.defineProperty(proxy, i, { configurable: false }),
+          true,
+        );
+      }
+    });
+
+    it("[[Delete]] is allowed when the property is not an index property or length", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      proxy.a = "etaoin";
+      assertStrictEquals(
+        Reflect.deleteProperty(proxy, "a"),
+        true,
+      );
+      assertStrictEquals(
+        Reflect.has(proxy, "a"),
+        false,
+      );
+    });
+
+    it("[[Delete]] is forbidden for index properties less than the length", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.deleteProperty(proxy, i),
+          false,
+        );
+      }
+    });
+
+    it("[[Delete]] is allowed for index properties greater than or equal to the length", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.deleteProperty(proxy, "4"),
+        true,
+      );
+      assertStrictEquals(
+        Reflect.deleteProperty(proxy, "5"),
+        true,
+      );
+    });
+
+    it("[[GetOwnProperty]] gives the value of an index property as a data property by default", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertEquals(
+        Object.getOwnPropertyDescriptor(proxy, 1),
+        {
+          configurable: true,
+          enumerable: true,
+          value: underlying[1],
+          writable: false,
+        },
+      );
+      assertEquals(
+        Object.getOwnPropertyDescriptor(proxy, 3),
+        {
+          configurable: true,
+          enumerable: true,
+          value: underlying[3],
+          writable: false,
+        },
+      );
+      /* test nonconfigurable data properties too */
+      Object.freeze(underlying);
+      Object.defineProperty(proxy, "1", { configurable: false });
+      assertEquals(
+        Object.getOwnPropertyDescriptor(proxy, 1),
+        {
+          configurable: false,
+          enumerable: true,
+          value: underlying[1],
+          writable: false,
+        },
+      );
+    });
+
+    it("[[GetOwnProperty]] gives a value of undefined if the underlying object does not have an index property as an own property", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertEquals(
+        Object.getOwnPropertyDescriptor(proxy, 0),
+        {
+          configurable: true,
+          enumerable: true,
+          value: undefined,
+          writable: false,
+        },
+      );
+      assertEquals(
+        Object.getOwnPropertyDescriptor(proxy, 2),
+        {
+          configurable: true,
+          enumerable: true,
+          value: undefined,
+          writable: false,
+        },
+      );
+    });
+
+    it("[[GetOwnProperty]] gives a value of undefined for index properties less than the length", () => {
+      const underlying = makeUnderlying();
+      underlying.length = 0;
+      const proxy = denseProxy(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Object.getOwnPropertyDescriptor(proxy, i),
+          undefined,
+        );
+      }
+    });
+
+    it("[[GetOwnProperty]] gives a getter when the underlying object has a getter and an index property is not configurable", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      Object.freeze(underlying);
+      Object.defineProperty(proxy, "3", { configurable: false });
+      const descriptor = Object.getOwnPropertyDescriptor(proxy, 3);
+      assertEquals(
+        descriptor,
+        {
+          configurable: false,
+          enumerable: true,
+          get: descriptor.get,
+          set: undefined,
+        },
+      );
+    });
+
+    describe("[[GetOwnProperty]].get.length", () => {
+      it("[[Get]] returns the correct length", () => {
+        const underlying = makeUnderlying();
+        const proxy = denseProxy(underlying);
+        Object.freeze(underlying);
+        Object.defineProperty(proxy, "3", { configurable: false });
+        assertStrictEquals(
+          Object.getOwnPropertyDescriptor(
+            proxy,
+            "3",
+          ).get.length,
+          0,
+        );
+      });
+    });
+
+    describe("[[GetOwnProperty]].get.name", () => {
+      it("[[Get]] returns the correct name", () => {
+        const underlying = makeUnderlying();
+        const proxy = denseProxy(underlying);
+        Object.freeze(underlying);
+        Object.defineProperty(proxy, "3", { configurable: false });
+        assertStrictEquals(
+          Object.getOwnPropertyDescriptor(
+            proxy,
+            "3",
+          ).get.name,
+          "get 3",
+        );
+      });
+    });
+
+    it("[[HasProperty]] works when the property is not an index property or length", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      proxy.a = "etaoin";
+      Object.getPrototypeOf(underlying).b = "shrdlu";
+      assertStrictEquals(
+        Reflect.has(proxy, "a"),
+        true,
+      );
+      assertStrictEquals(
+        Reflect.has(proxy, "b"),
+        true,
+      );
+      assertStrictEquals(
+        Reflect.has(proxy, "z"),
+        false,
+      );
+    });
+
+    it("[[HasProperty]] works for index properties less than the length", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.has(proxy, i),
+          true,
+        );
+      }
+      delete underlying.length;
+      for (let i = 0; i < 4; ++i) {
+        assertStrictEquals(
+          Reflect.has(proxy, i),
+          Reflect.has(underlying, i),
+        );
+      }
+    });
+
+    it("[[HasProperty]] works for index properties greater than or equal to the length", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.has(proxy, "4"),
+        false,
+      );
+      assertStrictEquals(
+        Reflect.has(proxy, "5"),
+        false,
+      );
+      underlying[4] = "inherited now";
+      assertStrictEquals(
+        Reflect.has(proxy, "4"),
+        true,
+      );
+    });
+  });
+
+  describe("~length", () => {
+    it("[[DefineProperty]] allows changing nothing", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "length",
+          {
+            configurable: true,
+            enumerable: false,
+            writable: false,
+            value: underlying.length >>> 0,
+          },
+        ),
+        true,
+      );
+      /* test nonconfigurable versions too */
+      Object.freeze(underlying);
+      Object.defineProperty(proxy, "length", { configurable: false });
+      assertStrictEquals(
+        Reflect.defineProperty(
+          proxy,
+          "length",
+          Object.getOwnPropertyDescriptor(proxy, "length"),
+        ),
+        true,
+      );
+    });
+
+    it("[[DefineProperty]] does not allow a change in enumerablility", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(proxy, "length", { enumerable: true }),
+        false,
+      );
+    });
+
+    it("[[DefineProperty]] does not allow a change in value", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(proxy, "length", { value: 0 }),
+        false,
+      );
+    });
+
+    it("[[DefineProperty]] does not allow a change in getter", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(proxy, "length", {
+          get: () => underlying.length >>> 0,
+        }),
+        false,
+      );
+    });
+
+    it("[[DefineProperty]] does not allow a change in setter", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(proxy, "length", { set: () => {} }),
+        false,
+      );
+    });
+
+    it("[[DefineProperty]] does not allow a change in configurability if the length of the underlying object may change", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.defineProperty(proxy, "length", {
+          configurable: false,
+        }),
+        false,
+      );
+      Object.defineProperty(underlying, "length", {
+        configurable: false,
+        get: () => 0,
+      });
+      assertStrictEquals(
+        Reflect.defineProperty(proxy, "length", {
+          configurable: false,
+        }),
+        false,
+      );
+    });
+
+    it("[[DefineProperty]] allows a change in configurability when it is safe to do so", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      Object.defineProperty(underlying, "length", {
+        configurable: false,
+        writable: false,
+      });
+      assertStrictEquals(
+        Reflect.defineProperty(proxy, "length", {
+          configurable: false,
+        }),
+        true,
+      );
+    });
+
+    it("[[Delete]] is forbidden", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.deleteProperty(
+          proxy,
+          "length",
+        ),
+        false,
+      );
+    });
+
+    it("[[GetOwnProperty]] gives the value as a data property", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertEquals(
+        Object.getOwnPropertyDescriptor(proxy, "length"),
+        {
+          configurable: true,
+          enumerable: false,
+          value: underlying.length >>> 0,
+          writable: false,
+        },
+      );
+      /* test nonconfigurable data properties too */
+      Object.freeze(underlying);
+      Object.defineProperty(proxy, "length", { configurable: false });
+      assertEquals(
+        Object.getOwnPropertyDescriptor(proxy, "length"),
+        {
+          configurable: false,
+          enumerable: false,
+          value: underlying.length >>> 0,
+          writable: false,
+        },
+      );
+    });
+
+    it("[[GetOwnProperty]] gives 0 if the underlying object does not have the property as an own property", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      delete underlying.length;
+      Object.getPrototypeOf(underlying).length = 3;
+      assertEquals(
+        Object.getOwnPropertyDescriptor(proxy, "length"),
+        {
+          configurable: true,
+          enumerable: false,
+          value: 0,
+          writable: false,
+        },
+      );
+    });
+
+    it("[[HasProperty]] is always true", () => {
+      const underlying = makeUnderlying();
+      const proxy = denseProxy(underlying);
+      assertStrictEquals(
+        Reflect.has(proxy, "length"),
+        true,
+      );
+      delete underlying.length;
+      assertStrictEquals(
+        Reflect.has(proxy, "length"),
+        true,
+      );
+    });
+  });
+});
+
+describe("fill", () => {
+  it("[[Call]] fills", () => {
+    assertEquals(
+      fill({ 1: "failure", length: 3 }, "success"),
+      { 0: "success", 1: "success", 2: "success", length: 3 },
+    );
+  });
+
+  it("[[Call]] can fill a range", () => {
+    assertEquals(
+      fill({ 1: "failure", length: 4 }, "success", 1, 3),
+      { 1: "success", 2: "success", length: 4 },
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new fill([], null));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(fill.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(fill.name, "fill");
+    });
+  });
+});
+
+describe("filter", () => {
+  it("[[Call]] filters", () => {
+    assertEquals(
+      filter(["failure", "success", ,], function ($) {
+        return !$ || $ == this;
+      }, "success"),
+      ["success"],
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new filter([], () => {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(filter.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(filter.name, "filter");
+    });
+  });
+});
+
+describe("findFirstIndex", () => {
+  it("[[Call]] returns undefined if no matching entry exists", () => {
+    assertStrictEquals(findFirstIndex([], () => true), undefined);
+    assertStrictEquals(findFirstIndex([1], () => false), undefined);
+  });
+
+  it("[[Call]] returns an index for the first match", () => {
+    assertStrictEquals(
+      findFirstIndex([, true, false], ($) => $ ?? true),
+      1,
+    );
+    assertStrictEquals(
+      findFirstIndex(
+        ["failure", "success", "success"],
+        ($) => $ == "success",
+      ),
+      1,
+    );
+  });
+
+  it("[[Call]] works on arraylike objects", () => {
+    assertStrictEquals(
+      findFirstIndex({ 1: "success", length: 2 }, ($) => $),
+      1,
+    );
+    assertStrictEquals(
+      findFirstIndex({ 1: "failure", length: 1 }, ($) => $),
+      undefined,
+    );
+  });
+
+  it("[[Call]] only gets the value once", () => {
+    const get1 = spy(() => true);
+    findFirstIndex({
+      get 1() {
+        return get1();
+      },
+      length: 2,
+    }, ($) => $);
+    assertSpyCalls(get1, 1);
+  });
+
+  it("[[Call]] passes the value, index, and this value to the callback", () => {
+    const arr = [, "failure", "success", "success"];
+    const callback = spy(($) => $ === "success");
+    const thisArg = {};
+    findFirstIndex(arr, callback, thisArg);
+    assertSpyCalls(callback, 2);
+    assertSpyCall(callback, 0, {
+      args: ["failure", 1, arr],
+      self: thisArg,
+    });
+    assertSpyCall(callback, 1, {
+      args: ["success", 2, arr],
+      self: thisArg,
+    });
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new findFirstIndex([], () => {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(findFirstIndex.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(findFirstIndex.name, "findFirstIndex");
+    });
+  });
+});
 
-describe("findIndexedEntry", () => {
+describe("findFirstIndexedEntry", () => {
   it("[[Call]] returns undefined if no matching entry exists", () => {
-    assertStrictEquals(findIndexedEntry([], () => true), void {});
-    assertStrictEquals(findIndexedEntry([1], () => false), void {});
+    assertStrictEquals(
+      findFirstIndexedEntry([], () => true),
+      undefined,
+    );
+    assertStrictEquals(
+      findFirstIndexedEntry([1], () => false),
+      undefined,
+    );
   });
 
   it("[[Call]] returns an entry for the first match", () => {
     assertEquals(
-      findIndexedEntry([, true, false], ($) => $ ?? true),
-      [0, void {}],
+      findFirstIndexedEntry([, true, false], ($) => $ ?? true),
+      [1, true],
     );
     assertEquals(
-      findIndexedEntry(["failure", "success"], ($) => $ == "success"),
+      findFirstIndexedEntry(
+        ["failure", "success", "success"],
+        ($) => $ == "success",
+      ),
       [1, "success"],
     );
   });
 
   it("[[Call]] works on arraylike objects", () => {
     assertEquals(
-      findIndexedEntry({ 1: "success", length: 2 }, ($) => $),
+      findFirstIndexedEntry({ 1: "success", length: 2 }, ($) => $),
       [1, "success"],
     );
     assertEquals(
-      findIndexedEntry({ 1: "failure", length: 1 }, ($) => $),
-      void {},
+      findFirstIndexedEntry({ 1: "failure", length: 1 }, ($) => $),
+      undefined,
+    );
+  });
+
+  it("[[Call]] only gets the value once", () => {
+    const get1 = spy(() => true);
+    findFirstIndexedEntry({
+      get 1() {
+        return get1();
+      },
+      length: 2,
+    }, ($) => $);
+    assertSpyCalls(get1, 1);
+  });
+
+  it("[[Call]] passes the value, index, and this value to the callback", () => {
+    const arr = [, "failure", "success", "success"];
+    const callback = spy(($) => $ === "success");
+    const thisArg = {};
+    findFirstIndexedEntry(arr, callback, thisArg);
+    assertSpyCalls(callback, 2);
+    assertSpyCall(callback, 0, {
+      args: ["failure", 1, arr],
+      self: thisArg,
+    });
+    assertSpyCall(callback, 1, {
+      args: ["success", 2, arr],
+      self: thisArg,
+    });
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new findFirstIndexedEntry([], () => {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(findFirstIndexedEntry.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        findFirstIndexedEntry.name,
+        "findFirstIndexedEntry",
+      );
+    });
+  });
+});
+
+describe("findFirstItem", () => {
+  it("[[Call]] returns undefined if no matching item exists", () => {
+    assertStrictEquals(findFirstItem([], () => true), undefined);
+    assertStrictEquals(findFirstItem([1], () => false), undefined);
+  });
+
+  it("[[Call]] returns the first match", () => {
+    assertStrictEquals(
+      findFirstItem([, true, false], ($) => $ ?? true),
+      true,
+    );
+    assertStrictEquals(
+      findFirstItem(
+        ["failure", "success", "success"],
+        ($) => $ == "success",
+      ),
+      "success",
+    );
+  });
+
+  it("[[Call]] works on arraylike objects", () => {
+    assertStrictEquals(
+      findFirstItem({ 1: "success", length: 2 }, ($) => $),
+      "success",
+    );
+    assertStrictEquals(
+      findFirstItem({ 1: "failure", length: 1 }, ($) => $),
+      undefined,
+    );
+  });
+
+  it("[[Call]] only gets the value once", () => {
+    const get1 = spy(() => true);
+    findFirstItem({
+      get 1() {
+        return get1();
+      },
+      length: 2,
+    }, ($) => $);
+    assertSpyCalls(get1, 1);
+  });
+
+  it("[[Call]] passes the value, index, and this value to the callback", () => {
+    const arr = [, "failure", "success", "success"];
+    const callback = spy(($) => $ === "success");
+    const thisArg = {};
+    findFirstItem(arr, callback, thisArg);
+    assertSpyCalls(callback, 2);
+    assertSpyCall(callback, 0, {
+      args: ["failure", 1, arr],
+      self: thisArg,
+    });
+    assertSpyCall(callback, 1, {
+      args: ["success", 2, arr],
+      self: thisArg,
+    });
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new findFirstItem([], () => {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(findFirstItem.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(findFirstItem.name, "findFirstItem");
+    });
+  });
+});
+
+describe("findLastIndex", () => {
+  it("[[Call]] returns undefined if no matching entry exists", () => {
+    assertStrictEquals(findLastIndex([], () => true), undefined);
+    assertStrictEquals(findLastIndex([1], () => false), undefined);
+  });
+
+  it("[[Call]] returns an index for the first match", () => {
+    assertStrictEquals(
+      findLastIndex([true, false, ,], ($) => $ ?? true),
+      0,
+    );
+    assertStrictEquals(
+      findLastIndex(
+        ["success", "success", "failure"],
+        ($) => $ == "success",
+      ),
+      1,
+    );
+  });
+
+  it("[[Call]] works on arraylike objects", () => {
+    assertStrictEquals(
+      findLastIndex({ 1: "success", length: 2 }, ($) => $),
+      1,
+    );
+    assertStrictEquals(
+      findLastIndex({ 1: "failure", length: 1 }, ($) => $),
+      undefined,
     );
   });
 
   it("[[Call]] only gets the value once", () => {
     const get1 = spy(() => true);
-    findIndexedEntry({
+    findLastIndex({
       get 1() {
         return get1();
       },
   });
 
   it("[[Call]] passes the value, index, and this value to the callback", () => {
-    const arr = ["failure", "success", "success"];
+    const arr = ["success", "success", "failure", ,];
     const callback = spy(($) => $ === "success");
     const thisArg = {};
-    findIndexedEntry(arr, callback, thisArg);
+    findLastIndex(arr, callback, thisArg);
     assertSpyCalls(callback, 2);
     assertSpyCall(callback, 0, {
-      args: ["failure", 0, arr],
+      args: ["failure", 2, arr],
       self: thisArg,
     });
     assertSpyCall(callback, 1, {
       self: thisArg,
     });
   });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new findLastIndex([], () => {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(findLastIndex.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(findLastIndex.name, "findLastIndex");
+    });
+  });
+});
+
+describe("findLastIndexedEntry", () => {
+  it("[[Call]] returns undefined if no matching entry exists", () => {
+    assertStrictEquals(
+      findLastIndexedEntry([], () => true),
+      undefined,
+    );
+    assertStrictEquals(
+      findLastIndexedEntry([1], () => false),
+      undefined,
+    );
+  });
+
+  it("[[Call]] returns an index for the first match", () => {
+    assertEquals(
+      findLastIndexedEntry([true, false, ,], ($) => $ ?? true),
+      [0, true],
+    );
+    assertEquals(
+      findLastIndexedEntry(
+        ["success", "success", "failure"],
+        ($) => $ == "success",
+      ),
+      [1, "success"],
+    );
+  });
+
+  it("[[Call]] works on arraylike objects", () => {
+    assertEquals(
+      findLastIndexedEntry({ 1: "success", length: 2 }, ($) => $),
+      [1, "success"],
+    );
+    assertEquals(
+      findLastIndexedEntry({ 1: "failure", length: 1 }, ($) => $),
+      undefined,
+    );
+  });
+
+  it("[[Call]] only gets the value once", () => {
+    const get1 = spy(() => true);
+    findLastIndexedEntry({
+      get 1() {
+        return get1();
+      },
+      length: 2,
+    }, ($) => $);
+    assertSpyCalls(get1, 1);
+  });
+
+  it("[[Call]] passes the value, index, and this value to the callback", () => {
+    const arr = ["success", "success", "failure", ,];
+    const callback = spy(($) => $ === "success");
+    const thisArg = {};
+    findLastIndexedEntry(arr, callback, thisArg);
+    assertSpyCalls(callback, 2);
+    assertSpyCall(callback, 0, {
+      args: ["failure", 2, arr],
+      self: thisArg,
+    });
+    assertSpyCall(callback, 1, {
+      args: ["success", 1, arr],
+      self: thisArg,
+    });
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new findLastIndexedEntry([], () => {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(findLastIndexedEntry.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(
+        findLastIndexedEntry.name,
+        "findLastIndexedEntry",
+      );
+    });
+  });
+});
+
+describe("findLastItem", () => {
+  it("[[Call]] returns undefined if no matching entry exists", () => {
+    assertStrictEquals(findLastItem([], () => true), undefined);
+    assertStrictEquals(findLastItem([1], () => false), undefined);
+  });
+
+  it("[[Call]] returns an index for the first match", () => {
+    assertStrictEquals(
+      findLastItem([true, false, ,], ($) => $ ?? true),
+      true,
+    );
+    assertStrictEquals(
+      findLastItem(
+        ["success", "success", "failure"],
+        ($) => $ == "success",
+      ),
+      "success",
+    );
+  });
+
+  it("[[Call]] works on arraylike objects", () => {
+    assertStrictEquals(
+      findLastItem({ 1: "success", length: 2 }, ($) => $),
+      "success",
+    );
+    assertStrictEquals(
+      findLastItem({ 1: "failure", length: 1 }, ($) => $),
+      undefined,
+    );
+  });
+
+  it("[[Call]] only gets the value once", () => {
+    const get1 = spy(() => true);
+    findLastItem({
+      get 1() {
+        return get1();
+      },
+      length: 2,
+    }, ($) => $);
+    assertSpyCalls(get1, 1);
+  });
+
+  it("[[Call]] passes the value, index, and this value to the callback", () => {
+    const arr = ["success", "success", "failure", ,];
+    const callback = spy(($) => $ === "success");
+    const thisArg = {};
+    findLastItem(arr, callback, thisArg);
+    assertSpyCalls(callback, 2);
+    assertSpyCall(callback, 0, {
+      args: ["failure", 2, arr],
+      self: thisArg,
+    });
+    assertSpyCall(callback, 1, {
+      args: ["success", 1, arr],
+      self: thisArg,
+    });
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new findLastItem([], () => {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(findLastItem.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(findLastItem.name, "findLastItem");
+    });
+  });
+});
+
+describe("flatmap", () => {
+  it("[[Call]] flatmaps", () => {
+    assertEquals(
+      flatmap([, "a", ["b"], [["c"]]], ($) => $),
+      ["a", "b", ["c"]],
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new flatmap([], () => {}));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(flatmap.length, 2);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(flatmap.name, "flatmap");
+    });
+  });
 });
 
 describe("isCollection", () => {
     );
   });
 });
+
+describe("isDenseProxy", () => {
+  it("[[Call]] returns true for dense proxies", () => {
+    const underlying = [];
+    const proxy = denseProxy(underlying);
+    assertStrictEquals(
+      isDenseProxy(proxy),
+      true,
+    );
+  });
+
+  it("[[Call]] returns false for others", () => {
+    assertStrictEquals(
+      isDenseProxy([]),
+      false,
+    );
+  });
+
+  it("[[Construct]] throws an error", () => {
+    assertThrows(() => new isDenseProxy([]));
+  });
+
+  describe(".length", () => {
+    it("[[Get]] returns the correct length", () => {
+      assertStrictEquals(isDenseProxy.length, 1);
+    });
+  });
+
+  describe(".name", () => {
+    it("[[Get]] returns the correct name", () => {
+      assertStrictEquals(isDenseProxy.name, "isDenseProxy");
+    });
+  });
+});
+
+describe("toArray", () => {
+  it("[[Call]] returns an array of the values in a provided arraylike", () => {
+    assertEquals(
+      toArray({ 1: "success", length: 3 }),
+      [, "success", ,],
+    );
+  });
+});
+
+describe("toDenseArray", () => {
+  it("[[Call]] returns a dense array of the values in a provided arraylike", () => {
+    assertEquals(
+      toDenseArray({ 1: "success", length: 3 }),
+      [undefined, "success", undefined],
+    );
+  });
+});