 false, isPendingDeprecation,
  );
  function deprecated(...args) {
    emitDeprecationWarning();
    return ReflectApply(fn, this, args);
  }
  return deprecated;
}

// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
function deprecate(fn, msg, code, useEmitSync) {
  // Lazy-load to avoid a circular dependency.
  if (validateString === undefined)
    ({ validateString } = require('internal/validators'));

  if (code !== undefined)
    validateString(code, 'code');

  const emitDeprecationWarning = getDeprecationWarningEmitter(
    code, msg, deprecated, useEmitSync,
  );

  function deprecated(...args) {
    // TODO(joyeecheung): use getOptionValue('--no-deprecation') instead.
    if (!process.noDeprecation) {
      emitDeprecationWarning();
    }
    if (new.target) {
      return ReflectConstruct(fn, args, new.target);
    }
    return ReflectApply(fn, this, args);
  }

  // The wrapper will keep the same prototype as fn to maintain prototype chain
  ObjectSetPrototypeOf(deprecated, fn);
  if (fn.prototype) {
    // Setting this (rather than using Object.setPrototype, as above) ensures
    // that calling the unwrapped constructor gives an instanceof the wrapped
    // constructor.
    deprecated.prototype = fn.prototype;
  }

  return deprecated;
}

function decorateErrorStack(err) {
  if (!(isError(err) && err.stack) || err[decorated_private_symbol])
    return;

  const arrow = err[arrow_message_private_symbol];

  if (arrow) {
    err.stack = arrow + err.stack;
    err[decorated_private_symbol] = true;
  }
}

function assertCrypto() {
  if (noCrypto)
    throw new ERR_NO_CRYPTO();
}

function assertTypeScript() {
  if (noTypeScript)
    throw new ERR_NO_TYPESCRIPT();
}

/**
 * Move the "slow cases" to a separate function to make sure this function gets
 * inlined properly. That prioritizes the common case.
 * @param {unknown} enc
 * @returns {string | undefined} Returns undefined if there is no match.
 */
function normalizeEncoding(enc) {
  if (enc == null || enc === 'utf8' || enc === 'utf-8') return 'utf8';
  return slowCases(enc);
}

function slowCases(enc) {
  switch (enc.length) {
    case 4:
      if (enc === 'UTF8') return 'utf8';
      if (enc === 'ucs2' || enc === 'UCS2') return 'utf16le';
      enc = StringPrototypeToLowerCase(enc);
      if (enc === 'utf8') return 'utf8';
      if (enc === 'ucs2') return 'utf16le';
      break;
    case 3:
      if (enc === 'hex' || enc === 'HEX' ||
      StringPrototypeToLowerCase(enc) === 'hex')
        return 'hex';
      break;
    case 5:
      if (enc === 'ascii') return 'ascii';
      if (enc === 'ucs-2') return 'utf16le';
      if (enc === 'UTF-8') return 'utf8';
      if (enc === 'ASCII') return 'ascii';
      if (enc === 'UCS-2') return 'utf16le';
      enc = StringPrototypeToLowerCase(enc);
      if (enc === 'utf-8') return 'utf8';
      if (enc === 'ascii') return 'ascii';
      if (enc === 'ucs-2') return 'utf16le';
      break;
    case 6:
      if (enc === 'base64') return 'base64';
      if (enc === 'latin1' || enc === 'binary') return 'latin1';
      if (enc === 'BASE64') return 'base64';
      if (enc === 'LATIN1' || enc === 'BINARY') return 'latin1';
      enc = StringPrototypeToLowerCase(enc);
      if (enc === 'base64') return 'base64';
      if (enc === 'latin1' || enc === 'binary') return 'latin1';
      break;
    case 7:
      if (enc === 'utf16le' || enc === 'UTF16LE' ||
      StringPrototypeToLowerCase(enc) === 'utf16le')
        return 'utf16le';
      break;
    case 8:
      if (enc === 'utf-16le' || enc === 'UTF-16LE' ||
      StringPrototypeToLowerCase(enc) === 'utf-16le')
        return 'utf16le';
      break;
    case 9:
      if (enc === 'base64url' || enc === 'BASE64URL' ||
      StringPrototypeToLowerCase(enc) === 'base64url')
        return 'base64url';
      break;
    default:
      if (enc === '') return 'utf8';
  }
}

/**
 * @param {string} feature Feature name used in the warning message
 * @param {string} messagePrefix Prefix of the warning message
 * @param {string} code See documentation of process.emitWarning
 * @param {string} ctor See documentation of process.emitWarning
 */
