// src/extensions/number.ts
function clamp(n, min, max) {
  return n < min ? min : n > max ? max : n;
}
function lerp(start, end, t) {
  return start + (end - start) * t;
}
function inverseLerp(start, end, value) {
  return start === end ? 0 : (value - start) / (end - start);
}
function remap(n, fromMin, fromMax, toMin, toMax) {
  const t = inverseLerp(fromMin, fromMax, n);
  return lerp(toMin, toMax, t);
}
function roundTo(n, decimals) {
  const factor = 10 ** decimals;
  return Math.round(n * factor) / factor;
}
function ceilTo(n, decimals) {
  const factor = 10 ** decimals;
  return Math.ceil(n * factor) / factor;
}
function floorTo(n, decimals) {
  const factor = 10 ** decimals;
  return Math.floor(n * factor) / factor;
}
function truncTo(n, decimals) {
  const factor = 10 ** decimals;
  return Math.trunc(n * factor) / factor;
}
function snap(n, step) {
  return Math.round(n / step) * step;
}
function isEven(n) {
  return n % 2 === 0;
}
function isOdd(n) {
  return n % 2 !== 0;
}
function isPositive(n) {
  return n > 0;
}
function isNegative(n) {
  return n < 0;
}
function isZero(n) {
  return n === 0;
}
function isInteger(n) {
  return Number.isInteger(n);
}
function isFiniteNum(n) {
  return Number.isFinite(n);
}
function isNaN_(n) {
  return Number.isNaN(n);
}
function isBetween(n, min, max) {
  return n >= min && n <= max;
}
function isMultipleOf(n, divisor) {
  return divisor !== 0 && n % divisor === 0;
}
function isPrime(n) {
  if (n < 2)
    return false;
  if (n < 4)
    return true;
  if (n % 2 === 0 || n % 3 === 0)
    return false;
  for (let i = 5; i * i <= n; i += 6) {
    if (n % i === 0 || n % (i + 2) === 0)
      return false;
  }
  return true;
}
function isPerfectSquare(n) {
  if (n < 0)
    return false;
  const s = Math.sqrt(n);
  return s === Math.floor(s);
}
function isPowerOfTwo(n) {
  return n > 0 && (n & n - 1) === 0;
}
function gcd(a, b) {
  a = Math.abs(a);
  b = Math.abs(b);
  while (b) {
    [a, b] = [b, a % b];
  }
  return a;
}
function lcm(a, b) {
  return a === 0 || b === 0 ? 0 : Math.abs(a * b) / gcd(a, b);
}
function factorial(n) {
  if (n < 0)
    throw new RangeError("factorial of negative number");
  if (n <= 1)
    return 1;
  let result = 1;
  for (let i = 2; i <= n; i++)
    result *= i;
  return result;
}
function fibonacci(n) {
  if (n < 0)
    throw new RangeError("fibonacci of negative number");
  let [a, b] = [0, 1];
  for (let i = 0; i < n; i++)
    [a, b] = [b, a + b];
  return a;
}
function nCr(n, r) {
  if (r < 0 || r > n)
    return 0;
  if (r === 0 || r === n)
    return 1;
  r = Math.min(r, n - r);
  let result = 1;
  for (let i = 0; i < r; i++) {
    result = result * (n - i) / (i + 1);
  }
  return Math.round(result);
}
function nPr(n, r) {
  if (r < 0 || r > n)
    return 0;
  let result = 1;
  for (let i = 0; i < r; i++)
    result *= n - i;
  return result;
}
function isqrt(n) {
  if (n < 0)
    throw new RangeError("isqrt of negative number");
  return Math.floor(Math.sqrt(n));
}
function digits(n, base = 10) {
  if (!Number.isInteger(n))
    throw new TypeError("digits requires an integer");
  n = Math.abs(n);
  if (n === 0)
    return [0];
  const result = [];
  while (n > 0) {
    result.unshift(n % base);
    n = Math.floor(n / base);
  }
  return result;
}
function digitSum(n) {
  return digits(n).reduce((a, b) => a + b, 0);
}
function divisors(n) {
  n = Math.abs(n);
  if (n === 0)
    return [];
  const result = [];
  for (let i = 1; i * i <= n; i++) {
    if (n % i === 0) {
      result.push(i);
      if (i !== n / i)
        result.push(n / i);
    }
  }
  return result.sort((a, b) => a - b);
}
function toBin(n) {
  return (n >>> 0).toString(2);
}
function toOct(n) {
  return (n >>> 0).toString(8);
}
function toHex(n) {
  return (n >>> 0).toString(16);
}
function toBase(n, base) {
  return n.toString(base);
}
function toOrdinal(n) {
  const s = ["th", "st", "nd", "rd"];
  const v = n % 100;
  return n + (s[(v - 20) % 10] || s[v] || s[0]);
}
function toWords(n) {
  if (n === 0)
    return "zero";
  if (!Number.isFinite(n))
    return String(n);
  const ones = [
    "",
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
    "seven",
    "eight",
    "nine",
    "ten",
    "eleven",
    "twelve",
    "thirteen",
    "fourteen",
    "fifteen",
    "sixteen",
    "seventeen",
    "eighteen",
    "nineteen"
  ];
  const tens = [
    "",
    "",
    "twenty",
    "thirty",
    "forty",
    "fifty",
    "sixty",
    "seventy",
    "eighty",
    "ninety"
  ];
  const negative = n < 0;
  n = Math.abs(Math.floor(n));
  if (n < 20)
    return (negative ? "negative " : "") + ones[n];
  if (n < 100)
    return (negative ? "negative " : "") + tens[Math.floor(n / 10)] + (n % 10 ? "-" + ones[n % 10] : "");
  if (n < 1e3)
    return (negative ? "negative " : "") + ones[Math.floor(n / 100)] + " hundred" + (n % 100 ? " and " + toWords(n % 100) : "");
  const scales = ["", "thousand", "million", "billion", "trillion"];
  const parts = [];
  let scaleIdx = 0;
  while (n > 0) {
    const chunk2 = n % 1e3;
    if (chunk2 > 0) {
      parts.unshift(toWords(chunk2) + (scales[scaleIdx] ? " " + scales[scaleIdx] : ""));
    }
    n = Math.floor(n / 1e3);
    scaleIdx++;
  }
  return (negative ? "negative " : "") + parts.join(", ");
}
function toRoman(n) {
  if (n <= 0 || n >= 4e3 || !Number.isInteger(n))
    throw new RangeError("Roman numerals require 1-3999");
  const vals = [1e3, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
  const syms = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
  let result = "";
  for (let i = 0; i < vals.length; i++) {
    while (n >= vals[i]) {
      result += syms[i];
      n -= vals[i];
    }
  }
  return result;
}
function padStart(n, length, fill = "0") {
  return String(n).padStart(length, fill);
}
function toPercent(n, decimals = 0) {
  return (n * 100).toFixed(decimals) + "%";
}
function toFileSize(bytes, decimals = 2) {
  if (bytes === 0)
    return "0 B";
  const k = 1024;
  const sizes = ["B", "KB", "MB", "GB", "TB", "PB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / k ** i).toFixed(decimals)) + " " + sizes[i];
}
function toDuration(ms) {
  const abs = Math.abs(ms);
  if (abs < 1e3)
    return `${ms}ms`;
  if (abs < 6e4)
    return `${(ms / 1e3).toFixed(1)}s`;
  if (abs < 36e5)
    return `${Math.floor(ms / 6e4)}m ${Math.floor(ms % 6e4 / 1e3)}s`;
  const h = Math.floor(ms / 36e5);
  const m = Math.floor(ms % 36e5 / 6e4);
  return `${h}h ${m}m`;
}
function toCompact(n) {
  const abs = Math.abs(n);
  if (abs >= 1e12)
    return (n / 1e12).toFixed(1) + "T";
  if (abs >= 1e9)
    return (n / 1e9).toFixed(1) + "B";
  if (abs >= 1e6)
    return (n / 1e6).toFixed(1) + "M";
  if (abs >= 1e3)
    return (n / 1e3).toFixed(1) + "K";
  return String(n);
}
function times(n, fn) {
  const result = [];
  for (let i = 0; i < n; i++)
    result.push(fn(i));
  return result;
}
function timesVoid(n, fn) {
  for (let i = 0; i < n; i++)
    fn(i);
}
function* upTo(start, end, step = 1) {
  for (let i = start; i <= end; i += step)
    yield i;
}
function* downTo(start, end, step = 1) {
  for (let i = start; i >= end; i -= step)
    yield i;
}
function rangeTo(start, end, step) {
  const s = step ?? (start <= end ? 1 : -1);
  const result = [];
  if (s > 0) {
    for (let i = start; i <= end; i += s)
      result.push(i);
  } else {
    for (let i = start; i >= end; i += s)
      result.push(i);
  }
  return result;
}
function rangeUntil(start, end, step) {
  const s = step ?? (start <= end ? 1 : -1);
  const result = [];
  if (s > 0) {
    for (let i = start; i < end; i += s)
      result.push(i);
  } else {
    for (let i = start; i > end; i += s)
      result.push(i);
  }
  return result;
}
function saturatingAdd(a, b, max = Number.MAX_SAFE_INTEGER) {
  const result = a + b;
  return result > max ? max : result;
}
function saturatingSub(a, b, min = Number.MIN_SAFE_INTEGER) {
  const result = a - b;
  return result < min ? min : result;
}
function wrappingAdd(a, b, bits = 32) {
  const max = 2 ** bits;
  return ((a + b) % max + max) % max;
}
function wrappingSub(a, b, bits = 32) {
  const max = 2 ** bits;
  return ((a - b) % max + max) % max;
}
function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
function randomFloat(min, max) {
  return Math.random() * (max - min) + min;
}
var NumberExt = {
  clamp,
  lerp,
  inverseLerp,
  remap,
  roundTo,
  ceilTo,
  floorTo,
  truncTo,
  snap,
  isEven,
  isOdd,
  isPositive,
  isNegative,
  isZero,
  isInteger,
  isFinite: isFiniteNum,
  isNaN: isNaN_,
  isBetween,
  isMultipleOf,
  isPrime,
  isPerfectSquare,
  isPowerOfTwo,
  gcd,
  lcm,
  factorial,
  fibonacci,
  nCr,
  nPr,
  isqrt,
  digits,
  digitSum,
  divisors,
  toBin,
  toOct,
  toHex,
  toBase,
  toOrdinal,
  toWords,
  toRoman,
  padStart,
  toPercent,
  toFileSize,
  toDuration,
  toCompact,
  times,
  timesVoid,
  upTo,
  downTo,
  rangeTo,
  rangeUntil,
  saturatingAdd,
  saturatingSub,
  wrappingAdd,
  wrappingSub,
  randomInt,
  randomFloat
};

// src/extensions/string.ts
function capitalize(s) {
  return s.charAt(0).toUpperCase() + s.slice(1);
}
function uncapitalize(s) {
  return s.charAt(0).toLowerCase() + s.slice(1);
}
function titleCase(s) {
  return words(s).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
}
function swapCase(s) {
  return [...s].map((c) => c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase()).join("");
}
function camelCase(s) {
  const w = words(s);
  return w.map((word, i) => i === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
}
function pascalCase(s) {
  return words(s).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join("");
}
function snakeCase(s) {
  return words(s).map((w) => w.toLowerCase()).join("_");
}
function kebabCase(s) {
  return words(s).map((w) => w.toLowerCase()).join("-");
}
function constantCase(s) {
  return words(s).map((w) => w.toUpperCase()).join("_");
}
function dotCase(s) {
  return words(s).map((w) => w.toLowerCase()).join(".");
}
function pathCase(s) {
  return words(s).map((w) => w.toLowerCase()).join("/");
}
function sentenceCase(s) {
  const w = words(s);
  return w.map((word, i) => i === 0 ? capitalize(word.toLowerCase()) : word.toLowerCase()).join(" ");
}
function words(s) {
  return s.match(/[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\d|\b)|[A-Z]|[0-9]+/g) || [];
}
function lines(s) {
  return s.split(/\r?\n/);
}
function chars(s) {
  return [...s];
}
function graphemes(s) {
  return [...new Intl.Segmenter().segment(s)].map((seg) => seg.segment);
}
function trimIndent(s) {
  const ls = lines(s);
  const nonEmpty = ls.filter((l) => l.trim().length > 0);
  if (nonEmpty.length === 0)
    return s;
  const minIndent = Math.min(...nonEmpty.map((l) => l.match(/^\s*/)?.[0].length ?? 0));
  return ls.map((l) => l.slice(minIndent)).join("\n");
}
function stripMargin(s, marginChar = "|") {
  const re = new RegExp(`^\\s*\\${marginChar}`, "gm");
  return s.replace(re, "");
}
function stripPrefix(s, prefix) {
  return s.startsWith(prefix) ? s.slice(prefix.length) : s;
}
function stripSuffix(s, suffix) {
  return s.endsWith(suffix) ? s.slice(0, -suffix.length) : s;
}
function removeSurrounding(s, prefix, suffix) {
  const suf = suffix ?? prefix;
  if (s.startsWith(prefix) && s.endsWith(suf)) {
    return s.slice(prefix.length, s.length - suf.length);
  }
  return s;
}
function squeeze(s, char) {
  if (char) {
    const escaped = char.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
    return s.replace(new RegExp(`(${escaped})+`, "g"), char);
  }
  return s.replace(/(.)\1+/g, "$1");
}
function collapseWhitespace(s) {
  return s.replace(/\s+/g, " ").trim();
}
function center(s, width, fill = " ") {
  if (s.length >= width)
    return s;
  const totalPad = width - s.length;
  const left = Math.floor(totalPad / 2);
  const right = totalPad - left;
  return fill.repeat(left).slice(0, left) + s + fill.repeat(right).slice(0, right);
}
function padLeft(s, width, fill = " ") {
  return s.padStart(width, fill);
}
function padRight(s, width, fill = " ") {
  return s.padEnd(width, fill);
}
function zfill(s, width) {
  const neg = s.startsWith("-");
  const abs = neg ? s.slice(1) : s;
  return (neg ? "-" : "") + abs.padStart(width - (neg ? 1 : 0), "0");
}
function truncate(s, maxLength, suffix = "...") {
  if (s.length <= maxLength)
    return s;
  return s.slice(0, maxLength - suffix.length) + suffix;
}
function truncateWords(s, maxWords, suffix = "...") {
  const w = s.split(/\s+/);
  if (w.length <= maxWords)
    return s;
  return w.slice(0, maxWords).join(" ") + suffix;
}
function ellipsis(s, maxLength) {
  return truncate(s, maxLength, "\u2026");
}
function substringBefore(s, delimiter) {
  const idx = s.indexOf(delimiter);
  return idx === -1 ? s : s.slice(0, idx);
}
function substringAfter(s, delimiter) {
  const idx = s.indexOf(delimiter);
  return idx === -1 ? s : s.slice(idx + delimiter.length);
}
function substringBeforeLast(s, delimiter) {
  const idx = s.lastIndexOf(delimiter);
  return idx === -1 ? s : s.slice(0, idx);
}
function substringAfterLast(s, delimiter) {
  const idx = s.lastIndexOf(delimiter);
  return idx === -1 ? s : s.slice(idx + delimiter.length);
}
function between(s, start, end) {
  const startIdx = s.indexOf(start);
  if (startIdx === -1)
    return "";
  const endIdx = s.indexOf(end, startIdx + start.length);
  if (endIdx === -1)
    return "";
  return s.slice(startIdx + start.length, endIdx);
}
function scan(s, pattern) {
  const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
  const re = new RegExp(pattern.source, flags);
  return [...s.matchAll(re)].map((m) => m[0]);
}
function count(s, sub) {
  if (sub.length === 0)
    return 0;
  let n = 0;
  let pos = 0;
  while ((pos = s.indexOf(sub, pos)) !== -1) {
    n++;
    pos += sub.length;
  }
  return n;
}
function reverse(s) {
  return [...s].reverse().join("");
}
function replaceAll(s, search, replacement) {
  return s.split(search).join(replacement);
}
function insert(s, index, value) {
  return s.slice(0, index) + value + s.slice(index);
}
function remove(s, pattern) {
  if (typeof pattern === "string")
    return replaceAll(s, pattern, "");
  return s.replace(pattern, "");
}
function wrap(s, wrapper) {
  return wrapper + s + wrapper;
}
function unwrap(s, wrapper) {
  return removeSurrounding(s, wrapper);
}
function indent(s, spaces = 2, char = " ") {
  const prefix = char.repeat(spaces);
  return lines(s).map((l) => prefix + l).join("\n");
}
function dedent(s) {
  return trimIndent(s);
}
function mask(s, start = 0, end, maskChar = "*") {
  const e = end ?? s.length;
  return s.slice(0, start) + maskChar.repeat(e - start) + s.slice(e);
}
function isBlank(s) {
  return s.trim().length === 0;
}
function isNotBlank(s) {
  return s.trim().length > 0;
}
function isAlpha(s) {
  return s.length > 0 && /^[a-zA-Z]+$/.test(s);
}
function isAlphaNumeric(s) {
  return s.length > 0 && /^[a-zA-Z0-9]+$/.test(s);
}
function isDigit(s) {
  return s.length > 0 && /^[0-9]+$/.test(s);
}
function isLowerCase(s) {
  return s === s.toLowerCase() && s !== s.toUpperCase();
}
function isUpperCase(s) {
  return s === s.toUpperCase() && s !== s.toLowerCase();
}
function isAscii(s) {
  return /^[\x00-\x7F]*$/.test(s);
}
function isPalindrome(s) {
  const clean = s.toLowerCase().replace(/[^a-z0-9]/g, "");
  return clean === [...clean].reverse().join("");
}
function isEmail(s) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s);
}
function isUrl(s) {
  try {
    new URL(s);
    return true;
  } catch {
    return false;
  }
}
function isJson(s) {
  try {
    JSON.parse(s);
    return true;
  } catch {
    return false;
  }
}
function isUuid(s) {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s);
}
function isHex(s) {
  return /^(0x)?[0-9a-fA-F]+$/.test(s);
}
function toSlug(s) {
  return s.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
}
function toNumber(s) {
  const n = Number(s);
  return isNaN(n) ? void 0 : n;
}
function toInt(s, radix = 10) {
  const n = parseInt(s, radix);
  return isNaN(n) ? void 0 : n;
}
function toFloat(s) {
  const n = parseFloat(s);
  return isNaN(n) ? void 0 : n;
}
function toBoolean(s) {
  const lower = s.trim().toLowerCase();
  if (lower === "true" || lower === "1" || lower === "yes")
    return true;
  if (lower === "false" || lower === "0" || lower === "no")
    return false;
  return void 0;
}
function toCharCodes(s) {
  return [...s].map((c) => c.codePointAt(0));
}
function fromCharCodes(codes) {
  return String.fromCodePoint(...codes);
}
function escapeHtml(s) {
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
}
function unescapeHtml(s) {
  return s.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#039;/g, "'");
}
function escapeRegex(s) {
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function toBase64(s) {
  if (typeof btoa !== "undefined")
    return btoa(s);
  return Buffer.from(s).toString("base64");
}
function fromBase64(s) {
  if (typeof atob !== "undefined")
    return atob(s);
  return Buffer.from(s, "base64").toString();
}
var StringExt = {
  capitalize,
  uncapitalize,
  titleCase,
  swapCase,
  camelCase,
  pascalCase,
  snakeCase,
  kebabCase,
  constantCase,
  dotCase,
  pathCase,
  sentenceCase,
  words,
  lines,
  chars,
  graphemes,
  trimIndent,
  stripMargin,
  stripPrefix,
  stripSuffix,
  removeSurrounding,
  squeeze,
  collapseWhitespace,
  center,
  padLeft,
  padRight,
  zfill,
  truncate,
  truncateWords,
  ellipsis,
  substringBefore,
  substringAfter,
  substringBeforeLast,
  substringAfterLast,
  between,
  scan,
  count,
  reverse,
  replaceAll,
  insert,
  remove,
  wrap,
  unwrap,
  indent,
  dedent,
  mask,
  isBlank,
  isNotBlank,
  isAlpha,
  isAlphaNumeric,
  isDigit,
  isLowerCase,
  isUpperCase,
  isAscii,
  isPalindrome,
  isEmail,
  isUrl,
  isJson,
  isUuid,
  isHex,
  toSlug,
  toNumber,
  toInt,
  toFloat,
  toBoolean,
  toCharCodes,
  fromCharCodes,
  escapeHtml,
  unescapeHtml,
  escapeRegex,
  toBase64,
  fromBase64
};

// src/extensions/array.ts
function head(arr) {
  return arr[0];
}
function tail(arr) {
  return arr.slice(1);
}
function init(arr) {
  return arr.slice(0, -1);
}
function last(arr) {
  return arr[arr.length - 1];
}
function headOrThrow(arr) {
  if (arr.length === 0)
    throw new Error("headOrThrow on empty array");
  return arr[0];
}
function lastOrThrow(arr) {
  if (arr.length === 0)
    throw new Error("lastOrThrow on empty array");
  return arr[arr.length - 1];
}
function nth(arr, n) {
  return n < 0 ? arr[arr.length + n] : arr[n];
}
function take(arr, n) {
  return arr.slice(0, n);
}
function drop(arr, n) {
  return arr.slice(n);
}
function takeRight(arr, n) {
  return arr.slice(-n);
}
function dropRight(arr, n) {
  return arr.slice(0, -n || void 0);
}
function takeWhile(arr, pred) {
  const result = [];
  for (const x of arr) {
    if (!pred(x))
      break;
    result.push(x);
  }
  return result;
}
function dropWhile(arr, pred) {
  let i = 0;
  while (i < arr.length && pred(arr[i]))
    i++;
  return arr.slice(i);
}
function splitAt(arr, n) {
  return [arr.slice(0, n), arr.slice(n)];
}
function span(arr, pred) {
  const taken = takeWhile(arr, pred);
  return [taken, arr.slice(taken.length)];
}
function groupBy(arr, fn) {
  const result = {};
  for (const x of arr) {
    const key = fn(x);
    (result[key] ??= []).push(x);
  }
  return result;
}
function keyBy(arr, fn) {
  const result = {};
  for (const x of arr)
    result[fn(x)] = x;
  return result;
}
function countBy(arr, fn) {
  const result = {};
  for (const x of arr) {
    const key = fn(x);
    result[key] = (result[key] ?? 0) + 1;
  }
  return result;
}
function chunk(arr, size2) {
  if (size2 <= 0)
    throw new RangeError("chunk size must be positive");
  const result = [];
  for (let i = 0; i < arr.length; i += size2) {
    result.push(arr.slice(i, i + size2));
  }
  return result;
}
function sliding(arr, size2, step = 1) {
  if (size2 <= 0 || step <= 0)
    throw new RangeError("sliding size and step must be positive");
  const result = [];
  for (let i = 0; i + size2 <= arr.length; i += step) {
    result.push(arr.slice(i, i + size2));
  }
  return result;
}
function partition(arr, pred) {
  const yes = [];
  const no = [];
  for (const x of arr)
    (pred(x) ? yes : no).push(x);
  return [yes, no];
}
function zip(a, b) {
  const len = Math.min(a.length, b.length);
  const result = [];
  for (let i = 0; i < len; i++)
    result.push([a[i], b[i]]);
  return result;
}
function zip3(a, b, c) {
  const len = Math.min(a.length, b.length, c.length);
  const result = [];
  for (let i = 0; i < len; i++)
    result.push([a[i], b[i], c[i]]);
  return result;
}
function zipWith(a, b, fn) {
  const len = Math.min(a.length, b.length);
  const result = [];
  for (let i = 0; i < len; i++)
    result.push(fn(a[i], b[i]));
  return result;
}
function zipWithIndex(arr) {
  return arr.map((x, i) => [x, i]);
}
function zipWithNext(arr) {
  const result = [];
  for (let i = 0; i < arr.length - 1; i++)
    result.push([arr[i], arr[i + 1]]);
  return result;
}
function unzip(arr) {
  const as = [];
  const bs = [];
  for (const [a, b] of arr) {
    as.push(a);
    bs.push(b);
  }
  return [as, bs];
}
function unique(arr) {
  return [...new Set(arr)];
}
function uniqueBy(arr, fn) {
  const seen = /* @__PURE__ */ new Set();
  const result = [];
  for (const x of arr) {
    const key = fn(x);
    if (!seen.has(key)) {
      seen.add(key);
      result.push(x);
    }
  }
  return result;
}
function duplicates(arr) {
  const seen = /* @__PURE__ */ new Set();
  const dups = /* @__PURE__ */ new Set();
  for (const x of arr) {
    if (seen.has(x))
      dups.add(x);
    seen.add(x);
  }
  return [...dups];
}
function frequencies(arr) {
  const map = /* @__PURE__ */ new Map();
  for (const x of arr)
    map.set(x, (map.get(x) ?? 0) + 1);
  return map;
}
function difference(a, b) {
  const set = new Set(b);
  return a.filter((x) => !set.has(x));
}
function intersection(a, b) {
  const set = new Set(b);
  return unique(a.filter((x) => set.has(x)));
}
function union(a, b) {
  return unique([...a, ...b]);
}
function symmetricDifference(a, b) {
  const setA = new Set(a);
  const setB = new Set(b);
  return [...a.filter((x) => !setB.has(x)), ...b.filter((x) => !setA.has(x))];
}
function isSubsetOf(a, b) {
  const set = new Set(b);
  return a.every((x) => set.has(x));
}
function isSupersetOf(a, b) {
  return isSubsetOf(b, a);
}
function foldRight(arr, init2, fn) {
  let acc = init2;
  for (let i = arr.length - 1; i >= 0; i--)
    acc = fn(arr[i], acc);
  return acc;
}
function scanLeft(arr, init2, fn) {
  const result = [init2];
  let acc = init2;
  for (const x of arr) {
    acc = fn(acc, x);
    result.push(acc);
  }
  return result;
}
function scanRight(arr, init2, fn) {
  const result = new Array(arr.length + 1);
  result[arr.length] = init2;
  let acc = init2;
  for (let i = arr.length - 1; i >= 0; i--) {
    acc = fn(arr[i], acc);
    result[i] = acc;
  }
  return result;
}
function reduceRight(arr, fn) {
  if (arr.length === 0)
    throw new Error("reduceRight on empty array");
  return arr.slice(0, -1).reduceRight((acc, x) => fn(x, acc), arr[arr.length - 1]);
}
function sumBy(arr, fn) {
  let sum = 0;
  for (const x of arr)
    sum += fn(x);
  return sum;
}
function minBy(arr, fn) {
  if (arr.length === 0)
    return void 0;
  let best = arr[0];
  let bestVal = fn(best);
  for (let i = 1; i < arr.length; i++) {
    const val = fn(arr[i]);
    if (val < bestVal) {
      best = arr[i];
      bestVal = val;
    }
  }
  return best;
}
function maxBy(arr, fn) {
  if (arr.length === 0)
    return void 0;
  let best = arr[0];
  let bestVal = fn(best);
  for (let i = 1; i < arr.length; i++) {
    const val = fn(arr[i]);
    if (val > bestVal) {
      best = arr[i];
      bestVal = val;
    }
  }
  return best;
}
function average(arr) {
  if (arr.length === 0)
    return 0;
  return arr.reduce((a, b) => a + b, 0) / arr.length;
}
function median(arr) {
  if (arr.length === 0)
    return 0;
  const sorted = [...arr].sort((a, b) => a - b);
  const mid = Math.floor(sorted.length / 2);
  return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
}
function product(arr) {
  return arr.reduce((a, b) => a * b, 1);
}
function sortBy(arr, fn) {
  return [...arr].sort((a, b) => {
    const ka = fn(a);
    const kb = fn(b);
    return ka < kb ? -1 : ka > kb ? 1 : 0;
  });
}
function sortByDesc(arr, fn) {
  return [...arr].sort((a, b) => {
    const ka = fn(a);
    const kb = fn(b);
    return ka > kb ? -1 : ka < kb ? 1 : 0;
  });
}
function intersperse(arr, sep) {
  if (arr.length <= 1)
    return [...arr];
  const result = [arr[0]];
  for (let i = 1; i < arr.length; i++) {
    result.push(sep, arr[i]);
  }
  return result;
}
function intercalate(arr, sep) {
  if (arr.length === 0)
    return [];
  const result = [...arr[0]];
  for (let i = 1; i < arr.length; i++) {
    result.push(...sep, ...arr[i]);
  }
  return result;
}
function compact(arr) {
  return arr.filter(Boolean);
}
function flatten(arr) {
  return arr.flat();
}
function flattenDeep(arr) {
  return arr.flat(Infinity);
}
function rotate(arr, n) {
  if (arr.length === 0)
    return [];
  const k = (n % arr.length + arr.length) % arr.length;
  return [...arr.slice(k), ...arr.slice(0, k)];
}
function transpose(arr) {
  if (arr.length === 0)
    return [];
  const maxLen = Math.max(...arr.map((r) => r.length));
  const result = [];
  for (let i = 0; i < maxLen; i++) {
    result.push(arr.map((r) => r[i]).filter((x) => x !== void 0));
  }
  return result;
}
function interleave(a, b) {
  const result = [];
  const len = Math.max(a.length, b.length);
  for (let i = 0; i < len; i++) {
    if (i < a.length)
      result.push(a[i]);
    if (i < b.length)
      result.push(b[i]);
  }
  return result;
}
function shuffle(arr) {
  const result = [...arr];
  for (let i = result.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [result[i], result[j]] = [result[j], result[i]];
  }
  return result;
}
function sample(arr) {
  if (arr.length === 0)
    return void 0;
  return arr[Math.floor(Math.random() * arr.length)];
}
function sampleN(arr, n) {
  return shuffle(arr).slice(0, n);
}
function none(arr, pred) {
  return !arr.some(pred);
}
function isPrefixOf(prefix, arr) {
  if (prefix.length > arr.length)
    return false;
  for (let i = 0; i < prefix.length; i++) {
    if (prefix[i] !== arr[i])
      return false;
  }
  return true;
}
function isSuffixOf(suffix, arr) {
  if (suffix.length > arr.length)
    return false;
  const offset = arr.length - suffix.length;
  for (let i = 0; i < suffix.length; i++) {
    if (suffix[i] !== arr[offset + i])
      return false;
  }
  return true;
}
function isSorted(arr, compare) {
  const cmp = compare ?? ((a, b) => a < b ? -1 : a > b ? 1 : 0);
  for (let i = 1; i < arr.length; i++) {
    if (cmp(arr[i - 1], arr[i]) > 0)
      return false;
  }
  return true;
}
function tails(arr) {
  const result = [];
  for (let i = 0; i <= arr.length; i++)
    result.push(arr.slice(i));
  return result;
}
function inits(arr) {
  const result = [];
  for (let i = 0; i <= arr.length; i++)
    result.push(arr.slice(0, i));
  return result;
}
function mkString(arr, sep = "", prefix = "", suffix = "") {
  return prefix + arr.join(sep) + suffix;
}
function associate(arr, fn) {
  const result = {};
  for (const x of arr) {
    const [k, v] = fn(x);
    result[k] = v;
  }
  return result;
}
function toMap(arr, fn) {
  return new Map(arr.map(fn));
}
function toSet(arr) {
  return new Set(arr);
}
function zipObject(keys, values) {
  const result = {};
  for (let i = 0; i < keys.length; i++) {
    result[keys[i]] = values[i];
  }
  return result;
}
var ArrayExt = {
  head,
  tail,
  init,
  last,
  headOrThrow,
  lastOrThrow,
  nth,
  take,
  drop,
  takeRight,
  dropRight,
  takeWhile,
  dropWhile,
  splitAt,
  span,
  groupBy,
  keyBy,
  countBy,
  chunk,
  sliding,
  partition,
  zip,
  zip3,
  zipWith,
  zipWithIndex,
  zipWithNext,
  unzip,
  unique,
  uniqueBy,
  duplicates,
  frequencies,
  difference,
  intersection,
  union,
  symmetricDifference,
  isSubsetOf,
  isSupersetOf,
  foldRight,
  scanLeft,
  scanRight,
  reduceRight,
  sumBy,
  minBy,
  maxBy,
  average,
  median,
  product,
  sortBy,
  sortByDesc,
  intersperse,
  intercalate,
  compact,
  flatten,
  flattenDeep,
  rotate,
  transpose,
  interleave,
  shuffle,
  sample,
  sampleN,
  none,
  isPrefixOf,
  isSuffixOf,
  isSorted,
  tails,
  inits,
  mkString,
  associate,
  toMap,
  toSet,
  zipObject
};

// src/extensions/object.ts
function pick(obj, keys) {
  const result = {};
  for (const key of keys) {
    if (key in obj)
      result[key] = obj[key];
  }
  return result;
}
function omit(obj, keys) {
  const result = { ...obj };
  for (const key of keys)
    delete result[key];
  return result;
}
function pickBy(obj, pred) {
  const result = {};
  for (const [k, v] of Object.entries(obj)) {
    if (pred(v, k))
      result[k] = v;
  }
  return result;
}
function omitBy(obj, pred) {
  return pickBy(obj, (v, k) => !pred(v, k));
}
function mapValues(obj, fn) {
  const result = {};
  for (const [k, v] of Object.entries(obj))
    result[k] = fn(v, k);
  return result;
}
function mapKeys(obj, fn) {
  const result = {};
  for (const [k, v] of Object.entries(obj))
    result[fn(k, v)] = v;
  return result;
}
function mapEntries(obj, fn) {
  const result = {};
  for (const [k, v] of Object.entries(obj)) {
    const [newK, newV] = fn(k, v);
    result[newK] = newV;
  }
  return result;
}
function filterKeys(obj, pred) {
  return pickBy(obj, (_, k) => pred(k));
}
function filterValues(obj, pred) {
  return pickBy(obj, (v) => pred(v));
}
function defaults(obj, ...sources) {
  const result = { ...obj };
  for (const source of sources) {
    for (const key of Object.keys(source)) {
      if (result[key] === void 0) {
        result[key] = source[key];
      }
    }
  }
  return result;
}
function deepMerge(target, ...sources) {
  const result = { ...target };
  for (const source of sources) {
    for (const [key, value] of Object.entries(source)) {
      if (value !== null && typeof value === "object" && !Array.isArray(value) && result[key] !== null && typeof result[key] === "object" && !Array.isArray(result[key])) {
        result[key] = deepMerge(result[key], value);
      } else {
        result[key] = value;
      }
    }
  }
  return result;
}
function getPath(obj, path) {
  const keys = typeof path === "string" ? path.split(".") : path;
  let current = obj;
  for (const key of keys) {
    if (current == null || typeof current !== "object")
      return void 0;
    current = current[key];
  }
  return current;
}
function getPathOr(obj, path, defaultValue) {
  const result = getPath(obj, path);
  return result === void 0 ? defaultValue : result;
}
function setPath(obj, path, value) {
  const keys = typeof path === "string" ? path.split(".") : [...path];
  if (keys.length === 0)
    return obj;
  const result = { ...obj };
  let current = result;
  for (let i = 0; i < keys.length - 1; i++) {
    const key = keys[i];
    current[key] = current[key] != null && typeof current[key] === "object" ? { ...current[key] } : {};
    current = current[key];
  }
  current[keys[keys.length - 1]] = value;
  return result;
}
function invert(obj) {
  const result = {};
  for (const [k, v] of Object.entries(obj))
    result[v] = k;
  return result;
}
function toPairs(obj) {
  return Object.entries(obj);
}
function fromPairs(pairs) {
  const result = {};
  for (const [k, v] of pairs)
    result[k] = v;
  return result;
}
function toMap2(obj) {
  return new Map(Object.entries(obj));
}
function fromMap(map) {
  const result = {};
  for (const [k, v] of map)
    result[k] = v;
  return result;
}
function deepClone(obj) {
  if (typeof structuredClone !== "undefined")
    return structuredClone(obj);
  return JSON.parse(JSON.stringify(obj));
}
function deepEqual(a, b) {
  if (a === b)
    return true;
  if (a == null || b == null)
    return false;
  if (typeof a !== typeof b)
    return false;
  if (Array.isArray(a) && Array.isArray(b)) {
    if (a.length !== b.length)
      return false;
    return a.every((v, i) => deepEqual(v, b[i]));
  }
  if (typeof a === "object" && typeof b === "object") {
    const keysA = Object.keys(a);
    const keysB = Object.keys(b);
    if (keysA.length !== keysB.length)
      return false;
    return keysA.every((k) => deepEqual(a[k], b[k]));
  }
  return false;
}
function deepFreeze(obj) {
  Object.freeze(obj);
  for (const value of Object.values(obj)) {
    if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
      deepFreeze(value);
    }
  }
  return obj;
}
function diff(a, b) {
  const result = {};
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)]);
  for (const key of allKeys) {
    if (!deepEqual(a[key], b[key])) {
      result[key] = { from: a[key], to: b[key] };
    }
  }
  return result;
}
function isEmpty(obj) {
  return Object.keys(obj).length === 0;
}
function isNotEmpty(obj) {
  return Object.keys(obj).length > 0;
}
function hasKey(obj, key) {
  return Object.prototype.hasOwnProperty.call(obj, key);
}
function size(obj) {
  return Object.keys(obj).length;
}
var ObjectExt = {
  pick,
  omit,
  pickBy,
  omitBy,
  mapValues,
  mapKeys,
  mapEntries,
  filterKeys,
  filterValues,
  defaults,
  deepMerge,
  getPath,
  getPathOr,
  setPath,
  invert,
  toPairs,
  fromPairs,
  toMap: toMap2,
  fromMap,
  deepClone,
  deepEqual,
  deepFreeze,
  diff,
  isEmpty,
  isNotEmpty,
  hasKey,
  size
};

