[
  {
    "path": ".editorconfig",
    "content": "# EditorConfig is awesome: https://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\ntab_width = 2\ntrim_trailing_whitespace = true\n\n# Tab indentation (no size specified)\n[{Makefile,makefile}]\nindent_style = tab\n\n[*.md]\n# indent 4 for code blocks\nindent_size = 4\n# preserve trailing space for line breaks\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [tj, shadowspawn]\ntidelift: npm/n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug Report\nabout: Found a bug?\n\n---\n\n# Bug Report\n\n<!--\nThe text in these markdown comments is instructions that will not appear in the displayed issue.\n-->\n\n## Summary\n\n<!--\nAdd a clear and concise description of the bug.\n-->\n\n## Steps to Reproduce\n\n<!--\nAdd precise steps to reproduce the bug.\n-->\n\n## Expected Behaviour\n\n<!--\nAdd a description of what you expected to happen.\n-->\n\n## Actual Behaviour\n\n<!--\nAdd a description of what actually happened.\n-->\n\n## Other Information\n\n<!--\nOptionally add any other useful information or commentary.\n-->\n\n## Configuration Details\n\n<!--\nRun these commands and copy in the info.\n-->\n\n```bash\n$ n --version\n?\n\n$ command -v node\n?\n\n$ node -p process.platform\n?\n```\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "--\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n# Feature Request\n\n<!--\nThe text in these markdown comments is instructions that will not appear in the displayed issue.\nThis is a suggested template, but you don't have to follow it!\n-->\n\n## Problem\n\n<!--\nA clear and concise description of what the problem is. e.g. I'm always frustrated when [...]\n-->\n\n## Proposed Solution\n\n<!--\nA description of what you want to happen.\n-->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/support.md",
    "content": "---\nname: Support\nabout: Got a problem?\n\n---\n\n# Problem\n\n<!--\nThe text in these markdown comments is instructions that will not appear in the displayed issue.\nThis is a suggested template, but you don't have to follow it!\n-->\n\n## Short Version\n\n<!--\nAdd a clear and concise description of your problem.\n-->\n\n## Long Version\n\n<!--\nAdd more explanation and useful information or commentary as needed.\n-->\n\n## Configuration Details\n\n<!--\nRun these commands and copy in the info.\n-->\n\n```bash\n$ n --version\n?\n\n$ command -v node\n?\n\n$ node -p process.platform\n?\n```\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "# Pull Request\n\n<!--\nThe text in these markdown comments is instructions that will not appear in the displayed pull request.\n-->\n\n## Problem\n\n<!--\nWhat problem are you solving? Include issue numbers if it has been reported. \nShow the broken output if appropriate.\n-->\n\n## Solution\n\n<!--\nHow did you solve the problem? \nShow the fixed output if appropriate.\n-->\n\n## ChangeLog\n\n<!--\nOptional. Suggest a line for adding to the CHANGELOG to summarise your change.\n-->\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\nnode_modules\ntest/proxy~~.dump\n"
  },
  {
    "path": ".markdownlint.json",
    "content": "{\n  \"ul-indent\": { \"indent\": 4 },\n  \"line-length\": false\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n<!-- markdownlint-disable MD024 -->\n\n## [Unreleased] (date goes here)\n\n## [10.2.0] (2025-05-21)\n\n### Added\n\n- environment variable `N_ARCH` to set architecture for download, like using `--arch` ([#832])\n\n## [10.1.0] (2024-11-09)\n\n### Added\n\n- `--cleanup` option to delete cached version after install for a one-shot install ([#818])\n- `download` command to download Node.js version into cache ([#821])\n- document using `--download` with run/exec/which in README\n- support trailing comments in `.nvmrc` file ([#820])\n- mask password in download URL when displayed ([#815])\n\n### Changed\n\n- removed stale code ([#817])\n\n## [10.0.0] (2024-09-06)\n\nThe major version bump is due to using `jq` in preference to `node` for reading `package.json`.\n\n### Changed\n\n- if `jq` is available, use `jq` for reading `engines` from `package.json` instead of using `node` ([#810])\n- avoid a network lookup if auto or engine find a fully specified numeric version. ([#813])\n\n## [9.2.3] (2024-04-21)\n\n### Fixed\n\n- avoid problems with `curl` 8.7.1 and `--compressed` by removing option until fixed\n\n## [9.2.2] (2024-04-21)\n\n(No changes.)\n\n## [9.2.1] (2024-02-25)\n\n### Fixed\n\n- `n doctor` works with custom `N_CACHE_PREFIX`\n\n### Added\n\n- expand tests in `n doctor` for folder existence and permissions\n\n## [9.2.0] (2023-10-15)\n\n### Added\n\n- `--offline` for resolving target version against cached downloads instead of internet lookup ([#785])\n\n## [9.1.0] (2023-04-15)\n\n### Added\n\n- check for possible problem with multiple `npm` locations when running `n doctor` ([#764])\n\n## [9.0.1] (2022-11-04)\n\n### Fixed\n\n- `Makefile` compatible with more flavours of `make` ([#745])\n- quote paths in `Makefile` in case `PREFIX` contains spaces ([#746])\n\n## [9.0.0] (2022-07-16)\n\n### Changed\n\n- `--preserve` preserves `corepack` too ([#736])\n\n### Added\n\n- optional `N_PRESERVE_COREPACK` to change default behaviour for preserving `corepack` ([#736])\n\n## [8.2.0] (2022-04-18)\n\n### Added\n\n- log before copying files during install ([#720])\n\n## [8.1.0] (2022-03-18)\n\n### Added\n\n- optional `N_CACHE_PREFIX` for separate location for downloaded files than install location ([#717])\n\n## [8.0.2] (2022-01-09)\n\n### Fixed\n\n- improved warning message when utility location hash may be holding old location to cover a wider range of shells including dash ([#707])\n\n## [8.0.1] (2021-12-04)\n\n### Fixed\n\n- improve error handling for tar extraction errors ([#701])\n- add tar flag for compatibility with tar builds which do not default to stdin ([#697])\n\n## [8.0.0] (2021-10-23)\n\n### Changed\n\n- display error if version missing in version file for `n auto` and `n engine` (rather than fallback to current) ([#693])\n\n## [7.5.0] (2021-09-26)\n\n### Added\n\n- support for Corepack (which was added to Node.js in v16.9.0)\n\n## [7.4.1] (2021-09-11)\n\n### Fixed\n\n- run commands from correct directory after `--download` causes a download\n\n## [7.4.0] (2021-09-10)\n\n### Added\n\n- support for `--download` option to `run` and `exec` to download the target version when needed ([#685])\n\n## [7.3.1] (2021-07-25)\n\n### Changed\n\n- Improved README for new users missing expected folders in `/usr/local` ([#679])\n\n## [7.3.0] (2021-06-06)\n\n### Added\n\n- ls-remote supports `engine` and `auto` labels ([#675])\n- reduce `engine` and `auto` logging with `--quiet` ([#675])\n- add WSL support to README ([#676])\n- support for Emacs up and down keys (`ctrl-p` and `ctrl-n`) ([#669])\n\n### Changed\n\n- diagnostic logging during processing of engine and auto written to stderr rather than stdout ([#675])\n\n## [7.2.2] (2021-04-25)\n\n### Fixed\n\n- arrow key navigation of version menu when terminal in application mode (e.g. PowerShell on Mac) ([#668])\n\n## [7.2.1] (2021-04-19)\n\n### Added\n\n- install native arm64 Node.js on Macs with Apple silicon for Node.js 16 and higher ([#664])\n\n## [7.2.0] (2021-04-19) [YANKED]\n\nReleased off wrong branch, essentially same as 7.1.0.\n\n## [7.1.0] (2021-03-12)\n\n### Added\n\n- support installs where /usr/local/share/man is a symlink (such as archlinux)\n- remove requirement for rsync for --preserve\n- avoid install pollution if user installs global packages when using n exec\n\n## [7.0.2] (2021-02-27)\n\n### Fixed\n\n- consistently log to STDOUT ([#654])\n\n## [7.0.1] (2021-01-30)\n\n### Changed\n\n- update bats, and use bats-assert for better unit test failure messages\n\n### Fixed\n\n- fail to display error in some cases for missing both `curl` and `wget` ([#649])\n\n## [7.0.0] (2020-12-20)\n\n### Changed\n\n- `auto` label now scans for `package.json` only if it can not find a version control file ([#644])\n\n### Added\n\n- `engine` label to look for `engines.node` in `package.json` (as used by`auto`) ([#644])\n\n### Fixed\n\n- avoid colorized grep output via `GREP_OPTIONS` breaking version lookup ([#643])\n\n## [6.8.0] (2020-12-12)\n\n### Fixed\n\n- suppress unwanted warning during `auto` when using npx with npm 7\n- temporary fix for installing on Mac with Apple M1 chip, look for x64 versions of node as arm64 not available yet\n\n## [6.7.1] (2020-11-25)\n\n### Fixed\n\n- detect and handle a failed download of full archive ([#635])\n\n## [6.7.0] (2020-07-25)\n\n### Added\n\n- `auto` support for:\n    - `.node-version`\n    - `.nvmrc`\n    - `engines` field of `package.json`\n\n## [6.6.0] (2020-07-04)\n\n### Added\n\n- labels for node support aliases, such as `lts_latest`\n\n### Fixed\n\n- Enable `xz` support by default for macOS 11+ ([#624])\n\n## [6.5.1] (2020-04-11)\n\n### Added\n\n- specify `auto` to read the target version from a `.n-node-version` file (i.e. change filename)\n\n## [6.5.0] (2020-04-11) [YANKED]\n\n### Added\n\n- specify `auto` to read the target version from a `.node-version` file ([#616])\n\n## [6.4.0] (2020-03-10)\n\n### Added\n\n- treat `armv8l` as `arm64` ([#614])\n\n## [6.3.1] (2020-02-25)\n\n### Fixed\n\n- remove old version of node before copy to avoid firewall issues on macOS ([#394])\n\n## [6.3.0] (2020-02-24)\n\n### Added\n\n- `--preserve` to preserve npm and npx during install of node ([#587])\n\n## [6.2.0] (2020-01-29)\n\n### Added\n\n- Downloads now default to using tarballs compressed by `xz` over `gzip`, if `xz` support detected. ([#606] [#607])\n\n## [6.1.3] (2019-11-23)\n\n### Added\n\n- added How It Works to README\n\n### Changed\n\n- simplified layout for `n doctor` output\n\n## [6.1.2] (2019-11-16)\n\n### Added\n\n- advice to reset command hash when node location changes ([#170] [#381] [#451] [#588])\n- in README describe raw download of `n` to bootstrap install of node and npm\n\n## [6.1.1] (2019-11-10)\n\n### Fixed\n\n- Specify `--no-same-owner` for tarball extraction so cache files not owned by unexpected user (when run with sudo) ([#593])\n\n## [6.1.0] (2019-10-25)\n\n### Added\n\n- deletion of cached versions from menu using 'd' ([#590])\n\n## [6.0.1] (2019-08-20)\n\n### Fixed\n\n- allow options to come after commands, especially `n lsr --all`\n\n## [6.0.0] (2019-08-16)\n\n### Added\n\n- version specified using release stream codenames, like `argon` ([#423])\n- version specified using nightly et al ([#376])\n- `n exec` for running arbitrary command with node and npm in `PATH` ([#185])\n- `n run` with legacy aliases of `as` and `use`\n- `n lsr` for listing matching remote versions, limited to 20 by default ([#383])\n- `n doctor` for displaying diagnostic information\n- `n install` for people used to other products with this command ([#524])\n- `--insecure` to disable curl/wget certificate checks\n- added npm version to installed message ([#210] [#484] [#574])\n  \n### Changed\n\n- **Breaking** wget now checks certificates (secure by default, same as curl setup). (#475 #509)\n- failure messages go to stderr instead of stdout\n- prefixed `N_NODE_MIRROR` to eventually replace `NODE_MIRROR`\n- **Breaking** `n ls` now lists local download versions (rather than remote versions)\n- lookup available versions using `index.tab` rather than screen-scraping (#560)\n\n### Fixed\n\n- download errors display informative message, instead of just `Invalid version` ([#482] [#492] et al)\n- improve reliability of downloads from custom node mirrors, including removing broken `is_oss_ok` ([#560])\n- restrict downloads to versions with architecture available ([#463])\n\n### Removed\n\n- **Breaking** support for `PROJECT_NAME` and `PROJECT_URL` for custom downloads ([#342])\n\n## [5.0.2] (2019-08-02)\n\n### Added\n\n- instructions to bottom of menu version selection\n\n## [5.0.1] (2019-07-20)\n\n### Changed\n\n- removed reference to prerelease version of v5.0.0 from README\n\n## [5.0.0] (2019-07-20)\n\n### Added\n\n- log message after install from cache (previously silent)\n- extra logging after install if the active and installed node locations are different\n- support for [NO_COLOR](https://no-color.org) and [CLICOLOR=0](https://bixense.com/clicolors)\n- suppress progress and colour if not interactive tty\n- define `N_USE_XZ` to download `.xz` compressed archives instead of `.gz` archives\n  \n### Changed\n\n- reinstalling active node version always does reinstall (previously silently did nothing)\n- log message for installing using menu now same format as `npm install` message\n- updates to GitHub templates and guidelines for contributing et al\n\n## [4.1.0] (2019-05-10)\n\n### Added\n\n- 'n uninstall` to remove node and npm\n- describe `NODE_MIRROR` in `README`\n\n### Removed\n\n- `PROJECT_NAME` and `PROJECT_URL` from `README`. First step to deprecating `n project`. Open an issue if you still need this!\n\n## [4.0.0] (2019-05-05)\n\nOnly minor functional changes, but technically could break scripts relying on specific behaviour.\n\n### Fixed\n\n- remove trailing space from `bin` output [#456]\n\n### Added\n\n- development tests [#545]\n\n### Changed\n\n- internal: improve shell script based on ShellCheck suggestions, quoting variables use etc [#187] [#465]\n- put single quote marks around parameters to clarify error messages [#485]\n- update terminology to be more careful with current/latest [#522]\n\n## [3.0.2] (2019-04-07)\n\n### Added\n\n- instructions to avoid need for `sudo` when installing to `/usr/local`  [#416] [#562]\n\n### Fixed\n\n- permission denied errors when running read-only commands without sudo [#416]\n\n## [3.0.1] (2019-04-05)\n\n### Added\n\n- install instruction using Homebrew (macOS) [#534]\n- Table of Contents to README [#466]\n\n### Fixed\n\n- lts lookup on node mirrors which don't purge old versions (e.g. taobao) [#512]\n- hide cursor while selecting version from menu [#528]\n\n### Removed\n\n- gitter badge from README, as gitter chatroom inactive\n- inactive Core Team from README\n- instructions for scripted install of npm from README, which should no longer be needed and not working on Mac [#536]\n\n## [3.0.0] (2019-03-29)\n\n### Added\n\n- detect arm64 architecture [#448][] [#521][]\n\n### Changed\n\n- allow `n rm` of active version of node [#541][] [#169][] [#327][] [#441][]\n- show more version examples in README, including partial version number [#548][]\n- updated description of interactive version selection [#518][]\n- make (old) stable an alias for lts [#467][] [#335][]\n- replace use of `which` with more standard `command -v` [#532][]\n\n### Fixed\n\n- error messages when selecting from version menu if active node version not listed [#541][] [#292][] [#367][] [#391][] [#400][]\n- removed inappropriate `shift` from prune function [#531][] [#529][]\n\n### Removed\n\n- Remove old io project support [#516][] [#331][]\n\n<!-- reference links for issues and pull requests -->\n\n[#169]: https://github.com/tj/n/issues/169\n[#170]: https://github.com/tj/n/issues/170\n[#185]: https://github.com/tj/n/issues/185\n[#187]: https://github.com/tj/n/issues/187\n[#210]: https://github.com/tj/n/issues/210\n[#292]: https://github.com/tj/n/issues/292\n[#327]: https://github.com/tj/n/issues/327\n[#331]: https://github.com/tj/n/issues/331\n[#335]: https://github.com/tj/n/issues/335\n[#342]: https://github.com/tj/n/issues/342\n[#367]: https://github.com/tj/n/issues/367\n[#376]: https://github.com/tj/n/issues/376\n[#381]: https://github.com/tj/n/issues/381\n[#383]: https://github.com/tj/n/issues/383\n[#391]: https://github.com/tj/n/issues/391\n[#394]: https://github.com/tj/n/issues/394\n[#400]: https://github.com/tj/n/issues/400\n[#416]: https://github.com/tj/n/issues/416\n[#423]: https://github.com/tj/n/issues/423\n[#441]: https://github.com/tj/n/issues/441\n[#448]: https://github.com/tj/n/issues/448\n[#451]: https://github.com/tj/n/issues/451\n[#456]: https://github.com/tj/n/issues/456\n[#463]: https://github.com/tj/n/issues/463\n[#465]: https://github.com/tj/n/issues/465\n[#466]: https://github.com/tj/n/issues/466\n[#467]: https://github.com/tj/n/issues/467\n[#482]: https://github.com/tj/n/issues/482\n[#484]: https://github.com/tj/n/issues/484\n[#485]: https://github.com/tj/n/issues/485\n[#492]: https://github.com/tj/n/issues/492\n[#512]: https://github.com/tj/n/issues/512\n[#516]: https://github.com/tj/n/issues/516\n[#518]: https://github.com/tj/n/issues/518\n[#521]: https://github.com/tj/n/issues/521\n[#522]: https://github.com/tj/n/issues/522\n[#524]: https://github.com/tj/n/issues/524\n[#528]: https://github.com/tj/n/issues/528\n[#529]: https://github.com/tj/n/issues/529\n[#531]: https://github.com/tj/n/issues/531\n[#532]: https://github.com/tj/n/issues/532\n[#534]: https://github.com/tj/n/issues/534\n[#536]: https://github.com/tj/n/issues/536\n[#541]: https://github.com/tj/n/issues/541\n[#545]: https://github.com/tj/n/issues/545\n[#548]: https://github.com/tj/n/issues/548\n[#560]: https://github.com/tj/n/issues/560\n[#562]: https://github.com/tj/n/issues/562\n[#574]: https://github.com/tj/n/issues/574\n[#587]: https://github.com/tj/n/issues/587\n[#588]: https://github.com/tj/n/issues/588\n[#590]: https://github.com/tj/n/issues/590\n[#593]: https://github.com/tj/n/issues/593\n[#606]: https://github.com/tj/n/issues/606\n[#607]: https://github.com/tj/n/issues/607\n[#614]: https://github.com/tj/n/issues/614\n[#616]: https://github.com/tj/n/issues/616\n[#624]: https://github.com/tj/n/issues/624\n[#635]: https://github.com/tj/n/pull/635\n[#643]: https://github.com/tj/n/pull/643\n[#644]: https://github.com/tj/n/pull/644\n[#649]: https://github.com/tj/n/issues/649\n[#654]: https://github.com/tj/n/issues/654\n[#664]: https://github.com/tj/n/pull/664\n[#668]: https://github.com/tj/n/pull/668\n[#669]: https://github.com/tj/n/pull/669\n[#675]: https://github.com/tj/n/pull/675\n[#676]: https://github.com/tj/n/pull/676\n[#679]: https://github.com/tj/n/issues/679\n[#685]: https://github.com/tj/n/issues/685\n[#693]: https://github.com/tj/n/issues/693\n[#697]: https://github.com/tj/n/issues/697\n[#701]: https://github.com/tj/n/issues/701\n[#707]: https://github.com/tj/n/issues/707\n[#717]: https://github.com/tj/n/issues/717\n[#720]: https://github.com/tj/n/issues/720\n[#736]: https://github.com/tj/n/pull/736\n[#745]: https://github.com/tj/n/pull/745\n[#746]: https://github.com/tj/n/pull/746\n[#764]: https://github.com/tj/n/pull/764\n[#785]: https://github.com/tj/n/pull/785\n[#810]: https://github.com/tj/n/pull/810\n[#813]: https://github.com/tj/n/pull/813\n[#815]: https://github.com/tj/n/pull/815\n[#817]: https://github.com/tj/n/pull/817\n[#818]: https://github.com/tj/n/pull/818\n[#820]: https://github.com/tj/n/pull/820\n[#821]: https://github.com/tj/n/pull/821\n[#832]: https://github.com/tj/n/pull/832\n\n<!-- reference links for releases -->\n\n[Unreleased]: https://github.com/tj/n/compare/master...develop\n[10.2.0]: https://github.com/tj/n/compare/v10.1.0...v10.2.0\n[10.1.0]: https://github.com/tj/n/compare/v10.0.0...v10.1.0\n[10.0.0]: https://github.com/tj/n/compare/v9.2.3...v10.0.0\n[9.2.3]: https://github.com/tj/n/compare/v9.2.2...v9.2.3\n[9.2.2]: https://github.com/tj/n/compare/v9.2.1...v9.2.2\n[9.2.1]: https://github.com/tj/n/compare/v9.2.0...v9.2.1\n[9.2.0]: https://github.com/tj/n/compare/v9.1.0...v9.2.0\n[9.1.0]: https://github.com/tj/n/compare/v9.0.1...v9.1.0\n[9.0.1]: https://github.com/tj/n/compare/v9.0.0...v9.0.1\n[9.0.0]: https://github.com/tj/n/compare/v8.2.0...v9.0.0\n[8.2.0]: https://github.com/tj/n/compare/v8.1.0...v8.2.0\n[8.1.0]: https://github.com/tj/n/compare/v8.0.2...v8.1.0\n[8.0.2]: https://github.com/tj/n/compare/v8.0.1...v8.0.2\n[8.0.1]: https://github.com/tj/n/compare/v8.0.0...v8.0.1\n[8.0.0]: https://github.com/tj/n/compare/v7.5.0...v8.0.0\n[7.5.0]: https://github.com/tj/n/compare/v7.4.1...v7.5.0\n[7.4.1]: https://github.com/tj/n/compare/v7.4.0...v7.4.1\n[7.4.0]: https://github.com/tj/n/compare/v7.3.1...v7.4.0\n[7.3.1]: https://github.com/tj/n/compare/v7.3.0...v7.3.1\n[7.3.0]: https://github.com/tj/n/compare/v7.2.2...v7.3.0\n[7.2.2]: https://github.com/tj/n/compare/v7.2.1...v7.2.2\n[7.2.1]: https://github.com/tj/n/compare/v7.1.0...v7.2.1\n[7.2.0]: https://github.com/tj/n/compare/v7.1.0...v7.2.0\n[7.1.0]: https://github.com/tj/n/compare/v7.0.2...v7.1.0\n[7.0.2]: https://github.com/tj/n/compare/v7.0.1...v7.0.2\n[7.0.1]: https://github.com/tj/n/compare/v7.0.0...v7.0.1\n[7.0.0]: https://github.com/tj/n/compare/v6.8.0...v7.0.0\n[6.8.0]: https://github.com/tj/n/compare/v6.7.1...v6.8.0\n[6.7.1]: https://github.com/tj/n/compare/v6.7.0...v6.7.1\n[6.7.0]: https://github.com/tj/n/compare/v6.6.0...v6.7.0\n[6.6.0]: https://github.com/tj/n/compare/v6.5.1...v6.6.0\n[6.5.1]: https://github.com/tj/n/compare/v6.5.0...v6.5.1\n[6.5.0]: https://github.com/tj/n/compare/v6.4.0...v6.5.0\n[6.4.0]: https://github.com/tj/n/compare/v6.3.1...v6.4.0\n[6.3.1]: https://github.com/tj/n/compare/v6.3.0...v6.3.1\n[6.3.0]: https://github.com/tj/n/compare/v6.2.0...v6.3.0\n[6.2.0]: https://github.com/tj/n/compare/v6.1.3...v6.2.0\n[6.1.3]: https://github.com/tj/n/compare/v6.0.2...v6.1.3\n[6.1.2]: https://github.com/tj/n/compare/v6.0.1...v6.1.2\n[6.1.1]: https://github.com/tj/n/compare/v6.0.0...v6.1.1\n[6.1.0]: https://github.com/tj/n/compare/v6.0.1...v6.1.0\n[6.0.1]: https://github.com/tj/n/compare/v6.0.0...v6.0.1\n[6.0.0]: https://github.com/tj/n/compare/v5.0.2...v6.0.0\n[5.0.2]: https://github.com/tj/n/compare/v5.0.1...v5.0.2\n[5.0.1]: https://github.com/tj/n/compare/v5.0.0...v5.0.1\n[5.0.0]: https://github.com/tj/n/compare/v4.1.0...v5.0.0\n[4.1.0]: https://github.com/tj/n/compare/v4.0.0...v4.1.0\n[4.0.0]: https://github.com/tj/n/compare/v3.0.2...v4.0.0\n[3.0.2]: https://github.com/tj/n/compare/v3.0.1...v3.0.2\n[3.0.1]: https://github.com/tj/n/compare/v3.0.0...v3.0.1\n[3.0.0]: https://github.com/tj/n/compare/v2.1.12...v3.0.0\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to n\n\n## Issues\n\nBefore opening up an issue, please search for previous reports.\n\nNew issues are welcome, whether questions or suggestions or reporting bugs.\nYou are also welcome to contribute by adding helpful comments on an existing issue.\n\n## Pull Requests\n\nPull Requests will be considered. Please open an issue to discuss your idea before requesting big changes.\n\nPlease submit pull requests against the `develop` branch. The template will prompt you for the details,\nsuch as what problem you are solving, and relevant issue numbers.\n\nDon't change the version number or CHANGELOG, as they are updated by maintainers as the release is being prepared.\n\n## Code of Conduct\n\nHate speech of any kind is not tolerated.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 TJ Holowaychuk\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "PREFIX ?= /usr/local\n\ninstall: bin/n\n\tmkdir -p \"$(PREFIX)/bin\"\n\tcp bin/n \"$(PREFIX)/bin/n\"\n\nuninstall:\n\trm -f \"$(PREFIX)/bin/n\"\n\n.PHONY: install uninstall\n"
  },
  {
    "path": "README.md",
    "content": "# `n` – Interactively Manage Your Node.js Versions\n\n[![npm](https://img.shields.io/npm/dt/n.svg?style=flat-square)](https://www.npmjs.com/package/n)\n[![npm](https://img.shields.io/npm/dm/n.svg?style=flat-square)](https://www.npmjs.com/package/n)\n[![npm](https://img.shields.io/npm/v/n.svg?style=flat-square)](https://www.npmjs.com/package/n)\n[![npm](https://img.shields.io/npm/l/n.svg?style=flat-square)](https://www.npmjs.com/package/n)\n\nNode.js version management: no subshells, no profile setup, no convoluted API, just **simple**.\n\n![usage animation](https://nimit.io/images/n/n.gif)\n\n- [`n` – Interactively Manage Your Node.js Versions](#n--interactively-manage-your-nodejs-versions)\n    - [Supported Platforms](#supported-platforms)\n    - [Installation](#installation)\n        - [Third Party Installers](#third-party-installers)\n        - [Replacing a previous node install](#replacing-a-previous-node-install)\n    - [Installing Node.js Versions](#installing-nodejs-versions)\n    - [Specifying Node.js Versions](#specifying-nodejs-versions)\n    - [Removing Versions](#removing-versions)\n    - [Using Downloaded Node.js Versions Without Reinstalling](#using-downloaded-nodejs-versions-without-reinstalling)\n    - [Preserving npm](#preserving-npm)\n    - [Miscellaneous](#miscellaneous)\n    - [Custom Mirror](#custom-mirror)\n    - [Custom Architecture](#custom-architecture)\n    - [Optional Environment Variables](#optional-environment-variables)\n    - [How It Works](#how-it-works)\n\n## Supported Platforms\n\n`n` is supported on macOS, Linux, including with Windows Subsystem for Linux, and various other unix-like systems.\nIt is written as a BASH script but does not require you to use BASH as your command shell.\n\n`n` does not work in native shells on Microsoft Windows (like PowerShell), or Git for Windows BASH, or with the Cygwin DLL.\n\n## Installation\n\nIf you already have Node.js installed, an easy way to install `n` is using `npm`:\n\n    npm install -g n\n\nThe default root location used when running `n` is `/usr/local` where a normal user does not have write permission. You may strike the same sort of permission error when using npm to install global modules, like the above command. You have three main options:\n\n1) change the ownership of the relevant directories to yourself (see below)\n2) tell `n` to use a custom location where you do have write permissions (see `N_PREFIX`)\n3) put `sudo` in front of the command to run it as super user\n\n`n` caches Node.js versions in subdirectory `n/versions`. The _active_ Node.js version is installed in subdirectories `bin`, `include`, `lib`, and `share`.\n\nTo take ownership of the system directories (option 1):\n\n    # make cache folder (if missing) and take ownership\n    sudo mkdir -p /usr/local/n\n    sudo chown -R $(whoami) /usr/local/n\n    # make sure the required folders exist (safe to execute even if they already exist)\n    sudo mkdir -p /usr/local/bin /usr/local/lib /usr/local/include /usr/local/share\n    # take ownership of Node.js install destination folders\n    sudo chown -R $(whoami) /usr/local/bin /usr/local/lib /usr/local/include /usr/local/share\n\n-----\n\nIf `npm` is not yet available, one way to bootstrap an install is to download and run `n` directly. To install the `lts` version of Node.js:\n\n    curl -fsSL https://raw.githubusercontent.com/tj/n/master/bin/n | bash -s install lts\n    # If you want n installed, you can use npm now.\n    npm install -g n\n\nIf you don't need support for updates to `n` itself you can just save the download:\n\n    curl -fsSL -o /usr/local/bin/n https://raw.githubusercontent.com/tj/n/master/bin/n \n    chmod 0755 /usr/local/bin/n\n    n install lts\n\n### Third Party Installers\n\nOn macOS with [Homebrew](https://brew.sh/) you can install the [n formula](https://formulae.brew.sh/formula/n).\n\n    brew install n\n\nOr on macOS with [MacPorts](https://www.macports.org/) you can install the [n port](https://ports.macports.org/port/n/summary):\n\n    port install n\n\nOn Linux and macOS, [n-install](https://github.com/mklement0/n-install) allows installation directly from GitHub; for instance:\n\n    curl -L https://bit.ly/n-install | bash\n\nn-install sets both `PREFIX` and `N_PREFIX` to `$HOME/n`, installs `n` to `$HOME/n/bin`, modifies the initialization files of supported shells to export `N_PREFIX` and add `$HOME/n/bin` to the `PATH`, and installs the latest LTS Node.js version.\n\nAs a result, both `n` itself and all Node.js versions it manages are hosted inside a single, optionally configurable directory, which you can later remove with the included `n-uninstall` script. `n-update` updates `n` itself to the latest version. See the [n-install repo](https://github.com/mklement0/n-install) for more details.\n\n### Replacing a previous node install\n\nChanging from a previous Node.js installed to a different location may involve a few extra steps. See docs for [changing node location](./docs/changing-node-location.md) for a walk-through example of switching from using Homebrew to using `n` to manage Node.js.\n\nYou have a problem with multiple versions if after installing node you see the \"installed\" and \"active\" locations are different:\n\n```console\n% n lts\n     copying : node/20.12.2\n   installed : v20.12.2 to /usr/local/bin/node\n      active : v21.7.3 at /opt/homebrew/bin/node\n```\n\n## Installing Node.js Versions\n\nSimply execute `n <version>` to download and install a version of Node.js. If `<version>` has already been downloaded, `n` will install from its cache.\n\n    n 10.16.0\n    n lts\n\nExecute `n` on its own to view your downloaded versions, and install the selected version.\n\n    $ n\n\n      node/4.9.1\n    ο node/8.11.3\n      node/10.15.0\n\n    Use up/down arrow keys to select a version, return key to install, d to delete, q to quit\n\n(You can also use <kbd>j</kbd> and <kbd>k</kbd> to select next or previous version instead of using arrows, or <kbd>ctrl+n</kbd> and <kbd>ctrl+p</kbd>.)\n\nIf the active node version does not change after install, try opening a new shell in case seeing a stale version.\n\n## Specifying Node.js Versions\n\nThere are a variety of ways of specifying the target Node.js version for `n` commands. Most commands use the latest matching version, and  `n ls-remote` lists multiple matching versions.\n\nNumeric version numbers can be complete or incomplete, with an optional leading `v`.\n\n- `4.9.1`\n- `8`: 8.x.y versions\n- `v6.1`: 6.1.x versions\n\nThere are labels for two especially useful versions:\n\n- `lts`: newest Long Term Support official release\n- `latest`, `current`: newest official release\n  \nThere is an `auto` label to read the target version from a file in the current directory, or any parent directory. `n` looks for in order:\n\n- `.n-node-version`: version on single line. Custom to `n`.\n- `.node-version`: version on single line. Used by multiple tools: [node-version-usage](https://github.com/shadowspawn/node-version-usage)\n- `.nvmrc`: version on single line. Used by `nvm`.\n- if no version file found, look for `engine` as below.\n\nThe `engine` label looks for a `package.json` file and reads the `engines` field to determine compatible Node.js. Requires an installed version of `jq` or `node`, and uses `npx semver` to resolve complex ranges.\n\nThere is support for the named release streams:\n\n- `argon`, `boron`, `carbon`: codenames for LTS release streams\n\nThese Node.js support aliases may be used, although simply resolve to the latest matching version:\n\n- `active`, `lts_active`, `lts_latest`, `lts`, `current`, `supported`\n\nThe last version form is for specifying [other releases](https://nodejs.org/download) available using the name of the remote download folder optionally followed by the complete or incomplete version.\n\n- `nightly`\n- `test/v11.0.0-test20180528`\n- `rc/10`\n\n## Removing Versions\n\nRemove some cached versions:\n\n    n rm 0.9.4 v0.10.0\n\nRemoving all cached versions except the installed version:\n\n    n prune\n\nRemove the installed Node.js (does not affect the cached versions). This can be useful\nto revert to the system version of node (if in a different location), or if you no longer\nwish to use node and npm, or are switching to a different way of managing them.\n\n    n uninstall\n\n## Using Downloaded Node.js Versions Without Reinstalling\n\nThere are three commands for working directly with your downloaded versions of Node.js, without reinstalling.\n\nYou can show the path to the downloaded `node` version:\n\n    $ n which 6.14.3\n    /usr/local/n/versions/6.14.3/bin/node\n\nOr run a downloaded `node` version with the `n run` command:\n\n    n run 8.11.3 --debug some.js\n\nOr execute a command with `PATH` modified so `node` and `npm` will be from the downloaded Node.js version.\n(NB: `npm` run this way will be using global node_modules from the target node version folder.)\n\n    n exec 10 my-script --fast test\n    n exec lts zsh\n\n## Preserving npm\n\nA Node.js install normally also includes `npm`,  `npx`, and `corepack`, but you may wish to preserve your current (especially newer) versions using `--preserve`:\n\n    $ npm install -g npm@latest\n    ...\n    $ npm --version\n    6.13.7\n    # Node.js 8.17.0 includes (older) npm 6.13.4\n    $ n -p 8\n       installed : v8.17.0\n    $ npm --version\n    6.13.7\n\nYou can make this the default by setting the environment variable to a non-empty string. There are separate environment variables for `npm` and `corepack`:\n\n    export N_PRESERVE_NPM=1\n    export N_PRESERVE_COREPACK=1\n\nYou can be explicit to get the desired behaviour whatever the environment variables:\n\n    n --preserve nightly\n    n --no-preserve latest\n\n## Miscellaneous\n\nCommand line help can be obtained from `n --help`.\n\nList matching remote versions available for download:\n\n    n ls-remote lts\n    n ls-remote latest\n    n lsr 10\n    n --all lsr\n\nList downloaded versions in cache:\n\n    n ls\n\nDownload version into cache:\n\n    n download 22\n\nUse `n` to access cached versions (already downloaded) without internet available.\n\n    n --offline 12\n\nRemove the cache version after installing using `--cleanup`. This is particularly useful for a one-shot install, like in a docker container.\n\n    curl -fsSL https://raw.githubusercontent.com/tj/n/master/bin/n | bash -s install --cleanup lts\n\nNormally `n run`, `n exec`, and `n which` will fail if the target version is not already in the cache. You can add `--download` to use the cache if available or download if required:\n\n    n --download run 18.3 my-script.js\n\nDisplay diagnostics to help resolve problems:\n\n    n doctor\n\n## Custom Mirror\n\nIf you would like to use a different Node.js mirror which has the same layout as the default <https://nodejs.org/dist/>, you can define `N_NODE_MIRROR`.\n\nOne example is for users in China who can define:\n\n    export N_NODE_MIRROR=https://npmmirror.com/mirrors/node\n\nAnother example is the Node.js [unofficial-builds project](https://github.com/nodejs/unofficial-builds/) which has downloads for some platforms not made available officially, such as armv6l (Raspberry Pi) and 32-bit x86.\n\n    export N_NODE_MIRROR=https://unofficial-builds.nodejs.org/download/release\n\nYou may need to specify the architecture explicitly if not autodetected by `n`, such as using `musl` `libc` on Alpine. You can do that with `N_ARCH` or `--arch`:\n\n    export N_NODE_MIRROR=https://unofficial-builds.nodejs.org/download/release\n    export N_ARCH=x64-musl\n    apk add bash curl libstdc++\n    n install lts\n\nIf the custom mirror requires authentication you can add the [url-encoded](https://urlencode.org) username and password into the URL. e.g.\n\n    export N_NODE_MIRROR=https://encoded-username:encoded-password@host:port/path\n\nThere is also `N_NODE_DOWNLOAD_MIRROR` for a different mirror with same layout as the default <https://nodejs.org/download>.\n\n## Custom Architecture\n\nBy default `n` picks the binaries matching your system architecture. For example, on a 64 bit system `n` will download 64 bit binaries.\n\nOn a Mac with Apple silicon:\n\n- for Node.js 16 and higher, `n` defaults to arm64 binaries which run natively\n- for older versions of Node.js, `n` defaults to x64 binaries which run in Rosetta 2\n\nYou can override the default architecture by using the `-a` or `--arch` option, or set `N_ARCH` environment variable.\n\ne.g. reinstall latest version of Node.js with x64 binaries:\n\n    n rm current\n    n --arch x64 current\n\n## Optional Environment Variables\n\nThe `n` command downloads and installs to `/usr/local` by default, but you may override this location by defining `N_PREFIX`.\nTo change the location to say `$HOME/.n`, add lines like the following to your shell initialization file:\n\n    export N_PREFIX=$HOME/.n\n    export PATH=$N_PREFIX/bin:$PATH\n\nIf you want to store the downloads under a different location, use `N_CACHE_PREFIX`. This does _not_ affect where the active\nnode version is installed.\n\n`n` defaults to using xz compressed Node.js tarballs for the download if it is likely tar on the system supports xz decompression.\nYou can override the automatic choice by setting an environment variable to zero or non-zero:\n\n    export N_USE_XZ=0 # to disable\n    export N_USE_XZ=1 # to enable\n\nYou can be explicit to get the desired behaviour whatever the environment variable:\n\n    n install --use-xz nightly\n    n install --no-use-xz latest\n\nIn brief:\n\n- `N_NODE_MIRROR`: see [Custom Mirror](#custom-mirror)\n- `N_NODE_DOWNLOAD_MIRROR`: see [Custom Mirror](#custom-mirror)\n- support for [NO_COLOR](https://no-color.org) and [CLICOLOR=0](https://bixense.com/clicolors) for controlling use of ANSI color codes\n- `N_MAX_REMOTE_MATCHES` to change the default `ls-remote` maximum of 20 matching versions\n- `N_PRESERVE_NPM`: see [Preserving npm](#preserving-npm)\n- `N_PRESERVE_COREPACK`: see [Preserving npm](#preserving-npm)\n- `N_ARCH`: see [Custom Architecture](#custom-architecture)\n\n## How It Works\n\n`n` downloads a prebuilt Node.js package and installs to a single prefix (e.g. `/usr/local`). This overwrites the previous version. The `bin` folder in this location should be in your `PATH` (e.g. `/usr/local/bin`).\n\nThe downloads are kept in a cache folder to be used for reinstalls. The downloads are also available for limited use using `n which` and `n run` and `n exec`.\n\nThe global `npm` packages are not changed by the install, with the\nexception of `npm` itself which is part of the Node.js install.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nThe latest two major versions get security updates.\n\nPull Requests for security issues will be considered for older versions.\n\n## Reporting a Vulnerability\n\nTo report a security vulnerability, please use the\n[Tidelift security contact](https://tidelift.com/security).\nTidelift will coordinate the fix and disclosure.\n"
  },
  {
    "path": "bin/dev/release",
    "content": "#!/usr/bin/env bash\n\n# Run this from the develop branch after setting the version number in bin/n,\n# when ready to release apart from copying up to master and tagging.\n\n{ # force scan of whole file into memory so not affected by changing branches and self-modifying.\n\n#\n# confirm <message>\n#\n\nfunction confirm {\n  read -p \"$1 \" -r\n  if [[ ! \"${REPLY}\" =~ ^[Yy]$ ]]; then\n    echo \"Stopping\"\n    exit 2\n  fi\n}\n\n\nreadonly N_VERSION=\"$(./bin/n --version)\"\nif [[ \"${N_VERSION}\" =~ ^[0-9.]+-[0-9]+$ ]]; then\n  echo \"Error: internal version number still prerelease, set it to desired version first.\"\n  exit 2\nfi\n\nconfirm \"Are you releasing version '${N_VERSION}' ?\"\nconfirm \"Have you updated CHANGELOG?\"\nconfirm \"Are you running this from a shell with full internet access (not through proxy to run tests)?\"\n\ngit checkout master\ngit merge develop\nnpm version \"${N_VERSION}\"\n\nread -p \"One Time Password for npm publish: \" -r\n\nset -x\nnpm publish . --otp \"${REPLY}\"\ngit push --follow-tags\ngit checkout develop\ngit merge master\nnpm version -no-git-tag-version prepatch\nset +x\n\necho \"Reminder: update the internal number to match.\"\necho \"Reminder: add release description to github (from CHANGELOG)\"\n\nexit\n}\n"
  },
  {
    "path": "bin/n",
    "content": "#!/usr/bin/env bash\n# shellcheck disable=SC2155\n# Disabled \"Declare and assign separately to avoid masking return values\": https://github.com/koalaman/shellcheck/wiki/SC2155\n\n#\n# log <type> <msg>\n#\n\nlog() {\n  printf \"  ${SGR_CYAN}%10s${SGR_RESET} : ${SGR_FAINT}%s${SGR_RESET}\\n\" \"$1\" \"$2\"\n}\n\n#\n# verbose_log <type> <msg>\n# Can suppress with --quiet.\n# Like log but to stderr rather than stdout, so can also be used from \"display\" routines.\n#\n\nverbose_log() {\n  if [[ \"${SHOW_VERBOSE_LOG}\" == \"true\" ]]; then\n    >&2 printf \"  ${SGR_CYAN}%10s${SGR_RESET} : ${SGR_FAINT}%s${SGR_RESET}\\n\" \"$1\" \"$2\"\n  fi\n}\n\n#\n# Exit with the given <msg ...>\n#\n\nabort() {\n  >&2 printf \"\\n  ${SGR_RED}Error: %s${SGR_RESET}\\n\\n\" \"$*\" && exit 1\n}\n\n#\n# Synopsis: trace message ...\n# Debugging output to stderr, not used in production code.\n#\n\nfunction trace() {\n  >&2 printf \"trace: %s\\n\" \"$*\"\n}\n\n#\n# Synopsis: echo_red message ...\n# Highlight message in colour (on stdout).\n#\n\nfunction echo_red() {\n  printf \"${SGR_RED}%s${SGR_RESET}\\n\" \"$*\"\n}\n\n#\n# Synopsis: n_grep <args...>\n# grep wrapper to ensure consistent grep options and circumvent aliases.\n#\n\nfunction n_grep() {\n  GREP_OPTIONS='' command grep \"$@\"\n}\n\n#\n# Setup and state\n#\n\nVERSION=\"10.2.0\"\n\nN_PREFIX=\"${N_PREFIX-/usr/local}\"\nN_PREFIX=${N_PREFIX%/}\nreadonly N_PREFIX\n\nN_CACHE_PREFIX=\"${N_CACHE_PREFIX-${N_PREFIX}}\"\nN_CACHE_PREFIX=${N_CACHE_PREFIX%/}\nCACHE_DIR=\"${N_CACHE_PREFIX}/n/versions\"\nreadonly N_CACHE_PREFIX CACHE_DIR\n\nN_NODE_MIRROR=${N_NODE_MIRROR:-${NODE_MIRROR:-https://nodejs.org/dist}}\nN_NODE_MIRROR=${N_NODE_MIRROR%/}\nreadonly N_NODE_MIRROR\n\nN_NODE_DOWNLOAD_MIRROR=${N_NODE_DOWNLOAD_MIRROR:-https://nodejs.org/download}\nN_NODE_DOWNLOAD_MIRROR=${N_NODE_DOWNLOAD_MIRROR%/}\nreadonly N_NODE_DOWNLOAD_MIRROR\n\n# Using xz instead of gzip is enabled by default, if xz compatibility checks pass.\n# User may set N_USE_XZ to 0 to disable, or set to anything else to enable.\n# May also be overridden by command line flags.\n\n# Normalise external values to true/false\nif [[ \"${N_USE_XZ}\" = \"0\" ]]; then\n  N_USE_XZ=\"false\"\nelif [[ -n \"${N_USE_XZ+defined}\" ]]; then\n  N_USE_XZ=\"true\"\nfi\n# Not setting to readonly. Overriden by CLI flags, and update_xz_settings_for_version.\n\nN_MAX_REMOTE_MATCHES=${N_MAX_REMOTE_MATCHES:-20}\n# modified by update_mirror_settings_for_version\ng_mirror_url=${N_NODE_MIRROR}\ng_mirror_folder_name=\"node\"\n\n# Options for curl and wget.\n# Defining commands in variables is fraught (https://mywiki.wooledge.org/BashFAQ/050)\n# but we can follow the simple case and store arguments in an array.\n\nGET_SHOWS_PROGRESS=\"false\"\n# --location to follow redirects\n# --fail to avoid happily downloading error page from web server for 404 et al\n# --show-error to show why failed (on stderr)\nCURL_OPTIONS=( \"--location\" \"--fail\" \"--show-error\" )\nif [[ -t 1 ]]; then\n  CURL_OPTIONS+=( \"--progress-bar\" )\n  command -v curl &> /dev/null && GET_SHOWS_PROGRESS=\"true\"\nelse\n  CURL_OPTIONS+=( \"--silent\" )\nfi\nWGET_OPTIONS=( \"-q\" \"-O-\" )\n\n# Legacy support using unprefixed env. No longer documented in README.\nif [ -n \"$HTTP_USER\" ];then\n  if [ -z \"$HTTP_PASSWORD\" ]; then\n    abort \"Must specify HTTP_PASSWORD when supplying HTTP_USER\"\n  fi\n  CURL_OPTIONS+=( \"-u $HTTP_USER:$HTTP_PASSWORD\" )\n  WGET_OPTIONS+=( \"--http-password=$HTTP_PASSWORD\"\n                \"--http-user=$HTTP_USER\" )\nelif [ -n \"$HTTP_PASSWORD\" ]; then\n  abort \"Must specify HTTP_USER when supplying HTTP_PASSWORD\"\nfi\n\n# Set by set_active_node\ng_active_node=\n\n# set by various lookups to allow mixed logging and return value from function, especially for engine and node\ng_target_node=\n\nDOWNLOAD=false # set to opt-out of activate (install), and opt-in to download (run, exec)\nCLEANUP=false # remove cached download after install\nARCH=\"${N_ARCH-}\"\nSHOW_VERBOSE_LOG=\"true\"\nOFFLINE=false\n\n# ANSI escape codes\n# https://en.wikipedia.org/wiki/ANSI_escape_code\n# https://no-color.org\n# https://bixense.com/clicolors\n\nUSE_COLOR=\"true\"\nif [[ -n \"${CLICOLOR_FORCE+defined}\" && \"${CLICOLOR_FORCE}\" != \"0\" ]]; then\n  USE_COLOR=\"true\"\nelif [[ -n \"${NO_COLOR+defined}\" || \"${CLICOLOR}\" = \"0\" || ! -t 1 ]]; then\n  USE_COLOR=\"false\"\nfi\nreadonly USE_COLOR\n# Select Graphic Rendition codes\nif [[ \"${USE_COLOR}\" = \"true\" ]]; then\n  # KISS and use codes rather than tput, avoid dealing with missing tput or TERM.\n  readonly SGR_RESET=\"\\033[0m\"\n  readonly SGR_FAINT=\"\\033[2m\"\n  readonly SGR_RED=\"\\033[31m\"\n  readonly SGR_CYAN=\"\\033[36m\"\nelse\n  readonly SGR_RESET=\n  readonly SGR_FAINT=\n  readonly SGR_RED=\n  readonly SGR_CYAN=\nfi\n\n#\n# set_arch <arch> to override $(uname -a)\n#\n\nset_arch() {\n  if test -n \"$1\"; then\n    ARCH=\"$1\"\n  else\n    abort \"missing -a|--arch value\"\n  fi\n}\n\n#\n# Synopsis: set_insecure\n# Globals modified:\n# - CURL_OPTIONS\n# - WGET_OPTIONS\n#\n\nfunction set_insecure() {\n  CURL_OPTIONS+=( \"--insecure\" )\n  WGET_OPTIONS+=( \"--no-check-certificate\" )\n}\n\n#\n# Synposis: display_major_version numeric-version\n#\ndisplay_major_version() {\n    local version=$1\n    version=\"${version#v}\"\n    version=\"${version%%.*}\"\n    echo \"${version}\"\n}\n\ndisplay_masked_url() {\n  echo \"$1\" | sed -r 's/(https?:\\/\\/[^:]+):([^@]+)@/\\1:****@/'\n}\n\n#\n# Synopsis: update_mirror_settings_for_version version\n# e.g. <nightly/latest> means using download mirror and folder is nightly\n# Globals modified:\n# - g_mirror_url\n# - g_mirror_folder_name\n#\n\nfunction update_mirror_settings_for_version() {\n  if is_download_folder \"$1\" ; then\n    g_mirror_folder_name=\"$1\"\n    g_mirror_url=\"${N_NODE_DOWNLOAD_MIRROR}/${g_mirror_folder_name}\"\n  elif is_download_version \"$1\"; then\n    [[ \"$1\" =~ ^([^/]+)/(.*) ]]\n    local remote_folder=\"${BASH_REMATCH[1]}\"\n    g_mirror_folder_name=\"${remote_folder}\"\n    g_mirror_url=\"${N_NODE_DOWNLOAD_MIRROR}/${g_mirror_folder_name}\"\n  fi\n}\n\n#\n# Synopsis: update_xz_settings_for_version numeric-version\n# Globals modified:\n# - N_USE_XZ\n#\n\nfunction update_xz_settings_for_version() {\n  # tarballs in xz format were available in later version of iojs, but KISS and only use xz from v4.\n  if [[ \"${N_USE_XZ}\" = \"true\" ]]; then\n    local major_version=\"$(display_major_version \"$1\")\"\n    if [[ \"${major_version}\" -lt 4 ]]; then\n      N_USE_XZ=\"false\"\n    fi\n  fi\n}\n\n#\n# Synopsis: update_arch_settings_for_version numeric-version\n# Globals modified:\n# - ARCH\n#\n\nfunction update_arch_settings_for_version() {\n  local tarball_platform=\"$(display_tarball_platform)\"\n  if [[ -z \"${ARCH}\" && \"${tarball_platform}\" = \"darwin-arm64\" ]]; then\n    # First native builds were for v16, but can use x64 in rosetta for older versions.\n    local major_version=\"$(display_major_version \"$1\")\"\n    if [[ \"${major_version}\" -lt 16 ]]; then\n      ARCH=x64\n    fi\n  fi\n}\n\n#\n# Synopsis: is_lts_codename version\n#\n\nfunction is_lts_codename() {\n  # https://github.com/nodejs/Release/blob/master/CODENAMES.md\n  # e.g. argon, Boron\n  [[ \"$1\" =~ ^([Aa]rgon|[Bb]oron|[Cc]arbon|[Dd]ubnium|[Ee]rbium|[Ff]ermium|[Gg]allium|[Hh]ydrogen|[Ii]ron|[Jj]od|[Kk]rypton|[Ll]ithium)$ ]]\n}\n\n#\n# Synopsis: is_download_folder version\n#\n\nfunction is_download_folder() {\n  # e.g. nightly\n  [[ \"$1\" =~ ^(next-nightly|nightly|rc|release|test|v8-canary)$ ]]\n}\n\n#\n# Synopsis: is_download_version version\n#\n\nfunction is_download_version() {\n  # e.g. nightly/, nightly/latest, nightly/v11\n  if [[ \"$1\" =~ ^([^/]+)/(.*) ]]; then\n    local remote_folder=\"${BASH_REMATCH[1]}\"\n    is_download_folder \"${remote_folder}\"\n    return\n  fi\n  return 2\n}\n\n#\n# Synopsis: is_numeric_version version\n#\n\nfunction is_numeric_version() {\n  # e.g. 6, v7.1, 8.11.3\n  [[ \"$1\" =~ ^[v]{0,1}[0-9]+(\\.[0-9]+){0,2}$ ]]\n}\n\n#\n# Synopsis: is_exact_numeric_version version\n#\n\nfunction is_exact_numeric_version() {\n  # e.g. 6, v7.1, 8.11.3\n  [[ \"$1\" =~ ^[v]{0,1}[0-9]+\\.[0-9]+\\.[0-9]+$ ]]\n}\n\n#\n# Synopsis: is_node_support_version version\n# Reference: https://github.com/nodejs/package-maintenance/issues/236#issue-474783582\n#\n\nfunction is_node_support_version() {\n  [[ \"$1\" =~ ^(active|lts_active|lts_latest|lts|current|supported)$ ]]\n}\n\n#\n# Synopsis: display_latest_node_support_alias version\n# Map aliases onto existing n aliases, current and lts\n#\n\nfunction display_latest_node_support_alias() {\n  case \"$1\" in\n    \"active\") printf \"current\" ;;\n    \"lts_active\") printf \"lts\" ;;\n    \"lts_latest\") printf \"lts\" ;;\n    \"lts\") printf \"lts\" ;;\n    \"current\") printf \"current\" ;;\n    \"supported\") printf \"current\" ;;\n    *) printf \"unexpected-version\"\n  esac\n}\n\n#\n# Functions used when showing versions installed\n#\n\nenter_fullscreen() {\n  # Set cursor to be invisible\n  tput civis 2> /dev/null\n  # Save screen contents\n  tput smcup 2> /dev/null\n  stty -echo\n}\n\nleave_fullscreen() {\n  # Set cursor to normal\n  tput cnorm 2> /dev/null\n  # Restore screen contents\n  tput rmcup 2> /dev/null\n  stty echo\n}\n\nhandle_sigint() {\n  leave_fullscreen\n  S=\"$?\"\n  kill 0\n  exit $S\n}\n\nhandle_sigtstp() {\n  leave_fullscreen\n  kill -s SIGSTOP $$\n}\n\n#\n# Output usage information.\n#\n\ndisplay_help() {\n  cat <<-EOF\n\nUsage: n [options] [COMMAND] [args]\n\nCommands:\n\n  n                              Display downloaded Node.js versions and install selection\n  n latest                       Install the latest Node.js release (downloading if necessary)\n  n lts                          Install the latest LTS Node.js release (downloading if necessary)\n  n <version>                    Install Node.js <version> (downloading if necessary)\n  n install <version>            Install Node.js <version> (downloading if necessary)\n  n run <version> [args ...]     Execute downloaded Node.js <version> with [args ...]\n  n which <version>              Output path for downloaded node <version>\n  n exec <vers> <cmd> [args...]  Execute command with modified PATH, so downloaded node <version> and npm first\n  n rm <version ...>             Remove the given downloaded version(s)\n  n prune                        Remove all downloaded versions except the installed version\n  n --latest                     Output the latest Node.js version available\n  n --lts                        Output the latest LTS Node.js version available\n  n ls                           Output downloaded versions\n  n ls-remote [version]          Output matching versions available for download\n  n uninstall                    Remove the installed Node.js\n  n download <version>           Download Node.js <version> into cache\n\nOptions:\n\n  -V, --version         Output version of n\n  -h, --help            Display help information\n  -p, --preserve        Preserve npm and npx during install of Node.js\n  -q, --quiet           Disable curl output. Disable log messages processing \"auto\" and \"engine\" labels.\n  -d, --download        Download if necessary. Used with run/exec/which.\n  --cleanup             Remove cached version after install\n  -a, --arch            Override system architecture\n  --offline             Resolve target version against cached downloads instead of internet lookup\n  --all                 ls-remote displays all matches instead of last 20\n  --insecure            Turn off certificate checking for https requests (may be needed from behind a proxy server)\n  --use-xz/--no-use-xz  Override automatic detection of xz support and enable/disable use of xz compressed node downloads.\n\nAliases:\n\n  install: i\n  latest: current\n  ls: list\n  lsr: ls-remote\n  lts: stable\n  rm: -\n  run: use, as\n  which: bin\n\nVersions:\n\n  Numeric version numbers can be complete or incomplete, with an optional leading 'v'.\n  Versions can also be specified by label, or codename,\n  and other downloadable releases by <remote-folder>/<version>\n\n    4.9.1, 8, v6.1    Numeric versions\n    lts               Newest Long Term Support official release\n    latest, current   Newest official release\n    auto              Read version from file: .n-node-version, .node-version, .nvmrc, or package.json\n    engine            Read version from package.json\n    boron, carbon     Codenames for release streams\n    lts_latest        Node.js support aliases\n\n    and nightly, rc/10 et al\n\nEOF\n}\n\nerr_no_installed_print_help() {\n  display_help\n  abort \"no downloaded versions yet, see above help for commands\"\n}\n\n#\n# Synopsis: next_version_installed selected_version\n# Output version after selected (which may be blank under some circumstances).\n#\n\nfunction next_version_installed() {\n  display_cache_versions | n_grep \"$1\" -A 1 | tail -n 1\n}\n\n#\n# Synopsis: prev_version_installed selected_version\n# Output version before selected  (which may be blank under some circumstances).\n#\n\nfunction prev_version_installed() {\n  display_cache_versions | n_grep \"$1\" -B 1 | head -n 1\n}\n\n#\n# Output n version.\n#\n\ndisplay_n_version() {\n  echo \"$VERSION\" && exit 0\n}\n\n#\n# Synopsis: set_active_node\n# Checks cached downloads for a binary matching the active node.\n# Globals modified:\n# - g_active_node\n#\n\nfunction set_active_node() {\n  g_active_node=\n  local node_path=\"$(command -v node)\"\n  if [[ -x \"${node_path}\" ]]; then\n    local installed_version=$(node --version)\n    installed_version=${installed_version#v}\n    for dir in \"${CACHE_DIR}\"/*/ ; do\n      local folder_name=\"${dir%/}\"\n      folder_name=\"${folder_name##*/}\"\n      if diff &> /dev/null \\\n        \"${CACHE_DIR}/${folder_name}/${installed_version}/bin/node\" \\\n        \"${node_path}\" ; then\n        g_active_node=\"${folder_name}/${installed_version}\"\n        break\n      fi\n    done\n  fi\n}\n\n#\n# Display sorted versions directories paths.\n#\n\ndisplay_versions_paths() {\n  find \"$CACHE_DIR\" -maxdepth 2 -type d \\\n    | sed 's|'\"$CACHE_DIR\"'/||g' \\\n    | n_grep -E \"/[0-9]+\\.[0-9]+\\.[0-9]+\" \\\n    | sed 's|/|.|' \\\n    | sort -k 1,1 -k 2,2n -k 3,3n -k 4,4n -t . \\\n    | sed 's|\\.|/|'\n}\n\n#\n# Display installed versions with <selected>\n#\n\ndisplay_versions_with_selected() {\n  local selected=\"$1\"\n  echo\n  for version in $(display_versions_paths); do\n    if test \"$version\" = \"$selected\"; then\n      printf \"  ${SGR_CYAN}ο${SGR_RESET} %s\\n\" \"$version\"\n    else\n      printf \"    ${SGR_FAINT}%s${SGR_RESET}\\n\" \"$version\"\n    fi\n  done\n  echo\n  printf \"Use up/down arrow keys to select a version, return key to install, d to delete, q to quit\"\n}\n\n#\n# Synopsis: display_cache_versions\n#\n\nfunction display_cache_versions() {\n  for folder_and_version in $(display_versions_paths); do\n    echo \"${folder_and_version}\"\n  done\n}\n\n#\n# Display current node --version and others installed.\n#\n\nmenu_select_cache_versions() {\n  enter_fullscreen\n  set_active_node\n  local selected=\"${g_active_node}\"\n\n  clear\n  display_versions_with_selected \"${selected}\"\n\n  trap handle_sigint INT\n  trap handle_sigtstp SIGTSTP\n\n  ESCAPE_SEQ=$'\\033'\n  UP=$'A'\n  DOWN=$'B'\n  CTRL_P=$'\\020'\n  CTRL_N=$'\\016'\n\n  while true; do\n    read -rsn 1 key\n    case \"$key\" in\n      \"$ESCAPE_SEQ\")\n        # Handle ESC sequences followed by other characters, i.e. arrow keys\n        read -rsn 1 -t 1 tmp\n        # See \"[\" if terminal in normal mode, and \"0\" in application mode\n        if [[ \"$tmp\" == \"[\" || \"$tmp\" == \"O\" ]]; then\n          read -rsn 1 -t 1 arrow\n          case \"$arrow\" in\n            \"$UP\")\n              clear\n              selected=\"$(prev_version_installed \"${selected}\")\"\n              display_versions_with_selected \"${selected}\"\n              ;;\n            \"$DOWN\")\n              clear\n              selected=\"$(next_version_installed \"${selected}\")\"\n              display_versions_with_selected \"${selected}\"\n              ;;\n          esac\n        fi\n        ;;\n      \"d\")\n        if [[ -n \"${selected}\" ]]; then\n          clear\n          # Note: prev/next is constrained to min/max\n          local after_delete_selection=\"$(next_version_installed \"${selected}\")\"\n          if [[ \"${after_delete_selection}\" == \"${selected}\"  ]]; then\n            after_delete_selection=\"$(prev_version_installed \"${selected}\")\"\n          fi\n          remove_versions \"${selected}\"\n\n          if [[ \"${after_delete_selection}\" == \"${selected}\" ]]; then\n            clear\n            leave_fullscreen\n            echo \"All downloaded versions have been deleted from cache.\"\n            exit\n          fi\n\n          selected=\"${after_delete_selection}\"\n          display_versions_with_selected \"${selected}\"\n        fi\n        ;;\n      # Vim or Emacs 'up' key\n      \"k\"|\"$CTRL_P\")\n        clear\n        selected=\"$(prev_version_installed \"${selected}\")\"\n        display_versions_with_selected \"${selected}\"\n        ;;\n      # Vim or Emacs 'down' key\n      \"j\"|\"$CTRL_N\")\n        clear\n        selected=\"$(next_version_installed \"${selected}\")\"\n        display_versions_with_selected \"${selected}\"\n        ;;\n      \"q\")\n        clear\n        leave_fullscreen\n        exit\n        ;;\n      \"\")\n        # enter key returns empty string\n        leave_fullscreen\n        [[ -n \"${selected}\" ]] && activate \"${selected}\"\n        exit\n        ;;\n    esac\n  done\n}\n\n#\n# Move up a line and erase.\n#\n\nerase_line() {\n  printf \"\\033[1A\\033[2K\"\n}\n\n#\n# Disable PaX mprotect for <binary>\n#\n\ndisable_pax_mprotect() {\n  test -z \"$1\" && abort \"binary required\"\n  local binary=\"$1\"\n\n  # try to disable mprotect via XATTR_PAX header\n  local PAXCTL=\"$(PATH=\"/sbin:/usr/sbin:$PATH\" command -v paxctl-ng 2>&1)\"\n  local PAXCTL_ERROR=1\n  if [ -x \"$PAXCTL\" ]; then\n    $PAXCTL -l && $PAXCTL -m \"$binary\" >/dev/null 2>&1\n    PAXCTL_ERROR=\"$?\"\n  fi\n\n  # try to disable mprotect via PT_PAX header\n  if [ \"$PAXCTL_ERROR\" != 0 ]; then\n    PAXCTL=\"$(PATH=\"/sbin:/usr/sbin:$PATH\" command -v paxctl 2>&1)\"\n    if [ -x \"$PAXCTL\" ]; then\n      $PAXCTL -Cm \"$binary\" >/dev/null 2>&1\n    fi\n  fi\n}\n\n#\n# clean_copy_folder <source> <target>\n#\n\nclean_copy_folder() {\n  local source=\"$1\"\n  local target=\"$2\"\n  if [[ -d \"${source}\" ]]; then\n    rm -rf \"${target}\"\n    cp -fR \"${source}\" \"${target}\"\n  fi\n}\n\n#\n# Activate <version>\n#\n\nactivate() {\n  local version=\"$1\"\n  local dir=\"$CACHE_DIR/$version\"\n  local original_node=\"$(command -v node)\"\n  local installed_node=\"${N_PREFIX}/bin/node\"\n  log \"copying\" \"$version\"\n\n\n  # Ideally we would just copy from cache to N_PREFIX, but there are some complications\n  # - various linux versions use symlinks for folders in /usr/local and also error when copy folder onto symlink\n  # - we have used cp for years, so keep using it for backwards compatibility (instead of say rsync)\n  # - we allow preserving npm\n  # - we want to be somewhat robust to changes in tarball contents, so use find instead of hard-code expected subfolders\n  #\n  # This code was purist and concise for a long time.\n  # Now twice as much code, but using same code path for all uses, and supporting more setups.\n\n  # Copy lib before bin so symlink targets exist.\n  # lib\n  mkdir -p \"$N_PREFIX/lib\"\n  # Copy everything except node_modules.\n  find \"$dir/lib\" -mindepth 1 -maxdepth 1 \\! -name node_modules -exec cp -fR \"{}\" \"$N_PREFIX/lib\" \\;\n  if [[ -z \"${N_PRESERVE_NPM}\" ]]; then\n    mkdir -p \"$N_PREFIX/lib/node_modules\"\n    # Copy just npm, skipping possible added global modules after download. Clean copy to avoid version change problems.\n    clean_copy_folder \"$dir/lib/node_modules/npm\" \"$N_PREFIX/lib/node_modules/npm\"\n  fi\n  # Takes same steps for corepack (experimental in node 16.9.0) as for npm, to avoid version problems.\n  if [[ -e \"$dir/lib/node_modules/corepack\" && -z \"${N_PRESERVE_COREPACK}\" ]]; then\n    mkdir -p \"$N_PREFIX/lib/node_modules\"\n    clean_copy_folder \"$dir/lib/node_modules/corepack\" \"$N_PREFIX/lib/node_modules/corepack\"\n  fi\n\n  # bin\n  mkdir -p \"$N_PREFIX/bin\"\n  # Remove old node to avoid potential problems with firewall getting confused on Darwin by overwrite.\n  rm -f \"$N_PREFIX/bin/node\"\n  # Copy bin items by hand, in case user has installed global npm modules into cache.\n  cp -f \"$dir/bin/node\" \"$N_PREFIX/bin\"\n  [[ -e \"$dir/bin/node-waf\" ]] && cp -f \"$dir/bin/node-waf\" \"$N_PREFIX/bin\" # v0.8.x\n  if [[ -z \"${N_PRESERVE_COREPACK}\" ]]; then\n    [[ -e \"$dir/bin/corepack\" ]] && cp -fR \"$dir/bin/corepack\" \"$N_PREFIX/bin\" # from 16.9.0\n  fi\n  if [[ -z \"${N_PRESERVE_NPM}\" ]]; then\n    [[ -e \"$dir/bin/npm\" ]] && cp -fR \"$dir/bin/npm\" \"$N_PREFIX/bin\"\n    [[ -e \"$dir/bin/npx\" ]] && cp -fR \"$dir/bin/npx\" \"$N_PREFIX/bin\"\n  fi\n\n  # include\n  mkdir -p \"$N_PREFIX/include\"\n  find \"$dir/include\" -mindepth 1 -maxdepth 1 -exec cp -fR \"{}\" \"$N_PREFIX/include\" \\;\n\n  # share\n  mkdir -p \"$N_PREFIX/share\"\n  # Copy everything except man, at it is a symlink on some Linux (e.g. archlinux).\n  find \"$dir/share\" -mindepth 1 -maxdepth 1 \\! -name man -exec cp -fR \"{}\" \"$N_PREFIX/share\" \\;\n  mkdir -p \"$N_PREFIX/share/man\"\n  find \"$dir/share/man\" -mindepth 1 -maxdepth 1 -exec cp -fR \"{}\" \"$N_PREFIX/share/man\" \\;\n\n  disable_pax_mprotect \"${installed_node}\"\n\n  local active_node=\"$(command -v node)\"\n  if [[ -e \"${active_node}\" && -e \"${installed_node}\" && \"${active_node}\" != \"${installed_node}\" ]]; then\n    # Installed and active are different which might be a PATH problem. List both to give user some clues.\n    log \"installed\" \"$(\"${installed_node}\" --version) to ${installed_node}\"\n    log \"active\" \"$(\"${active_node}\" --version) at ${active_node}\"\n  else\n    local npm_version_str=\"\"\n    local installed_npm=\"${N_PREFIX}/bin/npm\"\n    local active_npm=\"$(command -v npm)\"\n    if [[ -z \"${N_PRESERVE_NPM}\" && -e \"${active_npm}\" && -e \"${installed_npm}\" && \"${active_npm}\" = \"${installed_npm}\" ]]; then\n      npm_version_str=\" (with npm $(npm --version))\"\n    fi\n\n    log \"installed\" \"$(\"${installed_node}\" --version)${npm_version_str}\"\n\n    # Extra tips for changed location.\n    if [[ -e \"${active_node}\" && -e \"${original_node}\" && \"${active_node}\" != \"${original_node}\" ]]; then\n      printf '\\nNote: the node command changed location and the old location may be remembered in your current shell.\\n'\n      log old \"${original_node}\"\n      log new \"${active_node}\"\n      printf 'If \"node --version\" shows the old version then start a new shell, or reset the location hash with:\\nhash -r  (for bash, zsh, ash, dash, and ksh)\\nrehash   (for csh and tcsh)\\n'\n    fi\n  fi\n\n  if [[ \"$CLEANUP\" == \"true\" ]]; then\n    log \"cleanup\" \"removing cached $version\"\n    remove_versions \"$version\"\n  fi\n\n}\n\n#\n# Install <version>\n#\n\ninstall() {\n  [[ -z \"$1\" ]] && abort \"version required\"\n  local version\n  get_latest_resolved_version \"$1\" || return 2\n  version=\"${g_target_node}\"\n  [[ -n \"${version}\" ]] || abort \"no version found for '$1'\"\n  update_mirror_settings_for_version \"$1\"\n  update_xz_settings_for_version \"${version}\"\n  update_arch_settings_for_version \"${version}\"\n\n  local dir=\"${CACHE_DIR}/${g_mirror_folder_name}/${version}\"\n\n  # Note: decompression flags ignored with default Darwin tar which autodetects.\n  if test \"$N_USE_XZ\" = \"true\"; then\n    local tarflag=\"-Jx\"\n  else\n    local tarflag=\"-zx\"\n  fi\n\n  if test -d \"$dir\"; then\n    if [[ ! -e \"$dir/n.lock\" ]] ; then\n      if [[ \"$DOWNLOAD\" == \"false\" ]] ; then\n        activate \"${g_mirror_folder_name}/${version}\"\n      else\n        log downloaded \"${g_mirror_folder_name}/${version} already in cache\"\n      fi\n      exit\n    fi\n  fi\n  if [[ \"$OFFLINE\" == \"true\" ]]; then\n    abort \"version unavailable offline\"\n  fi\n\n  if [[ \"$DOWNLOAD\" == \"false\" ]]; then\n    log installing \"${g_mirror_folder_name}-v$version\"\n  else\n    log download \"${g_mirror_folder_name}-v$version\"\n  fi\n\n  local url=\"$(tarball_url \"$version\")\"\n  is_ok \"${url}\" || abort \"download preflight failed for '$version' ($(display_masked_url \"${url}\"))\"\n\n  log mkdir \"$dir\"\n  mkdir -p \"$dir\" || abort \"sudo required (or change ownership, or define N_PREFIX)\"\n  touch \"$dir/n.lock\"\n\n  cd \"${dir}\" || abort \"Failed to cd to ${dir}\"\n\n  log fetch \"$(display_masked_url \"${url}\")\"\n  do_get \"${url}\" | tar \"$tarflag\" --strip-components=1 --no-same-owner -f -\n  pipe_results=( \"${PIPESTATUS[@]}\" )\n  if [[ \"${pipe_results[0]}\" -ne 0 ]]; then\n    abort \"failed to download archive for $version\"\n  fi\n  if [[ \"${pipe_results[1]}\" -ne 0 ]]; then\n    abort \"failed to extract archive for $version\"\n  fi\n  [ \"$GET_SHOWS_PROGRESS\" = \"true\" ] && erase_line\n  rm -f \"$dir/n.lock\"\n\n  disable_pax_mprotect bin/node\n\n  if [[ \"$DOWNLOAD\" == \"false\" ]]; then\n    activate \"${g_mirror_folder_name}/$version\"\n  fi\n}\n\n#\n# Be more silent.\n#\n\nset_quiet() {\n  SHOW_VERBOSE_LOG=\"false\"\n  command -v curl > /dev/null && CURL_OPTIONS+=( \"--silent\" ) && GET_SHOWS_PROGRESS=\"false\"\n}\n\n#\n# Synopsis: do_get [option...] url\n# Call curl or wget with combination of global and passed options.\n#\n\nfunction do_get() {\n  if command -v curl &> /dev/null; then\n    curl \"${CURL_OPTIONS[@]}\" \"$@\"\n  elif command -v wget &> /dev/null; then\n    wget \"${WGET_OPTIONS[@]}\" \"$@\"\n  else\n    abort \"curl or wget command required\"\n  fi\n}\n\n#\n# Synopsis: do_get_index [option...] url\n# Call curl or wget with combination of global and passed options,\n# with options tweaked to be more suitable for getting index.\n#\n\nfunction do_get_index() {\n  if command -v curl &> /dev/null; then\n    # --silent to suppress progress et al\n    curl --silent \"${CURL_OPTIONS[@]}\" \"$@\"\n  elif command -v wget &> /dev/null; then\n    wget \"${WGET_OPTIONS[@]}\" \"$@\"\n  else\n    abort \"curl or wget command required\"\n  fi\n}\n\n#\n# Synopsis: remove_versions version ...\n#\n\nfunction remove_versions() {\n  [[ -z \"$1\" ]] && abort \"version(s) required\"\n  while [[ $# -ne 0 ]]; do\n    local version\n    get_latest_resolved_version \"$1\" || break\n    version=\"${g_target_node}\"\n    if [[ -n \"${version}\" ]]; then\n      update_mirror_settings_for_version \"$1\"\n      local dir=\"${CACHE_DIR}/${g_mirror_folder_name}/${version}\"\n      if [[ -s \"${dir}\" ]]; then\n        rm -rf \"${dir}\"\n      else\n        echo \"$1 (${version}) not in downloads cache\"\n      fi\n    else\n      echo \"No version found for '$1'\"\n    fi\n    shift\n  done\n}\n\n#\n# Synopsis: prune_cache\n#\n\nfunction prune_cache() {\n  set_active_node\n\n  for folder_and_version in $(display_versions_paths); do\n    if [[ \"${folder_and_version}\" != \"${g_active_node}\" ]]; then\n      echo \"${folder_and_version}\"\n      rm -rf \"${CACHE_DIR:?}/${folder_and_version}\"\n    fi\n  done\n}\n\n#\n# Synopsis: find_cached_version version\n# Finds cache directory for resolved version.\n# Globals modified:\n# - g_cached_version\n\nfunction find_cached_version() {\n  [[ -z \"$1\" ]] && abort \"version required\"\n  local version\n  get_latest_resolved_version \"$1\" || exit 1\n  version=\"${g_target_node}\"\n  [[ -n \"${version}\" ]] || abort \"no version found for '$1'\"\n\n  update_mirror_settings_for_version \"$1\"\n  g_cached_version=\"${CACHE_DIR}/${g_mirror_folder_name}/${version}\"\n  if [[ ! -d \"${g_cached_version}\" && \"${DOWNLOAD}\" == \"true\" ]]; then\n    (install \"${version}\")\n  fi\n  [[ -d \"${g_cached_version}\" ]] || abort \"'$1' (${version}) not in downloads cache\"\n}\n\n\n#\n# Synopsis: display_bin_path_for_version version\n#\n\nfunction display_bin_path_for_version() {\n  find_cached_version \"$1\"\n  echo \"${g_cached_version}/bin/node\"\n}\n\n#\n# Synopsis: run_with_version version [args...]\n# Run the given <version> of node with [args ..]\n#\n\nfunction run_with_version() {\n  find_cached_version \"$1\"\n  shift # remove version from parameters\n  exec \"${g_cached_version}/bin/node\" \"$@\"\n}\n\n#\n# Synopsis: exec_with_version <version> command [args...]\n# Modify the path to include <version> and execute command.\n#\n\nfunction exec_with_version() {\n  find_cached_version \"$1\"\n  shift # remove version from parameters\n  PATH=\"${g_cached_version}/bin:$PATH\" exec \"$@\"\n}\n\n#\n# Synopsis: is_ok url\n# Check the HEAD response of <url>.\n#\n\nfunction is_ok() {\n  # Note: both curl and wget can follow redirects, as present on some mirrors (e.g. https://npm.taobao.org/mirrors/node).\n  # The output is complicated with redirects, so keep it simple and use command status rather than parse output.\n  if command -v curl &> /dev/null; then\n    do_get --silent --head \"$1\" > /dev/null || return 1\n  else\n    do_get --spider \"$1\" > /dev/null || return 1\n  fi\n}\n\n#\n# Synopsis: can_use_xz\n# Test system to see if xz decompression is supported by tar.\n#\n\nfunction can_use_xz() {\n  # Be conservative and only enable if xz is likely to work. Unfortunately we can't directly query tar itself.\n  # For research, see https://github.com/shadowspawn/nvh/issues/8\n  local uname_s=\"$(uname -s)\"\n  if [[ \"${uname_s}\" = \"Linux\" ]] && command -v xz &> /dev/null ; then\n    # tar on linux is likely to support xz if it is available as a command\n    return 0\n  elif [[ \"${uname_s}\" = \"Darwin\" ]]; then\n    local macos_version=\"$(sw_vers -productVersion)\"\n    local macos_major_version=\"$(echo \"${macos_version}\" | cut -d '.' -f 1)\"\n    local macos_minor_version=\"$(echo \"${macos_version}\" | cut -d '.' -f 2)\"\n    if [[ \"${macos_major_version}\" -gt 10 || \"${macos_minor_version}\" -gt 8 ]]; then\n      # tar on recent Darwin has xz support built-in\n      return 0\n    fi\n  fi\n  return 2 # not supported\n}\n\n#\n# Synopsis: display_tarball_platform\n#\n\nfunction display_tarball_platform() {\n  # https://en.wikipedia.org/wiki/Uname\n\n  local os=\"unexpected_os\"\n  local uname_a=\"$(uname -a)\"\n  case \"${uname_a}\" in\n    Linux*) os=\"linux\" ;;\n    Darwin*) os=\"darwin\" ;;\n    SunOS*) os=\"sunos\" ;;\n    AIX*) os=\"aix\" ;;\n    CYGWIN*) >&2 echo_red \"Cygwin is not supported by n\" ;;\n    MINGW*) >&2 echo_red \"Git BASH (MSYS) is not supported by n\" ;;\n  esac\n\n  # architecture might already be known from (priority order):\n  # * --arch flag on the command line,\n  # * otherwise, from $N_ARCH\n  # * otherwise from version specific adjustment (if applicable, see update_arch_settings_for_version)\n  local arch=\"$ARCH\"\n  if [[ -z \"$arch\" ]]; then\n    arch=\"unexpected_arch\"\n    local uname_m=\"$(uname -m)\"\n    case \"${uname_m}\" in\n      x86_64) arch=x64 ;;\n      i386 | i686) arch=\"x86\" ;;\n      aarch64) arch=arm64 ;;\n      armv8l) arch=arm64 ;; # armv8l probably supports arm64, and there is no specific armv8l build so give it a go\n      *)\n        # e.g. armv6l, armv7l, arm64\n        arch=\"${uname_m}\"\n        ;;\n    esac\n  fi\n\n  echo \"${os}-${arch}\"\n}\n\n#\n# Synopsis: display_compatible_file_field\n# display <file> for current platform, as per <file> field in index.tab, which is different than actual download\n#\n\nfunction display_compatible_file_field {\n  local compatible_file_field=\"$(display_tarball_platform)\"\n  if [[ -z \"${ARCH}\" && \"${compatible_file_field}\" = \"darwin-arm64\" ]]; then\n    # Look for arm64 for native but also x64 for older versions which can run in rosetta.\n    # (Downside is will get an install error if install version above 16 with x64 and not arm64.)\n    compatible_file_field=\"osx-arm64-tar|osx-x64-tar\"\n  elif [[ \"${compatible_file_field}\" =~ darwin-(.*) ]]; then\n    compatible_file_field=\"osx-${BASH_REMATCH[1]}-tar\"\n  fi\n  echo \"${compatible_file_field}\"\n}\n\n#\n# Synopsis: tarball_url version\n#\n\nfunction tarball_url() {\n  local version=\"$1\"\n  local ext=gz\n  [ \"$N_USE_XZ\" = \"true\" ] && ext=\"xz\"\n  echo \"${g_mirror_url}/v${version}/node-v${version}-$(display_tarball_platform).tar.${ext}\"\n}\n\n#\n# Synopsis: get_file_node_version filename\n# Sets g_target_node\n#\n\nfunction get_file_node_version() {\n  g_target_node=\n  local filepath=\"$1\"\n  verbose_log \"found\" \"${filepath}\"\n  # read returns a non-zero status but does still work if there is no line ending\n  local version\n  <\"${filepath}\" read -r version\n  # trim possible trailing \\d from a Windows created file\n  version=\"${version%%[[:space:]]}\"\n  verbose_log \"read\" \"${version}\"\n  g_target_node=\"${version}\"\n}\n\n#\n# Synopsis: get_package_engine_version\\\n# Sets g_target_node\n#\n\nfunction get_package_engine_version() {\n  g_target_node=\n  local filepath=\"$1\"\n  verbose_log \"found\" \"${filepath}\"\n  local range\n  if command -v jq &> /dev/null; then\n    range=\"$(jq -r '.engines.node // \"\"' < \"${filepath}\")\"\n  elif command -v node &> /dev/null; then\n    range=\"$(node -e \"package = require('${filepath}'); if (package && package.engines && package.engines.node) console.log(package.engines.node)\")\"\n  else\n    abort \"either jq or an active version of node is required to read 'engines' from package.json\"\n  fi\n  verbose_log \"read\" \"${range}\"\n  [[ -n \"${range}\" ]] || return 2\n  if [[ \"*\" == \"${range}\" ]]; then\n    verbose_log \"target\" \"current\"\n    g_target_node=\"current\"\n    return\n  fi\n\n  local version\n  if [[ \"${range}\" =~ ^([>~^=]|\\>\\=)?v?([0-9]+(\\.[0-9]+){0,2})(.[xX*])?$ ]]; then\n    local operator=\"${BASH_REMATCH[1]}\"\n    version=\"${BASH_REMATCH[2]}\"\n    case \"${operator}\" in\n      '' | =) ;;\n      \\> | \\>=) version=\"current\" ;;\n      \\~) [[ \"${version}\" =~ ^([0-9]+\\.[0-9]+)\\.[0-9]+$ ]] && version=\"${BASH_REMATCH[1]}\" ;;\n      ^) [[ \"${version}\" =~ ^([0-9]+) ]] && version=\"${BASH_REMATCH[1]}\" ;;\n    esac\n    verbose_log \"target\" \"${version}\"\n  else\n    command -v npx &> /dev/null || abort \"an active version of npx is required to use complex 'engine' ranges from package.json\"\n    [[ \"$OFFLINE\" != \"true\" ]] || abort \"offline: an internet connection is required for looking up complex 'engine' ranges from package.json\"\n    verbose_log \"resolving\" \"${range}\"\n    local version_per_line=\"$(n lsr --all)\"\n    local versions_one_line=$(echo \"${version_per_line}\" | tr '\\n' ' ')\n    # Using semver@7 so works with older versions of node.\n    # shellcheck disable=SC2086\n    version=$(npm_config_yes=true npx --quiet semver@7 -r \"${range}\" ${versions_one_line} | tail -n 1)\n  fi\n  g_target_node=\"${version}\"\n}\n\n#\n# Synopsis: get_nvmrc_version\n# Sets g_target_node\n#\n\nfunction get_nvmrc_version() {\n  g_target_node=\n  local filepath=\"$1\"\n  verbose_log \"found\" \"${filepath}\"\n  local version\n  <\"${filepath}\" read -r version\n  # remove trailing comment, after #\n  version=\"$(echo \"${version}\" | sed 's/[[:space:]]*#.*//')\"\n  verbose_log \"read\" \"${version}\"\n  # Translate from nvm aliases\n  case \"${version}\" in\n    lts/\\*) version=\"lts\" ;;\n    lts/*) version=\"${version:4}\" ;;\n    node) version=\"current\" ;;\n    *) ;;\n  esac\n  g_target_node=\"${version}\"\n}\n\n#\n# Synopsis: get_engine_version [error-message]\n# Sets g_target_node\n#\n\nfunction get_engine_version() {\n  g_target_node=\n  local error_message=\"${1-package.json not found}\"\n  local parent\n  parent=\"${PWD}\"\n  while [[ -n \"${parent}\" ]]; do\n    if [[ -e \"${parent}/package.json\" ]]; then\n      get_package_engine_version \"${parent}/package.json\"\n    else\n      parent=${parent%/*}\n      continue\n    fi\n    break\n  done\n  [[ -n \"${parent}\" ]] || abort \"${error_message}\"\n  [[ -n \"${g_target_node}\" ]] || abort \"did not find supported version of node in 'engines' field of package.json\"\n}\n\n#\n# Synopsis: get_auto_version\n# Sets g_target_node\n#\n\nfunction get_auto_version() {\n  g_target_node=\n  # Search for a version control file first\n  local parent\n  parent=\"${PWD}\"\n  while [[ -n \"${parent}\" ]]; do\n    if [[ -e \"${parent}/.n-node-version\" ]]; then\n      get_file_node_version \"${parent}/.n-node-version\"\n    elif [[ -e \"${parent}/.node-version\" ]]; then\n      get_file_node_version \"${parent}/.node-version\"\n    elif [[ -e \"${parent}/.nvmrc\" ]]; then\n      get_nvmrc_version \"${parent}/.nvmrc\"\n    else\n      parent=${parent%/*}\n      continue\n    fi\n    break\n  done\n  # Fallback to package.json\n  [[ -n \"${parent}\" ]] || get_engine_version \"no file found for auto version (.n-node-version, .node-version, .nvmrc, or package.json)\"\n  [[ -n \"${g_target_node}\" ]] || abort \"file found for auto did not contain target version of node\"\n}\n\n#\n# Synopsis: get_latest_resolved_version version\n# Sets g_target_node\n#\n\nfunction get_latest_resolved_version() {\n  g_target_node=\n  local version=${1}\n\n  # Transform some labels before processing further to allow fast-track for exact numeric versions.\n  if [[ \"${version}\" = \"auto\" ]]; then\n    get_auto_version || return 2\n    version=\"${g_target_node}\"\n  elif [[ \"${version}\" = \"engine\" ]]; then\n    get_engine_version || return 2\n    version=\"${g_target_node}\"\n  fi\n\n  simple_version=${version#node/} # Only place supporting node/ [sic]\n  if is_exact_numeric_version \"${simple_version}\"; then\n    # Just numbers, already resolved, no need to lookup first.\n    simple_version=\"${simple_version#v}\"\n    g_target_node=\"${simple_version}\"\n  elif [[ \"$OFFLINE\" == \"true\" ]]; then\n    g_target_node=$(display_local_versions \"${version}\")\n  else\n    # Complicated recognising exact version, KISS and lookup.\n    g_target_node=$(N_MAX_REMOTE_MATCHES=1 display_remote_versions \"$version\")\n  fi\n}\n\n#\n# Synopsis: display_remote_index\n# index.tab reference: https://github.com/nodejs/nodejs-dist-indexer\n# Index fields are: version\tdate\tfiles\tnpm\tv8\tuv\tzlib\topenssl\tmodules\tlts security\n# KISS and just return fields we currently care about: version files lts\n#\n\ndisplay_remote_index() {\n  local index_url=\"${g_mirror_url}/index.tab\"\n  # tail to remove header line\n  do_get_index \"${index_url}\" | tail -n +2 | cut -f 1,3,10\n  if [[ \"${PIPESTATUS[0]}\" -ne 0 ]]; then\n    # Reminder: abort will only exit subshell, but consistent error display\n    abort \"failed to download version index ($(display_masked_url \"${index_url}\"))\"\n  fi\n}\n\n#\n# Synopsis: display_match_limit limit\n#\n\nfunction display_match_limit(){\n  if [[ \"$1\" -gt 1 && \"$1\" -lt 32000 ]]; then\n    echo \"Listing remote... Displaying $1 matches (use --all to see all).\"\n  fi\n}\n\n#\n# Synopsis: display_local_versions version\n#\n\nfunction display_local_versions() {\n  local version=\"$1\"\n  local match='.'\n  verbose_log \"offline\" \"matching cached versions\"\n\n    # Transform some labels before processing further.\n  if is_node_support_version \"${version}\"; then\n    version=\"$(display_latest_node_support_alias \"${version}\")\"\n    match_count=1\n  elif [[ \"${version}\" = \"auto\" ]]; then\n    get_auto_version || return 2\n    version=\"${g_target_node}\"\n  elif [[ \"${version}\" = \"engine\" ]]; then\n    get_engine_version || return 2\n    version=\"${g_target_node}\"\n  fi\n\n  if [[ \"${version}\" = \"latest\" || \"${version}\" = \"current\" ]]; then\n    match='^node/.'\n  elif is_exact_numeric_version \"${version}\"; then\n    # Quote any dots in version so they are literal for expression\n    match=\"^node/${version//\\./\\.}\"\n  elif is_numeric_version \"${version}\"; then\n    version=\"${version#v}\"\n    # Quote any dots in version so they are literal for expression\n    match=\"${version//\\./\\.}\"\n    # Avoid 1.2 matching 1.23\n    match=\"^node/${match}[^0-9]\"\n  # elif is_lts_codename \"${version}\"; then\n  # see if demand\n  elif is_download_folder \"${version}\"; then\n    match=\"^${version}/\"\n  # elif is_download_version \"${version}\"; then\n  # see if demand\n  else\n    abort \"invalid version '$1' for offline matching\"\n  fi\n\n  display_versions_paths \\\n    | n_grep -E \"${match}\" \\\n    | tail -n 1 \\\n    | sed 's|node/||'\n}\n\n#\n# Synopsis: display_remote_versions version\n#\n\nfunction display_remote_versions() {\n  local version=\"$1\"\n  update_mirror_settings_for_version \"${version}\"\n  local match='.'\n  local match_count=\"${N_MAX_REMOTE_MATCHES}\"\n\n  # Transform some labels before processing further.\n  if is_node_support_version \"${version}\"; then\n    version=\"$(display_latest_node_support_alias \"${version}\")\"\n    match_count=1\n  elif [[ \"${version}\" = \"auto\" ]]; then\n    get_auto_version || return 2\n    version=\"${g_target_node}\"\n  elif [[ \"${version}\" = \"engine\" ]]; then\n    get_engine_version || return 2\n    version=\"${g_target_node}\"\n  fi\n\n  if [[ -z \"${version}\" ]]; then\n    match='.'\n  elif [[ \"${version}\" = \"lts\" || \"${version}\" = \"stable\" ]]; then\n    match_count=1\n    # Codename is last field, first one with a name is newest lts\n    match=\"${TAB_CHAR}[a-zA-Z]+\\$\"\n  elif [[ \"${version}\" = \"latest\" || \"${version}\" = \"current\" ]]; then\n    match_count=1\n    match='.'\n  elif is_numeric_version \"${version}\"; then\n    version=\"v${version#v}\"\n    # Avoid restriction message if exact version\n    is_exact_numeric_version \"${version}\" && match_count=1\n    # Quote any dots in version so they are literal for expression\n    match=\"${version//\\./\\.}\"\n    # Avoid 1.2 matching 1.23\n    match=\"^${match}[^0-9]\"\n  elif is_lts_codename \"${version}\"; then\n    # Capitalise (could alternatively make grep case insensitive)\n    codename=\"$(echo \"${version:0:1}\" | tr '[:lower:]' '[:upper:]')${version:1}\"\n    # Codename is last field\n    match=\"${TAB_CHAR}${codename}\\$\"\n  elif is_download_folder \"${version}\"; then\n    match='.'\n  elif is_download_version \"${version}\"; then\n    version=\"${version#\"${g_mirror_folder_name}\"/}\"\n    if [[ \"${version}\" = \"latest\" || \"${version}\" = \"current\" ]]; then\n      match_count=1\n      match='.'\n    else\n      version=\"v${version#v}\"\n      match=\"${version//\\./\\.}\"\n      match=\"^${match}\" # prefix\n      if is_numeric_version \"${version}\"; then\n        # Exact numeric match\n        match=\"${match}[^0-9]\"\n      fi\n    fi\n  else\n    abort \"invalid version '$1'\"\n  fi\n  display_match_limit \"${match_count}\"\n\n  # Implementation notes:\n  # - using awk rather than head so do not close pipe early on curl\n  # - restrict search to compatible files as not always available, or not at same time\n  # - return status of curl command (i.e. PIPESTATUS[0])\n  display_remote_index \\\n    | n_grep -E \"$(display_compatible_file_field)\" \\\n    | n_grep -E \"${match}\" \\\n    | awk \"NR<=${match_count}\" \\\n    | cut -f 1 \\\n    | n_grep -E -o '[^v].*'\n  return \"${PIPESTATUS[0]}\"\n}\n\n#\n# Synopsis: delete_with_echo target\n#\n\nfunction delete_with_echo() {\n  if [[ -e \"$1\" ]]; then\n    echo \"$1\"\n    rm -rf \"$1\"\n  fi\n}\n\n#\n# Synopsis: uninstall_installed\n# Uninstall the installed node and npm (leaving alone the cache),\n# so undo install, and may expose possible system installed versions.\n#\n\nuninstall_installed() {\n  # npm: https://docs.npmjs.com/misc/removing-npm\n  #   rm -rf /usr/local/{lib/node{,/.npm,_modules},bin,share/man}/npm*\n  # node: https://stackabuse.com/how-to-uninstall-node-js-from-mac-osx/\n  # Doing it by hand rather than scanning cache, so still works if cache deleted first.\n  # This covers tarballs for at least node 4 through 10.\n\n  while true; do\n      read -r -p \"Do you wish to delete node and npm from ${N_PREFIX}? \" yn\n      case $yn in\n          [Yy]* ) break ;;\n          [Nn]* ) exit ;;\n          * ) echo \"Please answer yes or no.\";;\n      esac\n  done\n\n  echo \"\"\n  echo \"Uninstalling node and npm\"\n  delete_with_echo \"${N_PREFIX}/bin/node\"\n  delete_with_echo \"${N_PREFIX}/bin/npm\"\n  delete_with_echo \"${N_PREFIX}/bin/npx\"\n  delete_with_echo \"${N_PREFIX}/bin/corepack\"\n  delete_with_echo \"${N_PREFIX}/include/node\"\n  delete_with_echo \"${N_PREFIX}/lib/dtrace/node.d\"\n  delete_with_echo \"${N_PREFIX}/lib/node_modules/npm\"\n  delete_with_echo \"${N_PREFIX}/lib/node_modules/corepack\"\n  delete_with_echo \"${N_PREFIX}/share/doc/node\"\n  delete_with_echo \"${N_PREFIX}/share/man/man1/node.1\"\n  delete_with_echo \"${N_PREFIX}/share/systemtap/tapset/node.stp\"\n}\n\n#\n# Synopsis: show_permission_suggestions\n#\n\nfunction show_permission_suggestions() {\n  echo \"Suggestions:\"\n  echo \"- run n with sudo, or\"\n  if [[ \"${N_CACHE_PREFIX}\" == \"${N_PREFIX}\" ]]; then\n    echo \"- define N_PREFIX to a writeable location, or\"\n  else\n    echo \"- define N_PREFIX and N_CACHE_PREFIX to writeable locations, or\"\n  fi\n}\n\n#\n# Synopsis: show_diagnostics\n# Show environment and check for common problems.\n#\n\nfunction show_diagnostics() {\n  echo \"This information is to help you diagnose issues, and useful when reporting an issue.\"\n  echo \"Note: some output may contain passwords. Redact before sharing.\"\n\n  printf \"\\n\\nCOMMAND LOCATIONS AND VERSIONS\\n\"\n\n  printf \"\\nbash\\n\"\n  command -v bash && bash --version\n\n  printf \"\\nn\\n\"\n  command -v n && n --version\n\n  printf \"\\nnode\\n\"\n  if command -v node &> /dev/null; then\n    node --version\n    node -e 'if (process.versions.v8) console.log(\"JavaScript engine: v8\");'\n\n    printf \"\\nnpm\\n\"\n    command -v npm && npm --version\n  fi\n\n  printf \"\\ntar\\n\"\n  if command -v tar &> /dev/null; then\n    tar --version\n  else\n    echo_red \"tar not found. Needed for extracting downloads.\"\n  fi\n\n  printf \"\\ncurl or wget\\n\"\n  if command -v curl &> /dev/null; then\n    curl --version\n  elif command -v wget &> /dev/null; then\n    wget --version\n  else\n    echo_red \"Neither curl nor wget found. Need one of them for downloads.\"\n  fi\n\n  printf \"\\njq\\n\"\n  command -v jq && jq --version\n\n  printf \"\\nuname\\n\"\n  uname -a\n\n  printf \"\\n\\nSETTINGS\\n\"\n\n  printf \"\\nn\\n\"\n  echo \"node mirror: $(display_masked_url \"${N_NODE_MIRROR}\")\"\n  echo \"node downloads mirror: $(display_masked_url \"${N_NODE_DOWNLOAD_MIRROR}\")\"\n  echo \"install destination: ${N_PREFIX}\"\n  [[ -n \"${N_PREFIX}\" ]] && echo \"PATH: ${PATH}\"\n  [[ -n \"$N_ARCH\" ]] && echo \"default arch: $N_ARCH\"\n  echo \"ls-remote max matches: ${N_MAX_REMOTE_MATCHES}\"\n   [[ -n \"${N_PRESERVE_NPM}\" ]] && echo \"installs preserve npm by default\"\n   [[ -n \"${N_PRESERVE_COREPACK}\" ]] && echo \"installs preserve corepack by default\"\n\n  printf \"\\nProxy\\n\"\n  # disable \"var is referenced but not assigned\": https://github.com/koalaman/shellcheck/wiki/SC2154\n  # shellcheck disable=SC2154\n  [[ -n \"${http_proxy}\" ]] && echo \"http_proxy: ${http_proxy}\"\n  # shellcheck disable=SC2154\n  [[ -n \"${https_proxy}\" ]] && echo \"https_proxy: ${https_proxy}\"\n  if command -v curl &> /dev/null; then\n    # curl supports lower case and upper case!\n    # shellcheck disable=SC2154\n    [[ -n \"${all_proxy}\" ]] && echo \"all_proxy: ${all_proxy}\"\n    [[ -n \"${ALL_PROXY}\" ]] && echo \"ALL_PROXY: ${ALL_PROXY}\"\n    [[ -n \"${HTTP_PROXY}\" ]] && echo \"HTTP_PROXY: ${HTTP_PROXY}\"\n    [[ -n \"${HTTPS_PROXY}\" ]] && echo \"HTTPS_PROXY: ${HTTPS_PROXY}\"\n    if [[ -e \"${CURL_HOME}/.curlrc\" ]]; then\n       echo \"have \\$CURL_HOME/.curlrc\"\n    elif [[ -e \"${HOME}/.curlrc\" ]]; then\n      echo \"have \\$HOME/.curlrc\"\n    fi\n  elif command -v wget &> /dev/null; then\n    if [[ -e \"${WGETRC}\" ]]; then\n      echo \"have \\$WGETRC\"\n    elif [[ -e \"${HOME}/.wgetrc\" ]]; then\n      echo \"have \\$HOME/.wgetrc\"\n    fi\n  fi\n\n  printf \"\\n\\nCHECKS\\n\"\n\n  printf \"\\nChecking n install destination is in PATH...\\n\"\n  local install_bin=\"${N_PREFIX}/bin\"\n  local path_wth_guards=\":${PATH}:\"\n  if [[ \"${path_wth_guards}\" =~ :${install_bin}/?: ]]; then\n    printf \"good\\n\"\n  else\n    echo_red \"'${install_bin}' is not in PATH\"\n  fi\n  if command -v node &> /dev/null; then\n    printf \"\\nChecking n install destination priority in PATH...\\n\"\n    local node_dir=\"$(dirname \"$(command -v node)\")\"\n\n    local index=0\n    local path_entry\n    local path_entries\n    local install_bin_index=0\n    local node_index=999\n    IFS=':' read -ra path_entries <<< \"${PATH}\"\n    for path_entry in \"${path_entries[@]}\"; do\n      (( index++ ))\n      [[ \"${path_entry}\" =~ ^${node_dir}/?$ ]] && node_index=\"${index}\"\n      [[ \"${path_entry}\" =~ ^${install_bin}/?$ ]] && install_bin_index=\"${index}\"\n    done\n    if [[ \"${node_index}\" -lt \"${install_bin_index}\" ]]; then\n      echo_red \"There is a version of node installed which will be found in PATH before the n installed version.\"\n    else\n      printf \"good\\n\"\n    fi\n  fi\n\n  # Check npm too. Simpler check than for PATH and node, more like the runtime logging for active/installed node.\n  if [[ -z \"${N_PRESERVE_NPM}\" ]]; then\n    printf \"\\nChecking npm install destination...\\n\"\n    local installed_npm=\"${N_PREFIX}/bin/npm\"\n    local active_npm=\"$(command -v npm)\"\n    if [[ -e \"${active_npm}\" && -e \"${installed_npm}\" && \"${active_npm}\" != \"${installed_npm}\" ]]; then\n      echo_red \"There is an active version of npm shadowing the version installed by n. Check order of entries in PATH.\"\n      log \"installed\" \"${installed_npm}\"\n      log \"active\" \"${active_npm}\"\n    else\n      printf \"good\\n\"\n    fi\n  fi\n\n  printf \"\\nChecking prefix folders...\\n\"\n  if [[ ! -e \"${N_PREFIX}\" ]]; then\n    echo \"Folder does not exist: ${N_PREFIX}\"\n    echo \"- This folder will be created when you do an install.\"\n  fi\n  if [[ \"${N_PREFIX}\" != \"${N_CACHE_PREFIX}\" && ! -e \"${N_CACHE_PREFIX}\" ]]; then\n    echo \"Folder does not exist: ${N_CACHE_PREFIX}\"\n    echo \"- This folder will be created when you do an install.\"\n  fi\n  if [[ -e \"${N_PREFIX}\" && -e \"${N_CACHE_PREFIX}\" ]]; then\n    echo \"good\"\n  fi\n\n  if [[ -e \"${N_CACHE_PREFIX}\" ]]; then\n    printf \"\\nChecking permissions for cache folder...\\n\"\n    # Using knowledge cache path ends in /n/versions in following check.\n    if [[ ! -e \"${CACHE_DIR}\" && (( -e \"${N_CACHE_PREFIX}/n\" && ! -w \"${N_CACHE_PREFIX}/n\" ) || ( ! -e \"${N_CACHE_PREFIX}/n\" && ! -w \"${N_CACHE_PREFIX}\" )) ]]; then\n      echo_red \"You do not have write permission to create: ${CACHE_DIR}\"\n      show_permission_suggestions\n      echo \"- make a folder you own:\"\n      echo \"      sudo mkdir -p \\\"${CACHE_DIR}\\\"\"\n      echo \"      sudo chown $(whoami) \\\"${CACHE_DIR}\\\"\"\n    elif [[ ! -e \"${CACHE_DIR}\" ]]; then\n      echo \"Cache folder does not exist: ${CACHE_DIR}\"\n      echo \"- This is normal if you have not done an install yet, as cache is only created when needed.\"\n    elif [[ ! -w \"${CACHE_DIR}\" ]]; then\n      echo_red \"You do not have write permission to: ${CACHE_DIR}\"\n      show_permission_suggestions\n      echo \"- change folder ownership to yourself:\"\n      echo \"      sudo chown -R $(whoami) \\\"${CACHE_DIR}\\\"\"\n    else\n      echo \"good\"\n    fi\n  fi\n\n  if [[ -e \"${N_PREFIX}\" ]]; then\n    printf \"\\nChecking permissions for install folders...\\n\"\n    local install_writeable=\"true\"\n    for subdir in bin lib include share; do\n      if [[ -e \"${N_PREFIX}/${subdir}\" && ! -w \"${N_PREFIX}/${subdir}\" ]]; then\n        install_writeable=\"false\"\n        echo_red \"You do not have write permission to: ${N_PREFIX}/${subdir}\"\n        break\n      fi\n      if [[ ! -e \"${N_PREFIX}/${subdir}\" && ! -w \"${N_PREFIX}\" ]]; then\n        install_writeable=\"false\"\n        echo_red \"You do not have write permission to create: ${N_PREFIX}/${subdir}\"\n        break\n      fi\n    done\n    if [[ \"${install_writeable}\" = \"true\" ]]; then\n      echo \"good\"\n    else\n      show_permission_suggestions\n      echo \"- change folder ownerships to yourself:\"\n      echo \"      cd \\\"${N_PREFIX}\\\"\"\n      echo \"      sudo mkdir -p bin lib include share\"\n      echo \"      sudo chown -R $(whoami) bin lib include share\"\n    fi\n  fi\n\n  printf \"\\nChecking mirror is reachable...\\n\"\n  if is_ok \"${N_NODE_MIRROR}/\"; then\n    printf \"good\\n\"\n  else\n    echo_red \"mirror not reachable\"\n    printf \"Showing failing command and output\\n\"\n    if command -v curl &> /dev/null; then\n      ( set -x; do_get --head \"${N_NODE_MIRROR}/\" )\n    else\n      ( set -x; do_get --spider \"${N_NODE_MIRROR}/\" )\n    printf \"\\n\"\n   fi\n  fi\n}\n\n#\n# Handle arguments.\n#\n\n# First pass. Process the options so they can come before or after commands,\n# particularly for `n lsr --all` and `n install --arch x686`\n# which feel pretty natural.\n\nunprocessed_args=()\npositional_arg=\"false\"\n\nwhile [[ $# -ne 0 ]]; do\n  case \"$1\" in\n    --all) N_MAX_REMOTE_MATCHES=32000 ;;\n    -V|--version) display_n_version ;;\n    -h|--help|help) display_help; exit ;;\n    -q|--quiet) set_quiet ;;\n    -d|--download) DOWNLOAD=\"true\" ;;\n    --cleanup) CLEANUP=\"true\" ;;\n    --offline) OFFLINE=\"true\" ;;\n    --insecure) set_insecure ;;\n    -p|--preserve) N_PRESERVE_NPM=\"true\" N_PRESERVE_COREPACK=\"true\" ;;\n    --no-preserve) N_PRESERVE_NPM=\"\" N_PRESERVE_COREPACK=\"\" ;;\n    --use-xz) N_USE_XZ=\"true\" ;;\n    --no-use-xz) N_USE_XZ=\"false\" ;;\n    --latest) display_remote_versions latest; exit ;;\n    --stable) display_remote_versions lts; exit ;; # [sic] old terminology\n    --lts) display_remote_versions lts; exit ;;\n    -a|--arch) shift; set_arch \"$1\";; # set arch and continue\n    exec|run|as|use)\n      unprocessed_args+=( \"$1\" )\n      positional_arg=\"true\"\n      ;;\n    *)\n      if [[ \"${positional_arg}\" == \"true\" ]]; then\n        unprocessed_args+=( \"$@\" )\n        break\n      fi\n      unprocessed_args+=( \"$1\" )\n      ;;\n  esac\n  shift\ndone\n\nif [[ -z \"${N_USE_XZ+defined}\" ]]; then\n  N_USE_XZ=\"true\" # Default to using xz\n  can_use_xz || N_USE_XZ=\"false\"\nfi\n\nset -- \"${unprocessed_args[@]}\"\n\nif test $# -eq 0; then\n  test -z \"$(display_versions_paths)\" && err_no_installed_print_help\n  menu_select_cache_versions\nelse\n  case \"$1\" in\n    bin|which) display_bin_path_for_version \"$2\"; exit ;;\n    run|as|use) shift; run_with_version \"$@\"; exit ;;\n    exec) shift; exec_with_version \"$@\"; exit ;;\n    doctor) show_diagnostics; exit ;;\n    rm|-) shift; remove_versions \"$@\"; exit ;;\n    prune) prune_cache; exit ;;\n    latest) install latest; exit ;;\n    stable) install stable; exit ;;\n    lts) install lts; exit ;;\n    ls|list) display_versions_paths; exit ;;\n    lsr|ls-remote|list-remote) shift; display_remote_versions \"$1\"; exit ;;\n    uninstall) uninstall_installed; exit ;;\n    i|install) shift; install \"$1\"; exit ;;\n    download) shift; DOWNLOAD=\"true\"; install \"$1\"; exit ;;\n    N_TEST_DISPLAY_LATEST_RESOLVED_VERSION) shift; get_latest_resolved_version \"$1\" > /dev/null || exit 2; echo \"${g_target_node}\"; exit ;;\n    *) install \"$1\"; exit ;;\n  esac\nfi\n"
  },
  {
    "path": "docs/changing-node-location.md",
    "content": "# Switching To `n` Managed Node.js\n\nIf you already have Node.js installed to a different root than `n` uses, you can easily end up with multiple copies of node (and npm, and npx, and globally installed packages!). Some common situations are you already had Node.js installed  using your Linux package manager, or using another node version manager, or using say Homebrew. The two main ways you might resolve this are:\n\n- uninstall from the old directory and reinstall to the new directory\n- put the `bin` directory that `n` uses early in the `PATH` environment variable, so the `n` installed node is found first\n\nThe simplest setup to understand is the first one. Just have one version of `node` installed.\n\nLet's walk-through the process of switching over from using Homebrew as an example. Let's start off with Node.js installed, `npm` updated, and an example global npm package. The key point is there are two install prefixes involved:\n\n- old: `/opt/homebrew`\n- new: `/usr/local`\n\n```console\n% brew install node\n% npm install --global npm@latest\n% npm install --global @shadowspawn/forest-arborist\n% brew list node\n/opt/homebrew/Cellar/node/21.7.3/bin/node\n/opt/homebrew/Cellar/node/21.7.3/bin/npm\n/opt/homebrew/Cellar/node/21.7.3/bin/npx\n/opt/homebrew/Cellar/node/21.7.3/etc/bash_completion.d/npm\n/opt/homebrew/Cellar/node/21.7.3/include/node/ (107 files)\n/opt/homebrew/Cellar/node/21.7.3/libexec/bin/ (2 files)\n/opt/homebrew/Cellar/node/21.7.3/libexec/lib/ (2012 files)\n/opt/homebrew/Cellar/node/21.7.3/share/doc/ (2 files)\n/opt/homebrew/Cellar/node/21.7.3/share/man/man1/node.1\n% command -v node\n/opt/homebrew/bin/node\n% command -v npm \n/opt/homebrew/bin/npm\n% npm prefix --global\n/opt/homebrew\n```\n\nBefore we start transferring, list the global npm packages in the \"old\" location. We will refer back to this list.\n\n```console\n% npm list --global\n/opt/homebrew/lib\n├── @shadowspawn/forest-arborist@12.0.0\n└── npm@10.5.0\n```\n\nWe could clean out the old location first, but let's install `n` and another copy of node and see what that looks like. We end up with two versions of node, and the active one is still the Homebrew managed version.\n\n```console\n% brew install n\n% n lts\n  installing : node-v20.12.2\n       mkdir : /usr/local/n/versions/node/20.12.2\n       fetch : https://nodejs.org/dist/v20.12.2/node-v20.12.2-darwin-arm64.tar.xz\n     copying : node/20.12.2\n   installed : v20.12.2 to /usr/local/bin/node\n      active : v21.7.3 at /opt/homebrew/bin/node\n% command -v node\n/opt/homebrew/bin/node\n% which -a node\n/opt/homebrew/bin/node\n/usr/local/bin/node\n% command -v npm\n/opt/homebrew/bin/npm\n% command -v npx\n/opt/homebrew/bin/npx\n% n doctor\n<...>\n\nCHECKS\n\nChecking n install destination is in PATH...\ngood\n\nChecking n install destination priority in PATH...\n⚠️ There is a version of node installed which will be found in PATH before the n installed version.\n\nChecking npm install destination...\n⚠️ There is an active version of npm shadowing the version installed by n. Check order of entries in PATH.\n   installed : /usr/local/bin/npm\n      active : /opt/homebrew/bin/npm\n\n<...>\n```\n\nNow let's switch over. Delete everything from the old location. Delete all the global npm packages _except_ npm itself, then delete npm, then delete node.\n\n```console\nnpm uninstall --global @shadowspawn/forest-arborist\n\nnpm uninstall --global npm\n\nbrew uninstall node\n```\n\nCheck the active binaries are now the ones installed by `n`:\n```console\n% command -v node\n/usr/local/bin/node\n% command -v npm \n/usr/local/bin/npm\n% command -v npx\n/usr/local/bin/npx\n```\n\nAnd lastly, reinstall the global npm packages you started with:\n```\n% npm prefix --global\n/usr/local\n% npm install --global npm@latest\n% npm install --global @shadowspawn/forest-arborist\n% npm list -g\n/usr/local/lib\n├── @shadowspawn/forest-arborist@12.0.0\n└── npm@10.5.0\n```\n"
  },
  {
    "path": "docs/proxy-server.md",
    "content": "# Proxy Server\n\nUnder the hood, `n` uses `curl` or `wget` for the downloads. `curl` is used if available, and `wget` otherwise. Both `curl` and `wget` support using environment variables or startup files to set up the proxy.\n\n## Using Environment Variable\n\nYou can define the proxy server using an environment variable, which is read by multiple commands including `curl` and `wget`:\n\n    export https_proxy='https://host:port/path'\n\nIf your proxy requires authentication you can add the [url-encoded](https://urlencode.org) username and password into the URL. e.g.\n\n    export https_proxy='https://encoded-user:encoded-password@host:port/path'\n\nIf you have defined a custom node mirror which uses http, then you would define `http_proxy` rather than `https_proxy`.\n\nIf you use `sudo` to run `n`, you need to do something extra to make the environment variables available. A simple way is to use `-E` (`--preserve-env`):\n\n    sudo -E n lts\n\n## Certificate Checks\n\nYour proxy server may supply its own ssl certificates for remote sites (as a man-in-the-middle). If you can not arrange to trust the proxy in this role, you can turn off (all) certificate checking with `--insecure`. e.g.\n\n    n --insecure --lts\n\nAnother possible work-around for certificate problems is to use plain http by specifying a custom node mirror:\n\n    export NODE_MIRROR='http://nodejs.org/dist'\n    export http_proxy='http://host:port/path'\n    n --lts\n\n## Startup Files\n\nAn alternative to using an environment variable for the proxy settings is to configure a startup file for the command.\n\nExample `~/.curlrc` ([documentation](https://ec.haxx.se/cmdline-configfile.html))\n\n    proxy = http://host:port/path\n    proxy-user = user:password\n    # If need to disable certificate checks\n    --insecure\n\nExample `~/.wgetrc` ([documentation](https://www.gnu.org/software/wget/manual/html_node/Wgetrc-Commands.html#Wgetrc-Commands))\n\n    https_proxy = http://host:port/path\n    proxy_user = user\n    proxy_password = password\n    # If need to disable certificate checks\n    check_certificate = off\n\n## Troubleshooting\n\nTo experiment and find what settings you need, use `curl` (or `wget`) directly with the node mirror and check the error messages.\n\nFor these examples there is a proxy running on localhost:8080 which does not require authentication, but the certificates it offers\nare not trusted.\n\nFirst try fails because of the certificates and `curl` helpfully explains:\n\n    $ curl --proxy localhost:8080 https://nodejs.org/dist/\n    curl: (60) SSL certificate problem: self signed certificate in certificate chain\n    ...\n    If you'd like to turn off curl's verification of the certificate, use\n    the -k (or --insecure) option.\n    HTTPS-proxy has similar options --proxy-cacert and --proxy-insecure.\n\nOnce you get the command to work with settings appropriate for your setup, like:\n\n    $ curl --insecure --proxy localhost:8080 https://nodejs.org/dist/\n    <html>\n    <head><title>Index of /dist/</title></head>\n    ...\n\nthen you can try moving the proxy out of the command:\n\n    $ https_proxy=localhost:8080 curl --insecure https://nodejs.org/dist/\n    <html>\n    <head><title>Index of /dist/</title></head>\n    ...\n\nand then `n` should work the same way:\n\n    $ https_proxy=localhost:8080 n --insecure --lts\n    8.11.3\n\nTo make it permanent either add settings to the `curl` (or `wget`) startup file, or add the\nenvironment variable to your shell initialization file . e.g.\n\n    export https_proxy=localhost:8080\n\nFor curl, two options of note for debugging are:\n\n    -v, --verbose\n    Makes curl verbose during the operation. Useful for debugging and seeing what's going on \"under the hood\". ...\n\n    -q, --disable\n    If used as the first parameter on the command line, the curlrc config file will not be read and used. ...\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"n\",\n  \"description\": \"Interactively Manage All Your Node Versions\",\n  \"version\": \"10.2.0\",\n  \"author\": \"TJ Holowaychuk <tj@vision-media.ca>\",\n  \"homepage\": \"https://github.com/tj/n\",\n  \"bugs\": \"https://github.com/tj/n/issues\",\n  \"contributors\": [\n    {\n      \"name\": \"n Contributors\",\n      \"url\": \"https://github.com/tj/n/graphs/contributors\"\n    }\n  ],\n  \"keywords\": [\n    \"nvm\",\n    \"node\",\n    \"version\",\n    \"manager\",\n    \"switcher\",\n    \"node\",\n    \"binary\",\n    \"env\"\n  ],\n  \"bin\": {\n    \"n\": \"bin/n\"\n  },\n  \"files\": [\n    \"bin/n\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/tj/n.git\"\n  },\n  \"scripts\": {\n    \"test\": \"test/bin/run-all-tests\"\n  },\n  \"devDependencies\": {\n    \"bats\": \"^1.2.1\",\n    \"bats-assert\": \"github:bats-core/bats-assert\",\n    \"bats-support\": \"github:bats-core/bats-support\"\n  },\n  \"preferGlobal\": true,\n  \"os\": [\n    \"!win32\"\n  ],\n  \"engines\": {\n    \"node\": \"*\"\n  },\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "test/bin/run-all-tests",
    "content": "#!/usr/bin/env bash\nBIN_DIRECTORY=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" >/dev/null 2>&1 && pwd )\"\n\n# We want to cover curl and wget especially, gz and xz and variety of OS a bonus.\nservices=( fedora-curl ubuntu-wget )\n\ncd \"$(dirname \"${BIN_DIRECTORY}\")\" || exit 2\nfor service in \"${services[@]}\" ; do\n  echo \"${service}\"\n  docker compose run --rm \"${service}\" \"bats\" \"/mnt/test/tests\"\n  echo \"\"\ndone\n\n# host (current maintainer uses Mac)\nuname -s\n../node_modules/.bin/bats tests\n"
  },
  {
    "path": "test/docker-base.yml",
    "content": "version: '2'\n# Define base service to specify the mounts and environment variables\nservices:\n  testbed:\n    volumes:\n      # make locally installed  bats available in container (based on bats/install.sh)\n      - ../node_modules/bats/bin/bats:/usr/local/bin/bats\n      - ../node_modules/bats/libexec/bats-core:/usr/local/libexec/bats-core\n      - ../node_modules/bats/lib/bats-core:/usr/local/lib/bats-core\n      - ../node_modules/bats/man/bats.1:/usr/local/share/man/man1\"\n      - ../node_modules/bats/man/bats.7:/usr/local/share/man/man7\"\n      # the bats tests, same relative location to node_modules as in repo\n      - ./tests:/mnt/test/tests\n      # bats extra libraries, into similar relative location\n      - ../node_modules/bats-support:/mnt/node_modules/bats-support\n      - ../node_modules/bats-assert:/mnt/node_modules/bats-assert\n      # the n script\n      - ../bin/n:/usr/local/bin/n\n"
  },
  {
    "path": "test/docker-compose.yml",
    "content": "services:\n  ubuntu-curl:\n    extends:\n      file: ./docker-base.yml\n      service: testbed\n    build:\n      context: dockerfiles\n      dockerfile: Dockerfile-ubuntu-curl\n  ubuntu-wget:\n    extends:\n      file: ./docker-base.yml\n      service: testbed\n    build:\n      context: dockerfiles\n      dockerfile: Dockerfile-ubuntu-wget\n  fedora-curl:\n    extends:\n      file: ./docker-base.yml\n      service: testbed\n    build:\n      context: dockerfiles\n      dockerfile: Dockerfile-fedora-curl\n"
  },
  {
    "path": "test/dockerfiles/Dockerfile-fedora-curl",
    "content": "FROM fedora:latest\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "test/dockerfiles/Dockerfile-ubuntu-curl",
    "content": "FROM ubuntu:latest\n\n# curl\n\nRUN apt-get update \\\n&& apt-get install -y curl \\\n&& rm -rf /var/lib/apt/lists/*\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "test/dockerfiles/Dockerfile-ubuntu-wget",
    "content": "FROM ubuntu:latest\n\n# wget\n\nRUN apt-get update \\\n&& apt-get install -y wget \\\n&& rm -rf /var/lib/apt/lists/*\n\nCMD [\"/bin/bash\"]\n"
  },
  {
    "path": "test/tests/install-contents.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\nfunction setup() {\n  unset_n_env\n}\n\n\n# Test that files get installed to expected locations\n# https://github.com/tj/n/issues/246\n\n@test \"install: contents\" {\n  readonly TARGET_VERSION=\"4.9.1\"\n  setup_tmp_prefix\n\n  [ ! -d \"${N_PREFIX}/n/versions\" ]\n  [ ! -d \"${N_PREFIX}/bin\" ]\n  [ ! -d \"${N_PREFIX}/include\" ]\n  [ ! -d \"${N_PREFIX}/lib\" ]\n  [ ! -d \"${N_PREFIX}/shared\" ]\n\n  n ${TARGET_VERSION}\n\n  # Cached version\n  [ -d \"${N_PREFIX}/n/versions/node/${TARGET_VERSION}\" ]\n  # node and npm\n  [ -f \"${N_PREFIX}/bin/node\" ]\n  [ -f \"${N_PREFIX}/bin/npm\" ]\n  # Installed something into each of other key folders\n  [ -d \"${N_PREFIX}/include/node\" ]\n  [ -d \"${N_PREFIX}/lib/node_modules\" ]\n  [ -d \"${N_PREFIX}/share/doc/node\" ]\n  # Did not install files from top level of tarball\n  [ ! -f \"${N_PREFIX}/README.md\" ]\n\n  output=\"$(node --version)\"\n  assert_equal \"${output}\" \"v${TARGET_VERSION}\"\n\n  rm -rf \"${TMP_PREFIX_DIR}\"\n}\n\n@test \"install: cache prefix\" {\n  readonly N_CACHE_PREFIX=\"$(mktemp -d)\"\n  readonly TARGET_VERSION=\"4.9.1\"\n  setup_tmp_prefix\n  export N_CACHE_PREFIX\n\n  [ ! -d \"${N_CACHE_PREFIX}/n/versions/node/${TARGET_VERSION}\" ]\n  [ ! -d \"${N_PREFIX}/n/versions/node/${TARGET_VERSION}\" ]\n\n  n ${TARGET_VERSION}\n\n  # Cached version\n  [ -d \"${N_CACHE_PREFIX}/n/versions/node/${TARGET_VERSION}\" ]\n  [ ! -d \"${N_PREFIX}/n/versions/node/${TARGET_VERSION}\" ]\n\n  rm -rf \"${TMP_PREFIX_DIR}\" \"${N_CACHE_PREFIX}\"\n}\n"
  },
  {
    "path": "test/tests/install-options.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\nfunction setup() {\n  unset_n_env\n  setup_tmp_prefix\n}\n\n\nfunction teardown() {\n  rm -rf \"${TMP_PREFIX_DIR}\"\n}\n\n\n@test \"n --download 4.9.1\" {\n  # deprecated use of --download, replaced by download command\n  n --download 4.9.1\n  [ -d \"${N_PREFIX}/n/versions/node/4.9.1\" ]\n  [ ! -f \"${N_PREFIX}/bin/node\" ]\n  [ ! -f \"${N_PREFIX}/bin/npm\" ]\n  [ ! -d \"${N_PREFIX}/include\" ]\n  [ ! -d \"${N_PREFIX}/lib\" ]\n  [ ! -d \"${N_PREFIX}/shared\" ]\n}\n\n\n@test \"n download 4.9.1\" {\n  # not an option, but keep with --download so stays in sync\n  n download 4.9.1\n  [ -d \"${N_PREFIX}/n/versions/node/4.9.1\" ]\n  [ ! -f \"${N_PREFIX}/bin/node\" ]\n  [ ! -f \"${N_PREFIX}/bin/npm\" ]\n  [ ! -d \"${N_PREFIX}/include\" ]\n  [ ! -d \"${N_PREFIX}/lib\" ]\n  [ ! -d \"${N_PREFIX}/shared\" ]\n}\n\n\n@test \"n --quiet 4.9.1\" {\n  # just checking option is allowed, not testing functionality\n  n --quiet 4.9.1\n  output=\"$(node --version)\"\n  assert_equal \"${output}\" \"v4.9.1\"\n}\n\n\n@test \"n --cleanup 4.9.1\" {\n  n install --cleanup 4.9.1\n  output=\"$(node --version)\"\n  assert_equal \"${output}\" \"v4.9.1\"\n  [ ! -d \"${N_PREFIX}/n/versions/node/4.9.1\" ]\n}\n\n\n# mostly --preserve, but also variations with i/install and lts/numeric\n@test \"--preserve variations # (4 installs)\" {\n  local ARGON_VERSION=\"v4.9.1\"\n  local ARGON_NPM_VERSION=\"2.15.11\"\n  local LTS_VERSION=\"$(display_remote_version lts)\"\n\n  n ${ARGON_VERSION}\n  output=\"$(\"${N_PREFIX}/bin/node\" --version)\"\n  assert_equal \"$output\" \"${ARGON_VERSION}\"\n  output=\"$(\"${N_PREFIX}/bin/npm\" --version)\"\n  assert_equal \"$output\" \"${ARGON_NPM_VERSION}\"\n\n  n --preserve \"${LTS_VERSION}\"\n  output=\"$(\"${N_PREFIX}/bin/node\" --version)\"\n  assert_equal \"$output\" \"v${LTS_VERSION}\"\n  output=\"$(\"${N_PREFIX}/bin/npm\" --version)\"\n  assert_equal \"$output\" \"${ARGON_NPM_VERSION}\"\n\n  N_PRESERVE_NPM=1 n \"${LTS_VERSION}\"\n  output=\"$(\"${N_PREFIX}/bin/npm\" --version)\"\n  assert_equal \"$output\" \"${ARGON_NPM_VERSION}\"\n\n  N_PRESERVE_NPM=1 n --no-preserve \"${LTS_VERSION}\"\n  output=\"$(\"${N_PREFIX}/bin/npm\" --version)\"\n  assert [ \"$output\" != \"${ARGON_NPM_VERSION}\" ]\n}\n\n\n\n# ToDo: --arch\n"
  },
  {
    "path": "test/tests/install-versions.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\nfunction setup() {\n  unset_n_env\n  setup_tmp_prefix\n}\n\n\nfunction teardown() {\n  rm -rf \"${TMP_PREFIX_DIR}\"\n}\n\n\n# Testing version permutations in lsr tests\n\n@test \"n 4.9.1\" {\n  n 4.9.1\n  output=\"$(node --version)\"\n  assert_equal \"${output}\" \"v4.9.1\"\n}\n\n\n@test \"n lts\" {\n  n lts\n  output=\"$(node --version)\"\n  assert_equal \"${output}\" \"v$(display_remote_version lts)\"\n}\n\n\n@test \"n latest\" {\n  n latest\n  output=\"$(node --version)\"\n  assert_equal \"${output}\" \"v$(display_remote_version latest)\"\n}\n"
  },
  {
    "path": "test/tests/lookup.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\nfunction setup() {\n  unset_n_env\n}\n\n\n@test \"n --lts\" {\n  output=\"$(n --lts)\"\n  local expected_version\n  expected_version=\"$(display_remote_version lts)\"\n  expected_version=\"${expected_version#v}\"\n  assert_equal \"${output}\" \"${expected_version}\"\n}\n\n\n@test \"n --stable\" {\n  output=\"$(n --stable)\"\n  local expected_version\n  expected_version=\"$(display_remote_version lts)\"\n  expected_version=\"${expected_version#v}\"\n  assert_equal \"${output}\" \"${expected_version}\"\n}\n\n\n@test \"n --latest\" {\n  output=\"$(n --latest)\"\n  local expected_version\n  expected_version=\"$(display_remote_version latest)\"\n  expected_version=\"${expected_version#v}\"\n  assert_equal \"${output}\" \"${expected_version}\"\n}\n"
  },
  {
    "path": "test/tests/ls.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\nfunction setup() {\n  unset_n_env\n  setup_tmp_prefix\n}\n\nfunction teardown() {\n  rm -rf \"${TMP_PREFIX_DIR}\"\n}\n\n\n@test \"n ls # just plain node\" {\n  # KISS and just make folders rather than do actual installs\n  mkdir -p \"${N_PREFIX}/n/versions/node/4.9.1\"\n  mkdir -p \"${N_PREFIX}/n/versions/node/10.15.0\"\n\n  output=\"$(n ls)\"\n  assert_equal \"${output}\" \"node/4.9.1\nnode/10.15.0\"\n}\n\n\n@test \"n list # mixed node and nightly\" {\n  local NIGHTLY_VERSION=\"12.0.0-nightly201812104aabd7ed64\"\n  # KISS and just make folders rather than do actual installs\n  mkdir -p \"${N_PREFIX}/n/versions/nightly/${NIGHTLY_VERSION}\"\n  mkdir -p \"${N_PREFIX}/n/versions/node/10.15.0\"\n\n  output=\"$(n list)\"\n  assert_equal \"${output}\" \"nightly/${NIGHTLY_VERSION}\nnode/10.15.0\"\n}\n\n"
  },
  {
    "path": "test/tests/lsr.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\nfunction setup() {\n  unset_n_env\n}\n\n\n# labels\n\n@test \"n lsr lts\" {\n  output=\"$(n lsr lts)\"\n  assert_equal \"${output}\" \"$(display_remote_version lts)\"\n}\n\n@test \"n lsr stable\" {\n  output=\"$(n lsr lts)\"\n  assert_equal \"${output}\" \"$(display_remote_version lts)\"\n}\n\n@test \"n ls-remote latest\" {\n  output=\"$(n ls-remote latest)\"\n  assert_equal \"${output}\" \"$(display_remote_version latest)\"\n}\n\n@test \"n list-remote current\" {\n  output=\"$(n list-remote current)\"\n  assert_equal \"${output}\" \"$(display_remote_version latest)\"\n}\n\n\n# codenames\n\n@test \"n=1 n lsr argon\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr argon)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n@test \"n=1 n lsr Argon # case\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr Argon)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n\n# numeric versions\n\n@test \"n=1 n lsr 4\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr 4)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n@test \"n=1 n lsr v4\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr v4)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n@test \"n=1 n lsr 4.9\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr 4.9)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n@test \"n=1 n lsr 4.9.1\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr 4.9.1)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n@test \"n=1 n lsr v4.9.1\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr v4.9.1)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n@test \"n lsr 6.2 # multiple matches with header\" {\n  output=\"$(n lsr 6.2)\"\n  assert_equal \"${output}\" \"Listing remote... Displaying 20 matches (use --all to see all).\n6.2.2\n6.2.1\n6.2.0\"\n}\n\n@test \"n=1 n lsr --all 6.2 # --all, multiple matches with no header\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n --all lsr 6.2)\"\n  assert_equal \"${output}\" \"6.2.2\n6.2.1\n6.2.0\"\n}\n\n# Checking does not match 8.11\n@test \"n=1 n lsr v8.1 # numeric match\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr v8.1)\"\n  assert_equal \"${output}\" \"8.1.4\"\n}\n\n\n# Nightly\n\n@test \"n=1 n lsr nightly\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr nightly)\"\n  assert_equal \"${output}\" \"$(display_remote_version nightly)\"\n}\n\n@test \"n=1 n lsr nightly/\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr nightly/)\"\n  assert_equal \"${output}\" \"$(display_remote_version nightly)\"\n}\n\n@test \"n=1 n lsr nightly/latest\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr nightly/latest)\"\n  assert_equal \"${output}\" \"$(display_remote_version nightly)\"\n}\n\n@test \"n=1 n lsr nightly/v12.0.0-nightly2019040 # partial match\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr nightly/v12.0.0-nightly2019040)\"\n  assert_equal \"${output}\" \"12.0.0-nightly2019040166b95362df\"\n}\n\n# Numeric match should not find v7.10.1-nightly2017050369a8053e8a\n@test \"n=1 n lsr nightly/12.0 # numeric match\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr nightly/12.0)\"\n  assert_equal \"${output}\" \"12.0.0-nightly2019040166b95362df\"\n}\n\n# Numeric match should not find v7.10.1-nightly2017050369a8053e8a\n@test \"n=1 n lsr nightly/v12.0 # numeric match\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr nightly/v12.0)\"\n  assert_equal \"${output}\" \"12.0.0-nightly2019040166b95362df\"\n}\n\n@test \"n lsr nightly/v12.0.0-nightly2019040166b95362df # exact\" {\n  output=\"$(N_MAX_REMOTE_MATCHES=1 n lsr nightly/v12.0.0-nightly2019040166b95362df)\"\n  assert_equal \"${output}\" \"12.0.0-nightly2019040166b95362df\"\n}\n"
  },
  {
    "path": "test/tests/offline.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\nfunction setup_file() {\n  unset_n_env\n  setup_tmp_prefix\n  # Note, NOT latest version of 16.\n  n download 16.19.0\n  export N_NODE_MIRROR=\"https://no.internet.available\"\n}\n\nfunction teardown_file() {\n  rm -rf \"${TMP_PREFIX_DIR}\"\n}\n\nfunction setup() {\n  hash -r\n}\n\n@test \"n --offline 16\" {\n  n --offline 16\n  hash -r\n  output=\"$(node --version)\"\n  assert_equal \"${output}\" \"v16.19.0\"\n  rm \"${TMP_PREFIX_DIR}/bin/node\"\n}\n\n@test \"n --offline latest\" {\n  n --offline latest\n  hash -r\n  output=\"$(node --version)\"\n  assert_equal \"${output}\" \"v16.19.0\"\n  rm \"${TMP_PREFIX_DIR}/bin/node\"\n}\n\n@test \"n --offline run 16...\" {\n  output=\"$(n --offline run 16 --version)\"\n  assert_equal \"${output}\" \"v16.19.0\"\n}\n\n@test \"n --offline exec 16...\" {\n  output=\"$(n --offline exec 16 node --version)\"\n  assert_equal \"${output}\" \"v16.19.0\"\n}\n\n@test \"n --offline which 16...\" {\n  output=\"$(n --offline which 16)\"\n  assert_equal \"${output}\" \"${TMP_PREFIX_DIR}/n/versions/node/16.19.0/bin/node\"\n}\n"
  },
  {
    "path": "test/tests/run-which.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\nfunction setup_file() {\n  unset_n_env\n  # fixed directory so can reuse the two installs\n  tmpdir=\"${TMPDIR:-/tmp}\"\n  export N_PREFIX=\"${tmpdir}/n/test/run-which\"\n  n download 4.9.1\n  n download lts\n  # using \"latest\" for download tests with run and exec\n}\n\nfunction teardown_file() {\n  rm -rf \"${N_PREFIX}\"\n}\n\n@test \"setupAll for run/which/exec # (2 installs)\" {\n  # Dummy test so setupAll displayed while running first setup\n  [ -d \"${N_PREFIX}/n/versions/node/4.9.1\" ]\n}\n\n\n# n which\n\n@test \"n which 4\" {\n  output=\"$(n which 4)\"\n  assert_equal \"$output\" \"${N_PREFIX}/n/versions/node/4.9.1/bin/node\"\n}\n\n\n@test \"n which v4.9.1\" {\n  output=\"$(n which v4.9.1)\"\n  assert_equal \"$output\" \"${N_PREFIX}/n/versions/node/4.9.1/bin/node\"\n}\n\n@test \"n bin v4.9.1\" {\n  output=\"$(n bin v4.9.1)\"\n  assert_equal \"$output\" \"${N_PREFIX}/n/versions/node/4.9.1/bin/node\"\n}\n\n@test \"n which argon\" {\n  output=\"$(n which argon)\"\n  assert_equal \"$output\" \"${N_PREFIX}/n/versions/node/4.9.1/bin/node\"\n}\n\n@test \"n which lts\" {\n  output=\"$(n which lts)\"\n  local LTS_VERSION=\"$(display_remote_version lts)\"\n  assert_equal \"$output\" \"${N_PREFIX}/n/versions/node/${LTS_VERSION}/bin/node\"\n}\n\n\n# n run\n\n@test \"n run 4\" {\n  output=\"$(n run 4 --version)\"\n  assert_equal \"$output\" \"v4.9.1\"\n}\n\n@test \"n run lts\" {\n  output=\"$(n run lts --version)\"\n  local LTS_VERSION=\"$(display_remote_version lts)\"\n  assert_equal \"$output\" \"v${LTS_VERSION}\"\n}\n\n@test \"n use 4\" {\n  output=\"$(n use 4 --version)\"\n  assert_equal \"$output\" \"v4.9.1\"\n}\n\n@test \"n as 4\" {\n  output=\"$(n as 4 --version)\"\n  assert_equal \"$output\" \"v4.9.1\"\n}\n\n@test \"n run --download latest\" {\n  n rm latest || true\n  n run --download latest --version\n  output=\"$(n run latest --version)\"\n  local LATEST_VERSION=\"$(display_remote_version latest)\"\n  assert_equal \"$output\" \"v${LATEST_VERSION}\"\n}\n\n\n# n exec\n\n@test \"n exec v4.9.1 node\" {\n  output=\"$(n exec v4.9.1 node --version)\"\n  assert_equal \"$output\" \"v4.9.1\"\n}\n\n@test \"n exec 4 npm\" {\n  output=\"$(n exec 4 npm --version)\"\n  assert_equal \"$output\" \"2.15.11\"\n}\n\n@test \"n exec lts\" {\n  output=\"$(n exec lts node --version)\"\n  local LTS_VERSION=\"$(display_remote_version lts)\"\n  assert_equal \"$output\" \"v${LTS_VERSION}\"\n}\n\n@test \"n exec -d latest\" {\n  n rm latest || true\n  n exec -d latest node --version\n  output=\"$(n exec latest node --version)\"\n  local LATEST_VERSION=\"$(display_remote_version latest)\"\n  assert_equal \"$output\" \"v${LATEST_VERSION}\"\n}\n"
  },
  {
    "path": "test/tests/shared-functions.bash",
    "content": "#!/usr/bin/env bash\n\n\n# unset the n environment variables so tests running from known state.\n# Globals:\n#   lots\n\nfunction unset_n_env(){\n  unset N_PREFIX\n  unset N_CACHE_PREFIX\n  unset NODE_MIRROR\n  unset N_NODE_MIRROR\n  unset N_NODE_DOWNLOAD_MIRROR\n  unset N_MAX_REMOTE_MATCHES\n  unset N_PRESERVE_NPM\n  unset N_PRESERVE_COREPACK\n  unset HTTP_USER\n  unset HTTP_PASSWORD\n  unset GREP_OPTIONS\n}\n\n\n# Create temporary dir and configure n to use it.\n# Globals:\n#   TMP_PREFIX_DIR\n#   N_PREFIX\n#   PATH\n\nfunction setup_tmp_prefix() {\n  TMP_PREFIX_DIR=\"$(mktemp -d)\"\n  [ -d \"${TMP_PREFIX_DIR}\" ] || exit 2\n  # return a safer variable to `rm -rf` later than N_PREFIX\n  export TMP_PREFIX_DIR\n\n  export N_PREFIX=\"${TMP_PREFIX_DIR}\"\n  export PATH=\"${N_PREFIX}/bin:${PATH}\"\n}\n\n\n# Display relevant file name (third field of index.tab) for current platform.\n# Based on code from nvm rather than n for independent approach. Simplified for just common platforms initially.\n# See list on https://github.com/nodejs/nodejs-dist-indexer\n\nfunction display_compatible_file_field() {\n  local os=\"unexpected\"\n  case \"$(uname -a)\" in\n    Linux\\ *) os=\"linux\" ;;\n    Darwin\\ *) os=\"osx\" ;;\n  esac\n\n  local arch=\"unexpected\"\n  local uname_m\n  uname_m=\"$(uname -m)\"\n  case \"${uname_m}\" in\n    x86_64 | amd64) arch=\"x64\" ;;\n    i*86) arch=\"x86\" ;;\n    aarch64) arch=\"arm64\" ;;\n    *) arch=\"${uname_m}\" ;;\n  esac\n\n  echo \"${os}-${arch}\"\n}\n\n\n# display_remote_version <version>\n# Limited support for using index.tab to resolve version into a number.\n# Return version number, without leading v.\n#\n# The simper (and independent) code here can cause transient false positive failures, like if the latest nightly version\n# has not been build for all architectures yet.\n\nfunction display_remote_version() {\n  # ToDo: support NODE_MIRROR\n\n  local fetch\n  if command -v curl &> /dev/null; then\n    fetch=\"curl --silent --location --fail --compressed\"\n  else\n    # insecure to match current n implementation\n    fetch=\"wget -q -O- --no-check-certificate\"\n  fi\n\n  local TAB_CHAR=$'\\t'\n  local match='xxx'\n  local mirror=\"${N_NODE_MIRROR:-https://nodejs.org/dist}\"\n  if [[ \"$1\" = \"lts\" || \"$1\" = \"stable\" ]]; then\n    match=\"^([^${TAB_CHAR}]+${TAB_CHAR}){9}[^-]\"\n  elif [[ \"$1\" = \"latest\" ]]; then\n    match='.'\n  elif [[ \"$1\" = \"nightly\" ]]; then\n    match='.'\n    mirror=\"${N_NODE_DOWNLOAD_MIRROR:-https://nodejs.org/download}/nightly\"\n  fi\n\n  # Using awk rather than head so do not close pipe early on curl\n  ${fetch} \"${mirror}/index.tab\" \\\n    | tail -n +2 \\\n    | grep \"$(display_compatible_file_field)\" \\\n    | grep -E \"${match}\" \\\n    | cut -f -1 \\\n    | awk \"NR==1\" \\\n    | grep -E -o '[^v].*'\n}\n"
  },
  {
    "path": "test/tests/uninstall.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\nfunction setup() {\n  unset_n_env\n  setup_tmp_prefix\n}\n\nfunction teardown() {\n  rm -rf \"${TMP_PREFIX_DIR}\"\n}\n\n\n@test \"n uninstall (of lts)\" {\n  n lts\n  [ -f \"${N_PREFIX}/bin/node\" ]\n  [ -f \"${N_PREFIX}/bin/npm\" ]\n  [ -f \"${N_PREFIX}/lib/node_modules/npm/package.json\" ]\n\n  # Check we get all the files if we uninstall and rm cache.\n  echo y | n uninstall\n  n rm lts\n  output=\"$(find \"${N_PREFIX}\" -not -type d)\"\n  assert_equal \"$output\" \"\"\n}\n\n\n@test \"n uninstall (of nightly/latest)\" {\n  n nightly/latest\n  [ -f \"${N_PREFIX}/bin/node\" ]\n  [ -f \"${N_PREFIX}/bin/npm\" ]\n  [ -f \"${N_PREFIX}/lib/node_modules/npm/package.json\" ]\n\n  # Check we get all the files if we uninstall and rm cache.\n  echo y | n uninstall\n  n rm nightly/latest\n  output=\"$(find \"${N_PREFIX}\" -not -type d)\"\n  assert_equal \"$output\" \"\"\n}\n"
  },
  {
    "path": "test/tests/version-auto-priority.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\n# auto\n\nfunction setup_file() {\n  unset_n_env\n  tmpdir=\"${TMPDIR:-/tmp}\"\n  export MY_DIR=\"${tmpdir}/n/test/version-resolve-auto-priority\"\n  mkdir -p \"${MY_DIR}\"\n\n  # Need a version of node available for reading package.json\n  export N_PREFIX=\"${MY_DIR}\"\n  export PATH=\"${MY_DIR}/bin:${PATH}\"\n  n install lts\n}\n\nfunction teardown_file() {\n  rm -rf \"${MY_DIR}\"\n}\n\nfunction setup() {\n  # Bit fragile, but reuse directory and clean up between tests.\n  rm -f \"${MY_DIR}/package.json\"\n  rm -f \"${MY_DIR}/.n-node-version\"\n  rm -f \"${MY_DIR}/.node-version\"\n  rm -f \"${MY_DIR}/.nvmrc\"\n}\n\n@test \".n-node-version first\" {\n  cd \"${MY_DIR}\"\n  echo \"8.1.4\" > .n-node-version\n  echo \"8.2.0\" > .node-version\n  echo \"8.3.0\" > .nvmrc\n  echo '{ \"engines\" : { \"node\" : \"v8.4.0\" } }' > package.json\n\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.1.4\"\n}\n\n@test \".node-version second\" {\n  cd \"${MY_DIR}\"\n  echo \"8.2.0\" > .node-version\n  echo \"8.3.0\" > .nvmrc\n  echo '{ \"engines\" : { \"node\" : \"v8.4.0\" } }' > package.json\n\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.2.0\"\n}\n\n@test \".nvmrc third\" {\n  cd \"${MY_DIR}\"\n  echo \"8.3.0\" > .nvmrc\n  echo '{ \"engines\" : { \"node\" : \"v8.4.0\" } }' > package.json\n\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.3.0\"\n}\n\n@test \".package.json last\" {\n  cd \"${MY_DIR}\"\n  echo '{ \"engines\" : { \"node\" : \"v8.4.0\" } }' > package.json\n\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.4.0\"\n}\n\n@test \".package.json last, after parent scanning\" {\n  cd \"${MY_DIR}\"\n  echo \"8.2.0\" > .node-version\n  mkdir package\n  cd package\n  echo '{ \"engines\" : { \"node\" : \"v8.4.0\" } }' > package.json\n\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.2.0\"\n\n  rm package.json\n  cd ..\n  rmdir package\n}\n"
  },
  {
    "path": "test/tests/version-resolve-auto-engine.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\n# auto\n# engine is a label too! These tests mostly use auto as first available only through auto.\n\nfunction setup_file() {\n  unset_n_env\n  tmpdir=\"${TMPDIR:-/tmp}\"\n  export MY_DIR=\"${tmpdir}/n/test/version-resolve-auto-engine\"\n  mkdir -p \"${MY_DIR}\"\n\n  # Need a version of node and npx available for reading package.json\n  export N_PREFIX=\"${MY_DIR}\"\n  export PATH=\"${MY_DIR}/bin:${PATH}\"\n  n install lts\n}\n\nfunction teardown_file() {\n  rm -rf \"${MY_DIR}\"\n}\n\nfunction setup() {\n  rm -f \"${MY_DIR}/package.json\"\n}\n\nfunction write_engine() {\n  echo '{ \"engines\" : { \"node\" : \"'\"$1\"'\" } }' > package.json\n}\n\n@test \"setupAll for auto-engine # (1 install)\" {\n  # Dummy test so setupAll displayed while running first setup\n}\n\n@test \"auto engine, 8.9.0\" {\n  cd \"${MY_DIR}\"\n  write_engine \"8.9.0\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.9.0\"\n}\n\n@test \"auto engine, v8.9.1\" {\n  cd \"${MY_DIR}\"\n  write_engine \"v8.9.1\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.9.1\"\n}\n\n@test \"auto engine, =8.9.2\" {\n  cd \"${MY_DIR}\"\n  write_engine \"=8.9.2\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.9.2\"\n}\n\n@test \"auto engine, =v8.9.3\" {\n  cd \"${MY_DIR}\"\n  write_engine \"=v8.9.3\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.9.3\"\n}\n\n@test \"engine, =v8.9.4\" {\n  cd \"${MY_DIR}\"\n  write_engine \"=v8.9.4\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION engine)\"\n  assert_equal \"${output}\" \"8.9.4\"\n}\n\n@test \"auto engine, >1\" {\n  local TARGET_VERSION=\"$(display_remote_version latest)\"\n  cd \"${MY_DIR}\"\n  write_engine \">1\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"${TARGET_VERSION}\"\n}\n\n@test \"auto engine, >=2\" {\n  local TARGET_VERSION=\"$(display_remote_version latest)\"\n  cd \"${MY_DIR}\"\n  write_engine \">=2\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"${TARGET_VERSION}\"\n}\n\n@test \"auto engine, 8\" {\n  cd \"${MY_DIR}\"\n  write_engine \"8\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.17.0\"\n}\n\n@test \"auto engine, 8.x\" {\n  cd \"${MY_DIR}\"\n  write_engine \"8.x\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.17.0\"\n}\n\n@test \"auto engine, 8.X\" {\n  cd \"${MY_DIR}\"\n  write_engine \"8.X\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.17.0\"\n}\n\n@test \"auto engine, 8.*\" {\n  cd \"${MY_DIR}\"\n  write_engine \"8.*\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.17.0\"\n}\n\n@test \"auto engine, ~8.11.0\" {\n  cd \"${MY_DIR}\"\n  write_engine \"~8.11.0\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.11.4\"\n}\n\n@test \"auto engine, ~8.11\" {\n  cd \"${MY_DIR}\"\n  write_engine \"~8.11\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.11.4\"\n}\n\n@test \"auto engine, ~8\" {\n  cd \"${MY_DIR}\"\n  write_engine \"~8\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.17.0\"\n}\n\n@test \"auto engine, ^8.11.0\" {\n  cd \"${MY_DIR}\"\n  write_engine \"^8.11.0\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.17.0\"\n}\n\n@test \"auto engine, ^8.x\" {\n  cd \"${MY_DIR}\"\n  write_engine \"^8.x\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.17.0\"\n}\n\n@test \"auto engine, subdir\" {\n  cd \"${MY_DIR}\"\n  write_engine \"8.11.2\"\n  mkdir -p sub-engine\n  cd sub-engine\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.11.2\"\n}\n\n@test \"auto engine (semver), <8.12\" {\n  cd \"${MY_DIR}\"\n  write_engine \"<8.12\"\n  # newer versions of npx not liking proxy as used in tests\n  output=\"$(https_proxy= n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.11.4\"\n}\n\n@test \"auto engine (semver), 8.11.1 - 8.11.3\" {\n  cd \"${MY_DIR}\"\n  write_engine \"8.11.1 - 8.11.3\"\n  # newer versions of npx not liking proxy as used in tests\n  output=\"$(https_proxy= n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.11.3\"\n}\n\n@test \"auto engine (semver), >8.1 <8.12 || >2.1 <3.4\" {\n  cd \"${MY_DIR}\"\n  write_engine \">8.1 <8.12 || >2.1 <3.4\"\n  # newer versions of npx not liking proxy as used in tests\n  output=\"$(https_proxy= n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.11.4\"\n}\n"
  },
  {
    "path": "test/tests/version-resolve-auto-file.bats",
    "content": "#!/usr/bin/env bats\n\n# Not testing all the permutations on both files, as know they are currenly implemented using same code!\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\n# auto\n\nfunction setup_file() {\n  unset_n_env\n  tmpdir=\"${TMPDIR:-/tmp}\"\n  export MY_DIR=\"${tmpdir}/n/test/version-resolve-auto-file\"\n  mkdir -p \"${MY_DIR}\"\n}\n\nfunction teardown_file() {\n  rm -rf \"${MY_DIR}\"\n}\n\nfunction setup() {\n  rm -f \"${MY_DIR}/.n-node-version\"\n  rm -f \"${MY_DIR}/.node-version\"\n}\n\n@test \"auto, missing file\" {\n  cd \"${MY_DIR}\"\n  run n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto\n  assert [ \"$status\" -ne 0 ]\n}\n\n@test \"auto .n-node-version, no eol\" {\n  cd \"${MY_DIR}\"\n  printf \"8.1.0\" > .n-node-version\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.1.0\"\n}\n\n@test \"auto .n-node-version, unix eol\" {\n  cd \"${MY_DIR}\"\n  printf \"8.1.1\\n\" > .n-node-version\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.1.1\"\n}\n\n@test \"auto .n-node-version, Windows eol\" {\n  cd \"${MY_DIR}\"\n  printf \"8.1.2\\r\\n\" > .n-node-version\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.1.2\"\n}\n\n@test \"auto .n-node-version, leading v\" {\n  cd \"${MY_DIR}\"\n  printf \"v8.1.3\\n\" > .n-node-version\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.1.3\"\n}\n\n@test \"auto .n-node-version, first line only\" {\n  cd \"${MY_DIR}\"\n  printf \"8.1.4\\nmore text\\n\" > .n-node-version\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.1.4\"\n}\n\n@test \"auto .n-node-version, from sub directory\" {\n  cd \"${MY_DIR}\"\n  printf \"8.2.0\\n\" > .n-node-version\n  mkdir -p sub6\n  cd sub6\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.2.0\"\n}\n\n@test \"auto .node-version, partial version lookup\" {\n  # Check normal resolving\n  cd \"${MY_DIR}\"\n  printf \"4.9\\n\" > .node-version\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n@test \"auto .node-version, from sub directory\" {\n  cd \"${MY_DIR}\"\n  printf \"8.2.1\\n\" > .n-node-version\n  mkdir -p sub7\n  cd sub7\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.2.1\"\n}\n\n"
  },
  {
    "path": "test/tests/version-resolve-auto-nvmrc.bats",
    "content": "#!/usr/bin/env bats\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\n# auto\n\nfunction setup_file() {\n  unset_n_env\n  tmpdir=\"${TMPDIR:-/tmp}\"\n  export MY_DIR=\"${tmpdir}/n/test/version-resolve-auto-nvmrc\"\n  mkdir -p \"${MY_DIR}\"\n}\n\nfunction teardown_file() {\n  rm -rf \"${MY_DIR}\"\n}\n\nfunction setup() {\n  rm -f \"${MY_DIR}/.nvmrc\"\n}\n\n@test \"auto .nvmrc, numeric\" {\n  cd \"${MY_DIR}\"\n  printf \"8.10.0\\n\" > .nvmrc\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.10.0\"\n}\n\n@test \"auto .nvmrc, numeric with leading v\" {\n  cd \"${MY_DIR}\"\n  printf \"v8.11.0\\n\" > .nvmrc\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.11.0\"\n}\n\n@test \"auto .nvmrc, node\" {\n  local TARGET_VERSION=\"$(display_remote_version latest)\"\n  cd \"${MY_DIR}\"\n  printf \"node\\n\" > .nvmrc\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"${TARGET_VERSION}\"\n}\n\n@test \"auto .nvmrc, lts/*\" {\n  local TARGET_VERSION=\"$(display_remote_version lts)\"\n  cd \"${MY_DIR}\"\n  printf \"lts/*\\n\" > .nvmrc\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"${TARGET_VERSION}\"\n}\n\n@test \"auto .nvmrc, lts/argon\" {\n  local TARGET_VERSION=\"$(display_remote_version lts)\"\n  cd \"${MY_DIR}\"\n  printf \"lts/argon\\n\" > .nvmrc\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"4.9.1\"\n}\n\n@test \"auto .nvmrc, sub directory\" {\n  cd \"${MY_DIR}\"\n  printf \"v8.11.1\\n\" > .nvmrc\n  mkdir -p sub-npmrc\n  cd sub-npmrc\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"8.11.1\"\n}\n\n@test \"auto .nvmrc, trailing comment\" {\n  local TARGET_VERSION=\"8.10.0\"\n  cd \"${MY_DIR}\"\n  printf \"${TARGET_VERSION} # comment\" > .nvmrc\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION auto)\"\n  assert_equal \"${output}\" \"${TARGET_VERSION}\"\n}\n"
  },
  {
    "path": "test/tests/version-resolve.bats",
    "content": "#!/usr/bin/env bats\n\n# Note: full semver is resolved without lookup, so can use arbitrary versions for testing like 999.999.999\n\nload shared-functions\nload '../../node_modules/bats-support/load'\nload '../../node_modules/bats-assert/load'\n\n\nfunction setup() {\n  unset_n_env\n}\n\n\n# node support aliases\n\n@test \"display_latest_resolved_version active\" {\n  local TARGET_VERSION=\"$(display_remote_version latest)\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION active)\"\n  assert_equal \"$output\" \"${TARGET_VERSION}\"\n}\n\n@test \"display_latest_resolved_version lts_active\" {\n  local TARGET_VERSION=\"$(display_remote_version lts)\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION lts_active)\"\n  assert_equal \"$output\" \"${TARGET_VERSION}\"\n}\n\n@test \"display_latest_resolved_version lts_latest\" {\n  local TARGET_VERSION=\"$(display_remote_version lts)\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION lts_latest)\"\n  assert_equal \"$output\" \"${TARGET_VERSION}\"\n}\n\n@test \"display_latest_resolved_version lts\" {\n  local TARGET_VERSION=\"$(display_remote_version lts)\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION lts)\"\n  assert_equal \"$output\" \"${TARGET_VERSION}\"\n}\n\n@test \"display_latest_resolved_version current\" {\n  local TARGET_VERSION=\"$(display_remote_version latest)\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION current)\"\n  assert_equal \"$output\" \"${TARGET_VERSION}\"\n}\n\n@test \"display_latest_resolved_version supported\" {\n  local TARGET_VERSION=\"$(display_remote_version latest)\"\n  output=\"$(n N_TEST_DISPLAY_LATEST_RESOLVED_VERSION supported)\"\n  assert_equal \"$output\" \"${TARGET_VERSION}\"\n}\n"
  },
  {
    "path": "test/tests.md",
    "content": "# Tests\n\nAutomated tests for `n`.\n\n## Setup\n\nOptional proxy using mitmproxy:\n\n    # using homebrew (Mac) to install mitmproxy\n    brew install mitmproxy\n\n\n## Running Tests\n\nRun all the tests across a range of containers and on the host system:\n\n    npm run test\n\nRun all the tests on a single system:\n\n    cd test\n    npx bats tests\n    docker compose run ubuntu-curl bats /mnt/test/tests\n\nRun single test on a single system::\n\n    cd test\n    npx bats tests/install-contents.bats\n    docker compose run ubuntu-curl bats /mnt/test/tests/install-contents.bats\n\n## Docker Tips\n\nUsing `docker compose` in addition to `docker` for convenient mounting of `n` script and the tests into the container. Changes to the tests or to `n` itself are reflected immediately without needing to rebuild the containers.\n\n`bats` is being mounted directly out of `node_modules` into the container as a manual install based on its own install script. This is a bit of a hack, but avoids needing to install `git` or `npm` for a full remote install of `bats`, and means everything on the same version of `bats`.\n\nThe containers each have:\n\n* either curl or wget (or both) installed\n\nUsing `docker compose` to run the container adds:\n\n* specified `n` script mounted to `/usr/local/bin/n`\n* `test/tests` mounted to `/mnt/test/tests`\n* `node_modules/bats` provides `/usr/local/bin/bats` et al\n* `.curlrc` with `--insecure` to allow use of proxy\n\nSo for example:\n\n    cd test\n    docker compose run ubuntu-curl\n      # in container\n      n --version\n      bats /mnt/test/tests\n"
  }
]