function emitExperimentalWarning(feature, messagePrefix, code, ctor) {
  if (experimentalWarnings.has(feature)) return;
  experimentalWarnings.add(feature);
  let msg = `${feature} is an experimental feature and might change at any time`;
  if (messagePrefix) {
    msg = messagePrefix + msg;
  }
  process.emitWarning(msg, 'ExperimentalWarning', code, ctor);
}

function filterDuplicateStrings(items, low) {
  const map = new SafeMap();
  for (let i = 0; i < items.length; i++) {
    const item = items[i];
    const key = StringPrototypeToLowerCase(item);
    if (low) {
      map.set(key, key);
    } else {
      map.set(key, item);
    }
  }
  return ArrayPrototypeSort(ArrayFrom(map.values()));
}

function cachedResult(fn) {
  let result;
  return () => {
    if (result === undefined)
      result = fn();
    return ArrayPrototypeSlice(result);
  };
}

// Useful for Wrapping an ES6 Class with a constructor Function that
// does not require the new keyword. For instance:
//   class A { constructor(x) {this.x = x;}}
//   const B = createClassWrapper(A);
//   B() instanceof A // true
//   B() instanceof B // true
function createClassWrapper(type) {
  function fn(...args) {
    return ReflectConstruct(type, args, new.target || type);
  }
  // Mask the wrapper function name and length values
  ObjectDefineProperties(fn, {
    name: { __proto__: null, value: type.name },
    length: { __proto__: null, value: type.length },
  });
  ObjectSetPrototypeOf(fn, type);
  fn.prototype = type.prototype;
  return fn;
}

let signalsToNamesMapping;
function getSignalsToNamesMapping() {
  if (signalsToNamesMapping !== undefined)
    return signalsToNamesMapping;

  signalsToNamesMapping = { __proto__: null };
  for (const key in signals) {
    signalsToNamesMapping[signals[key]] = key;
  }

  return signalsToNamesMapping;
}

function convertToValidSignal(signal) {
  if (typeof signal === 'number' && getSignalsToNamesMapping()[signal])
    return signal;

  if (typeof signal === 'string') {
    const signalName = signals[StringPrototypeToUpperCase(signal)];
    if (signalName) return signalName;
  }

  throw new ERR_UNKNOWN_SIGNAL(signal);
}

function getConstructorOf(obj) {
  while (obj) {
    const descriptor = ObjectGetOwnPropertyDescriptor(obj, 'constructor');
    if (descriptor !== undefined &&
        typeof descriptor.value === 'function' &&
        descriptor.value.name !== '') {
      return descriptor.value;
    }

    obj = ObjectGetPrototypeOf(obj);
  }

  return null;
}

let cachedURL;
let cachedCWD;

/**
 * Get the current working directory while accounting for the possibility that it has been deleted.
 * `process.cwd()` can fail if the parent directory is deleted while the process runs.
 * @returns {URL} The current working directory or the volume root if it cannot be determined.
 */
function getCWDURL() {
  const { sep } = require('path');
  const { pathToFileURL } = require('internal/url');

  let cwd;

  try {
    // The implementation of `process.cwd()` already uses proper cache when it can.
    // It's a relatively cheap call performance-wise for the most common use case.
    cwd = process.cwd();
  } catch {
    cachedURL ??= pathToFileURL(sep);
  }

  if (cwd != null && cwd !== cachedCWD) {
    cachedURL = pathToFileURL(cwd + sep);
    cachedCWD = cwd;
  }

  return cachedURL;
}

function getSystemErrorMessage(err) {
  return lazyUv().getErrorMessage(err);
}

function getSystemErrorName(err) {
  const entry = uvErrmapGet(err);
  return entry ? entry[0] : `Unknown system error ${err}`;
}

function getSystemErrorMap() {
  return lazyUv().getErrorMap();
}

const kCustomPromisifiedSymbol = SymbolFor('nodejs.util.promisify.custom');
const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs');

let validateFunction;