// src/extensions/boolean.ts
function toInt2(b) {
  return b ? 1 : 0;
}
function toSign(b) {
  return b ? 1 : -1;
}
function toString(b) {
  return b ? "true" : "false";
}
function toYesNo(b) {
  return b ? "yes" : "no";
}
function toOnOff(b) {
  return b ? "on" : "off";
}
function thenSome(b, value) {
  return b ? value : void 0;
}
function then(b, fn) {
  return b ? fn() : void 0;
}
function elseSome(b, value) {
  return b ? void 0 : value;
}
function bool(falseVal, trueVal, b) {
  return b ? trueVal : falseVal;
}
function fold(b, onFalse, onTrue) {
  return b ? onTrue() : onFalse();
}
function toggle(b) {
  return !b;
}
function and(a, b) {
  return a && b;
}
function or(a, b) {
  return a || b;
}
function xor(a, b) {
  return a !== b;
}
function nand(a, b) {
  return !(a && b);
}
function nor(a, b) {
  return !(a || b);
}
function implies(a, b) {
  return !a || b;
}
function guard(b, error = "Guard failed") {
  if (!b)
    throw typeof error === "string" ? new Error(error) : error;
}
function expect(b, value, error = "Expected true") {
  if (!b)
    throw new Error(error);
  return value;
}
function compareTo(a, b) {
  if (a === b)
    return 0;
  return a ? 1 : -1;
}
var BooleanExt = {
  toInt: toInt2,
  toSign,
  toString,
  toYesNo,
  toOnOff,
  thenSome,
  then,
  elseSome,
  bool,
  fold,
  toggle,
  and,
  or,
  xor,
  nand,
  nor,
  implies,
  guard,
  expect,
  compareTo
};