function promisify(original) {
  // Lazy-load to avoid a circular dependency.
  if (validateFunction === undefined)
    ({ validateFunction } = require('internal/validators'));

  validateFunction(original, 'original');

  if (original[kCustomPromisifiedSymbol]) {
    const fn = original[kCustomPromisifiedSymbol];

    validateFunction(fn, 'util.promisify.custom');

    return ObjectDefineProperty(fn, kCustomPromisifiedSymbol, {
      __proto__: null,
      value: fn, enumerable: false, writable: false, configurable: true,
    });
  }

  // Names to create an object from in case the callback receives multiple
  // arguments, e.g. ['bytesRead', 'buffer'] for fs.read.
  const argumentNames = original[kCustomPromisifyArgsSymbol];

  function fn(...args) {
    return new Promise((resolve, reject) => {
      ArrayPrototypePush(args, (err, ...values) => {
        if (err) {
          return reject(err);
        }
        if (argumentNames !== undefined && values.length > 1) {
          const obj = {};
          for (let i = 0; i < argumentNames.length; i++)
            obj[argumentNames[i]] = values[i];
          resolve(obj);
        } else {
          resolve(values[0]);
        }
      });
      if (isPromise(ReflectApply(original, this, args))) {
        process.emitWarning('Calling promisify on a function that returns a Promise is likely a mistake.',
                            'DeprecationWarning', 'DEP0174');
      }
    });
  }

  ObjectSetPrototypeOf(fn, ObjectGetPrototypeOf(original));

  ObjectDefineProperty(fn, kCustomPromisifiedSymbol, {
    __proto__: null,
    value: fn, enumerable: false, writable: false, configurable: true,
  });

  const descriptors = ObjectGetOwnPropertyDescriptors(original);
  const propertiesValues = ObjectValues(descriptors);
  for (let i = 0; i < propertiesValues.length; i++) {
    // We want to use null-prototype objects to not rely on globally mutable
    // %Object.prototype%.
    ObjectSetPrototypeOf(propertiesValues[i], null);
  }
  return ObjectDefineProperties(fn, descriptors);
}

promisify.custom = kCustomPromisifiedSymbol;

// The built-in Array#join is slower in v8 6.0
function join(output, separator) {
  let str = '';
  if (output.length !== 0) {
    const lastIndex = output.length - 1;
    for (let i = 0; i < lastIndex; i++) {
      // It is faster not to use a template string here
      str += output[i];
      str += separator;
    }
    str += output[lastIndex];
  }
  return str;
}

// As of V8 6.6, depending on the size of the array, this is anywhere
// between 1.5-10x faster than the two-arg version of Array#splice()
function spliceOne(list, index) {
  for (; index + 1 < list.length; index++)
    list[index] = list[index + 1];
  list.pop();
}

const kNodeModulesRE = /^(?:.*)[\\/]node_modules[\\/]/;

function isUnderNodeModules(filename) {
  return filename && (RegExpPrototypeExec(kNodeModulesRE, filename) !== null);
}

let getStructuredStackImpl;

function lazyGetStructuredStack() {
  if (getStructuredStackImpl === undefined) {
    // Lazy-load to avoid a circular dependency.
    const { runInNewContext } = require('vm');
    // Use `runInNewContext()` to get something tamper-proof and
    // side-effect-free. Since this is currently only used for a deprecated API
    // and module mocking, the perf implications should be okay.
    getStructuredStackImpl = runInNewContext(`(function() {
      try { Error.stackTraceLimit = Infinity; } catch {}
      return function structuredStack() {
        const e = new Error();
        overrideStackTrace.set(e, (err, trace) => trace);
        return e.stack;
      };
    })()`, { overrideStackTrace }, { filename: 'structured-stack' });
  }

  return getStructuredStackImpl;
}

function getStructuredStack() {
  const getStructuredStackImpl = lazyGetStructuredStack();

  return getStructuredStackImpl();
}

function once(callback, { preserveReturnValue = false } = kEmptyObject) {
  let called = false;
  let returnValue;
  return function(...args) {
    if (called) return returnValue;
    called = true;
    const result = ReflectApply(callback, this, args);
    returnValue = preserveReturnValue ? result : undefined;
    return result;
  };
}

let validateUint32;

function sleep(msec) {
  // Lazy-load to avoid a circular dependency.
  if (validateUint32 === undefined)
    ({ validateUint32 } = require('internal/validators'));

  validateUint32(msec, 'msec');
  _sleep(msec);
}

// https://heycam.github.io/webidl/#define-the-operations
function defineOperation(target, name, method) {
  ObjectDefineProperty(target, name, {
    __proto__: null,
    writable: true,
    enumerable: true,
    configurable: true,
    value: method,
  });
}

// https://heycam.github.io/webidl/#es-interfaces
function exposeInterface(target, name, interfaceObject) {
  ObjectDefineProperty(target, name, {
    __proto__: null,
    writable: true,
    enumerable: false,
    configurable: true,
    value: interfaceObject,
  });
}