// src/extensions/date.ts
function addMilliseconds(date, ms) {
  return new Date(date.getTime() + ms);
}
function addSeconds(date, seconds) {
  return addMilliseconds(date, seconds * 1e3);
}
function addMinutes(date, minutes) {
  return addMilliseconds(date, minutes * 6e4);
}
function addHours(date, hours) {
  return addMilliseconds(date, hours * 36e5);
}
function addDays(date, days) {
  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}
function addWeeks(date, weeks) {
  return addDays(date, weeks * 7);
}
function addMonths(date, months) {
  const result = new Date(date);
  const day = result.getDate();
  result.setMonth(result.getMonth() + months);
  if (result.getDate() !== day)
    result.setDate(0);
  return result;
}
function addYears(date, years) {
  return addMonths(date, years * 12);
}
function diffInMilliseconds(a, b) {
  return a.getTime() - b.getTime();
}
function diffInSeconds(a, b) {
  return diffInMilliseconds(a, b) / 1e3;
}
function diffInMinutes(a, b) {
  return diffInMilliseconds(a, b) / 6e4;
}
function diffInHours(a, b) {
  return diffInMilliseconds(a, b) / 36e5;
}
function diffInDays(a, b) {
  return diffInMilliseconds(a, b) / 864e5;
}
function diffInWeeks(a, b) {
  return diffInDays(a, b) / 7;
}
function diffInMonths(a, b) {
  return (a.getFullYear() - b.getFullYear()) * 12 + (a.getMonth() - b.getMonth());
}
function diffInYears(a, b) {
  return a.getFullYear() - b.getFullYear();
}
function startOfDay(date) {
  const result = new Date(date);
  result.setHours(0, 0, 0, 0);
  return result;
}
function endOfDay(date) {
  const result = new Date(date);
  result.setHours(23, 59, 59, 999);
  return result;
}
function startOfWeek(date, weekStartsOn = 0) {
  const result = new Date(date);
  const day = result.getDay();
  const diff2 = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
  result.setDate(result.getDate() - diff2);
  result.setHours(0, 0, 0, 0);
  return result;
}
function startOfMonth(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1);
}
function endOfMonth(date) {
  return new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59, 999);
}
function startOfYear(date) {
  return new Date(date.getFullYear(), 0, 1);
}
function endOfYear(date) {
  return new Date(date.getFullYear(), 11, 31, 23, 59, 59, 999);
}
function isAfter(date, other) {
  return date.getTime() > other.getTime();
}
function isBefore(date, other) {
  return date.getTime() < other.getTime();
}
function isSameDay(a, b) {
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
}
function isSameMonth(a, b) {
  return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
}
function isSameYear(a, b) {
  return a.getFullYear() === b.getFullYear();
}
function isBetweenDates(date, start, end) {
  const t = date.getTime();
  return t >= start.getTime() && t <= end.getTime();
}
function isToday(date) {
  return isSameDay(date, /* @__PURE__ */ new Date());
}
function isYesterday(date) {
  return isSameDay(date, addDays(/* @__PURE__ */ new Date(), -1));
}
function isTomorrow(date) {
  return isSameDay(date, addDays(/* @__PURE__ */ new Date(), 1));
}
function isWeekend(date) {
  const day = date.getDay();
  return day === 0 || day === 6;
}
function isWeekday(date) {
  return !isWeekend(date);
}
function isLeapYear(date) {
  const year = date.getFullYear();
  return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
}
function formatRelative(date, now = /* @__PURE__ */ new Date()) {
  const diffMs = now.getTime() - date.getTime();
  const absDiff = Math.abs(diffMs);
  const future = diffMs < 0;
  const suffix = future ? "from now" : "ago";
  if (absDiff < 1e3)
    return "just now";
  if (absDiff < 6e4)
    return `${Math.floor(absDiff / 1e3)} seconds ${suffix}`;
  if (absDiff < 36e5)
    return `${Math.floor(absDiff / 6e4)} minutes ${suffix}`;
  if (absDiff < 864e5)
    return `${Math.floor(absDiff / 36e5)} hours ${suffix}`;
  if (absDiff < 2592e6)
    return `${Math.floor(absDiff / 864e5)} days ${suffix}`;
  if (absDiff < 31536e6)
    return `${Math.floor(absDiff / 2592e6)} months ${suffix}`;
  return `${Math.floor(absDiff / 31536e6)} years ${suffix}`;
}
function formatISO(date) {
  return date.toISOString();
}
function formatDate(date) {
  return date.toISOString().split("T")[0];
}
function formatTime(date) {
  return date.toTimeString().split(" ")[0];
}
function formatDateTime(date) {
  return `${formatDate(date)} ${formatTime(date)}`;
}
function dayOfYear(date) {
  const start = startOfYear(date);
  return Math.floor(diffInDays(date, start)) + 1;
}
function weekOfYear(date) {
  const start = startOfYear(date);
  return Math.ceil((diffInDays(date, start) + start.getDay() + 1) / 7);
}
function daysInMonth(date) {
  return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
}
function daysInYear(date) {
  return isLeapYear(date) ? 366 : 365;
}
function quarter(date) {
  return Math.floor(date.getMonth() / 3) + 1;
}
function clampDate(date, min, max) {
  const t = date.getTime();
  if (t < min.getTime())
    return new Date(min);
  if (t > max.getTime())
    return new Date(max);
  return new Date(date);
}
function minDate(...dates) {
  return new Date(Math.min(...dates.map((d) => d.getTime())));
}
function maxDate(...dates) {
  return new Date(Math.max(...dates.map((d) => d.getTime())));
}
function eachDay(start, end) {
  const result = [];
  let current = startOfDay(start);
  const last2 = startOfDay(end);
  while (current <= last2) {
    result.push(new Date(current));
    current = addDays(current, 1);
  }
  return result;
}
var DateExt = {
  addMilliseconds,
  addSeconds,
  addMinutes,
  addHours,
  addDays,
  addWeeks,
  addMonths,
  addYears,
  diffInMilliseconds,
  diffInSeconds,
  diffInMinutes,
  diffInHours,
  diffInDays,
  diffInWeeks,
  diffInMonths,
  diffInYears,
  startOfDay,
  endOfDay,
  startOfWeek,
  startOfMonth,
  endOfMonth,
  startOfYear,
  endOfYear,
  isAfter,
  isBefore,
  isSameDay,
  isSameMonth,
  isSameYear,
  isBetween: isBetweenDates,
  isToday,
  isYesterday,
  isTomorrow,
  isWeekend,
  isWeekday,
  isLeapYear,
  formatRelative,
  formatISO,
  formatDate,
  formatTime,
  formatDateTime,
  dayOfYear,
  weekOfYear,
  daysInMonth,
  daysInYear,
  quarter,
  clamp: clampDate,
  min: minDate,
  max: maxDate,
  eachDay
};

// src/extensions/map.ts
function getOrDefault(map, key, defaultValue) {
  return map.has(key) ? map.get(key) : defaultValue;
}
function getOrPut(map, key, factory) {
  if (map.has(key))
    return map.get(key);
  const value = factory();
  map.set(key, value);
  return value;
}
function mapMapValues(map, fn) {
  const result = /* @__PURE__ */ new Map();
  for (const [k, v] of map)
    result.set(k, fn(v, k));
  return result;
}
function mapMapKeys(map, fn) {
  const result = /* @__PURE__ */ new Map();
  for (const [k, v] of map)
    result.set(fn(k, v), v);
  return result;
}
function filterMap(map, pred) {
  const result = /* @__PURE__ */ new Map();
  for (const [k, v] of map) {
    if (pred(v, k))
      result.set(k, v);
  }
  return result;
}
function filterMapKeys(map, pred) {
  return filterMap(map, (_, k) => pred(k));
}
function filterMapValues(map, pred) {
  return filterMap(map, (v) => pred(v));
}
function mergeMap(a, b, resolve) {
  const result = new Map(a);
  for (const [k, v] of b) {
    if (result.has(k) && resolve) {
      result.set(k, resolve(result.get(k), v, k));
    } else {
      result.set(k, v);
    }
  }
  return result;
}
function mapUnion(a, b) {
  return mergeMap(a, b);
}
function mapIntersection(a, b) {
  const result = /* @__PURE__ */ new Map();
  for (const [k, v] of a) {
    if (b.has(k))
      result.set(k, v);
  }
  return result;
}
function mapDifference(a, b) {
  const result = /* @__PURE__ */ new Map();
  for (const [k, v] of a) {
    if (!b.has(k))
      result.set(k, v);
  }
  return result;
}
function invertMap(map) {
  const result = /* @__PURE__ */ new Map();
  for (const [k, v] of map)
    result.set(v, k);
  return result;
}
function groupMapBy(map, fn) {
  const result = /* @__PURE__ */ new Map();
  for (const [k, v] of map) {
    const group = fn(v, k);
    if (!result.has(group))
      result.set(group, /* @__PURE__ */ new Map());
    result.get(group).set(k, v);
  }
  return result;
}
function mapToObject(map) {
  const result = {};
  for (const [k, v] of map)
    result[k] = v;
  return result;
}
function mapToPairs(map) {
  return [...map.entries()];
}
function mapFromPairs(pairs) {
  return new Map(pairs);
}
function mapFold(map, init2, fn) {
  let acc = init2;
  for (const [k, v] of map)
    acc = fn(acc, v, k);
  return acc;
}
function setUnion(a, b) {
  return /* @__PURE__ */ new Set([...a, ...b]);
}
function setIntersection(a, b) {
  const result = /* @__PURE__ */ new Set();
  for (const x of a) {
    if (b.has(x))
      result.add(x);
  }
  return result;
}
function setDifference(a, b) {
  const result = /* @__PURE__ */ new Set();
  for (const x of a) {
    if (!b.has(x))
      result.add(x);
  }
  return result;
}
function setSymmetricDifference(a, b) {
  const result = /* @__PURE__ */ new Set();
  for (const x of a)
    if (!b.has(x))
      result.add(x);
  for (const x of b)
    if (!a.has(x))
      result.add(x);
  return result;
}
function isSubset(a, b) {
  for (const x of a)
    if (!b.has(x))
      return false;
  return true;
}
function isSuperset(a, b) {
  return isSubset(b, a);
}
function isDisjoint(a, b) {
  for (const x of a)
    if (b.has(x))
      return false;
  return true;
}
function setMap(set, fn) {
  const result = /* @__PURE__ */ new Set();
  for (const x of set)
    result.add(fn(x));
  return result;
}
function setFilter(set, pred) {
  const result = /* @__PURE__ */ new Set();
  for (const x of set)
    if (pred(x))
      result.add(x);
  return result;
}
function setPartition(set, pred) {
  const yes = /* @__PURE__ */ new Set();
  const no = /* @__PURE__ */ new Set();
  for (const x of set)
    (pred(x) ? yes : no).add(x);
  return [yes, no];
}
function setToArray(set) {
  return [...set];
}
function powerSet(set) {
  const arr = [...set];
  const result = /* @__PURE__ */ new Set();
  const total = 1 << arr.length;
  for (let mask2 = 0; mask2 < total; mask2++) {
    const subset = /* @__PURE__ */ new Set();
    for (let i = 0; i < arr.length; i++) {
      if (mask2 & 1 << i)
        subset.add(arr[i]);
    }
    result.add(subset);
  }
  return result;
}
var MapExt = {
  getOrDefault,
  getOrPut,
  mapValues: mapMapValues,
  mapKeys: mapMapKeys,
  filter: filterMap,
  filterKeys: filterMapKeys,
  filterValues: filterMapValues,
  merge: mergeMap,
  union: mapUnion,
  intersection: mapIntersection,
  difference: mapDifference,
  invert: invertMap,
  groupBy: groupMapBy,
  toObject: mapToObject,
  toPairs: mapToPairs,
  fromPairs: mapFromPairs,
  fold: mapFold
};
var SetExt = {
  union: setUnion,
  intersection: setIntersection,
  difference: setDifference,
  symmetricDifference: setSymmetricDifference,
  isSubset,
  isSuperset,
  isDisjoint,
  map: setMap,
  filter: setFilter,
  partition: setPartition,
  toArray: setToArray,
  powerSet
};