// https://heycam.github.io/webidl/#es-namespaces
function exposeNamespace(target, name, namespaceObject) {
  ObjectDefineProperty(target, name, {
    __proto__: null,
    writable: true,
    enumerable: false,
    configurable: true,
    value: namespaceObject,
  });
}

function exposeGetterAndSetter(target, name, getter, setter = undefined) {
  ObjectDefineProperty(target, name, {
    __proto__: null,
    enumerable: false,
    configurable: true,
    get: getter,
    set: setter,
  });
}

function defineReplaceableLazyAttribute(target, id, keys, writable = true, check) {
  let mod;
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i];
    let value;
    let setterCalled = false;

    function get() {
      if (check !== undefined) {
        FunctionPrototypeCall(check, this);
      }
      if (setterCalled) {
        return value;
      }
      mod ??= require(id);
      value ??= mod[key];
      return value;
    }

    ObjectDefineProperty(get, 'name', {
      __proto__: null,
      value: `get ${key}`,
    });

    function set(val) {
      setterCalled = true;
      value = val;
    }
    ObjectDefineProperty(set, 'name', {
      __proto__: null,
      value: `set ${key}`,
    });

    ObjectDefineProperty(target, key, {
      __proto__: null,
      enumerable: true,
      configurable: true,
      get,
      set: writable ? set : undefined,
    });
  }
}

function exposeLazyInterfaces(target, id, keys) {
  defineLazyProperties(target, id, keys, false);
}

let _DOMException;
const lazyDOMExceptionClass = () => {
  _DOMException ??= internalBinding('messaging').DOMException;
  return _DOMException;
};

const lazyDOMException = (message, name) => {
  _DOMException ??= internalBinding('messaging').DOMException;
  if (isErrorStackTraceLimitWritable()) {
    const limit = Error.stackTraceLimit;
    Error.stackTraceLimit = 0;
    const ex = new _DOMException(message, name);
    Error.stackTraceLimit = limit;
    ErrorCaptureStackTrace(ex, lazyDOMException);
    return ex;
  }
  return new _DOMException(message, name);

};

const kEnumerableProperty = { __proto__: null };
kEnumerableProperty.enumerable = true;
ObjectFreeze(kEnumerableProperty);

const kEmptyObject = ObjectFreeze({ __proto__: null });

function filterOwnProperties(source, keys) {
  const filtered = { __proto__: null };
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i];
    if (ObjectPrototypeHasOwnProperty(source, key)) {
      filtered[key] = source[key];
    }
  }

  return filtered;
}

/**
 * Mimics `obj[key] = value` but ignoring potential prototype inheritance.
 * @param {any} obj
 * @param {string} key
 * @param {any} value
 * @returns {any}
 */
function setOwnProperty(obj, key, value) {
  return ObjectDefineProperty(obj, key, {
    __proto__: null,
    configurable: true,
    enumerable: true,
    value,
    writable: true,
  });
}

let internalGlobal;
function getInternalGlobal() {
  if (internalGlobal == null) {
    // Lazy-load to avoid a circular dependency.
    const { runInNewContext } = require('vm');
    internalGlobal = runInNewContext('this', undefined, { contextName: 'internal' });
  }
  return internalGlobal;
}

function SideEffectFreeRegExpPrototypeExec(regex, string) {
  const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal();
  return FunctionPrototypeCall(RegExpFromAnotherRealm.prototype.exec, regex, string);
}

const crossRealmRegexes = new SafeWeakMap();
function getCrossRealmRegex(regex) {
  const cached = crossRealmRegexes.get(regex);
  if (cached) return cached;

  let flagString = '';
  if (RegExpPrototypeGetHasIndices(regex)) flagString += 'd';
  if (RegExpPrototypeGetGlobal(regex)) flagString += 'g';
  if (RegExpPrototypeGetIgnoreCase(regex)) flagString += 'i';
  if (RegExpPrototypeGetMultiline(regex)) flagString += 'm';
  if (RegExpPrototypeGetDotAll(regex)) flagString += 's';
  if (RegExpPrototypeGetUnicode(regex)) flagString += 'u';
  if (RegExpPrototypeGetSticky(regex)) flagString += 'y';

  const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal();
  const crossRealmRegex = new RegExpFromAnotherRealm(RegExpPrototypeGetSource(regex), flagString);
  crossRealmRegexes.set(regex, crossRealmRegex);
  return crossRealmRegex;
}