// src/extensions/promise.ts
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
function timeout(promise, ms, message) {
  return Promise.race([
    promise,
    delay(ms).then(() => {
      throw new Error(message ?? `Promise timed out after ${ms}ms`);
    })
  ]);
}
function timeoutOr(promise, ms, fallback) {
  return Promise.race([promise, delay(ms).then(() => fallback)]);
}
async function retry(fn, options) {
  const { retries, delay: baseDelay = 0, backoff = "linear", maxDelay = 3e4, onRetry, shouldRetry } = options;
  let lastError;
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      return await fn(attempt);
    } catch (err) {
      lastError = err instanceof Error ? err : new Error(String(err));
      if (shouldRetry && !shouldRetry(lastError))
        throw lastError;
      if (attempt < retries) {
        onRetry?.(lastError, attempt + 1);
        if (baseDelay > 0) {
          const d = backoff === "exponential" ? Math.min(baseDelay * 2 ** attempt, maxDelay) : Math.min(baseDelay * (attempt + 1), maxDelay);
          await delay(d);
        }
      }
    }
  }
  throw lastError;
}
async function tap(promise, fn) {
  const value = await promise;
  await fn(value);
  return value;
}
async function tapError(promise, fn) {
  try {
    return await promise;
  } catch (err) {
    await fn(err instanceof Error ? err : new Error(String(err)));
    throw err;
  }
}
async function recover(promise, fn) {
  try {
    return await promise;
  } catch (err) {
    return fn(err instanceof Error ? err : new Error(String(err)));
  }
}
async function fallbackTo(promise, fallback) {
  try {
    return await promise;
  } catch {
    return fallback;
  }
}
async function mapConcurrent(items, fn, concurrency = Infinity) {
  if (concurrency === Infinity) {
    return Promise.all(items.map(fn));
  }
  const results = new Array(items.length);
  let nextIndex = 0;
  async function worker() {
    while (nextIndex < items.length) {
      const i = nextIndex++;
      results[i] = await fn(items[i], i);
    }
  }
  const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => worker());
  await Promise.all(workers);
  return results;
}
async function filterConcurrent(items, pred, concurrency = Infinity) {
  const results = await mapConcurrent(items, pred, concurrency);
  return items.filter((_, i) => results[i]);
}
async function settle(promises) {
  return Promise.all(promises.map((p) => p.then((value) => ({ status: "fulfilled", value })).catch((reason) => ({
    status: "rejected",
    reason: reason instanceof Error ? reason : new Error(String(reason))
  }))));
}
async function allFulfilled(promises) {
  const results = await settle(promises);
  return results.filter((r) => r.status === "fulfilled").map((r) => r.value);
}
async function props(obj) {
  const keys = Object.keys(obj);
  const values = await Promise.all(keys.map((k) => obj[k]));
  const result = {};
  keys.forEach((k, i) => {
    result[k] = values[i];
  });
  return result;
}
function createDeferred() {
  let resolve;
  let reject;
  const promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });
  return { promise, resolve, reject };
}
async function sleep(ms) {
  return delay(ms);
}
function lazy(fn) {
  let cached;
  return () => {
    if (!cached)
      cached = fn();
    return cached;
  };
}
function memo(fn) {
  const cache = /* @__PURE__ */ new Map();
  return (arg) => {
    if (!cache.has(arg))
      cache.set(arg, fn(arg));
    return cache.get(arg);
  };
}
var PromiseExt = {
  delay,
  timeout,
  timeoutOr,
  retry,
  tap,
  tapError,
  recover,
  fallbackTo,
  mapConcurrent,
  filterConcurrent,
  settle,
  allFulfilled,
  props,
  createDeferred,
  sleep,
  lazy,
  memo
};