function SideEffectFreeRegExpPrototypeSymbolReplace(regex, string, replacement) {
  return getCrossRealmRegex(regex)[SymbolReplace](string, replacement);
}

function SideEffectFreeRegExpPrototypeSymbolSplit(regex, string, limit = undefined) {
  return getCrossRealmRegex(regex)[SymbolSplit](string, limit);
}

/**
 * Helper function to lazy-load an initialize-once value.
 * @template T Return value of initializer
 * @param {()=>T} initializer Initializer of the lazily loaded value.
 * @returns {()=>T}
 */
function getLazy(initializer) {
  let value;
  let initialized = false;
  return function() {
    if (initialized === false) {
      value = initializer();
      initialized = true;
    }
    return value;
  };
}

// Setup user-facing NODE_V8_COVERAGE environment variable that writes
// ScriptCoverage objects to a specified directory.
function setupCoverageHooks(dir) {
  const cwd = require('internal/process/execution').tryGetCwd();
  const { resolve } = require('path');
  const coverageDirectory = resolve(cwd, dir);
  const { sourceMapCacheToObject } =
    require('internal/source_map/source_map_cache');

  if (process.features.inspector) {
    internalBinding('profiler').setCoverageDirectory(coverageDirectory);
    internalBinding('profiler').setSourceMapCacheGetter(sourceMapCacheToObject);
  } else {
    process.emitWarning('The inspector is disabled, ' +
                        'coverage could not be collected',
                        'Warning');
    return '';
  }
  return coverageDirectory;
}


const handleTypes = ['TCP', 'TTY', 'UDP', 'FILE', 'PIPE', 'UNKNOWN'];
function guessHandleType(fd) {
  const type = _guessHandleType(fd);
  return handleTypes[type];
}

class WeakReference {
  #weak = null;
  // eslint-disable-next-line no-unused-private-class-members
  #strong = null;
  #refCount = 0;
  constructor(object) {
    this.#weak = new SafeWeakRef(object);
  }

  incRef() {
    this.#refCount++;
    if (this.#refCount === 1) {
      const derefed = this.#weak.deref();
      if (derefed !== undefined) {
        this.#strong = derefed;
      }
    }
    return this.#refCount;
  }

  decRef() {
    this.#refCount--;
    if (this.#refCount === 0) {
      this.#strong = null;
    }
    return this.#refCount;
  }

  get() {
    return this.#weak.deref();
  }
}

const encodingsMap = { __proto__: null };
for (let i = 0; i < encodings.length; ++i)
  encodingsMap[encodings[i]] = i;

module.exports = {
  getLazy,
  assertCrypto,
  assertTypeScript,
  cachedResult,
  convertToValidSignal,
  createClassWrapper,
  decorateErrorStack,
  defineOperation,
  defineLazyProperties,
  defineReplaceableLazyAttribute,
  deprecate,
  emitExperimentalWarning,
  encodingsMap,
  exposeInterface,
  exposeLazyInterfaces,
  exposeNamespace,
  exposeGetterAndSetter,
  filterDuplicateStrings,
  filterOwnProperties,
  getConstructorOf,
  getCWDURL,
  getInternalGlobal,
  getStructuredStack,
  getSystemErrorMap,
  getSystemErrorName,
  getSystemErrorMessage,
  guessHandleType,
  isError,
  isUnderNodeModules,
  isMacOS,
  isWindows,
  join,
  lazyDOMException,
  lazyDOMExceptionClass,
  normalizeEncoding,
  once,
  promisify,
  SideEffectFreeRegExpPrototypeExec,
  SideEffectFreeRegExpPrototypeSymbolReplace,
  SideEffectFreeRegExpPrototypeSymbolSplit,
  sleep,
  spliceOne,
  setupCoverageHooks,
  removeColors,

  // Symbol used to customize promisify conversion
  customPromisifyArgs: kCustomPromisifyArgsSymbol,

  // Symbol used to provide a custom inspect function for an object as an
  // alternative to using 'inspect'
  customInspectSymbol: SymbolFor('nodejs.util.inspect.custom'),

  // Used by the buffer module to capture an internal reference to the
  // default isEncoding implementation, just in case userland overrides it.
  kIsEncodingSymbol: Symbol('kIsEncodingSymbol'),
  kVmBreakFirstLineSymbol: Symbol('kVmBreakFirstLineSymbol'),

  kEmptyObject,
  kEnumerableProperty,
  setOwnProperty,
  pendingDeprecate,
  WeakReference,
};