// src/extensions/function.ts
function identity(a) {
  return a;
}
function constant(a) {
  return () => a;
}
function flip(fn) {
  return (b, a) => fn(a, b);
}
function negate(fn) {
  return (...args) => !fn(...args);
}
function complement(fn) {
  return negate(fn);
}
function noop() {
}
function absurd(_) {
  throw new Error("absurd: this should never be called");
}
function curry2(fn) {
  return (a) => (b) => fn(a, b);
}
function curry3(fn) {
  return (a) => (b) => (c) => fn(a, b, c);
}
function uncurry2(fn) {
  return (a, b) => fn(a)(b);
}
function uncurry3(fn) {
  return (a, b, c) => fn(a)(b)(c);
}
function partial(fn, a) {
  return (...rest) => fn(a, ...rest);
}
function partial2(fn, a, b) {
  return (...rest) => fn(a, b, ...rest);
}
function tupled(fn) {
  return ([a, b]) => fn(a, b);
}
function tupled3(fn) {
  return ([a, b, c]) => fn(a, b, c);
}
function untupled(fn) {
  return (a, b) => fn([a, b]);
}
function debounce(fn, ms) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), ms);
  };
}
function throttle(fn, ms) {
  let last2 = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last2 >= ms) {
      last2 = now;
      fn(...args);
    }
  };
}
function memoize(fn, keyFn) {
  const cache = /* @__PURE__ */ new Map();
  return (...args) => {
    const key = keyFn ? keyFn(...args) : JSON.stringify(args);
    if (cache.has(key))
      return cache.get(key);
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
}
function memoizeWeak(fn) {
  const cache = /* @__PURE__ */ new WeakMap();
  return (a) => {
    if (cache.has(a))
      return cache.get(a);
    const result = fn(a);
    cache.set(a, result);
    return result;
  };
}
function once(fn) {
  let called = false;
  let result;
  return (...args) => {
    if (!called) {
      called = true;
      result = fn(...args);
    }
    return result;
  };
}
function after(n, fn) {
  let count2 = 0;
  return (...args) => {
    count2++;
    if (count2 >= n)
      return fn(...args);
    return void 0;
  };
}
function before(n, fn) {
  let count2 = 0;
  let lastResult;
  return (...args) => {
    count2++;
    if (count2 < n) {
      lastResult = fn(...args);
      return lastResult;
    }
    return lastResult;
  };
}
function tryCatch(fn, onError) {
  return (...args) => {
    try {
      return fn(...args);
    } catch (err) {
      return onError(err instanceof Error ? err : new Error(String(err)), ...args);
    }
  };
}
function juxt(...fns) {
  return (...args) => fns.map((fn) => fn(...args));
}
function converge(after2, ...branches) {
  return (...args) => {
    const results = branches.map((fn) => fn(...args));
    return after2(...results);
  };
}
function on(fn, transform) {
  return (a1, a2) => fn(transform(a1), transform(a2));
}
var FunctionExt = {
  identity,
  constant,
  flip,
  negate,
  complement,
  noop,
  absurd,
  curry2,
  curry3,
  uncurry2,
  uncurry3,
  partial,
  partial2,
  tupled,
  tupled3,
  untupled,
  debounce,
  throttle,
  memoize,
  memoizeWeak,
  once,
  after,
  before,
  tryCatch,
  juxt,
  converge,
  on
};

export {
  clamp,
  lerp,
  inverseLerp,
  remap,
  roundTo,
  ceilTo,
  floorTo,
  truncTo,
  snap,
  isEven,
  isOdd,
  isPositive,
  isNegative,
  isZero,
  isInteger,
  isFiniteNum,
  isNaN_,
  isBetween,
  isMultipleOf,
  isPrime,
  isPerfectSquare,
  isPowerOfTwo,
  gcd,
  lcm,
  factorial,
  fibonacci,
  nCr,
  nPr,
  isqrt,
  digits,
  digitSum,
  divisors,
  toBin,
  toOct,
  toHex,
  toBase,
  toOrdinal,
  toWords,
  toRoman,
  padStart,
  toPercent,
  toFileSize,
  toDuration,
  toCompact,
  times,
  timesVoid,
  upTo,
  downTo,
  rangeTo,
  rangeUntil,
  saturatingAdd,
  saturatingSub,
  wrappingAdd,
  wrappingSub,
  randomInt,
  randomFloat,
  NumberExt,
  capitalize,
  camelCase,
  pascalCase,
  snakeCase,
  kebabCase,
  words,
  truncate,
  isBlank,
  toInt,
  StringExt,
  takeWhile,
  dropWhile,
  groupBy,
  chunk,
  partition,
  zip,
  zipWith,
  unique,
  uniqueBy,
  sortBy,
  intersperse,
  compact,
  flatten,
  shuffle,
  toMap,
  ArrayExt,
  pick,
  omit,
  mapValues,
  mapKeys,
  defaults,
  deepMerge,
  invert,
  toMap2,
  ObjectExt,
  toInt2,
  BooleanExt,
  addMilliseconds,
  addSeconds,
  addMinutes,
  addHours,
  addDays,
  addWeeks,
  addMonths,
  addYears,
  diffInMilliseconds,
  diffInSeconds,
  diffInMinutes,
  diffInHours,
  diffInDays,
  diffInWeeks,
  diffInMonths,
  diffInYears,
  startOfDay,
  endOfDay,
  startOfWeek,
  startOfMonth,
  endOfMonth,
  startOfYear,
  endOfYear,
  isAfter,
  isBefore,
  isSameDay,
  isSameMonth,
  isSameYear,
  isBetweenDates,
  isToday,
  isYesterday,
  isTomorrow,
  isWeekend,
  isWeekday,
  isLeapYear,
  formatRelative,
  formatISO,
  formatDate,
  formatTime,
  formatDateTime,
  dayOfYear,
  weekOfYear,
  daysInMonth,
  daysInYear,
  quarter,
  clampDate,
  minDate,
  maxDate,
  eachDay,
  DateExt,
  filterMapKeys,
  filterMapValues,
  setUnion,
  setIntersection,
  setDifference,
  MapExt,
  SetExt,
  delay,
  timeout,
  timeoutOr,
  retry,
  tap,
  tapError,
  recover,
  fallbackTo,
  mapConcurrent,
  filterConcurrent,
  settle,
  allFulfilled,
  props,
  createDeferred,
  sleep,
  lazy,
  memo,
  PromiseExt,
  identity,
  constant,
  flip,
  negate,
  complement,
  noop,
  absurd,
  curry2,
  curry3,
  uncurry2,
  uncurry3,
  partial,
  partial2,
  tupled,
  tupled3,
  untupled,
  debounce,
  throttle,
  memoize,
  memoizeWeak,
  once,
  after,
  before,
  tryCatch,
  juxt,
  converge,
  on,
  FunctionExt
};
//# sourceMappingURL=chunk-4ILFFER5.js.map