Full Code of ScoopInstaller/Scoop for AI

master b588a06e41d9 cached
134 files
583.4 KB
159.1k tokens
13 symbols
1 requests
Download .txt
Showing preview only (620K chars total). Download the full file or copy to clipboard to get everything.
Repository: ScoopInstaller/Scoop
Branch: master
Commit: b588a06e41d9
Files: 134
Total size: 583.4 KB

Directory structure:
gitextract_ros1r64f/

├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug_report.md
│   │   ├── Feature_request.md
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── PSScriptAnalyzerSettings.psd1
├── README.md
├── appveyor.yml
├── bin/
│   ├── auto-pr.ps1
│   ├── checkhashes.ps1
│   ├── checkurls.ps1
│   ├── checkver.ps1
│   ├── describe.ps1
│   ├── formatjson.ps1
│   ├── install.ps1
│   ├── missing-checkver.ps1
│   ├── refresh.ps1
│   ├── scoop.ps1
│   ├── test.ps1
│   └── uninstall.ps1
├── buckets.json
├── lib/
│   ├── autoupdate.ps1
│   ├── buckets.ps1
│   ├── commands.ps1
│   ├── core.ps1
│   ├── database.ps1
│   ├── decompress.ps1
│   ├── depends.ps1
│   ├── description.ps1
│   ├── diagnostic.ps1
│   ├── download.ps1
│   ├── getopt.ps1
│   ├── help.ps1
│   ├── install.ps1
│   ├── json.ps1
│   ├── manifest.ps1
│   ├── psmodules.ps1
│   ├── shortcuts.ps1
│   ├── system.ps1
│   └── versions.ps1
├── libexec/
│   ├── scoop-alias.ps1
│   ├── scoop-bucket.ps1
│   ├── scoop-cache.ps1
│   ├── scoop-cat.ps1
│   ├── scoop-checkup.ps1
│   ├── scoop-cleanup.ps1
│   ├── scoop-config.ps1
│   ├── scoop-create.ps1
│   ├── scoop-depends.ps1
│   ├── scoop-download.ps1
│   ├── scoop-export.ps1
│   ├── scoop-help.ps1
│   ├── scoop-hold.ps1
│   ├── scoop-home.ps1
│   ├── scoop-import.ps1
│   ├── scoop-info.ps1
│   ├── scoop-install.ps1
│   ├── scoop-list.ps1
│   ├── scoop-prefix.ps1
│   ├── scoop-reset.ps1
│   ├── scoop-search.ps1
│   ├── scoop-shim.ps1
│   ├── scoop-status.ps1
│   ├── scoop-unhold.ps1
│   ├── scoop-uninstall.ps1
│   ├── scoop-update.ps1
│   ├── scoop-virustotal.ps1
│   └── scoop-which.ps1
├── schema.json
├── supporting/
│   ├── formats/
│   │   └── ScoopTypes.Format.ps1xml
│   ├── shims/
│   │   ├── 71/
│   │   │   ├── checksum.sha256
│   │   │   └── checksum.sha512
│   │   ├── kiennq/
│   │   │   ├── checksum.sha256
│   │   │   ├── checksum.sha512
│   │   │   └── version.txt
│   │   └── scoopcs/
│   │       ├── checksum.sha256
│   │       ├── checksum.sha512
│   │       └── version.txt
│   └── validator/
│       ├── .gitignore
│       ├── Scoop.Validator.cs
│       ├── bin/
│       │   ├── checksum.sha256
│       │   └── checksum.sha512
│       ├── build.ps1
│       ├── install.ps1
│       ├── packages.config
│       ├── update.ps1
│       ├── validator.cs
│       └── validator.csproj
└── test/
    ├── Import-Bucket-Tests.ps1
    ├── Scoop-00File.Tests.ps1
    ├── Scoop-00Linting.Tests.ps1
    ├── Scoop-Commands.Tests.ps1
    ├── Scoop-Config.Tests.ps1
    ├── Scoop-Core.Tests.ps1
    ├── Scoop-Decompress.Tests.ps1
    ├── Scoop-Depends.Tests.ps1
    ├── Scoop-Download.Tests.ps1
    ├── Scoop-GetOpts.Tests.ps1
    ├── Scoop-Install.Tests.ps1
    ├── Scoop-Manifest.Tests.ps1
    ├── Scoop-TestLib.ps1
    ├── Scoop-Versions.Tests.ps1
    ├── bin/
    │   ├── init.ps1
    │   └── test.ps1
    └── fixtures/
        ├── format/
        │   ├── formatted/
        │   │   ├── 1-easy.json
        │   │   ├── 2-whitespaces-mess.json
        │   │   ├── 3-array-with-single-and-multi.json
        │   │   └── 4-script-block.json
        │   └── unformatted/
        │       ├── 1-easy.json
        │       ├── 2-whitespaces-mess.json
        │       ├── 3-array-with-single-and-multi.json
        │       └── 4-script-block.json
        ├── is_directory/
        │   ├── i_am_a_directory/
        │   │   └── .gitkeep
        │   └── i_am_a_file.txt
        ├── manifest/
        │   ├── broken_schema.json
        │   ├── broken_wget.json
        │   ├── invalid_wget.json
        │   └── wget.json
        ├── movedir/
        │   ├── user/
        │   │   └── _tmp/
        │   │       ├── subdir/
        │   │       │   └── test.txt
        │   │       └── test.txt
        │   ├── user with 'quote/
        │   │   └── _tmp/
        │   │       ├── subdir/
        │   │       │   └── test.txt
        │   │       └── test.txt
        │   └── user with space/
        │       └── _tmp/
        │           ├── subdir/
        │           │   └── test.txt
        │           └── test.txt
        └── shim/
            ├── shim-test.ps1
            └── user with 'quote/
                └── shim-test.ps1

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# EditorConfig (is awesome): http://EditorConfig.org

# * top-most EditorConfig file
root = true

# default style settings
[*]
charset = utf-8
end_of_line = crlf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

[*.{[Bb][Aa][Tt],[Cc][Mm][Dd]}]
# DOS/Win *requires* BAT/CMD files to have CRLF newlines
end_of_line = crlf

[*.{yml, yaml}]
indent_size = 2

# Makefiles require tab indentation
[{{M,m,GNU}akefile{,.*},*.mak,*.mk}]
indent_style = tab
end_of_line = lf


================================================
FILE: .gitattributes
================================================
# retain windows line-endings in case checked out on mac or linux
* text eol=crlf
*.exe -text
*.zip -text
*.dll -text


================================================
FILE: .github/ISSUE_TEMPLATE/Bug_report.md
================================================
---
name: "Bug Report"
about: "I am facing some problems."
title: '[Bug] '
labels: "bug"

---

<!--
  IMPORTANT:
  If your problem is related to a specific package, open the issue in the relevant bucket,
  not here.
  By opening this issue you confirm that you have searched for similar issues/PRs here already.
  Failing to do so will most likely result in closing of this issue without any explanation.
  Incomplete form details below might also result in closing of the issue.
-->

## Bug Report

#### Current Behavior
<!-- A clear and concise description of the behavior. -->

#### Expected Behavior
<!-- A clear and concise description of what you expected to happen. -->

#### Additional context/output
<!-- Add any other context about the problem here. If applicable, paste terminal output here to help explain. -->

#### Possible Solution
<!--- Only if you have suggestions on a fix for the bug -->

### System details

**Windows version:** [e.g. 7, 8, 10, 11]

**OS architecture:** [e.g. 32bit, 64bit, arm64]

**PowerShell version:** [output of `"$($PSVersionTable.PSVersion)"`]

**Additional software:** [(optional) e.g. ConEmu, Git]

#### Scoop Configuration
<!-- Can be found in  ~/.config/scoop/config.json -->

```json
//# Your configuration here
```


================================================
FILE: .github/ISSUE_TEMPLATE/Feature_request.md
================================================
---
name: "Feature Request"
about: "I have a suggestion (and may want to implement it)!"
title: '[Feature] '
labels: "enhancement"

---

<!--
  IMPORTANT:
  If your request is related to a specific package, open the issue in the relevant bucket,
  not here.
  By opening this issue you confirm that you have searched for similar issues/PRs here already.
  Failing to do so will most likely result in closing of this issue without any explanation.
  Incomplete form details below might also result in closing of the issue.
-->

## Feature Request

#### Is your feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I have an issue when [...] -->

#### Describe the solution you'd like
<!-- A clear and concise description of what you want to happen. Add any considered drawbacks. -->

#### Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false



================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
<!-- Provide a general summary of your changes in the Title above -->
<!-- To help with semantic versioning the PR title should start with one of the conventional commit types. -->
<!-- The conventional commit types for Semantic PR are: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert -->

<!--
  By opening this PR you confirm that you have searched for similar issues/PRs here already.
  Failing to do so will most likely result in closing of this PR without any explanation.
  It is also mandatory to open a relevant issue for discussion with the maintainers,
  before creating any new PR.
  Read the contributing guide first to save both your and our time.
-->

#### Description
<!-- Describe your changes in detail -->

#### Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
<!-- If it fixes an open issue, please link to the issue here. -->
Closes #XXXX
<!-- or -->
Relates to #XXXX

#### How Has This Been Tested?
<!-- Please describe in detail how you tested your changes. -->
<!-- Include details of your testing environment, tests ran to see how -->
<!-- your change affects other areas of the code, etc. -->

#### Checklist:
<!-- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] I have read the [Contributing Guide](https://github.com/ScoopInstaller/.github/blob/main/.github/CONTRIBUTING.md).
- [ ] I have ensured that I am targeting the `develop` branch.
- [ ] I have updated the documentation accordingly.
- [ ] I have updated the tests accordingly.
- [ ] I have added an entry in the CHANGELOG.


================================================
FILE: .github/dependabot.yml
================================================
---
# ~/.github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/" # == /.github/workflows/
    schedule:
      interval: "daily"


================================================
FILE: .github/workflows/ci.yml
================================================
name: Scoop Core CI Tests

on:
  pull_request:
  workflow_dispatch:

jobs:
  test_powershell:
    name: WindowsPowerShell
    runs-on: windows-latest
    steps:
      - name: Checkout
        uses: actions/checkout@main
        with:
          fetch-depth: 2
      - name: Init Test Suite
        uses: potatoqualitee/psmodulecache@main
        with:
          modules-to-cache: BuildHelpers
          shell: powershell
      - name: Test Scoop Core
        shell: powershell
        run: ./test/bin/test.ps1
  test_pwsh:
    name: PowerShell
    runs-on: windows-latest
    steps:
      - name: Checkout
        uses: actions/checkout@main
        with:
          fetch-depth: 2
      - name: Init Test Suite
        uses: potatoqualitee/psmodulecache@main
        with:
          modules-to-cache: BuildHelpers
          shell: pwsh
      - name: Test Scoop Core
        shell: pwsh
        run: ./test/bin/test.ps1


================================================
FILE: .gitignore
================================================
*.log
.DS_Store
._.DS_Store
scoop.sublime-workspace
test/installer/tmp/*
test/tmp/*
*~
TestResults.xml
supporting/sqlite/*


================================================
FILE: .vscode/extensions.json
================================================
{
    "recommendations": [
        "EditorConfig.EditorConfig",
        "ms-vscode.PowerShell"
    ]
}


================================================
FILE: .vscode/settings.json
================================================
// Configure PSScriptAnalyzer settings
{
    "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1",
    "powershell.codeFormatting.preset": "OTBS",
    "powershell.codeFormatting.alignPropertyValuePairs": true,
    "powershell.codeFormatting.ignoreOneLineBlock": true,
    "powershell.codeFormatting.useConstantStrings": true,
    "powershell.codeFormatting.useCorrectCasing": true,
    "powershell.codeFormatting.whitespaceBetweenParameters": true,
    "files.exclude": {
        "**/.git": true,
        "**/.svn": true,
        "**/.hg": true,
        "**/CVS": true,
        "**/.DS_Store": true,
        "**/tmp": true
    }
}


================================================
FILE: CHANGELOG.md
================================================
## [v0.5.3](https://github.com/ScoopInstaller/Scoop/compare/v0.5.2...v0.5.3) - 2025-08-11

### Features

**autoupdate:** GitHub predefined hashes support ([#6416](https://github.com/ScoopInstaller/Scoop/issues/6416), [#6435](https://github.com/ScoopInstaller/Scoop/issues/6435))

### Bug Fixes

- **scoop-download|install|update:** Fallback to default downloader when aria2 fails ([#4292](https://github.com/ScoopInstaller/Scoop/issues/4292))
- **decompress**: `Expand-7zipArchive` only delete temp dir / `$extractDir` if it is empty ([#6092](https://github.com/ScoopInstaller/Scoop/issues/6092))
- **decompress**: Replace deprecated 7ZIPEXTRACT_USE_EXTERNAL config with USE_EXTERNAL_7ZIP ([#6327](https://github.com/ScoopInstaller/Scoop/issues/6327))
- **commands**: Handling broken aliases ([#6141](https://github.com/ScoopInstaller/Scoop/issues/6141))
- **shim:** Do not suppress `stderr`, properly check `wslpath`/`cygpath` command first ([#6114](https://github.com/ScoopInstaller/Scoop/issues/6114))
- **scoop-bucket:** Add missing import for `no_junction` envs ([#6181](https://github.com/ScoopInstaller/Scoop/issues/6181))
- **scoop-uninstall:** Fix uninstaller does not gain Global state ([#6430](https://github.com/ScoopInstaller/Scoop/issues/6430))
- **scoop-depends-tests:** Mocking `USE_EXTERNAL_7ZIP` as $false to avoding error when it is $true ([#6431](https://github.com/ScoopInstaller/Scoop/issues/6431))

### Code Refactoring

- **download:** Move download-related functions to 'download.ps1' ([#6095](https://github.com/ScoopInstaller/Scoop/issues/6095))
- **Get-Manifest:** Select actual source for manifest ([#6142](https://github.com/ScoopInstaller/Scoop/issues/6142))

### Performance Improvements

- **shim:** Update kiennq-shim to v3.1.2 ([#6261](https://github.com/ScoopInstaller/Scoop/issues/6261))

## [v0.5.2](https://github.com/ScoopInstaller/Scoop/compare/v0.5.1...v0.5.2) - 2024-07-26

### Bug Fixes

- **scoop-alias:** Fix 'Option --verbose not recognized.' ([#6062](https://github.com/ScoopInstaller/Scoop/issues/6062))
- **scoop-hold:** Use 'foreach' loop to allow 'continue' statement ([#6078](https://github.com/ScoopInstaller/Scoop/issues/6078))
- **core:** Use 'Join-Path' to construct cache file path ([#6079](https://github.com/ScoopInstaller/Scoop/issues/6079))
- **json:** Don't serialize jsonpath return if only one result ([#6066](https://github.com/ScoopInstaller/Scoop/issues/6066), [#6073](https://github.com/ScoopInstaller/Scoop/issues/6073))

### Builds

- **supporting:** Update Json.Schema to 4.0.1 ([#6072](https://github.com/ScoopInstaller/Scoop/issues/6072))

## [v0.5.1](https://github.com/ScoopInstaller/Scoop/compare/v0.5.0...v0.5.1) - 2024-07-16

### Bug Fixes

- **scoop-alias:** Pass options correctly ([#6003](https://github.com/ScoopInstaller/Scoop/issues/6003))
- **scoop-virustotal:** Adjust `json_path` parameters to retrieve correct analysis stats ([#6044](https://github.com/ScoopInstaller/Scoop/issues/6044))
- **bucket:** Implement error handling for failed bucket addition ([#6051](https://github.com/ScoopInstaller/Scoop/issues/6051))
- **database:** Fix compatibility with Windows PowerShell ([#6045](https://github.com/ScoopInstaller/Scoop/issues/6045))
- **install:** Expand `env_set` items before setting Environment Variables ([#6050](https://github.com/ScoopInstaller/Scoop/issues/6050))
- **install:** Fix parsing error when installing multiple apps w/ specific version ([#6039](https://github.com/ScoopInstaller/Scoop/issues/6039))

## [v0.5.0](https://github.com/ScoopInstaller/Scoop/compare/v0.4.2...v0.5.0) - 2024-07-01

### Features

- **scoop-search:** Use SQLite for caching apps to speed up local search ([#5851](https://github.com/ScoopInstaller/Scoop/issues/5851), [#5918](https://github.com/ScoopInstaller/Scoop/issues/5918), [#5946](https://github.com/ScoopInstaller/Scoop/issues/5946), [#5949](https://github.com/ScoopInstaller/Scoop/issues/5949), [#5955](https://github.com/ScoopInstaller/Scoop/issues/5955), [#5966](https://github.com/ScoopInstaller/Scoop/issues/5966), [#5967](https://github.com/ScoopInstaller/Scoop/issues/5967), [#5981](https://github.com/ScoopInstaller/Scoop/issues/5981))
- **core:** New cache filename format ([#5929](https://github.com/ScoopInstaller/Scoop/issues/5929), [#5944](https://github.com/ScoopInstaller/Scoop/issues/5944))
- **decompress:** Use innounp-unicode as default Inno Setup Unpacker ([#6028](https://github.com/ScoopInstaller/Scoop/issues/6028))
- **install:** Added the ability to install specific version of app from URL/file link ([#5988](https://github.com/ScoopInstaller/Scoop/issues/5988))

### Bug Fixes

- **scoop-download|install|update:** Use consistent options ([#5956](https://github.com/ScoopInstaller/Scoop/issues/5956))
- **scoop-info:** Fix download size estimating ([#5958](https://github.com/ScoopInstaller/Scoop/issues/5958))
- **scoop-search:** Catch error of parsing invalid manifest ([#5930](https://github.com/ScoopInstaller/Scoop/issues/5930))
- **checkver:** Correct variable 'regex' to 'regexp' ([#5993](https://github.com/ScoopInstaller/Scoop/issues/5993))
- **checkver:** Correct error messages ([#6024](https://github.com/ScoopInstaller/Scoop/issues/6024))
- **core:** Search for Git executable instead of any cmdlet ([#5998](https://github.com/ScoopInstaller/Scoop/issues/5998))
- **core:** Use correct path in 'bash' ([#6006](https://github.com/ScoopInstaller/Scoop/issues/6006))
- **core:** Limit the number of commands to get when search for git executable ([#6013](https://github.com/ScoopInstaller/Scoop/issues/6013))
- **decompress:** Match `extract_dir`/`extract_to` and archives ([#5983](https://github.com/ScoopInstaller/Scoop/issues/5983))
- **json:** Serialize jsonpath return ([#5921](https://github.com/ScoopInstaller/Scoop/issues/5921))
- **shim:** Restore original path for JAR cmd ([#6030](https://github.com/ScoopInstaller/Scoop/issues/6030))

### Code Refactoring

- **decompress:** Use 7zip to extract Zstd archive ([#5973](https://github.com/ScoopInstaller/Scoop/issues/5973))
- **install:** Separate archive extraction from downloader ([#5951](https://github.com/ScoopInstaller/Scoop/issues/5951))
- **install:** Replace 'run_(un)installer()' with 'Invoke-Installer()' ([#5968](https://github.com/ScoopInstaller/Scoop/issues/5968), [#5971](https://github.com/ScoopInstaller/Scoop/issues/5971))

## [v0.4.2](https://github.com/ScoopInstaller/Scoop/compare/v0.4.1...v0.4.2) - 2024-05-14

### Bug Fixes

- **autoupdate:** Copy `PSCustomObject`-type properties within `substitute()` to prevent reference changes ([#5934](https://github.com/ScoopInstaller/Scoop/issues/5934), [#5962](https://github.com/ScoopInstaller/Scoop/issues/5962))
- **core:** Fix `Invoke-ExternalCommand` quoting rules ([#5945](https://github.com/ScoopInstaller/Scoop/issues/5945))
- **system:** Fix argument passing to `Split-PathLikeEnvVar()` in deprecated `strip_path()` ([#5937](https://github.com/ScoopInstaller/Scoop/issues/5937))

## [v0.4.1](https://github.com/ScoopInstaller/Scoop/compare/v0.4.0...v0.4.1) - 2024-04-25

### Bug Fixes

- **core:** Fix `Invoke-ExternalCommand` regression ([#5923](https://github.com/ScoopInstaller/Scoop/issues/5923))

## [v0.4.0](https://github.com/ScoopInstaller/Scoop/compare/v0.3.1...v0.4.0) - 2024-04-18

### Features

- **scoop-update:** Add support for parallel syncing buckets in PowerShell 7 and improve output ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122))
- **bucket:** Switch nirsoft bucket to ScoopInstaller/Nirsoft ([#5328](https://github.com/ScoopInstaller/Scoop/issues/5328))
- **bucket:** Make official buckets higher priority ([#5398](https://github.com/ScoopInstaller/Scoop/issues/5398))
- **config:** Support portable config file ([#5369](https://github.com/ScoopInstaller/Scoop/issues/5369))
- **core:** Add `-Quiet` switch for `Invoke-ExternalCommand` ([#5346](https://github.com/ScoopInstaller/Scoop/issues/5346))
- **core:** Allow global install of PowerShell modules ([#5611](https://github.com/ScoopInstaller/Scoop/issues/5611))
- **path:** Isolate Scoop apps' PATH ([#5840](https://github.com/ScoopInstaller/Scoop/issues/5840))

### Bug Fixes

- **scoop-alias:** Prevent overwrite existing file when adding alias ([#5577](https://github.com/ScoopInstaller/Scoop/issues/5577))
- **scoop-checkup:** Skip defender check in Windows Sandbox ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
- **scoop-checkup:** Change the message level of helpers from ERROR to WARN ([#5614](https://github.com/ScoopInstaller/Scoop/issues/5614))
- **scoop-checkup:** Don't throw 7zip error when external 7zip is used ([#5703](https://github.com/ScoopInstaller/Scoop/issues/5703))
- **scoop-(un)hold:** Correct output the messages when manifest not found, (already|not) held ([#5519](https://github.com/ScoopInstaller/Scoop/issues/5519))
- **scoop-info:** Fix errors in file size collection when `--verbose` ([#5352](https://github.com/ScoopInstaller/Scoop/issues/5352))
- **scoop-reset:** Don't abort when multiple apps are passed and an app is running ([#5687](https://github.com/ScoopInstaller/Scoop/issues/5687))
- **scoop-update:** Change error message to a better instruction ([#5677](https://github.com/ScoopInstaller/Scoop/issues/5677))
- **scoop-virustotal:** Fix `scoop-virustotal` when `--all` has been passed without app ([#5593](https://github.com/ScoopInstaller/Scoop/issues/5593))
- **scoop-virustotal:** Fix the issue that escape character not available in PowerShell 5.1 ([#5870](https://github.com/ScoopInstaller/Scoop/issues/5870))
- **autoupdate:** Fix file hash extraction ([#5295](https://github.com/ScoopInstaller/Scoop/issues/5295))
- **autoupdate:** Fix bug that 'WebClient' doesn't auto-extract 'gzip' ([#5901](https://github.com/ScoopInstaller/Scoop/issues/5901))
- **buckets:** Avoid error messages for unexpected dir ([#5549](https://github.com/ScoopInstaller/Scoop/issues/5549))
- **config:** Warn users about misconfigured GitHub token ([#5777](https://github.com/ScoopInstaller/Scoop/issues/5777))
- **core:** Fix scripts' calling parameters ([#5365](https://github.com/ScoopInstaller/Scoop/issues/5365))
- **core:** Fix `is_in_dir` under Unix ([#5391](https://github.com/ScoopInstaller/Scoop/issues/5391))
- **core:** Rewrite config file when needed ([#5439](https://github.com/ScoopInstaller/Scoop/issues/5439))
- **core:** Prevents leaking HTTP(S)_PROXY env vars to current sessions after Invoke-Git in parallel execution ([#5436](https://github.com/ScoopInstaller/Scoop/issues/5436))
- **core:** Handle scoop aliases and broken(edited,copied) shim ([#5551](https://github.com/ScoopInstaller/Scoop/issues/5551))
- **core:** Avoid error messages when deleting non-existent environment variable ([#5547](https://github.com/ScoopInstaller/Scoop/issues/5547))
- **core:** Use relative path as fallback of `$scoopdir` ([#5544](https://github.com/ScoopInstaller/Scoop/issues/5544))
- **core:** Fix detection of Git ([#5545](https://github.com/ScoopInstaller/Scoop/issues/5545))
- **core:** Do not call `scoop` externally from inside the code ([#5695](https://github.com/ScoopInstaller/Scoop/issues/5695))
- **core:** Fix arguments parsing method of `Invoke-ExternalCommand()` ([#5839](https://github.com/ScoopInstaller/Scoop/issues/5839))
- **decompress:** Exclude '*.nsis' that may cause error ([#5294](https://github.com/ScoopInstaller/Scoop/issues/5294))
- **decompress:** Remove unused parent dir w/ 'extract_dir' ([#5682](https://github.com/ScoopInstaller/Scoop/issues/5682))
- **decompress:** Use `wix.exe` in WiX Toolset v4+ as primary extractor of `Expand-DarkArchive()` ([#5871](https://github.com/ScoopInstaller/Scoop/issues/5871))
- **env:** Avoid automatic expansion of `%%` in env ([#5395](https://github.com/ScoopInstaller/Scoop/issues/5395), [#5452](https://github.com/ScoopInstaller/Scoop/issues/5452), [#5631](https://github.com/ScoopInstaller/Scoop/issues/5631))
- **getopt:** Stop split arguments in `getopt()` and ensure array by explicit arguments type ([#5326](https://github.com/ScoopInstaller/Scoop/issues/5326))
- **install:** Fix download from private GitHub repositories ([#5361](https://github.com/ScoopInstaller/Scoop/issues/5361))
- **install:** Avoid error when unlinking non-existent junction/hardlink ([#5552](https://github.com/ScoopInstaller/Scoop/issues/5552))
- **manifest:** Correct source of manifest ([#5575](https://github.com/ScoopInstaller/Scoop/issues/5575))
- **shim:** Remove console window for GUI applications ([#5559](https://github.com/ScoopInstaller/Scoop/issues/5559))
- **shim:** Use bash executable directly ([#5433](https://github.com/ScoopInstaller/Scoop/issues/5433))
- **shim:** Check literal path in `Get-ShimPath` ([#5680](https://github.com/ScoopInstaller/Scoop/issues/5680))
- **shim:** Avoid unexpected output of `list` subcommand ([#5681](https://github.com/ScoopInstaller/Scoop/issues/5681))
- **shim:** Allow GUI applications to attach to the shell's console when launched using the GUI shim ([#5721](https://github.com/ScoopInstaller/Scoop/issues/5721))
- **shim:** Run JAR file from app's root directory ([#5872](https://github.com/ScoopInstaller/Scoop/issues/5872))
- **shortcuts:** Output correctly formatted path ([#5333](https://github.com/ScoopInstaller/Scoop/issues/5333))
- **update/uninstall:** Remove items from PATH correctly ([#5833](https://github.com/ScoopInstaller/Scoop/issues/5833))

### Performance Improvements

- **scoop-search:** Improve performance for local search ([#5644](https://github.com/ScoopInstaller/Scoop/issues/5644))
- **scoop-update:** Check for running process before wasting time on download ([#5799](https://github.com/ScoopInstaller/Scoop/issues/5799))
- **decompress:** Disable progress bar to improve `Expand-Archive` performance ([#5410](https://github.com/ScoopInstaller/Scoop/issues/5410))
- **shim:** Update kiennq-shim to v3.1.1 ([#5841](https://github.com/ScoopInstaller/Scoop/issues/5841), [#5847](https://github.com/ScoopInstaller/Scoop/issues/5847))

### Code Refactoring

- **scoop-download:** Output more detailed manifest information ([#5277](https://github.com/ScoopInstaller/Scoop/issues/5277))
- **core:** Cleanup some old codes, e.g., msi section and config migration ([#5715](https://github.com/ScoopInstaller/Scoop/issues/5715), [#5824](https://github.com/ScoopInstaller/Scoop/issues/5824))
- **core:** Rewrite and separate path-related functions to `system.ps1` ([#5836](https://github.com/ScoopInstaller/Scoop/issues/5836), [#5858](https://github.com/ScoopInstaller/Scoop/issues/5858), [#5864](https://github.com/ScoopInstaller/Scoop/issues/5864))
- **core:** Get rid of 'fullpath' ([#3533](https://github.com/ScoopInstaller/Scoop/issues/3533))
- **git:** Use Invoke-Git() with direct path to git.exe to prevent spawning shim subprocesses ([#5122](https://github.com/ScoopInstaller/Scoop/issues/5122), [#5375](https://github.com/ScoopInstaller/Scoop/issues/5375))
- **helper:** Remove 7zip's fallback '7zip-zstd' ([#5548](https://github.com/ScoopInstaller/Scoop/issues/5548))
- **shim:** Remove CS shim codebase ([#5903](https://github.com/ScoopInstaller/Scoop/issues/5903))

### Builds

- **checkver:** Read the private_host config variable ([#5381](https://github.com/ScoopInstaller/Scoop/issues/5381))
- **supporting:** Update Json to 13.0.3, Json.Schema to 3.0.15 ([#5835](https://github.com/ScoopInstaller/Scoop/issues/5835))

### Continuous Integration

- **dependabot:** Add dependabot.yml for GitHub Actions ([#5377](https://github.com/ScoopInstaller/Scoop/issues/5377))
- **module:** Update 'psmodulecache' version to 'main' ([#5828](https://github.com/ScoopInstaller/Scoop/issues/5828))

### Tests

- **bucket:** Skip manifest validation if no manifest changes ([#5270](https://github.com/ScoopInstaller/Scoop/issues/5270))

### Documentation

- **scoop-info:** Fix help message([#5445](https://github.com/ScoopInstaller/Scoop/issues/5445))
- **readme:** Improve documentation language ([#5638](https://github.com/ScoopInstaller/Scoop/issues/5638))

## [v0.3.1](https://github.com/ScoopInstaller/Scoop/compare/v0.3.0...v0.3.1) - 2022-11-15

### Features

- **config:** Allow Scoop to check if apps versioned as 'nightly' are outdated ([#5166](https://github.com/ScoopInstaller/Scoop/issues/5166))
- **checkup:** Add Windows Developer Mode check ([#5233](https://github.com/ScoopInstaller/Scoop/issues/5233))
- **bucket:** Add 'sysinternals' bucket to known ([#5237](https://github.com/ScoopInstaller/Scoop/issues/5237))

### Bug Fixes

- **decompress:** Use PS's default 'Expand-Archive()' ([#5185](https://github.com/ScoopInstaller/Scoop/issues/5185))
- **hash:** Fix SourceForge's hash extraction ([#5189](https://github.com/ScoopInstaller/Scoop/issues/5189))
- **decompress:** Trim ending '/' ([#5195](https://github.com/ScoopInstaller/Scoop/issues/5195))
- **shim:** Exit if shim creating failed 'cause no git ([#5225](https://github.com/ScoopInstaller/Scoop/issues/5225))
- **scoop-import:** Add correct architecture argument ([#5210](https://github.com/ScoopInstaller/Scoop/issues/5210))
- **scoop-config:** Output `[DateTime]` as `[String]` ([#5232](https://github.com/ScoopInstaller/Scoop/issues/5232))
- **shim:** fixed shim add bug related to Resolve-Path ([#5492](https://github.com/ScoopInstaller/Scoop/issues/5492))

### Code Refactoring

- **hash:** Use `Get-FileHash()` directly ([#5177](https://github.com/ScoopInstaller/Scoop/issues/5177))
- **installer:** Drop the old installer ([#5186](https://github.com/ScoopInstaller/Scoop/issues/5186))
- **unix:** Remove `unix.ps1` ([#5235](https://github.com/ScoopInstaller/Scoop/issues/5235))

### Builds

- **auto-pr:** Add `CommitMessageFormat` option ([#5171](https://github.com/ScoopInstaller/Scoop/issues/5171))
- **checkver:** Support XML default namespace ([#5191](https://github.com/ScoopInstaller/Scoop/issues/5191))
- **pssa:** Remove unused 'ExcludeRules' ([#5201](https://github.com/ScoopInstaller/Scoop/issues/5201))
- **schema:** Add 'installer' and 'shortcuts' to 'autoupdate' ([#5220](https://github.com/ScoopInstaller/Scoop/issues/5220))
- **checkhashes:** Use correct version number if `UseCache` ([#5240](https://github.com/ScoopInstaller/Scoop/issues/5240))

### Continuous Integration

- **module:** Update modules version ([#5209](https://github.com/ScoopInstaller/Scoop/issues/5209))

### Tests

- **unix:** Fix tests in Linux and macOS ([#5179](https://github.com/ScoopInstaller/Scoop/issues/5179))
- **pester:** Update to Pester 5 ([#5222](https://github.com/ScoopInstaller/Scoop/issues/5222))
- **bucket:** Use BuildHelpers' EnvVars ([#5226](https://github.com/ScoopInstaller/Scoop/issues/5226))

### Documentation

- **scoop-cat:** Fix help message([#5224](https://github.com/ScoopInstaller/Scoop/issues/5224))

## [v0.3.0](https://github.com/ScoopInstaller/Scoop/compare/v0.2.4...v0.3.0) - 2022-10-10

### Features

- **install:** Add support for ARM64 architecture ([#5154](https://github.com/ScoopInstaller/Scoop/issues/5154))
- **install:** Show the running process ([#5102](https://github.com/ScoopInstaller/Scoop/issues/5102))
- **getopt:** Support option terminator (`--`) ([#5121](https://github.com/ScoopInstaller/Scoop/issues/5121))
- **subdir:** Allow subdir in 'bucket' ([#5119](https://github.com/ScoopInstaller/Scoop/issues/5119))
- **scoop-config:** Allow 'hold_update_until' be set manually ([#5100](https://github.com/ScoopInstaller/Scoop/issues/5100))
- **scoop-(un)hold:** Support `scoop (un)hold scoop` ([#5089](https://github.com/ScoopInstaller/Scoop/issues/5089))
- **scoop-update:** Stash uncommitted changes before update ([#5091](https://github.com/ScoopInstaller/Scoop/issues/5091))

### Bug Fixes

- **config:** Change config option to snake_case in file and SCREAMING_CASE in code ([#5116](https://github.com/ScoopInstaller/Scoop/issues/5116))
- **jsonpath:** Prevent converting date string to DateTime in JSONPath ([#5130](https://github.com/ScoopInstaller/Scoop/issues/5130))
- **psmodule:** Remove folder recursively when unlinking previous module path ([#5127](https://github.com/ScoopInstaller/Scoop/issues/5127))
- **scoop-update:** Add `uninstall_psmodule` to update process ([#5136](https://github.com/ScoopInstaller/Scoop/issues/5136))

### Code Refactoring

- **download:** Rename `dl()` to `Invoke-Download()` ([#5143](https://github.com/ScoopInstaller/Scoop/issues/5143))
- **path:** Use 'Convert-Path()' instead of 'Resolve-Path()' ([#5109](https://github.com/ScoopInstaller/Scoop/issues/5109))
- **scoop-shim:** Use `getopt` to parse arguments ([#5125](https://github.com/ScoopInstaller/Scoop/issues/5125))

### Builds

- **checkver:** Implement SourceForge checkver functionality ([#5113](https://github.com/ScoopInstaller/Scoop/issues/5113), [#5163](https://github.com/ScoopInstaller/Scoop/issues/5163))
- **checkurls:** Allow checking URLs from private_hosts ([#5152](https://github.com/ScoopInstaller/Scoop/issues/5152))
- **schema:** Set manifest schema to be stricter ([#5093](https://github.com/ScoopInstaller/Scoop/issues/5093))
- **vscode:** Tweak VSCode setting ([#5149](https://github.com/ScoopInstaller/Scoop/issues/5149))

## [v0.2.4](https://github.com/ScoopInstaller/Scoop/compare/v0.2.3...v0.2.4) - 2022-08-08

### Features

- **core:** Create no window by default in `Invoke-ExternalCommand` ([#5066](https://github.com/ScoopInstaller/Scoop/issues/5066))
- **core:** Improve argument concatenation in `Invoke-ExternalCommand` ([#5065](https://github.com/ScoopInstaller/Scoop/issues/5065))
- **install:** Show bucket name while installing an app ([#5075](https://github.com/ScoopInstaller/Scoop/issues/5075))
- **scoop-status:** Add flag to disable remote checking ([#5073](https://github.com/ScoopInstaller/Scoop/issues/5073))
- **scoop-update:** Add support for `pre_uninstall` and `post_uninstall` ([#5085](https://github.com/ScoopInstaller/Scoop/issues/5085))

### Bug Fixes

- **core:** Avoid deadlock in `Invoke-ExternalCommand` ([#5064](https://github.com/ScoopInstaller/Scoop/issues/5064))
- **core:** Use 'System.Nullable<bool>' for param 'global' ([#5088](https://github.com/ScoopInstaller/Scoop/issues/5088))
- **install:** Move from cache when `--no-cache` is specified ([#5039](https://github.com/ScoopInstaller/Scoop/issues/5039))
- **scoop-status:** Correct formatting of `Info` output ([#5047](https://github.com/ScoopInstaller/Scoop/issues/5047))

### Builds

- **checkver:** Load page content before running 'script' ([#5080](https://github.com/ScoopInstaller/Scoop/issues/5080))
- **json:** Update Newtonsoft.Json.Schema to 3.0.15-beta2 ([#5053](https://github.com/ScoopInstaller/Scoop/issues/5053))

## [v0.2.3](https://github.com/ScoopInstaller/Scoop/compare/v0.2.2...v0.2.3) - 2022-07-07

### Features

- **chore:** Add missing -a/--all param to all commands ([#5004](https://github.com/ScoopInstaller/Scoop/issues/5004))
- **scoop-status:** Check bucket status, improve output ([#5011](https://github.com/ScoopInstaller/Scoop/issues/5011))
- **scoop-info:** Show app installed/download size ([#4886](https://github.com/ScoopInstaller/Scoop/issues/4886))
- **scoop-import:** Import a Scoop installation from JSON ([#5014](https://github.com/ScoopInstaller/Scoop/issues/5014), [#5034](https://github.com/ScoopInstaller/Scoop/issues/5034))

### Bug Fixes

- **chore:** Update help documentation ([#5002](https://github.com/ScoopInstaller/Scoop/issues/5002), [#5029](https://github.com/ScoopInstaller/Scoop/issues/5029))
- **decompress:** Handle split RAR archives ([#4994](https://github.com/ScoopInstaller/Scoop/issues/4994))
- **shortcuts:** Fix network drive shortcut creation ([#4410](https://github.com/ScoopInstaller/Scoop/issues/4410), [#5006](https://github.com/ScoopInstaller/Scoop/issues/5006))

### Code Refactoring

- **scoop-search:** Output PSObject, use API token ([#4997](https://github.com/ScoopInstaller/Scoop/issues/4997))

### Builds

- **checkver,auto-pr:** Allow passing file path ([#5019](https://github.com/ScoopInstaller/Scoop/issues/5019))
- **checkver:** Exit routine earlier if error ([#5025](https://github.com/ScoopInstaller/Scoop/issues/5025))
- **json:** Update Newton.Json to 13.0.1 ([#5026](https://github.com/ScoopInstaller/Scoop/issues/5026))

### Tests

- **typo:** Fix typo ('formated' -> 'formatted') ([#4217](https://github.com/ScoopInstaller/Scoop/issues/4217))

## [v0.2.2](https://github.com/ScoopInstaller/Scoop/compare/v0.2.1...v0.2.2) - 2022-06-21

### Features

- **core:** Add `Get-Encoding` function to fix missing webclient encoding ([#4956](https://github.com/ScoopInstaller/Scoop/issues/4956))
- **scoop-(un)hold:** Add `-g`/`--global` flag ([#4991](https://github.com/ScoopInstaller/Scoop/issues/4991))
- **scoop-update:** Support `scoop update scoop` ([#4992](https://github.com/ScoopInstaller/Scoop/issues/4992))
- **scoop-virustotal:** Migrate to VirusTotal API v3 ([#4983](https://github.com/ScoopInstaller/Scoop/issues/4983))

### Bug Fixes

- **manifest:** Fix bugs in 'Get-Manifest()' ([#4986](https://github.com/ScoopInstaller/Scoop/issues/4986))

## [v0.2.1](https://github.com/ScoopInstaller/Scoop/compare/v0.2.0...v0.2.1) - 2022-06-10

### Features

- **core:** Add pre_uninstall and post_uninstall hooks ([#4957](https://github.com/ScoopInstaller/Scoop/issues/4957), [#4962](https://github.com/ScoopInstaller/Scoop/issues/4962))

### Bug Fixes

- **bucket:** Make sure `list_buckets` return array ([#4979](https://github.com/ScoopInstaller/Scoop/issues/4979))
- **chore:** Deprecate tls1 and tls1.1 ([#4950](https://github.com/ScoopInstaller/Scoop/issues/4950))
- **chore:** Update Nonportable bucket URL ([#4955](https://github.com/ScoopInstaller/Scoop/issues/4955))
- **core:** Using `Invoke-Command` instead of `Invoke-Expression` ([#4941](https://github.com/ScoopInstaller/Scoop/issues/4941))
- **core:** Load config file before initialization ([#4932](https://github.com/ScoopInstaller/Scoop/issues/4932))
- **core:** Allow to use '_' and '.' in bucket name ([#4952](https://github.com/ScoopInstaller/Scoop/issues/4952))
- **depends:** Avoid digits in archive file extension (except for .7z and .001) ([#4915](https://github.com/ScoopInstaller/Scoop/issues/4915))
- **bucket:** Don't check remote URL of non-git buckets ([#4923](https://github.com/ScoopInstaller/Scoop/issues/4923))
- **bucket:** Don't write message OK before bucket is cloned ([#4925](https://github.com/ScoopInstaller/Scoop/issues/4925))
- **shim:** Add 'Get-CommandPath()' to find git ([#4913](https://github.com/ScoopInstaller/Scoop/issues/4913))
- **shim:** Remove character replacement in .cmd -> .ps1 shims ([#4914](https://github.com/ScoopInstaller/Scoop/issues/4914))
- **scoop:** Pass CLI arguments as string objects ([#4931](https://github.com/ScoopInstaller/Scoop/issues/4931))
- **scoop-info:** Fix error message when manifest is not found ([#4935](https://github.com/ScoopInstaller/Scoop/issues/4935))
- **scoop-search:** Require files in 'bucket' dir for remote known buckets ([#4944](https://github.com/ScoopInstaller/Scoop/issues/4944))
- **update:** Prevent uninstall when update ([#4949](https://github.com/ScoopInstaller/Scoop/issues/4949))
- **scoop-download:** Use correct Args when calling `Get-Manifest` ([#4970](https://github.com/ScoopInstaller/Scoop/issues/4970))

### Code Refactoring

- **manifest:** Rename 'Find-Manifest()' to 'Get-Manifest() ([#4966](https://github.com/ScoopInstaller/Scoop/issues/4966), [#4981](https://github.com/ScoopInstaller/Scoop/issues/4981))

### Documentation

- **readme:** Update license badge ([#4929](https://github.com/ScoopInstaller/Scoop/issues/4929))

## [v0.2.0](https://github.com/ScoopInstaller/Scoop/compare/v0.1.0...v0.2.0) - 2022-05-10

### Features

- **relicense:** Relicense to dual-license (Unlicense or MIT) ([#4903](https://github.com/ScoopInstaller/Scoop/issues/4903), [#4870](https://github.com/ScoopInstaller/Scoop/issues/4870))
- **install:** Allow downloading from private repositories ([#4254](https://github.com/ScoopInstaller/Scoop/issues/4254))
- **scoop-cleanup:** Add `-a/--all` switch to cleanup all apps ([#4906](https://github.com/ScoopInstaller/Scoop/issues/4906))

### Bug Fixes

- **bucket:** Return empty list correctly in `Get-LocalBucket` ([#4885](https://github.com/ScoopInstaller/Scoop/issues/4885))
- **install:** Fix issue with installation inside containers ([#4837](https://github.com/ScoopInstaller/Scoop/issues/4837))
- **installed:** If no `$global`, check both local and global installed ([#4798](https://github.com/ScoopInstaller/Scoop/issues/4798))
- **shim:** Manipulating shims with UTF8 encoding ([#4791](https://github.com/ScoopInstaller/Scoop/issues/4791), [#4813](https://github.com/ScoopInstaller/Scoop/issues/4813))
- **shim:** Correctly quote $@ in sh->ps1 shims ([#4809](https://github.com/ScoopInstaller/Scoop/issues/4809))
- **update:** Skip logs starting with `(chore)` ([#4800](https://github.com/ScoopInstaller/Scoop/issues/4800))
- **scoop-download:** Add failure check ([#4822](https://github.com/ScoopInstaller/Scoop/issues/4822))
- **scoop-list:** Fix date in 'Updated' column showing the months in the place of minutes ([#4880](https://github.com/ScoopInstaller/Scoop/issues/4880))
- **scoop-prefix:** Fix typo that breaks global installed apps ([#4795](https://github.com/ScoopInstaller/Scoop/issues/4795))

### Performance Improvements

- **scoop:** Load libs only once ([#4839](https://github.com/ScoopInstaller/Scoop/issues/4839), [#4884](https://github.com/ScoopInstaller/Scoop/issues/4884))

### Code Refactoring

- **bucket:** Move 'Find-Manifest' and 'list_buckets' to 'buckets' ([#4814](https://github.com/ScoopInstaller/Scoop/issues/4814))
- **relpath:** Use `$PSScriptRoot` instead of `relpath` ([#4793](https://github.com/ScoopInstaller/Scoop/issues/4793))
- **reset_aliases:** Move core function of `reset_aliases` to `scoop` ([#4794](https://github.com/ScoopInstaller/Scoop/issues/4794))
- **config:** Rename checkver_token to gh_token and SCOOP_CHECKVER_TOKEN to SCOOP_GH_TOKEN ([#4832](https://github.com/ScoopInstaller/Scoop/issues/4832), [#4842](https://github.com/ScoopInstaller/Scoop/issues/4842))

### Builds

- **checkver:** Add option to throw error as exception ([#4867](https://github.com/ScoopInstaller/Scoop/issues/4867))
- **schema:** Remove 'description' from required fields ([#4853](https://github.com/ScoopInstaller/Scoop/issues/4853), [#4874](https://github.com/ScoopInstaller/Scoop/issues/4874))

### Documentation

- **changelog:** Rearrange CHANGELOG ([#4897](https://github.com/ScoopInstaller/Scoop/issues/4897))
- **readme:** Update installation instruction ([#4825](https://github.com/ScoopInstaller/Scoop/issues/4825))
- **readme:** Fix badges for Gitter and CI Tests ([#4830](https://github.com/ScoopInstaller/Scoop/issues/4830))
- **scoop-shim:** Fix typo ([#4836](https://github.com/ScoopInstaller/Scoop/issues/4836))

## [v0.1.0](https://github.com/ScoopInstaller/Scoop/compare/2021-12-26...v0.1.0) - 2022-03-01

### Features

- **scoop-bucket:** List more detailed information for buckets ([#4704](https://github.com/ScoopInstaller/Scoop/issues/4704), [#4756](https://github.com/ScoopInstaller/Scoop/issues/4756), [#4759](https://github.com/ScoopInstaller/Scoop/issues/4759))
- **scoop-cache:** Handle multiple apps and show detailed information ([#4738](https://github.com/ScoopInstaller/Scoop/issues/4738))
- **scoop-cat:** Use `bat` to pretty-print JSON ([#4742](https://github.com/ScoopInstaller/Scoop/issues/4742))
- **scoop-config:** Allow Scoop to ignore running processes during reset/uninstall/update ([#4713](https://github.com/ScoopInstaller/Scoop/issues/4713), [#4731](https://github.com/ScoopInstaller/Scoop/issues/4731))
- **scoop-config:** Show all settings ([#4765](https://github.com/ScoopInstaller/Scoop/issues/4765))
- **scoop-download:** Add `scoop download` command ([#4621](https://github.com/ScoopInstaller/Scoop/issues/4621))
- **scoop-(install|virustotal):** Allow skipping update check ([#4634](https://github.com/ScoopInstaller/Scoop/issues/4634))
- **scoop-list:** Allow list manipulation ([#4718](https://github.com/ScoopInstaller/Scoop/issues/4718))
- **scoop-list:** Show last-updated time ([#4723](https://github.com/ScoopInstaller/Scoop/issues/4723))
- **scoop-info:** Revamp details and show more information ([#4747](https://github.com/ScoopInstaller/Scoop/issues/4747))
- **scoop-shim:** Add `scoop shim` to manipulate shims ([#4727](https://github.com/ScoopInstaller/Scoop/issues/4727), [#4736](https://github.com/ScoopInstaller/Scoop/issues/4736))

### Bug Fixes

- **autoupdate:** Allow checksum file that contains whitespaces ([#4619](https://github.com/ScoopInstaller/Scoop/issues/4619))
- **autoupdate:** Rename $response to $res ([#4706](https://github.com/ScoopInstaller/Scoop/issues/4706))
- **config:** Ensure manipulating config with UTF8 encoding ([#4644](https://github.com/ScoopInstaller/Scoop/issues/4644))
- **config:** Allow scoop config use Unicode characters ([#4631](https://github.com/ScoopInstaller/Scoop/issues/4631))
- **config:** Fix `set_config` bugs ([#3681](https://github.com/ScoopInstaller/Scoop/issues/3681))
- **current:** Remove 'current' while it's not a junction ([#4687](https://github.com/ScoopInstaller/Scoop/issues/4687))
- **depends:** Prevent error on no URL ([#4595](https://github.com/ScoopInstaller/Scoop/issues/4595))
- **depends:** Check if extractor is available ([#4042](https://github.com/ScoopInstaller/Scoop/issues/4042))
- **decompress:** Fix nested Zstd archive extraction ([#4608](https://github.com/ScoopInstaller/Scoop/issues/4608), [#4639](https://github.com/ScoopInstaller/Scoop/issues/4639))
- **installed:** Fix 'core/installed' that mark failed app as 'installed' ([#4650](https://github.com/ScoopInstaller/Scoop/issues/4650), [#4676](https://github.com/ScoopInstaller/Scoop/issues/4676), [#4689](https://github.com/ScoopInstaller/Scoop/issues/4689), [#4785](https://github.com/ScoopInstaller/Scoop/issues/4785))
- **no-junctions:** Fix error when `NO_JUNCTIONS` is been set ([#4722](https://github.com/ScoopInstaller/Scoop/issues/4722), [#4726](https://github.com/ScoopInstaller/Scoop/issues/4726))
- **shim:** Fix PS1 shim error when in different drive in PS7 ([#4614](https://github.com/ScoopInstaller/Scoop/issues/4614))
- **shim:** Fix `sh` shim error in WSL ([#4637](https://github.com/ScoopInstaller/Scoop/issues/4637))
- **shim:** Use `-file` instead of `-command` in ps1 script shims ([#4721](https://github.com/ScoopInstaller/Scoop/issues/4721))
- **shim:** Fix exe shim when app path has white spaces ([#4734](https://github.com/ScoopInstaller/Scoop/issues/4734), [#4780](https://github.com/ScoopInstaller/Scoop/issues/4780))
- **versions:** Fix wrong version number when only one version dir ([#4679](https://github.com/ScoopInstaller/Scoop/issues/4679))
- **versions:** Get current version from failed installation if possible ([#4720](https://github.com/ScoopInstaller/Scoop/issues/4720), [#4725](https://github.com/ScoopInstaller/Scoop/issues/4725))
- **scoop-alias:** Fix alias initialization ([#4737](https://github.com/ScoopInstaller/Scoop/issues/4737))
- **scoop-checkup:** Skip 'check_windows_defender' when have not admin privileges ([#4699](https://github.com/ScoopInstaller/Scoop/issues/4699))
- **scoop-cleanup:** Remove apps other than current version ([#4665](https://github.com/ScoopInstaller/Scoop/issues/4665))
- **scoop-search:** Remove redundant 'bucket/' in search result ([#4773](https://github.com/ScoopInstaller/Scoop/issues/4773))
- **scoop-update:** Skip updating non git buckets ([#4670](https://github.com/ScoopInstaller/Scoop/issues/4670), [#4672](https://github.com/ScoopInstaller/Scoop/issues/4672))

### Performance Improvements

- **uninstall:** Avoid checking all files for unlinking persisted data ([#4681](https://github.com/ScoopInstaller/Scoop/issues/4681), [#4763](https://github.com/ScoopInstaller/Scoop/issues/4763))

### Code Refactoring

- **depends:** Rewrite 'depends.ps1' ([#4638](https://github.com/ScoopInstaller/Scoop/issues/4638), [#4673](https://github.com/ScoopInstaller/Scoop/issues/4673))
- **mklink:** Use 'New-Item' instead of 'mklink' ([#4690](https://github.com/ScoopInstaller/Scoop/issues/4690))
- **rmdir:** Use 'Remove-Item' instead of 'rmdir' ([#4691](https://github.com/ScoopInstaller/Scoop/issues/4691))
- **COMSPEC:** Deprecate use of subshell cmd.exe ([#4692](https://github.com/ScoopInstaller/Scoop/issues/4692))
- **git:** Use 'git -C' to specify the work directory instead of 'Push-Location'/'Pop-Location' ([#4697](https://github.com/ScoopInstaller/Scoop/issues/4697))
- **scoop-info:** Use List View for output ([#4741](https://github.com/ScoopInstaller/Scoop/issues/4741))
- **scoop-config:** Use underscores everywhere ([#4745](https://github.com/ScoopInstaller/Scoop/issues/4745))

### Builds

- **checkver:** Fix output with '-Version' ([#3774](https://github.com/ScoopInstaller/Scoop/issues/3774))
- **schema:** Add '$schema' property ([#4623](https://github.com/ScoopInstaller/Scoop/issues/4623))
- **schema:** Add explicit escape to opening bracket matcher in jp/jsonpath regex ([#3719](https://github.com/ScoopInstaller/Scoop/issues/3719))
- **schema:** Fix typo ('note' -> 'notes') ([#4678](https://github.com/ScoopInstaller/Scoop/issues/4678))
- **tests:** Support both AppVeyor and GitHub Actions ([#4655](https://github.com/ScoopInstaller/Scoop/issues/4655))
- **tests:** Run GitHub Actions CI on each commit ([#4664](https://github.com/ScoopInstaller/Scoop/issues/4664))
- **tests:** Use cache in GitHub Actions ([#4671](https://github.com/ScoopInstaller/Scoop/issues/4671))
- **tests:** Disable CI test on 'push' ([#4677](https://github.com/ScoopInstaller/Scoop/issues/4677))
- **vscode-settings:** Remove 'formatOnSave' trigger ([#4635](https://github.com/ScoopInstaller/Scoop/issues/4635))

### Styles

- **test:** Format scripts by VSCode's PowerShell extension ([#4609](https://github.com/ScoopInstaller/Scoop/issues/4609))
- **style:** Use correct casing for `$PSScriptRoot` ([#4775](https://github.com/ScoopInstaller/Scoop/issues/4775))

### Tests

- **test-bin:** Only write output file in CI and fix trailing whitespaces ([#4613](https://github.com/ScoopInstaller/Scoop/issues/4613))
- **manifest:** Fix manifests validation ([#4620](https://github.com/ScoopInstaller/Scoop/issues/4620))
- **zstd:** Fix 'zstd' extraction error in test ([#4651](https://github.com/ScoopInstaller/Scoop/issues/4651))

### Documentation

- **changelog:** Add 'CHANGLOG.md' ([#4600](https://github.com/ScoopInstaller/Scoop/issues/4600))
- **changelog:** Rearrange CHANGELOG ([#4729](https://github.com/ScoopInstaller/Scoop/issues/4729))
- **changelog:** Link CHANGELOG headers to 'releases/tag' ([#4730](https://github.com/ScoopInstaller/Scoop/issues/4730))

## [2021-12-26](https://github.com/ScoopInstaller/Scoop/compare/2021-11-22...2021-12-26)

### Features

- **core:** Redirect 'StandardError' in `Invoke-ExternalCommand()` ([#4570](https://github.com/ScoopInstaller/Scoop/issues/4570), [#4582](https://github.com/ScoopInstaller/Scoop/issues/4582))
- **install:** Add portableapps.com to strip_filename skips ([#3244](https://github.com/ScoopInstaller/Scoop/issues/3244))
- **install:** Show manifest on installation ([#4155](https://github.com/ScoopInstaller/Scoop/issues/4155), [fb496c48](https://github.com/ScoopInstaller/Scoop/commit/fb496c482bec4063e01b328f943224ab703dbbd8), [#4581](https://github.com/ScoopInstaller/Scoop/issues/4581))
- **template:** Add issue/PR templates ([#4572](https://github.com/ScoopInstaller/Scoop/issues/4572))
- **scoop-cat:** Add `scoop cat` command ([#4532](https://github.com/ScoopInstaller/Scoop/issues/4532))
- **scoop-config:** Document all configuration options ([#4579](https://github.com/ScoopInstaller/Scoop/issues/4579))

### Bug Fixes

- **bucket:** Remove JetBrains bucket ([dec25980](https://github.com/ScoopInstaller/Scoop/commit/dec25980525a81c176b3fd5f238e964db00f3be3))
- **bucket:** Remove nightlies bucket ([48b035d7](https://github.com/ScoopInstaller/Scoop/commit/48b035d7f99baa2e81d87ead4ff03a9594e49c3d))
- **core:** Escape '.' in 'parse_app()'. ([#4578](https://github.com/ScoopInstaller/Scoop/issues/4578))
- **core:** Use '-Encoding ASCII' in 'Out-File' ([#4571](https://github.com/ScoopInstaller/Scoop/issues/4571))
- **depends:** Specify function scope ([4d5fee36](https://github.com/ScoopInstaller/Scoop/commit/4d5fee36e1ed13fc850fd22a5414186aec030c6e))
- **install:** Use `Select-CurrentVersion` ([#4535](https://github.com/ScoopInstaller/Scoop/issues/4535))
- **install:** 'env_add_path' doesn't append '.' ([#4550](https://github.com/ScoopInstaller/Scoop/issues/4550))
- **repo:** Update repo links ([cbe29edd](https://github.com/ScoopInstaller/Scoop/commit/cbe29eddb3475e34740300eb1c2c52715446e3be))
- **scoop-update:** Update apps with '--all' ([ac71fccb](https://github.com/ScoopInstaller/Scoop/commit/ac71fccbecb3d4158f249db9c1b9bb043cb8e966))
- **scoop-update:** Fix scoop update -a requiring arguments ([#4531](https://github.com/ScoopInstaller/Scoop/issues/4531))

### Code Refactoring

- **shim:** Rework shimming logic ([#4543](https://github.com/ScoopInstaller/Scoop/issues/4543), [#4555](https://github.com/ScoopInstaller/Scoop/issues/4555), [3c90d1a0](https://github.com/ScoopInstaller/Scoop/commit/3c90d1a0701b0b64730dbf9ebc8d31f9b9c238f1), [2ec00d57](https://github.com/ScoopInstaller/Scoop/commit/2ec00d576c7e594dc5c0f1eac4536c5310ce6f17))

### Builds

- **auto-pr:** Remove hardcoded 'master' branch ([#4567](https://github.com/ScoopInstaller/Scoop/issues/4567))
- **checkver:** Improve JSONPath extraction support ([#4522](https://github.com/ScoopInstaller/Scoop/issues/4522))
- **checkver:** Use GitHub token from environment ([#4557](https://github.com/ScoopInstaller/Scoop/issues/4557))
- **schema:** Enable autoupdate for 'license' ([#4528](https://github.com/ScoopInstaller/Scoop/issues/4528), [#4596](https://github.com/ScoopInstaller/Scoop/issues/4596))

### Documentation

- **readme:** Add link to Contributing Guide ([5e11c94a](https://github.com/ScoopInstaller/Scoop/commit/5e11c94a544ff2adbdbec5072c32a94d3e5acb9c))
- **readme:** Fix links ([3bb7036e](https://github.com/ScoopInstaller/Scoop/commit/3bb7036ee111bfe58e82ba3d0fd39189b058776a))

### Reverts

- **shim:** Revert [#4229](https://github.com/ScoopInstaller/Scoop/issues/4229) ([#4553](https://github.com/ScoopInstaller/Scoop/issues/4553))

## [2021-11-22](https://github.com/ScoopInstaller/Scoop/compare/2020-11-26...2021-11-22)

### Features

- **bucket:** Move extras bucket to [@ScoopInstaller](https://github.com/ScoopInstaller) ([3e9a4d4e](https://github.com/ScoopInstaller/Scoop/commit/3e9a4d4ea0e7e4d6489099c46a763f58db07e633))
- **decompress:** Support Zstandard archive ([#4372](https://github.com/ScoopInstaller/Scoop/issues/4372), [e35ff313](https://github.com/ScoopInstaller/Scoop/commit/e35ff313a5d35cab1049024938c3423a5f6bf060), [47ebc6f1](https://github.com/ScoopInstaller/Scoop/commit/47ebc6f176b0db0afeb51b4ee237a20b2d8649e9))
- **install:** Handle arch-specific env_add_path ([#4013](https://github.com/ScoopInstaller/Scoop/issues/4013))
- **install:** s/lukesamson/ScoopInstaller in install.ps1 ([5226f26f](https://github.com/ScoopInstaller/Scoop/commit/5226f26f18157ed78f1529144404ec682374452e))
- **message:** Add config to disable aria2 warning message ([#4422](https://github.com/ScoopInstaller/Scoop/issues/4422))
- **shim:** Add another alternative shim written in rust ([#4229](https://github.com/ScoopInstaller/Scoop/issues/4229))
- **scoop-prefix:** Remove unused imports and functions ([#4494](https://github.com/ScoopInstaller/Scoop/issues/4494))
- **scoop-install:** Auto uninstall previous failed installation ([#3281](https://github.com/ScoopInstaller/Scoop/issues/3281))
- **scoop-update:** Add flags `--all` as an alternative to '*' to update all ([#3871](https://github.com/ScoopInstaller/Scoop/issues/3871))

### Bug Fixes

- **core:** Change url() scope to avoid conflict with global aliases ([#4342](https://github.com/ScoopInstaller/Scoop/issues/4342), [#4492](https://github.com/ScoopInstaller/Scoop/issues/4492))
- **install:** Fix `aria2`'s resume download feature ([#3292](https://github.com/ScoopInstaller/Scoop/issues/3292))
- **shim:** Fixed trailing whitespace issue ([#4307](https://github.com/ScoopInstaller/Scoop/issues/4307))
- **scoop-reset:** Skip when app instance is running ([#4359](https://github.com/ScoopInstaller/Scoop/issues/4359))

### Code Refactoring

- **versions:** Refactor 'versions.ps1' ([#3721](https://github.com/ScoopInstaller/Scoop/issues/3721), [e6630272](https://github.com/ScoopInstaller/Scoop/commit/e663027299d03ca768a252fa4bcbc51d124d4cae), [ae892138](https://github.com/ScoopInstaller/Scoop/commit/ae892138423bb9bbf54c8f0bed8331b93199f6b8))

### Builds

- **autoupdate:** Add multiple URL/hash/extract_dir... support ([#3518](https://github.com/ScoopInstaller/Scoop/issues/3518), [#4502](https://github.com/ScoopInstaller/Scoop/issues/4502))
- **schema:** Fix Schema to support `+` in version ([#4504](https://github.com/ScoopInstaller/Scoop/issues/4504))
- **supporting:** Update Json to 12.0.3, Json.Schema to 3.0.14 ([#3352](https://github.com/ScoopInstaller/Scoop/issues/3352))

### Documentation

- **readme:** Capitalize to prevent redirect ([#4483](https://github.com/ScoopInstaller/Scoop/issues/4483))
- **readme:** s/lukesampson/ScoopInstaller in readme ([4f5acd72](https://github.com/ScoopInstaller/Scoop/commit/4f5acd72109a98a148d1bfa269c23a2d43644d23))
- **readme:** Update extras bucket url in readme ([f1a46e10](https://github.com/ScoopInstaller/Scoop/commit/f1a46e109596c55c7e83c77fc1fc9daedbe71636))
- **readme:** Update Java bucket text ([#4514](https://github.com/ScoopInstaller/Scoop/issues/4514))
- **readme:** Update notes about the NirSoft bucket ([#4524](https://github.com/ScoopInstaller/Scoop/issues/4524))

## [2020-11-26](https://github.com/ScoopInstaller/Scoop/compare/2020-10-22...2020-11-26)

### Bug Fixes

- **shim:** Fix Makefile typo ([0948824e](https://github.com/ScoopInstaller/Scoop/commit/0948824ec7269c979882d09342d9a269193cd674)) ([227de6cf](https://github.com/ScoopInstaller/Scoop/commit/227de6cfb8433a86ac0f0a279e691327ae04554c))

## [2020-10-22](https://github.com/ScoopInstaller/Scoop/compare/2019-10-23...2020-10-22)

### Features

- **aria2:** Inline progress ([#3987](https://github.com/ScoopInstaller/Scoop/issues/3987))
- **autoupdate:** Add $urlNoExt and $basenameNoExt substitutions ([#3742](https://github.com/ScoopInstaller/Scoop/issues/3742))
- **config:** Add configuration option for default architecture ([#3778](https://github.com/ScoopInstaller/Scoop/issues/3778))
- **install:** Follow HTTP redirections when downloading a file ([#3902](https://github.com/ScoopInstaller/Scoop/issues/3902))
- **install:** Let pathes in 'env_add_path' be added ascendantly ([#3788](https://github.com/ScoopInstaller/Scoop/issues/3788), [#3976](https://github.com/ScoopInstaller/Scoop/issues/3976))
- **list:** Display main bucket name ([#3759](https://github.com/ScoopInstaller/Scoop/issues/3759))
- **shim:** Add alt-shim support ([#3998](https://github.com/ScoopInstaller/Scoop/issues/3998))
- **scoop-checkup:** Add check_envs_requirements ([#3860](https://github.com/ScoopInstaller/Scoop/issues/3860))

### Bug Fixes

- **bucket:** Update scoop-nonportable URL ([#3776](https://github.com/ScoopInstaller/Scoop/issues/3776))
- **download:** Fosshub download ([#4051](https://github.com/ScoopInstaller/Scoop/issues/4051))
- **download:** Progress bar on small files ([96de9c14](https://github.com/ScoopInstaller/Scoop/commit/96de9c14bb483f9278e4b0a9e22b1923ee752901))
- **hold:** Replace "locked" terminology with "held" for consistency ([#3917](https://github.com/ScoopInstaller/Scoop/issues/3917))
- **git:** Don't execute autostart programs when executing git commands ([#3993](https://github.com/ScoopInstaller/Scoop/issues/3993))
- **git:** Enforce pull without rebase ([#3765](https://github.com/ScoopInstaller/Scoop/issues/3765))
- **install:** Aria2 inline progress negative values ([#4053](https://github.com/ScoopInstaller/Scoop/issues/4053))
- **install:** Fix wrong output of 'install/failed' ([#3784](https://github.com/ScoopInstaller/Scoop/issues/3784), [#3867](https://github.com/ScoopInstaller/Scoop/issues/3867))
- **install:** Re-add "Don't send referer to portableapps.com" ([#3961](https://github.com/ScoopInstaller/Scoop/issues/3961))
- **scoop:** Remove temporary code from the scoop executable ([#3898](https://github.com/ScoopInstaller/Scoop/issues/3898))
- **update:** Update outdated PowerShell 5 warning ([#3986](https://github.com/ScoopInstaller/Scoop/issues/3986))
- **scoop-info:** Check bucket of installed app ([#3740](https://github.com/ScoopInstaller/Scoop/issues/3740))

### Builds

- **checkver:** Present script property ([#3900](https://github.com/ScoopInstaller/Scoop/issues/3900))

### Tests

- **init:** Force pester v4 ([#4040](https://github.com/ScoopInstaller/Scoop/issues/4040))

## [2019-10-23](https://github.com/ScoopInstaller/Scoop/compare/2019-10-18...2019-10-23)

### Features

- **update:** Support $persist_dir in uninstaller.script ([#3692](https://github.com/ScoopInstaller/Scoop/issues/3692))

### Bug Fixes

- **core:** Use [Environment]::Is64BitOperatingSystem instead of [intptr]::size ([#3690](https://github.com/ScoopInstaller/Scoop/issues/3690))
- **git:** Remove unnecessary git_proxy_cmd() calls for local commands ([8ee45a57](https://github.com/ScoopInstaller/Scoop/commit/8ee45a57dc01a525dcf8776bf9bb45263992c81f))
- **install:** Check execution policy ([#3619](https://github.com/ScoopInstaller/Scoop/issues/3619))
- **update:** Fix scoop update changelog output ([e997017f](https://github.com/ScoopInstaller/Scoop/commit/e997017f1a03e2eefef2157acdfefe2e4fced896))

## [2019-10-18](https://github.com/ScoopInstaller/Scoop/compare/2019-06-24...2019-10-18)

### Features

- **core:** Tweak Invoke-ExternalCommand parameters ([#3547](https://github.com/ScoopInstaller/Scoop/issues/3547))
- **install:** Use 7zip when available for faster zip file extraction ([#3460](https://github.com/ScoopInstaller/Scoop/issues/3460))
- **install:** Add arch support to `env_add_path` and `env_set` ([#3503](https://github.com/ScoopInstaller/Scoop/issues/3503))
- **install:** Allow $version to be used in uninstaller scripts ([#3592](https://github.com/ScoopInstaller/Scoop/issues/3592))
- **install:** Allow installing specific version if latest is installed ([11c42d78](https://github.com/ScoopInstaller/Scoop/commit/11c42d782f8adb29fbe0d94daa5f121cdda935ab))
- **update:** Allow updating apps from local manifest or URL ([#3685](https://github.com/ScoopInstaller/Scoop/issues/3685))

### Bug Fixes

- **autoupdate:** Decode basename when extract hash ([#3615](https://github.com/ScoopInstaller/Scoop/issues/3615))
- **autoupdate:** Remove any whitespace from hash ([#3579](https://github.com/ScoopInstaller/Scoop/issues/3579))
- **bucket:** Only lookup directories in buckets folder ([#3631](https://github.com/ScoopInstaller/Scoop/issues/3631))
- **comspec:** Escape variables when calling COMSPEC commands ([#3538](https://github.com/ScoopInstaller/Scoop/issues/3538))
- **decompress:** Fix bugs on extract_dir ([#3540](https://github.com/ScoopInstaller/Scoop/issues/3540))
- **editorconfig:** Add missing } to bat/cmd regex ([#3529](https://github.com/ScoopInstaller/Scoop/issues/3529))
- **help:** Rename help() to scoop_help() ([#3564](https://github.com/ScoopInstaller/Scoop/issues/3564))
- **install:** Use Join-Path instead of string gluing. ([#3566](https://github.com/ScoopInstaller/Scoop/issues/3566))
- **scoop-info:** Fix output for single binaries with alias ([#3651](https://github.com/ScoopInstaller/Scoop/issues/3651))
- **scoop-info:** Remove a whitespace ([#3652](https://github.com/ScoopInstaller/Scoop/issues/3652))

### Builds

- **auto-pr:** Fix git status detection ([7decfd4c](https://github.com/ScoopInstaller/Scoop/commit/7decfd4c107b8d8a59d7eedfe8a56e1801120c2f))
- **auto-pr:** Hard reset bucket after running ([79f8538b](https://github.com/ScoopInstaller/Scoop/commit/79f8538b57b9021db71a279879b9032fefd1ae52))
- **checkurls:** Trim renaming suffix in url ([#3677](https://github.com/ScoopInstaller/Scoop/issues/3677))

### Continuous Integration

- **appveyor:** use VS2019 image to fix PS6 issues ([#3646](https://github.com/ScoopInstaller/Scoop/issues/3646))
- **tests:** Do not force maintainers to have SCOOP_HELPERS ([#3604](https://github.com/ScoopInstaller/Scoop/issues/3604))

### Documentation

- **readme:** Improve installation instructions ([#3600](https://github.com/ScoopInstaller/Scoop/issues/3600))

## [2019-06-24](https://github.com/ScoopInstaller/Scoop/compare/2019-05-15...2019-06-24)

### Features

- **decompress:** Add 'ExtractDir' to 'Expand-...' functions ([#3466](https://github.com/ScoopInstaller/Scoop/issues/3466), [#3470](https://github.com/ScoopInstaller/Scoop/issues/3470), [#3472](https://github.com/ScoopInstaller/Scoop/issues/3472))
- **decompress:** Allow 'Expand-InnoArchive -ExtractDir' to accept '{xxx}' ([#3487](https://github.com/ScoopInstaller/Scoop/issues/3487))

### Bug Fixes

- **config:** Show correct output when removing a config value ([#3462](https://github.com/ScoopInstaller/Scoop/issues/3462))
- **decompress:** Change dark.exe parameter order ([6141e46d](https://github.com/ScoopInstaller/Scoop/commit/6141e46d6ae74b3ccf65e02a1c3fc92e1b4d3e7a))
- **proxy:** Rename parameters for Net.NetworkCredential ([#3483](https://github.com/ScoopInstaller/Scoop/issues/3483))

### Code Refactoring

- **core:**  `run()` -> 'Invoke-ExternalCommand()' ([#3432](https://github.com/ScoopInstaller/Scoop/issues/3432))

### Builds

- **checkhashes:** Checkhashes downloading twice when architecture properties does hot have url property ([#3479](https://github.com/ScoopInstaller/Scoop/issues/3479))
- **checkhashes:** Do not call scoop directly ([#3527](https://github.com/ScoopInstaller/Scoop/issues/3527))

### Documentation

- **readme:** Add known buckets to end of readme ([2849e0f9](https://github.com/ScoopInstaller/Scoop/commit/2849e0f96099004f761d7d8c715377e0d2c105f2))
- **readme:** Adjust URL of `runat.json` ([#3484](https://github.com/ScoopInstaller/Scoop/issues/3484))
- **readme:** Fix a small typo ([#3512](https://github.com/ScoopInstaller/Scoop/issues/3512))
- **readme:** Fix typo in readme ([03bb07c8](https://github.com/ScoopInstaller/Scoop/commit/03bb07c8231563fa3a2092b9b52d4dde372f2a8e))
- **readme:** Update readme with correct count of nirsoft apps ([e8d0be66](https://github.com/ScoopInstaller/Scoop/commit/e8d0be663b3bab25d9ee55c597b90bf922f4ec5d))

## [2019-05-15](https://github.com/ScoopInstaller/Scoop/compare/2019-05-12...2019-05-15)

### Features

- **manifest:** XPath support in checkver and autoupdate ([#3458](https://github.com/ScoopInstaller/Scoop/issues/3458))
- **update:** Support changing scoop tracking repository ([#3459](https://github.com/ScoopInstaller/Scoop/issues/3459))

### Bug Fixes

- **autoupdate:** Handle xml namespace in xpath mode ([#3465](https://github.com/ScoopInstaller/Scoop/issues/3465))

## [2019-05-12](https://github.com/ScoopInstaller/Scoop/releases/tag/2019-05-12)

### BREAKING CHANGE

- **core:** Finalize bucket extraction ([#3399](https://github.com/ScoopInstaller/Scoop/issues/3399))
- **core:** Bucket extraction and refactoring ([#3449](https://github.com/ScoopInstaller/Scoop/issues/3449))

### Features

- **autoupdate:** Add 'regex' alias for 'find' ([3453487e](https://github.com/ScoopInstaller/Scoop/commit/3453487ed65378cc9ba2efc658ed6bc1431ef463))
- **autoupdate:** Allow simple metalink and meta4 hash extraction ([ecf627c3](https://github.com/ScoopInstaller/Scoop/commit/ecf627c3b8493b3ccf7ddb882b0c946533774d76))
- **autoupdate:** Add version variables to autoupdate.hash.regex ([#2966](https://github.com/ScoopInstaller/Scoop/issues/2996))
- **autoupdate:** Autoupdate improvements ([#1371](https://github.com/ScoopInstaller/Scoop/issues/1371))
- **autoupdate:** Convert base64 encoded hash values ([04c9ddeb](https://github.com/ScoopInstaller/Scoop/commit/04c9ddeb6d3b99496c39543ad468d34f4f1adeff))
- **autoupdate:** Improve base64 hash detection ([310096e2](https://github.com/ScoopInstaller/Scoop/commit/310096e2386ff3bf9082d547b140a98b92b87a83))
- **core:** Add basic WSL support by appending .exe to powershell ([#2323](https://github.com/ScoopInstaller/Scoop/issues/2323))
- **core:** Add Expand-DarkArchive and some other dependency features ([#3450](https://github.com/ScoopInstaller/Scoop/issues/3450))
- **core:** Enable TLS 1.2 in core.ps1 ([#2074](https://github.com/ScoopInstaller/Scoop/issues/2074))
- **core:** Prepare extraction of main bucket ([#3060](https://github.com/ScoopInstaller/Scoop/issues/3060))
- **core:** Support loading basedirs from config ([#3121](https://github.com/ScoopInstaller/Scoop/issues/3121))
- **core:** Update requirement to version 5 or greater ([#3330](https://github.com/ScoopInstaller/Scoop/issues/3330))
- **core:** Use consistent User-Agent Header on all webrequests ([12962acf](https://github.com/ScoopInstaller/Scoop/commit/12962acfa853593e371d09186e51660aece331e5))
- **core:** Warn on shim overwrite ([#2033](https://github.com/ScoopInstaller/Scoop/issues/2033))
- **debug:** Add option to indent debug output ([bf54a978](https://github.com/ScoopInstaller/Scoop/commit/bf54a978a1bc2efcde52513a60ec5bcb7bb1a44e))
- **decompress:** Allow other args to be passthrough ([#3411](https://github.com/ScoopInstaller/Scoop/issues/3411))
- **download:** Add support for multi-connection downloads via aria2c ([#2312](https://github.com/ScoopInstaller/Scoop/issues/2312))
- **download:** Convert sourceforge urls to use downloads mirror ([#3340](https://github.com/ScoopInstaller/Scoop/issues/3340))
- **install:** Add .NET 4.5 check to scoop install script ([e52c24c9](https://github.com/ScoopInstaller/Scoop/commit/e52c24c94ec805a327440cc07aec699afc7cc308))
- **install:** Set file write permission to global persist dir ([#2524](https://github.com/ScoopInstaller/Scoop/issues/2524))
- **json:** Normalize multi-line strings to string arrays on format ([#2444](https://github.com/ScoopInstaller/Scoop/issues/2444))
- **persist:** Support persisting files without a file extension ([#2408](https://github.com/ScoopInstaller/Scoop/issues/2408))
- **shim:** Add '.com'-type shim ([#3366](https://github.com/ScoopInstaller/Scoop/issues/3366))
- **shim:** Enabled applications which require elevated privileges ([#2053](https://github.com/ScoopInstaller/Scoop/issues/2053))
- **shim:** Enabled shimming of external applications ([#2072](https://github.com/ScoopInstaller/Scoop/issues/2072))
- **shim:** Enabled wide characters forwarding in shims ([#2106](https://github.com/ScoopInstaller/Scoop/issues/2106))
- **shim:** Make shim support PowerShell 2.0 ([#2562](https://github.com/ScoopInstaller/Scoop/issues/2562))
- **shim:** Create sh shim ([#1951](https://github.com/ScoopInstaller/Scoop/issues/1951))
- **shortcuts:** Add subdirectories/arguments for shortcuts ([#1945](https://github.com/ScoopInstaller/Scoop/issues/1945))
- **shortcuts:** Allow $dir, $original_dir and $persist_dir substitutions for shortcuts ([f3ddf0c0](https://github.com/ScoopInstaller/Scoop/commit/f3ddf0c0f81ee2a11466edf5d9f6e38a0fc2b9d4))
- **shortcuts:** Get start menu folder location from environment rather than predefined user profile path ([c245a7fe](https://github.com/ScoopInstaller/Scoop/commit/c245a7fe96ffa0b0fba23bd47f31480ea93cc183))
- **uninstall:** Print purge step to console ([#3123](https://github.com/ScoopInstaller/Scoop/issues/3123))
- **uninstall:** Add support for soft/purge uninstalling of scoop itself ([#2781](https://github.com/ScoopInstaller/Scoop/issues/2781))
- **update:** Add hold/unhold command ([#3444](https://github.com/ScoopInstaller/Scoop/issues/3444))
- **scoop-checkup:** Add NTFS check to checkup command ([#1944](https://github.com/ScoopInstaller/Scoop/issues/1944))
- **scoop-checkup:** Check for LongPaths setting ([#3387](https://github.com/ScoopInstaller/Scoop/issues/3387))
- **scoop-info:** Add scoop-info command ([#2165](https://github.com/ScoopInstaller/Scoop/issues/2165))
- **scoop-info:** Support url manifest ([#2538](https://github.com/ScoopInstaller/Scoop/issues/2538))
- **scoop-prefix:** Add scoop prefix command ([#2117](https://github.com/ScoopInstaller/Scoop/issues/2117))
- **scoop-update:** Add notification for new main bucket ([#3392](https://github.com/ScoopInstaller/Scoop/issues/3392))
- **scoop-update:** Show changelog after updating scoop and buckets ([56c35f8f](https://github.com/ScoopInstaller/Scoop/commit/56c35f8f05ed387997ef1a80ec0362adec6e51a5))
- **scoop-which:** Also show other applications in PATH with 'scoop which' ([79bf99c3](https://github.com/ScoopInstaller/Scoop/commit/79bf99c3c110494d799e147263db7b6f2f921d4e))

### Bug Fixes

- **autoupdate:** Fix base64 hash extraction ([98afb999](https://github.com/ScoopInstaller/Scoop/commit/98afb99990561c4f98f1e1334f348e52b4bee4e7))
- **autoupdate:** Fix base64 hash extraction length ([#2852](https://github.com/ScoopInstaller/Scoop/issues/2852))
- **autoupdate:** Fix metalink hash extraction ([2ad54747](https://github.com/ScoopInstaller/Scoop/commit/2ad547477b1432e7a269c90b393d62d88dce9803))
- **autoupdate:** Fix single line hash extraction ([#3015](https://github.com/ScoopInstaller/Scoop/issues/3015))
- **autoupdate:** Improve auto-update hash extraction regex ([21bf0dea](https://github.com/ScoopInstaller/Scoop/commit/21bf0dea561db021aa59bcd9363792436ac7c162))
- **autoupdate:** Linter fix ([c9539b65](https://github.com/ScoopInstaller/Scoop/commit/c9539b6575e8842a8f895d82b4119c3aef01d7c2))
- **autoupdate:** Use normal variable instead of magic $matches variable name ([d74e0a85](https://github.com/ScoopInstaller/Scoop/commit/d74e0a85b4081745bd1ab107a45794f02299737d))
- **bucket:** Change wording of new_issue_msg() ([e82587df](https://github.com/ScoopInstaller/Scoop/commit/e82587dfc41618474e03347df333e847dfaffc70))
- **bucket:** Fix new_issue_msg ([#3375](https://github.com/ScoopInstaller/Scoop/issues/3375))
- **bucket:** Use $_.Name on gci result ([1eb2609d](https://github.com/ScoopInstaller/Scoop/commit/1eb2609db51587772a4b5d1b6f58114f52639568))
- **config:** Enable writing to hidden .scoop file ([#1982](https://github.com/ScoopInstaller/Scoop/issues/1982))
- **config:** Save and load true/false values as booleans in scoops config ([16aec1a4](https://github.com/ScoopInstaller/Scoop/commit/16aec1a40b45ba241ef2ac45ccf89de7206891be))
- **core:** Allowed underscores in package names ([#2930](https://github.com/ScoopInstaller/Scoop/issues/2930))
- **core:** Clean up some error messages ([#2032](https://github.com/ScoopInstaller/Scoop/issues/2032))
- **core:** Change sf regex not to break some manifests ([#2476](https://github.com/ScoopInstaller/Scoop/issues/2476))
- **core:** Check if 7zip installed via Scoop instead of using 7z.exe from PATH ([55ce0c0b](https://github.com/ScoopInstaller/Scoop/commit/55ce0c0b0c481ec3807655cb7aeac6dfcf9ef271))
- **core:** Filter null or empty string from Scoops directory settings ([5d5c7fa9](https://github.com/ScoopInstaller/Scoop/commit/5d5c7fa91c03f05b705d3420618ec96d8e870174))
- **core:** Fix "enable-encryptionscheme" for OSes before Windows 10 ([#2084](https://github.com/ScoopInstaller/Scoop/issues/2084))
- **core:** Fix bug with Start-Process -Wait, exclusive to PowerShell Core on Windows 7 ([#3415](https://github.com/ScoopInstaller/Scoop/issues/3415))
- **core:** Fix for relative paths ([ff9c0c3d](https://github.com/ScoopInstaller/Scoop/commit/ff9c0c3dafb3567ee958379b83205da84a925ecf))
- **core:** Fix robocopy not releasing a directory after moving it ([e2792f2e](https://github.com/ScoopInstaller/Scoop/commit/e2792f2e02adee5947ebb95022a62282fb61024f))
- **core:** Fix substitute() for arrays ([#2048](https://github.com/ScoopInstaller/Scoop/issues/2048))
- **core:** Format hashes to lowercase ([5d56f8ff](https://github.com/ScoopInstaller/Scoop/commit/5d56f8ff5760ddedaf44eaf9652000e833b0944e))
- **core:** Invoke powershell with -noprofile flag from bash shims ([#3165](https://github.com/ScoopInstaller/Scoop/issues/3165))
- **core:** Removed the bucket from the app name when checking directories ([#2435](https://github.com/ScoopInstaller/Scoop/issues/2435))
- **core:** Return true for checking if a directory is 'in' itself ([ac8a1567](https://github.com/ScoopInstaller/Scoop/commit/ac8a156796cb6d3d9cba24a2839271d924ab8fea))
- **core:** Store last update time as String ([e8af15cc](https://github.com/ScoopInstaller/Scoop/commit/e8af15cc0615b707aee79be95f9c00e3ae0bfd9b))
- **decompress:** Add .bz2 files to decompression ([#2085](https://github.com/ScoopInstaller/Scoop/issues/2085))
- **decompress:** Added retry when unzip fail because of AV ([#1822](https://github.com/ScoopInstaller/Scoop/issues/1822))
- **decompress:** Catch unzip failures from bad file names ([#2472](https://github.com/ScoopInstaller/Scoop/issues/2472))
- **decompress:** Compatible Expand-ZipArchive() with Pscx ([#3425](https://github.com/ScoopInstaller/Scoop/issues/3425))
- **decompress:** Correct deprecation function name ([#3406](https://github.com/ScoopInstaller/Scoop/issues/3406))
- **decompress:** Fix dark parameter order ([87a1e784](https://github.com/ScoopInstaller/Scoop/commit/87a1e784d7463fea36fa41fcb7cb5537cbcfdc52))
- **depends:** Don't force adding dark dependency ([#3453](https://github.com/ScoopInstaller/Scoop/issues/3453))
- **depends:** Don't include the requested app in the list of dependencies ([1bc6a479](https://github.com/ScoopInstaller/Scoop/commit/1bc6a479ee969e44e2b0d83ed6ff19efd86c6ae9))
- **depends:** Fix empty bucket name ([#2827](https://github.com/ScoopInstaller/Scoop/issues/2827))
- **depends:** Fix null reference error when no buckets are configured ([88040972](https://github.com/ScoopInstaller/Scoop/commit/88040972a30b459a3859c7c2f883e47e19da9f84))
- **depends:** Show message about missing bucket when installing dependencies ([7a6218c5](https://github.com/ScoopInstaller/Scoop/commit/7a6218c58677170fe32cf1c2bfcfe7488e4c3655))
- **download:** Don't send referer to portableapps.com ([0c2b3da3](https://github.com/ScoopInstaller/Scoop/commit/0c2b3da3ff639722ad3ddf587219bb3155e97c7f))
- **download:** Fix fosshub downloads with aria2c ([803525a8](https://github.com/ScoopInstaller/Scoop/commit/803525a8661ffaa39fc4ad6f0dc776cccad4c45e))
- **download:** Interrupt download causes partial cache file to be used for next install ([5be02865](https://github.com/ScoopInstaller/Scoop/commit/5be0286561398debfee2c0610e51f006ef2dc2fb))
- **download:** Overwrite any existing files when extracting ([58cca68f](https://github.com/ScoopInstaller/Scoop/commit/58cca68f7565bd5e8f63e08ad052c0029b98a23d))
- **download:** Show warning about SourceForge.net hash validation fails ([8504338b](https://github.com/ScoopInstaller/Scoop/commit/8504338bc5faab3235cef2e1c2f41abd7ae496eb))
- **getopt:** Don't try to parse int arguments ([23fe5a53](https://github.com/ScoopInstaller/Scoop/commit/23fe5a5319d4ede84c532df04f576c3854fd5826))
- **getopt:** Don't try to parse array arguments ([9b6e7b5e](https://github.com/ScoopInstaller/Scoop/commit/9b6e7b5e0f7f6ddecdb139f932ad7d582fe639a4))
- **getopt:** Return remaining args, use getopt for scoop install ([b7cfd6fd](https://github.com/ScoopInstaller/Scoop/commit/b7cfd6fdb0e18a623ceacfa6fc824241dabc6d01))
- **getopt:** Skip if arg is $null ([f2d9f0d7](https://github.com/ScoopInstaller/Scoop/commit/f2d9f0d79fdf4a63879c1b87a6c0f5317a40a1d9))
- **getopt:** Skip arg if it's decimal ([5f0c8cfb](https://github.com/ScoopInstaller/Scoop/commit/5f0c8cfb0a34078bb8118a21191cf046ddad18ac))
- **git:** Disable git pager when running git log ([cac99759](https://github.com/ScoopInstaller/Scoop/commit/cac9975924691fe6e608789218b06be56bb8c658))
- **git:** Fix update log output ([0daa25c6](https://github.com/ScoopInstaller/Scoop/commit/0daa25c6300cd2ab605d63b71037d741c9c904c6))
- **json:** Catch JsonReaderException ([fb58e92c](https://github.com/ScoopInstaller/Scoop/commit/fb58e92c13552199f19f5df112801fc41321eee2))
- **install:** Add filename to warning for files without hash in the manifest ([4c9beee8](https://github.com/ScoopInstaller/Scoop/commit/4c9beee8f2df891b2ec314e1efffb2ee9d5cca20))
- **install:** Add multi-line support to pre/post_install ([#1980](https://github.com/ScoopInstaller/Scoop/issues/1980))
- **install:** Added exclusion for sourceforge. [#METR-21516] ([#2109](https://github.com/ScoopInstaller/Scoop/issues/2109))
- **install:** Ignore url fragment for PowerShell Core 6.1.0 ([#2602](https://github.com/ScoopInstaller/Scoop/issues/2602))
- **install:** Fix fail when installing from non-default bucket ([#2247](https://github.com/ScoopInstaller/Scoop/issues/2247))
- **install:** Fix PowerShell core crash ([#2554](https://github.com/ScoopInstaller/Scoop/issues/2554))
- **install:** Option to skip hash validation and error message improvements ([#2260](https://github.com/ScoopInstaller/Scoop/issues/2260))
- **install:** Remove env_ensure_home ([#1967](https://github.com/ScoopInstaller/Scoop/issues/1967))
- **install:** Show first 8 bytes of file in the hash check error message ([e4cbb42e](https://github.com/ScoopInstaller/Scoop/commit/e4cbb42e64843e53b5b24de92f43062bca98c474))
- **persist:** Fix condition for persist_permission() ([eb7b7cbf](https://github.com/ScoopInstaller/Scoop/commit/eb7b7cbf4f30e4122762856723155f3c1e980d1b)) ([1a2598bc](https://github.com/ScoopInstaller/Scoop/commit/1a2598bc3082a2e3fffac1a6bea0b42032e388f0))
- **persist:** Fixed persisting bug when force update app with same version ([#2774](https://github.com/ScoopInstaller/Scoop/issues/2774))
- **persist:** Fix the target didn't be created ([#3008](https://github.com/ScoopInstaller/Scoop/issues/3008))
- **persist:** Prevent directory creation from being output ([#1999](https://github.com/ScoopInstaller/Scoop/issues/1999))
- **scoop:** Force to add new main bucket ([#3419](https://github.com/ScoopInstaller/Scoop/issues/3419))
- **shim:** Fix .ps1 shim parsing logic ([#2564](https://github.com/ScoopInstaller/Scoop/issues/2564))
- **shim:** Fixed ps1/jar->ps1 shims args handling ([#2120](https://github.com/ScoopInstaller/Scoop/issues/2120))
- **shortcuts:** Improve Shortcut creation ([83b82386](https://github.com/ScoopInstaller/Scoop/commit/83b823868f5ef5256d3dcfbecff278bb355fefc8))
- **uninstall:** Better error handling during uninstallation ([#2079](https://github.com/ScoopInstaller/Scoop/issues/2079))
- **uninstall:** Uninstall fails to remove architecture-specific shims ([8b1871b2](https://github.com/ScoopInstaller/Scoop/commit/8b1871b20df4dbf1b603d4066937ba213c03bb32))
- **update:** Rewording PowerShell update notice ([d006fb93](https://github.com/ScoopInstaller/Scoop/commit/d006fb9315b55a9d8e6a36218cf5dbdde51433ec))
- **versions:** Improvements for the reset command to deal with empty current alias dir correctly ([#2896](https://github.com/ScoopInstaller/Scoop/issues/2896))
- **scoop-alias:** Improve "scoop alias list" output ([#2163](https://github.com/ScoopInstaller/Scoop/issues/2163))
- **scoop-cache:** Display help on incorrect cache command ([#3431](https://github.com/ScoopInstaller/Scoop/issues/3431))
- **scoop-cache:** scoop cache command not using $SCOOP_CACHE ([#1990](https://github.com/ScoopInstaller/Scoop/issues/1990))
- **scoop-info:** Improve scoop-info license attributes output ([#2397](https://github.com/ScoopInstaller/Scoop/issues/2397))
- **scoop-install:** Prevent installing programs from JSON multiple times ([936cf9cb](https://github.com/ScoopInstaller/Scoop/commit/936cf9cbb0c4dd3a594fbaf5c696ce519e586d8c))
- **scoop-reset:** Persist data on reset ([#2773](https://github.com/ScoopInstaller/Scoop/issues/2773))
- **scoop-reset:** Re-create shortcuts ([6e5b7e57](https://github.com/ScoopInstaller/Scoop/commit/6e5b7e57bb0628f072872d9a5b8c8a0fa58389e1))
- **scoop-search:** Better handling for invalid query ([bf024705](https://github.com/ScoopInstaller/Scoop/commit/bf024705a8cc38592571aa3026dca2471f19ac5a))
- **scoop-uninstall:** Checked if uninstaller removed its directory ([#2078](https://github.com/ScoopInstaller/Scoop/issues/2078))
- **scoop-update:** Add config option "show_update_log" ([d68cb3ce](https://github.com/ScoopInstaller/Scoop/commit/d68cb3ce52acaa9983f278822febd506f54ebe02))
- **scoop-update:** First scoop update fails because scoop deletes itself too early ([376630fd](https://github.com/ScoopInstaller/Scoop/commit/376630fd80a3f9012fd6e673460b9e28e375e951))
- **scoop-update:** Fix branch switching ([#3372](https://github.com/ScoopInstaller/Scoop/issues/3372))
- **scoop-update:** Fix update with cookies ([#3261](https://github.com/ScoopInstaller/Scoop/issues/3261))
- **scoop-update:** Improve is_scoop_outdated() and add last_scoop_update() ([f3f559c4](https://github.com/ScoopInstaller/Scoop/commit/f3f559c460406689dab2375310fb1026e2be58bd))
- **scoop-update:** Resolve linting, fix appveyor tests error ([#2148](https://github.com/ScoopInstaller/Scoop/issues/2148))

### Code Refactoring

- **bucket:** Move function into lib from lib-exec ([#3062](https://github.com/ScoopInstaller/Scoop/issues/3062))
- **bucket:** Optimize buckets function ([#3341](https://github.com/ScoopInstaller/Scoop/issues/3341))
- **config:** Move configuration handling to core.ps1 ([#3242](https://github.com/ScoopInstaller/Scoop/issues/3242))
- **core:** aria2_path() -> file_path() ([0f464016](https://github.com/ScoopInstaller/Scoop/commit/0f4640168da8d68a52eb2b80af2f3ffa01c9b658))
- **core:** cmd_available() -> Test-CommandAvailable() ([#3314](https://github.com/ScoopInstaller/Scoop/issues/3314))
- **core:** ensure_all_installed() -> Confirm-InstallationStatus() ([#3293](https://github.com/ScoopInstaller/Scoop/issues/3293))
- **core:** Move default_aliases into the scoped function ([#3233](https://github.com/ScoopInstaller/Scoop/issues/3233))
- **core:** Refactor function names and fix installing 7zip locally if already globally available ([#3416](https://github.com/ScoopInstaller/Scoop/issues/3416))
- **core:** Simplified last_scoop_update() ([#2931](https://github.com/ScoopInstaller/Scoop/issues/2931))
- **core:** Tweak SecurityProtocol usage ([#3065](https://github.com/ScoopInstaller/Scoop/issues/3065))
- **decompress:** Refactored (w/ install.ps1, core.ps1) ([#3169](https://github.com/ScoopInstaller/Scoop/issues/3169))
- **decompress:** Refactor extraction handling functions ([#3204](https://github.com/ScoopInstaller/Scoop/issues/3204))
- **download:** Download functionality refactor ([#1329](https://github.com/ScoopInstaller/Scoop/issues/1329))
- **install:** Rename locate() to Find-Manifest() ([9eed3d89](https://github.com/ScoopInstaller/Scoop/commit/9eed3d8914c7a0fa294110eb0761776a01adf034))

### Builds

- **auto-pr:** Add -App parameter ([#3157](https://github.com/ScoopInstaller/Scoop/issues/3157))
- **auto-pr:** Add SkipUpdated parameter ([#3168](https://github.com/ScoopInstaller/Scoop/issues/3168))
- **checkhashes:** Add bin\checkhashes.ps1 ([#2766](https://github.com/ScoopInstaller/Scoop/issues/2766))
- **checkurls:** Add SkipValid Parameter ([#2845](https://github.com/ScoopInstaller/Scoop/issues/2845))
- **checkurls:** Import config.ps1 in checkurls.ps1 ([126e9c97](https://github.com/ScoopInstaller/Scoop/commit/126e9c97d2ef7db537a5137167089a97f343e98e))
- **checkver:** Add 'useragent' property ([8feb3867](https://github.com/ScoopInstaller/Scoop/commit/8feb3867a74ea0340585e3e695934d96cf483a05))
- **checkver:** Add 'jsonpath' alias for 'jp' ([76fdb6b7](https://github.com/ScoopInstaller/Scoop/commit/76fdb6b74c1772bf607d2dad5f6c50269369ff88))
- **checkver:** Add 're' alias 'regex' ([468649c8](https://github.com/ScoopInstaller/Scoop/commit/468649c88dea9c1ff9614f2cdf29a521d572664e))
- **checkver:** Allow using the current version in checkver URL ([607ac9ca](https://github.com/ScoopInstaller/Scoop/commit/607ac9ca7c185da61e2c746ea87d28c2abe62adc))
- **checkver:** Fix example parameters ([#3413](https://github.com/ScoopInstaller/Scoop/issues/3413))
- **checkver:** GitHub checkver case-insensitive version check ([2e2633e9](https://github.com/ScoopInstaller/Scoop/commit/2e2633e9640f6cab5c2f895b680345cd6ca))
- **checkver:** Remove old commented code ([72754036](https://github.com/ScoopInstaller/Scoop/commit/72754036a251fffd2f2eb0e242edfd9895543e3c))
- **checkver:** Resolve issue on Powershell >6.1.0 ([#2592](https://github.com/ScoopInstaller/Scoop/issues/2592))
- **checkver:** Support skipping up to date manifests ([#2624](https://github.com/ScoopInstaller/Scoop/issues/2624))
- **schema:** Add shortcutsArray definition to schema.json ([0c7e6002](https://github.com/ScoopInstaller/Scoop/commit/0c7e60024a06e122331b17a204a158e4c5800a3d))
- **schema:** extract_to property is on active duty (not deprecated) ([59e994c5](https://github.com/ScoopInstaller/Scoop/commit/59e994c5fdeb8dffe6037ca6767d56ad13bf04da))
- **schema:** Improve comments in schema.json ([b5ed0761](https://github.com/ScoopInstaller/Scoop/commit/b5ed0761aef4f3e864533dc0460d110115850ba7))
- **supporting:** Update validator.exe and shim.exe ([#2024](https://github.com/ScoopInstaller/Scoop/issues/2024), [#2034](https://github.com/ScoopInstaller/Scoop/issues/2034))
- **supporting:** Update Newtonsoft.Json to 11.0.2, Newtonsoft.Json.Schema to 3.0.10 ([#3043](https://github.com/ScoopInstaller/Scoop/issues/3043))
- **validator:** Improve error reporting, add support for multiple files ([#3134](https://github.com/ScoopInstaller/Scoop/issues/3134))

### Continuous Integration

- **appveyor:** Rebuild cache ([7311b41b](https://github.com/ScoopInstaller/Scoop/commit/7311b41b8d1e2e010175fb7d079662bbcba5bac8))
- **appveyor:** Run tests for PowerShell 5 and 6 ([#2603](https://github.com/ScoopInstaller/Scoop/issues/2603))
- **test:** Improve installation of lessmsi and innounp ([#3409](https://github.com/ScoopInstaller/Scoop/issues/3409))

### Styles

- **lint:** PSAvoidUsingCmdletAliases ([#2075](https://github.com/ScoopInstaller/Scoop/issues/2075))

### Tests

- **bucket:** Add importable tests for Buckets ([478f52c4](https://github.com/ScoopInstaller/Scoop/commit/478f52c421ca35ea35b5fd0b2df2631cf7d82487))
- **bucket:** Fix manifest tests for buckets ([589303fa](https://github.com/ScoopInstaller/Scoop/commit/589303facc5284f6f95c1305191e0558c0169691))
- **bucket:** Handle JSON.NET schema validation limit exceeded. ([139813a8](https://github.com/ScoopInstaller/Scoop/commit/139813a8f50ace85e2752d9b6c9f82fc64ff3e48))
- **file:** Move style constraints tests to separate test file ([7b7113fc](https://github.com/ScoopInstaller/Scoop/commit/7b7113fc3bf962aaeba625f58341c30a80f0fe6a))
- **linux:** Fix some tests on linux ([#2153](https://github.com/ScoopInstaller/Scoop/issues/2153))
- **manifest:** Expose bucketdir variable in manifest test script ([#2182](https://github.com/ScoopInstaller/Scoop/issues/2182))
- **test:** Add -TestPath param to test.ps1 ([f857dce9](https://github.com/ScoopInstaller/Scoop/commit/f857dce9f59a490f6dd07085c3abaa51e9577fda))
- **test:** Force install PSScriptAnalyzer and BuildHelpers ([7a1b5a18](https://github.com/ScoopInstaller/Scoop/commit/7a1b5a1840e30321951fa0f5333c34d10f57fa94))
- **test:** Require BuildHelpers version 2.0.0 ([ac3ee766](https://github.com/ScoopInstaller/Scoop/commit/ac3ee766722e99c1f15dc60a1f1dfb0a48428c55))
- **test:** Update BuildHelpers to version 2.0.1 ([dde4d0f9](https://github.com/ScoopInstaller/Scoop/commit/dde4d0f93f260191af5524c0ecab927f3e252361))
- **core:** Use Pester 4.0 syntax in core tests ([#2712](https://github.com/ScoopInstaller/Scoop/issues/2712))
- **install:** Use Pester 4.0 syntax to the install tests ([#2713](https://github.com/ScoopInstaller/Scoop/issues/2713))
- **test:** Use Pester 4.0 syntax to multiple files ([#2714](https://github.com/ScoopInstaller/Scoop/issues/2714))

### Documentation

- **readme:** Add discord chat badge ([#3241](https://github.com/ScoopInstaller/Scoop/issues/3241))
- **readme:** Add more details about scoops installation ([#2273](https://github.com/ScoopInstaller/Scoop/issues/2273))
- **readme:** Corrected enable powershell executionpolicy ([#2020](https://github.com/ScoopInstaller/Scoop/issues/2020))
- **readme:** Update Discord invite link ([5f269249](https://github.com/ScoopInstaller/Scoop/commit/5f269249609b43f5c4fa9aba4def999e7ee05fe1))
- **readme:** Update requirements note ([#2509](https://github.com/ScoopInstaller/Scoop/issues/2509))
- **readme:** Fix typo (you -> your), (it's -> its) ([#2698](https://github.com/ScoopInstaller/Scoop/issues/2698))
- **readme:** Remove trailing whitespaces ([d25186bf](https://github.com/ScoopInstaller/Scoop/commit/d25186bf1f833e30d8c5b530b7c260fe399b75ed))
- **readme:** Remove "tail" from example (is coreutils) ([#2158](https://github.com/ScoopInstaller/Scoop/issues/2158))

## *Commits before 2018 are trimmed*


================================================
FILE: LICENSE
================================================
SPDX-License-Identifier: UNLICENSE or MIT

INFORMATION ABOUT THIS PROJECT'S LICENSE (SHORT)
============================================================================================
This project is licensed under the Unlicense or the MIT license,
at your option.

INFORMATION ABOUT THIS PROJECT'S LICENSE (LONG)
============================================================================================
This project ("Scoop") is free software, licensed under the Unlicense or the
MIT license, at your option. Scoop was previously licensed under only the Unlicense,
but was dual-licensed from version 0.2.0.

Scoop comes with ABSOLUTELY NO WARRANTY. Use it at your own risk. Scoop is provided
on an AS-IS BASIS and its contributors disclaim all warranties.

You may use, modify, distribute, sell, copy, compile, or merge Scoop by any means.

Copies of both licenses can be found below.

THE LICENSE OF SCOOP
============================================================================================
Unlicense
---------
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org/>

MIT license
-----------
The MIT License (MIT)

Copyright (c) 2013-2017 Luke Sampson (https://github.com/lukesampson)
Copyright (c) 2013-present Scoop contributors (https://github.com/ScoopInstaller/Scoop/graphs/contributors)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: PSScriptAnalyzerSettings.psd1
================================================
@{
    # Only diagnostic records of the specified severity will be generated.
    # Uncomment the following line if you only want Errors and Warnings but
    # not Information diagnostic records.
    Severity = @('Error')

    # Analyze **only** the following rules. Use IncludeRules when you want
    # to invoke only a small subset of the defualt rules.
    # IncludeRules = @('PSAvoidDefaultValueSwitchParameter',
    #                  'PSMisleadingBacktick',
    #                  'PSMissingModuleManifestField',
    #                  'PSReservedCmdletChar',
    #                  'PSReservedParams',
    #                  'PSShouldProcess',
    #                  'PSUseApprovedVerbs',
    #                  'PSAvoidUsingCmdletAliases',
    #                  'PSUseDeclaredVarsMoreThanAssignments')

    # Do not analyze the following rules. Use ExcludeRules when you have
    # commented out the IncludeRules settings above and want to include all
    # the default rules except for those you exclude below.
    # Note: if a rule is in both IncludeRules and ExcludeRules, the rule
    # will be excluded.
    ExcludeRules = @(
        # Currently Scoop widely uses Write-Host to output colored text.
        'PSAvoidUsingWriteHost'
    )
}


================================================
FILE: README.md
================================================
<h1 align="center">Scoop</h1>

<!--<img src="scoop.png" alt="Long live Scoop!"/>-->
<p align="center">
        <a href="https://github.com/ScoopInstaller/Scoop#what-does-scoop-do">Features</a>
        |
        <a href="https://github.com/ScoopInstaller/Scoop#installation">Installation</a>
        |
        <a href="https://github.com/ScoopInstaller/Scoop/wiki">Documentation</a>
</p>

---

<p align="center">
    <a href="https://github.com/ScoopInstaller/Scoop">
        <img src="https://img.shields.io/github/languages/code-size/ScoopInstaller/Scoop.svg" alt="Code Size" />
    </a>
    <a href="https://github.com/ScoopInstaller/Scoop">
        <img src="https://img.shields.io/github/repo-size/ScoopInstaller/Scoop.svg" alt="Repository size" />
    </a>
    <a href="https://github.com/ScoopInstaller/Scoop/actions/workflows/ci.yml">
        <img src="https://github.com/ScoopInstaller/Scoop/actions/workflows/ci.yml/badge.svg" alt="Scoop Core CI Tests" />
    </a>
    <a href="https://discord.gg/s9yRQHt">
        <img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Discord Chat" />
    </a>
    <a href="https://gitter.im/lukesampson/scoop">
        <img src="https://badges.gitter.im/lukesampson/scoop.png" alt="Gitter Chat" />
    </a>
    <a href="./LICENSE">
        <img src="https://img.shields.io/badge/license-UNLICENSE%20or%20MIT-blue" alt="License" />
    </a>
</p>

Scoop is a command-line installer for Windows.

## What does Scoop do?

Scoop installs apps from the command line with a minimal amount of friction. It:

- Eliminates [User Account Control](https://learn.microsoft.com/windows/security/application-security/application-control/user-account-control/) (UAC) prompt notifications.
- Hides the graphical user interface (GUI) of wizard-style installers.
- Prevents polluting the `PATH` environment variable. Normally, this variable gets cluttered as different apps are installed on the device.
- Avoids unexpected side effects from installing and uninstalling apps.
- Resolves and installs dependencies automatically.
- Performs all the necessary steps to get an app to a working state.

Scoop is quite script-friendly. Your environment can become the way you like by using repeatable setups. For example:

```console
scoop install sudo
sudo scoop install 7zip git openssh --global
scoop install aria2 curl grep sed less touch
scoop install python ruby go perl
```

If you have built software that you would like others to use, Scoop is an alternative to building an installer (like MSI or InnoSetup). You just need to compress your app to a `.zip` file and provide a JSON manifest that describes how to install it.

## Installation

Run the following commands from a regular (non-admin) PowerShell terminal to install Scoop:

```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
```

**Note**: The first command makes your device allow running the installation and management scripts. This is necessary because Windows 10 client devices restrict execution of any PowerShell scripts by default.

It will install Scoop to its default location:

`C:\Users\<YOUR USERNAME>\scoop`

You can find the complete documentation about the installer, including advanced installation configurations, in [ScoopInstaller/Install](https://github.com/ScoopInstaller/Install). Please create new issues there if you have questions about the installation.

## Multi-connection downloads with `aria2`

Scoop can utilize [`aria2`](https://github.com/aria2/aria2) to use multi-connection downloads. Simply install `aria2` through Scoop and it will be used for all downloads afterward.

```console
scoop install aria2
```

By default, `scoop` displays a warning when running `scoop install` or `scoop update` while `aria2` is enabled. This warning can be suppressed by running `scoop config aria2-warning-enabled false`.

You can tweak the following `aria2` settings with the `scoop config` command:

- aria2-enabled (default: true)
- aria2-warning-enabled (default: true)
- [aria2-retry-wait](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-retry-wait) (default: 2)
- [aria2-split](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-s) (default: 5)
- [aria2-max-connection-per-server](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-x) (default: 5)
- [aria2-min-split-size](https://aria2.github.io/manual/en/html/aria2c.html#cmdoption-k) (default: 5M)
- [aria2-options](https://aria2.github.io/manual/en/html/aria2c.html#options) (default: )

## Inspiration

- [Homebrew](https://brew.sh/)
- [Sub](https://signalvnoise.com/posts/3264-automating-with-convention-introducing-sub)

## What sort of apps can Scoop install?

The apps that are most likely to get installed fine with Scoop are those referred to as "portable" apps. These apps are compressed files which can run standalone after being extracted. This type of apps does not produce side effects like changing the Windows Registry or placing files outside the app directory.

Scoop also supports installer files and their uninstallation methods. Likewise, it can handle single-file apps and PowerShell scripts. These do not even need to be compressed. See the [runat](https://github.com/ScoopInstaller/Main/blob/master/bucket/runat.json) package for an example: it is simply a GitHub gist.

### Contribute to this project

If you would like to improve Scoop by adding features or fixing bugs, please read our [Contributing Guide](https://github.com/ScoopInstaller/.github/blob/main/.github/CONTRIBUTING.md).

### Support this project

If you find Scoop useful and would like to support the ongoing development and maintenance of this project, you can donate here:

- [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DM2SUH9EUXSKJ) (one-time donations)

## Known application buckets

The following buckets are known to Scoop:

- [main](https://github.com/ScoopInstaller/Main) - Default bucket which contains popular non-GUI apps.
- [extras](https://github.com/ScoopInstaller/Extras) - Apps that do not fit the main bucket's [criteria](https://github.com/ScoopInstaller/Scoop/wiki/Criteria-for-including-apps-in-the-main-bucket).
- [games](https://github.com/Calinou/scoop-games) - Open-source and freeware video games and game-related tools.
- [nerd-fonts](https://github.com/matthewjberger/scoop-nerd-fonts) -  Nerd Fonts.
- [nirsoft](https://github.com/ScoopInstaller/Nirsoft) - A collection of over 250+ apps from [Nirsoft](https://nirsoft.net).
- [sysinternals](https://github.com/niheaven/scoop-sysinternals) - The Sysinternals suite from [Microsoft](https://learn.microsoft.com/sysinternals/).
- [java](https://github.com/ScoopInstaller/Java) - A collection of Java development kits (JDKs) and Java runtime engines (JREs), Java's virtual machine debugging tools and Java based runtime engines.
- [nonportable](https://github.com/ScoopInstaller/Nonportable) - Non-portable apps (may trigger UAC prompts).
- [php](https://github.com/ScoopInstaller/PHP) - Installers for most versions of PHP.
- [versions](https://github.com/ScoopInstaller/Versions) - Alternative versions of apps found in other buckets.

The `main` bucket is installed by default. You can make use of more buckets by typing:

```console
scoop bucket add <name>
```

For example, to add the `extras` bucket, type:

```console
scoop bucket add extras
```

You would be able to install apps from the `extras` bucket now.

## Other application buckets

Many other application buckets hosted on GitHub can be found on [ScoopSearch](https://scoop.sh/) or via [other search engines](https://rasa.github.io/scoop-directory/#other-search-engines).


================================================
FILE: appveyor.yml
================================================
version: "{build}-{branch}"
branches:
  except:
    - gh-pages
build: false
deploy: false
clone_depth: 2
image: Visual Studio 2022
environment:
  matrix:
    - PowerShell: 5
    - PowerShell: 7
matrix:
  fast_finish: true
for:
  - matrix:
      only:
        - PowerShell: 5
    cache:
      - '%USERPROFILE%\Documents\WindowsPowerShell\Modules -> appveyor.yml, test\bin\*.ps1'
      - C:\projects\helpers  -> appveyor.yml, test\bin\*.ps1
    install:
      - ps: .\test\bin\init.ps1
    test_script:
      - ps: .\test\bin\test.ps1
  - matrix:
      only:
        - PowerShell: 7
    cache:
      - '%USERPROFILE%\Documents\PowerShell\Modules -> appveyor.yml, test\bin\*.ps1'
      - C:\projects\helpers  -> appveyor.yml, test\bin\*.ps1
    install:
      - pwsh: .\test\bin\init.ps1
    test_script:
      - pwsh: .\test\bin\test.ps1


================================================
FILE: bin/auto-pr.ps1
================================================
<#
.SYNOPSIS
    Updates manifests and pushes them or creates pull-requests.
.DESCRIPTION
    Updates manifests and pushes them directly to the origin branch or creates pull-requests for upstream.
.PARAMETER Upstream
    Upstream repository with the target branch.
    Must be in format '<user>/<repo>:<branch>'
.PARAMETER OriginBranch
    Origin (local) branch name.
.PARAMETER App
    Manifest name to search.
    Placeholders are supported.
.PARAMETER CommitMessageFormat
    The format of the commit message.
    <app> will be replaced with the file name of manifest.
    <version> will be replaced with the version of the latest manifest.
.PARAMETER Dir
    The directory where to search for manifests.
.PARAMETER Push
    Push updates directly to 'origin branch'.
.PARAMETER Request
    Create pull-requests on 'upstream branch' for each update.
.PARAMETER Help
    Print help to console.
.PARAMETER SpecialSnowflakes
    An array of manifests, which should be updated all the time. (-ForceUpdate parameter to checkver)
.PARAMETER SkipUpdated
    Updated manifests will not be shown.
.PARAMETER ThrowError
    Throw error as exception instead of just printing it.
.EXAMPLE
    PS BUCKETROOT > .\bin\auto-pr.ps1 'someUsername/repository:branch' -Request
.EXAMPLE
    PS BUCKETROOT > .\bin\auto-pr.ps1 -Push
    Update all manifests inside 'bucket/' directory.
#>

param(
    [Parameter(Mandatory = $true)]
    [ValidateScript( {
        if (!($_ -match '^(.*)\/(.*):(.*)$')) {
            throw 'Upstream must be in this format: <user>/<repo>:<branch>'
        }
        $true
    })]
    [String] $Upstream,
    [String] $OriginBranch = 'master',
    [String] $App = '*',
    [String] $CommitMessageFormat = '<app>: Update to version <version>',
    [ValidateScript( {
        if (!(Test-Path $_ -Type Container)) {
            throw "$_ is not a directory!"
        } else {
            $true
        }
    })]
    [String] $Dir,
    [Switch] $Push,
    [Switch] $Request,
    [Switch] $Help,
    [string[]] $SpecialSnowflakes,
    [Switch] $SkipUpdated,
    [Switch] $ThrowError
)

. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\json.ps1"

if ($App -ne '*' -and (Test-Path $App -PathType Leaf)) {
    $Dir = Split-Path $App
} elseif ($Dir) {
    $Dir = Convert-Path $Dir
} else {
    throw "'-Dir' parameter required if '-App' is not a filepath!"
}

if ((!$Push -and !$Request) -or $Help) {
    Write-Host @'
Usage: auto-pr.ps1 [OPTION]

Mandatory options:
  -p,  -push                       push updates directly to 'origin branch'
  -r,  -request                    create pull-requests on 'upstream branch' for each update

Optional options:
  -u,  -upstream                   upstream repository with target branch
  -o,  -originbranch               origin (local) branch name
  -h,  -help
'@
    exit 0
}

if ($IsLinux -or $IsMacOS) {
    if (!(which hub)) {
        Write-Host "Please install hub ('brew install hub' or visit: https://hub.github.com/)" -ForegroundColor Yellow
        exit 1
    }
} else {
    if (!(scoop which hub)) {
        Write-Host "Please install hub 'scoop install hub'" -ForegroundColor Yellow
        exit 1
    }
}

function execute($cmd) {
    Write-Host $cmd -ForegroundColor Green
    $output = Invoke-Command ([scriptblock]::Create($cmd))

    if ($LASTEXITCODE -gt 0) {
        abort "^^^ Error! See above ^^^ (last command: $cmd)"
    }

    return $output
}

function pull_requests($json, [String] $app, [String] $upstream, [String] $manifest, [String] $commitMessage) {
    $version = $json.version
    $homepage = $json.homepage
    $branch = "manifest/$app-$version"

    execute "hub checkout $OriginBranch"
    Write-Host "hub rev-parse --verify $branch" -ForegroundColor Green
    hub rev-parse --verify $branch

    if ($LASTEXITCODE -eq 0) {
        Write-Host "Skipping update $app ($version) ..." -ForegroundColor Yellow
        return
    }

    Write-Host "Creating update $app ($version) ..." -ForegroundColor DarkCyan
    execute "hub checkout -b $branch"
    execute "hub add $manifest"
    execute "hub commit -m '$commitMessage"
    Write-Host "Pushing update $app ($version) ..." -ForegroundColor DarkCyan
    execute "hub push origin $branch"

    if ($LASTEXITCODE -gt 0) {
        error "Push failed! (hub push origin $branch)"
        execute 'hub reset'
        return
    }

    Start-Sleep 1
    Write-Host "Pull-Request update $app ($version) ..." -ForegroundColor DarkCyan
    Write-Host "hub pull-request -m '<msg>' -b '$upstream' -h '$branch'" -ForegroundColor Green

    $msg = @"
$commitMessage

Hello lovely humans,
a new version of [$app]($homepage) is available.

| State       | Update :rocket: |
| :---------- | :-------------- |
| New version | $version        |
"@

    hub pull-request -m "$msg" -b "$upstream" -h "$branch"
    if ($LASTEXITCODE -gt 0) {
        execute 'hub reset'
        abort "Pull Request failed! (hub pull-request -m '$commitMessage' -b '$upstream' -h '$branch')"
    }
}

Write-Host 'Updating ...' -ForegroundColor DarkCyan
if ($Push) {
    execute "hub pull origin $OriginBranch"
    execute "hub checkout $OriginBranch"
} else {
    execute "hub pull upstream $OriginBranch"
    execute "hub push origin $OriginBranch"
}

. "$PSScriptRoot\checkver.ps1" -App $App -Dir $Dir -Update -SkipUpdated:$SkipUpdated -ThrowError:$ThrowError
if ($SpecialSnowflakes) {
    Write-Host "Forcing update on our special snowflakes: $($SpecialSnowflakes -join ',')" -ForegroundColor DarkCyan
    $SpecialSnowflakes -split ',' | ForEach-Object {
        . "$PSScriptRoot\checkver.ps1" $_ -Dir $Dir -ForceUpdate -ThrowError:$ThrowError
    }
}

hub diff --name-only | ForEach-Object {
    $manifest = $_
    if (!$manifest.EndsWith('.json')) {
        return
    }

    $app = ([System.IO.Path]::GetFileNameWithoutExtension($manifest))
    $json = parse_json $manifest
    if (!$json.version) {
        error "Invalid manifest: $manifest ..."
        return
    }
    $version = $json.version
    $CommitMessage = $CommitMessageFormat -replace '<app>',$app -replace '<version>',$version
    if ($Push) {
        Write-Host "Creating update $app ($version) ..." -ForegroundColor DarkCyan
        execute "hub add $manifest"

        # detect if file was staged, because it's not when only LF or CRLF have changed
        $status = execute 'hub status --porcelain -uno'
        $status = $status | Where-Object { $_ -match "M\s{2}.*$app.json" }
        if ($status -and $status.StartsWith('M  ') -and $status.EndsWith("$app.json")) {
            execute "hub commit -m '$commitMessage'"
        } else {
            Write-Host "Skipping $app because only LF/CRLF changes were detected ..." -ForegroundColor Yellow
        }
    } else {
        pull_requests $json $app $Upstream $manifest $CommitMessage
    }
}

if ($Push) {
    Write-Host 'Pushing updates ...' -ForegroundColor DarkCyan
    execute "hub push origin $OriginBranch"
} else {
    Write-Host "Returning to $OriginBranch branch and removing unstaged files ..." -ForegroundColor DarkCyan
    execute "hub checkout -f $OriginBranch"
}

execute 'hub reset --hard'


================================================
FILE: bin/checkhashes.ps1
================================================
<#
.SYNOPSIS
    Check if ALL urls inside manifest have correct hashes.
.PARAMETER App
    Manifest to be checked.
    Wildcard is supported.
.PARAMETER Dir
    Where to search for manifest(s).
.PARAMETER Update
    When there are mismatched hashes, manifest will be updated.
.PARAMETER ForceUpdate
    Manifest will be updated all the time. Not only when there are mismatched hashes.
.PARAMETER SkipCorrect
    Manifests without mismatch will not be shown.
.PARAMETER UseCache
    Downloaded files will not be deleted after script finish.
    Should not be used, because check should be used for downloading actual version of file (as normal user, not finding in some document from vendors, which could be damaged / wrong (Example: Slack@3.3.1 ScoopInstaller/Extras#1192)), not some previously downloaded.
.EXAMPLE
    PS BUCKETROOT> .\bin\checkhashes.ps1
    Check all manifests for hash mismatch.
.EXAMPLE
    PS BUCKETROOT> .\bin\checkhashes.ps1 MANIFEST -Update
    Check MANIFEST and Update if there are some wrong hashes.
#>
param(
    [String] $App = '*',
    [Parameter(Mandatory = $true)]
    [ValidateScript( {
        if (!(Test-Path $_ -Type Container)) {
            throw "$_ is not a directory!"
        } else {
            $true
        }
    })]
    [String] $Dir,
    [Switch] $Update,
    [Switch] $ForceUpdate,
    [Switch] $SkipCorrect,
    [Alias('k')]
    [Switch] $UseCache
)

. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\autoupdate.ps1"
. "$PSScriptRoot\..\lib\json.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\download.ps1"

$Dir = Convert-Path $Dir
if ($ForceUpdate) { $Update = $true }
# Cleanup
if (!$UseCache) { Remove-Item "$cachedir\*HASH_CHECK*" -Force }

function err ([String] $name, [String[]] $message) {
    Write-Host "$name`: " -ForegroundColor Red -NoNewline
    Write-Host ($message -join "`r`n") -ForegroundColor Red
}

$MANIFESTS = @()
foreach ($single in Get-ChildItem $Dir -Filter "$App.json" -Recurse) {
    $name = $single.BaseName
    $file = $single.FullName
    $manifest = parse_json $file

    # Skip nighly manifests, since their hash validation is skipped
    if ($manifest.version -eq 'nightly') { continue }

    $urls = @()
    $hashes = @()

    if ($manifest.url) {
        $manifest.url | ForEach-Object { $urls += $_ }
        $manifest.hash | ForEach-Object { $hashes += $_ }
    } elseif ($manifest.architecture) {
        # First handle 64bit
        script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
        hash $manifest '64bit' | ForEach-Object { $hashes += $_ }
        script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
        hash $manifest '32bit' | ForEach-Object { $hashes += $_ }
        script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
        hash $manifest 'arm64' | ForEach-Object { $hashes += $_ }
    } else {
        err $name 'Manifest does not contain URL property.'
        continue
    }

    # Number of URLS and Hashes is different
    if ($urls.Length -ne $hashes.Length) {
        err $name 'URLS and hashes count mismatch.'
        continue
    }

    $MANIFESTS += @{
        app      = $name
        file     = $file
        manifest = $manifest
        urls     = $urls
        hashes   = $hashes
    }
}

# clear any existing events
Get-Event | ForEach-Object { Remove-Event $_.SourceIdentifier }

foreach ($current in $MANIFESTS) {
    $count = 0
    # Array of indexes mismatched hashes.
    $mismatched = @()
    # Array of computed hashes
    $actuals = @()

    $current.urls | ForEach-Object {
        $algorithm, $expected = get_hash $current.hashes[$count]
        if ($UseCache) {
            $version = $current.manifest.version
        } else {
            $version = 'HASH_CHECK'
        }

        Invoke-CachedDownload $current.app $version $_ $null $null -use_cache:$UseCache

        $to_check = cache_path $current.app $version $_
        $actual_hash = (Get-FileHash -Path $to_check -Algorithm $algorithm).Hash.ToLower()

        # Append type of algorithm to both expected and actual if it's not sha256
        if ($algorithm -ne 'sha256') {
            $actual_hash = "$algorithm`:$actual_hash"
            $expected = "$algorithm`:$expected"
        }

        $actuals += $actual_hash
        if ($actual_hash -ne $expected) {
            $mismatched += $count
        }
        $count++
    }

    if ($mismatched.Length -eq 0 ) {
        if (!$SkipCorrect) {
            Write-Host "$($current.app): " -NoNewline
            Write-Host 'OK' -ForegroundColor Green
        }
    } else {
        Write-Host "$($current.app): " -NoNewline
        Write-Host 'Mismatch found ' -ForegroundColor Red
        $mismatched | ForEach-Object {
            $file = cache_path $current.app $version $current.urls[$_]
            Write-Host "`tURL:`t`t$($current.urls[$_])"
            if (Test-Path $file) {
                Write-Host "`tFirst bytes:`t$((get_magic_bytes_pretty $file ' ').ToUpper())"
            }
            Write-Host "`tExpected:`t$($current.hashes[$_])" -ForegroundColor Green
            Write-Host "`tActual:`t`t$($actuals[$_])" -ForegroundColor Red
        }
    }

    if ($Update) {
        if ($current.manifest.url -and $current.manifest.hash) {
            $current.manifest.hash = $actuals
        } else {
            $platforms = ($current.manifest.architecture | Get-Member -MemberType NoteProperty).Name
            # Defaults to zero, don't know, which architecture is available
            $64bit_count = 0
            $32bit_count = 0
            $arm64_count = 0

            # 64bit is get, donwloaded and added first
            if ($platforms.Contains('64bit')) {
                $64bit_count = $current.manifest.architecture.'64bit'.hash.Count
                $current.manifest.architecture.'64bit'.hash = $actuals[0..($64bit_count - 1)]
            }
            if ($platforms.Contains('32bit')) {
                $32bit_count = $current.manifest.architecture.'32bit'.hash.Count
                $current.manifest.architecture.'32bit'.hash = $actuals[($64bit_count)..($64bit_count + $32bit_count - 1)]
            }
            if ($platforms.Contains('arm64')) {
                $arm64_count = $current.manifest.architecture.'arm64'.hash.Count
                $current.manifest.architecture.'arm64'.hash = $actuals[($64bit_count + $32bit_count)..($64bit_count + $32bit_count + $arm64_count - 1)]
            }
        }

        Write-Host "Writing updated $($current.app) manifest" -ForegroundColor DarkGreen

        $current.manifest = $current.manifest | ConvertToPrettyJson
        $path = Convert-Path $current.file
        [System.IO.File]::WriteAllLines($path, $current.manifest)
    }
}


================================================
FILE: bin/checkurls.ps1
================================================
<#
.SYNOPSIS
    List manifests which do not have valid URLs.
.PARAMETER App
    Manifest name to search.
    Placeholder is supported.
.PARAMETER Dir
    Where to search for manifest(s).
.PARAMETER Timeout
    How long (seconds) the request can be pending before it times out.
.PARAMETER SkipValid
    Manifests will all valid URLs will not be shown.
#>
param(
    [String] $App = '*',
    [Parameter(Mandatory = $true)]
    [ValidateScript( {
        if (!(Test-Path $_ -Type Container)) {
            throw "$_ is not a directory!"
        } else {
            $true
        }
    })]
    [String] $Dir,
    [Int] $Timeout = 5,
    [Switch] $SkipValid
)

. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\download.ps1"

$Dir = Convert-Path $Dir
$Queue = @()

Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
    $manifest = parse_json $_.FullName
    $Queue += , @($_.BaseName, $manifest)
}

Write-Host '[' -NoNewLine
Write-Host 'U' -NoNewLine -ForegroundColor Cyan
Write-Host ']RLs'
Write-Host ' | [' -NoNewLine
Write-Host 'O' -NoNewLine -ForegroundColor Green
Write-Host ']kay'
Write-Host ' |  | [' -NoNewLine
Write-Host 'F' -NoNewLine -ForegroundColor Red
Write-Host ']ailed'
Write-Host ' |  |  |'

function test_dl([String] $url, $cookies) {
    # Trim renaming suffix, prevent getting 40x response
    $url = ($url -split '#/')[0]

    $wreq = [Net.WebRequest]::Create($url)
    $wreq.Timeout = $Timeout * 1000
    if ($wreq -is [Net.HttpWebRequest]) {
        $wreq.UserAgent = Get-UserAgent
        $wreq.Referer = strip_filename $url
        if ($cookies) {
            $wreq.Headers.Add('Cookie', (cookie_header $cookies))
        }
    }

    get_config PRIVATE_HOSTS | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
        (ConvertFrom-StringData -StringData $_.Headers).GetEnumerator() | ForEach-Object {
            $wreq.Headers[$_.Key] = $_.Value
        }
    }

    $wres = $null
    try {
        $wres = $wreq.GetResponse()

        return $url, $wres.StatusCode, $null
    } catch {
        $e = $_.Exception
        if ($e.InnerException) { $e = $e.InnerException }

        return $url, 'Error', $e.Message
    } finally {
        if ($null -ne $wres -and $wres -isnot [Net.FtpWebResponse]) {
            $wres.Close()
        }
    }
}

foreach ($man in $Queue) {
    $name, $manifest = $man
    $urls = @()
    $ok = 0
    $failed = 0
    $errors = @()

    if ($manifest.url) {
        $manifest.url | ForEach-Object { $urls += $_ }
    } else {
        script:url $manifest '64bit' | ForEach-Object { $urls += $_ }
        script:url $manifest '32bit' | ForEach-Object { $urls += $_ }
        script:url $manifest 'arm64' | ForEach-Object { $urls += $_ }
    }

    $urls | ForEach-Object {
        $url, $status, $msg = test_dl $_ $manifest.cookie
        if ($msg) { $errors += "$msg ($url)" }
        if ($status -eq 'OK' -or $status -eq 'OpeningData') { $ok += 1 } else { $failed += 1 }
    }

    if (($ok -eq $urls.Length) -and $SkipValid) { continue }

    # URLS
    Write-Host '[' -NoNewLine
    Write-Host $urls.Length -NoNewLine -ForegroundColor Cyan
    Write-Host ']' -NoNewLine

    # Okay
    Write-Host '[' -NoNewLine
    if ($ok -eq $urls.Length) {
        Write-Host $ok -NoNewLine -ForegroundColor Green
    } elseif ($ok -eq 0) {
        Write-Host $ok -NoNewLine -ForegroundColor Red
    } else {
        Write-Host $ok -NoNewLine -ForegroundColor Yellow
    }
    Write-Host ']' -NoNewLine

    # Failed
    Write-Host '[' -NoNewLine
    if ($failed -eq 0) {
        Write-Host $failed -NoNewLine -ForegroundColor Green
    } else {
        Write-Host $failed -NoNewLine -ForegroundColor Red
    }
    Write-Host '] ' -NoNewLine
    Write-Host $name

    $errors | ForEach-Object {
        Write-Host "       > $_" -ForegroundColor DarkRed
    }
}


================================================
FILE: bin/checkver.ps1
================================================
<#
.SYNOPSIS
    Check manifest for a newer version.
.DESCRIPTION
    Checks websites for newer versions using an (optional) regular expression defined in the manifest.
.PARAMETER App
    Manifest name to search.
    Placeholders are supported.
.PARAMETER Dir
    Where to search for manifest(s).
.PARAMETER Update
    Update given manifest
.PARAMETER ForceUpdate
    Update given manifest(s) even when there is no new version.
    Useful for hash updates.
.PARAMETER SkipUpdated
    Updated manifests will not be shown.
.PARAMETER Version
    Update manifest to specific version.
.PARAMETER ThrowError
    Throw error as exception instead of just printing it.
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1
    Check all manifest inside default directory.
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 -SkipUpdated
    Check all manifest inside default directory (list only outdated manifests).
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 -Update
    Check all manifests and update All outdated manifests.
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 APP
    Check manifest APP.json inside default directory.
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 APP -Update
    Check manifest APP.json and update, if there is newer version.
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 APP -ForceUpdate
    Check manifest APP.json and update, even if there is no new version.
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 APP -Update -Version VER
    Check manifest APP.json and update, using version VER
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 APP DIR
    Check manifest APP.json inside ./DIR directory.
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 -Dir DIR
    Check all manifests inside ./DIR directory.
.EXAMPLE
    PS BUCKETROOT > .\bin\checkver.ps1 APP DIR -Update
    Check manifest APP.json inside ./DIR directory and update if there is newer version.
#>
param(
    [String] $App = '*',
    [ValidateScript( {
        if (!(Test-Path $_ -Type Container)) {
            throw "$_ is not a directory!"
        } else {
            $true
        }
    })]
    [String] $Dir,
    [Switch] $Update,
    [Switch] $ForceUpdate,
    [Switch] $SkipUpdated,
    [String] $Version = '',
    [Switch] $ThrowError
)

. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\autoupdate.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\json.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\download.ps1"

if ($App -ne '*' -and (Test-Path $App -PathType Leaf)) {
    $Dir = Split-Path $App
    $files = Get-ChildItem $Dir -Filter (Split-Path $App -Leaf)
} elseif ($Dir) {
    $Dir = Convert-Path $Dir
    $files = Get-ChildItem $Dir -Filter "$App.json" -Recurse
} else {
    throw "'-Dir' parameter required if '-App' is not a filepath!"
}

$GitHubToken = Get-GitHubToken

# don't use $Version with $App = '*'
if ($App -eq '*' -and $Version -ne '') {
    throw "Don't use '-Version' with '-App *'!"
}

# get apps to check
$Queue = @()
$json = ''
$files | ForEach-Object {
    $file = $_.FullName
    $json = parse_json $file
    if ($json.checkver) {
        $Queue += , @($_.BaseName, $json, $file)
    }
}

# clear any existing events
Get-Event | Remove-Event
Get-EventSubscriber | Unregister-Event

# start all downloads
$Queue | ForEach-Object {
    $name, $json, $file = $_

    $substitutions = Get-VersionSubstitution $json.version # 'autoupdate.ps1'

    $wc = New-Object Net.Webclient
    if ($json.checkver.useragent) {
        $wc.Headers.Add('User-Agent', (substitute $json.checkver.useragent $substitutions))
    } else {
        $wc.Headers.Add('User-Agent', (Get-UserAgent))
    }
    Register-ObjectEvent $wc downloadDataCompleted -ErrorAction Stop | Out-Null

    # Not Specified
    if ($json.checkver.url) {
        $url = $json.checkver.url
    } else {
        $url = $json.homepage
    }

    if ($json.checkver.re) {
        $regex = $json.checkver.re
    } elseif ($json.checkver.regex) {
        $regex = $json.checkver.regex
    } else {
        $regex = ''
    }

    $jsonpath = ''
    $xpath = ''
    $replace = ''
    $useGithubAPI = $false

    # GitHub
    if ($regex) {
        $githubRegex = $regex
    } else {
        $githubRegex = '/releases/tag/(?:v|V)?([\d.]+)'
    }
    if ($json.checkver -eq 'github') {
        if (!$json.homepage.StartsWith('https://github.com/')) {
            error "$name checkver expects the homepage to be a github repository"
        }
        $url = $json.homepage.TrimEnd('/') + '/releases/latest'
        $regex = $githubRegex
        $useGithubAPI = $true
    }

    if ($json.checkver.github) {
        $url = $json.checkver.github.TrimEnd('/') + '/releases/latest'
        $regex = $githubRegex
        if ($json.checkver.PSObject.Properties.Count -eq 1) { $useGithubAPI = $true }
    }

    # SourceForge
    if ($regex) {
        $sourceforgeRegex = $regex
    } else {
        $sourceforgeRegex = '(?!\.)([\d.]+)(?<=\d)'
    }
    if ($json.checkver -eq 'sourceforge') {
        if ($json.homepage -match '//(sourceforge|sf)\.net/projects/(?<project>[^/]+)(/files/(?<path>[^/]+))?|//(?<project>[^.]+)\.(sourceforge\.(net|io)|sf\.net)') {
            $project = $Matches['project']
            $path = $Matches['path']
        } else {
            $project = strip_ext $name
        }
        $url = "https://sourceforge.net/projects/$project/rss"
        if ($path) {
            $url = $url + '?path=/' + $path.TrimStart('/')
        }
        $regex = "CDATA\[/$path/.*?$sourceforgeRegex.*?\]".Replace('//', '/')
    }
    if ($json.checkver.sourceforge) {
        if ($json.checkver.sourceforge -is [System.String] -and $json.checkver.sourceforge -match '(?<project>[\w-]*)(/(?<path>.*))?') {
            $project = $Matches['project']
            $path = $Matches['path']
        } else {
            $project = $json.checkver.sourceforge.project
            $path = $json.checkver.sourceforge.path
        }
        $url = "https://sourceforge.net/projects/$project/rss"
        if ($path) {
            $url = $url + '?path=/' + $path.TrimStart('/')
        }
        $regex = "CDATA\[/$path/.*?$sourceforgeRegex.*?\]".Replace('//', '/')
    }

    if ($json.checkver.jp) {
        $jsonpath = $json.checkver.jp
    }
    if ($json.checkver.jsonpath) {
        $jsonpath = $json.checkver.jsonpath
    }
    if ($json.checkver.xpath) {
        $xpath = $json.checkver.xpath
    }

    if ($json.checkver.replace -is [System.String]) { # If `checkver` is [System.String], it has a method called `Replace`
        $replace = $json.checkver.replace
    }

    if (!$jsonpath -and !$regex -and !$xpath) {
        $regex = $json.checkver
    }

    $reverse = $json.checkver.reverse -and $json.checkver.reverse -eq 'true'

    if ($url -like '*api.github.com/*') { $useGithubAPI = $true }

    if ($useGithubAPI -and ($null -ne $GitHubToken)) {
        $url = $url -replace '//(www\.)?github.com/', '//api.github.com/repos/'
        $wc.Headers.Add('Authorization', "token $GitHubToken")
    }

    $url = substitute $url $substitutions

    $state = New-Object psobject @{
        app      = $name
        file     = $file
        url      = $url
        regex    = $regex
        json     = $json
        jsonpath = $jsonpath
        xpath    = $xpath
        reverse  = $reverse
        replace  = $replace
    }

    get_config PRIVATE_HOSTS | Where-Object { $_ -ne $null -and $url -match $_.match } | ForEach-Object {
        (ConvertFrom-StringData -StringData $_.Headers).GetEnumerator() | ForEach-Object {
            $wc.Headers[$_.Key] = $_.Value
        }
    }

    $wc.Headers.Add('Referer', (strip_filename $url))
    $wc.DownloadDataAsync($url, $state)
}

function next($er) {
    Write-Host "$App`: " -NoNewline
    Write-Host $er -ForegroundColor DarkRed
}

# wait for all to complete
$in_progress = $Queue.length
while ($in_progress -gt 0) {
    $ev = Wait-Event
    Remove-Event $ev.SourceIdentifier
    $in_progress--

    $state = $ev.SourceEventArgs.UserState
    $result = $ev.SourceEventArgs.Result
    $app = $state.app
    $file = $state.file
    $json = $state.json
    $url = $state.url
    $regexp = $state.regex
    $jsonpath = $state.jsonpath
    $xpath = $state.xpath
    $script = $json.checkver.script
    $reverse = $state.reverse
    $replace = $state.replace
    $expected_ver = $json.version
    $ver = $Version

    if (!$ver) {
        if (!$regexp -and $replace) {
            next "'replace' requires 're' or 'regex'"
            continue
        }
        $err = $ev.SourceEventArgs.Error
        if ($err) {
            next "$($err.message)`r`nURL $url is not valid"
            continue
        }

        if ($url) {
            $ms = New-Object System.IO.MemoryStream
            $ms.Write($result, 0, $result.Length)
            $ms.Seek(0, 0) | Out-Null
            if ($result[0] -eq 0x1F -and $result[1] -eq 0x8B) {
                $ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
            }
            $page = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
        }
        $source = $url
        if ($script) {
            $page = Invoke-Command ([scriptblock]::Create($script -join "`r`n"))
            $source = 'the output of script'
        }

        if ($jsonpath) {
            # Return only a single value if regex is absent
            $noregex = [String]::IsNullOrEmpty($regexp)
            # If reverse is ON and regex is ON,
            # Then reverse would have no effect because regex handles reverse
            # on its own
            # So in this case we have to disable reverse
            $ver = json_path $page $jsonpath $null ($reverse -and $noregex) $noregex
            if (!$ver) {
                $ver = json_path_legacy $page $jsonpath
            }
            if (!$ver) {
                next "couldn't find '$jsonpath' in $source"
                continue
            }
        }

        if ($xpath) {
            $xml = [xml]$page
            # Find all `significant namespace declarations` from the XML file
            $nsList = $xml.SelectNodes("//namespace::*[not(. = ../../namespace::*)]")
            # Then add them into the NamespaceManager
            $nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
            $nsList | ForEach-Object {
                if ($_.LocalName -eq 'xmlns') {
                    $nsmgr.AddNamespace('ns', $_.Value)
                    $xpath = $xpath -replace '/([^:/]+)((?=/)|(?=$))', '/ns:$1'
                } else {
                    $nsmgr.AddNamespace($_.LocalName, $_.Value)
                }
            }
            # Getting version from XML, using XPath
            $ver = $xml.SelectSingleNode($xpath, $nsmgr).'#text'
            if (!$ver) {
                next "couldn't find '$($xpath -replace 'ns:', '')' in $source"
                continue
            }
        }

        if ($jsonpath -and $regexp) {
            $page = $ver
            $ver = ''
        }

        if ($xpath -and $regexp) {
            $page = $ver
            $ver = ''
        }

        if ($regexp) {
            $re = New-Object System.Text.RegularExpressions.Regex($regexp)
            if ($reverse) {
                $match = $re.Matches($page) | Select-Object -Last 1
            } else {
                $match = $re.Matches($page) | Select-Object -First 1
            }

            if ($match -and $match.Success) {
                $matchesHashtable = @{}
                $re.GetGroupNames() | ForEach-Object { $matchesHashtable.Add($_, $match.Groups[$_].Value) }
                $ver = $matchesHashtable['1']
                if ($replace) {
                    $ver = $re.Replace($match.Value, $replace)
                }
                if (!$ver) {
                    $ver = $matchesHashtable['version']
                }
            } else {
                next "couldn't match '$regexp' in $source"
                continue
            }
        }

        if (!$ver) {
            next "couldn't find new version in $source"
            continue
        }
    }

    # Skip actual only if versions are same and there is no -f
    if (($ver -eq $expected_ver) -and !$ForceUpdate -and $SkipUpdated) { continue }

    Write-Host "$app`: " -NoNewline

    # version hasn't changed (step over if forced update)
    if ($ver -eq $expected_ver -and !$ForceUpdate) {
        Write-Host $ver -ForegroundColor DarkGreen
        continue
    }

    Write-Host $ver -ForegroundColor DarkRed -NoNewline
    Write-Host " (scoop version is $expected_ver)" -NoNewline
    $update_available = (Compare-Version -ReferenceVersion $ver -DifferenceVersion $expected_ver) -ne 0

    if ($json.autoupdate -and $update_available) {
        Write-Host ' autoupdate available' -ForegroundColor Cyan
    } else {
        Write-Host ''
    }

    # forcing an update implies updating, right?
    if ($ForceUpdate) { $Update = $true }

    if ($Update -and $json.autoupdate) {
        if ($ForceUpdate) {
            Write-Host 'Forcing autoupdate!' -ForegroundColor DarkMagenta
        }
        try {
            Invoke-AutoUpdate $app $file $json $ver $matchesHashtable # 'autoupdate.ps1'
        } catch {
            if ($ThrowError) {
                throw $_
            } else {
                error $_.Exception.Message
            }
        }
    }
}


================================================
FILE: bin/describe.ps1
================================================
<#
.SYNOPSIS
    Search for application description on homepage.
.PARAMETER App
    Manifest name to search.
    Placeholders are supported.
.PARAMETER Dir
    Where to search for manifest(s).
#>
param(
    [String] $App = '*',
    [Parameter(Mandatory = $true)]
    [ValidateScript( {
        if (!(Test-Path $_ -Type Container)) {
            throw "$_ is not a directory!"
        } else {
            $true
        }
    })]
    [String] $Dir
)

. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\description.ps1"
. "$PSScriptRoot\..\lib\download.ps1"

$Dir = Convert-Path $Dir
$Queue = @()

Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
    $manifest = parse_json $_.FullName
    $Queue += , @($_.BaseName, $manifest)
}

$Queue | ForEach-Object {
    $name, $manifest = $_
    Write-Host "$name`: " -NoNewline

    if (!$manifest.homepage) {
        Write-Host "`nNo homepage set." -ForegroundColor Red
        return
    }
    # get description from homepage
    try {
        $wc = New-Object Net.Webclient
        $wc.Headers.Add('User-Agent', (Get-UserAgent))
        $homepage = $wc.DownloadData($manifest.homepage)
        $home_html = (Get-Encoding($wc)).GetString($homepage)
    } catch {
        Write-Host "`n$($_.Exception.Message)" -ForegroundColor Red
        return
    }

    $description, $descr_method = find_description $manifest.homepage $home_html
    if (!$description) {
        Write-Host "`nDescription not found ($($manifest.homepage))" -ForegroundColor Red
        return
    }

    $description = clean_description $description

    Write-Host "(found by $descr_method)"
    Write-Host "  ""$description""" -ForegroundColor Green
}


================================================
FILE: bin/formatjson.ps1
================================================
<#
.SYNOPSIS
    Format manifest.
.PARAMETER App
    Manifest to format.

    Wildcards are supported.
.PARAMETER Dir
    Where to search for manifest(s).
.EXAMPLE
    PS BUCKETROOT> .\bin\formatjson.ps1
    Format all manifests inside bucket directory.
.EXAMPLE
    PS BUCKETROOT> .\bin\formatjson.ps1 7zip
    Format manifest '7zip' inside bucket directory.
#>
param(
    [String] $App = '*',
    [Parameter(Mandatory = $true)]
    [ValidateScript( {
        if (!(Test-Path $_ -Type Container)) {
            throw "$_ is not a directory!"
        } else {
            $true
        }
    })]
    [String] $Dir
)

. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"
. "$PSScriptRoot\..\lib\json.ps1"

$Dir = Convert-Path $Dir

Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
    $file = $_.FullName
    # beautify
    $json = parse_json $file | ConvertToPrettyJson

    # convert to 4 spaces
    $json = $json -replace "`t", '    '
    [System.IO.File]::WriteAllLines($file, $json)
}


================================================
FILE: bin/install.ps1
================================================
#Requires -Version 5
Invoke-RestMethod https://get.scoop.sh | Invoke-Expression


================================================
FILE: bin/missing-checkver.ps1
================================================
<#
.SYNOPSIS
    Check if manifest contains checkver and autoupdate property.
.PARAMETER App
    Manifest name.
    Wirldcard is supported.
.PARAMETER Dir
    Location of manifests.
.PARAMETER SkipSupported
    Manifests with checkver and autoupdate will not be presented.
#>
param(
    [String] $App = '*',
    [Parameter(Mandatory = $true)]
    [ValidateScript( {
        if (!(Test-Path $_ -Type Container)) {
            throw "$_ is not a directory!"
        } else {
            $true
        }
    })]
    [String] $Dir,
    [Switch] $SkipSupported
)

. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"

$Dir = Convert-Path $Dir

Write-Host '[' -NoNewLine
Write-Host 'C' -NoNewLine -ForegroundColor Green
Write-Host ']heckver'
Write-Host ' | [' -NoNewLine
Write-Host 'A' -NoNewLine -ForegroundColor Cyan
Write-Host ']utoupdate'
Write-Host ' |  |'

Get-ChildItem $Dir -Filter "$App.json" -Recurse | ForEach-Object {
    $json = parse_json $_.FullName

    if ($SkipSupported -and $json.checkver -and $json.autoupdate) { return }

    Write-Host '[' -NoNewLine
    Write-Host $(if ($json.checkver) { 'C' } else { ' ' }) -NoNewLine -ForegroundColor Green
    Write-Host ']' -NoNewLine

    Write-Host '[' -NoNewLine
    Write-Host $(if ($json.autoupdate) { 'A' } else { ' ' }) -NoNewLine -ForegroundColor Cyan
    Write-Host '] ' -NoNewLine
    Write-Host $_.BaseName
}


================================================
FILE: bin/refresh.ps1
================================================
# for development, update the installed scripts to match local source
. "$PSScriptRoot\..\lib\core.ps1"

$src = "$PSScriptRoot\.."
$dest = ensure (versiondir 'scoop' 'current')

# make sure not running from the installed directory
if("$src" -eq "$dest") { abort "$(strip_ext $myinvocation.mycommand.name) is for development only" }

'copying files...'
$output = robocopy $src $dest /mir /njh /njs /nfl /ndl /xd .git tmp /xf .DS_Store last_updated

$output | Where-Object { $_ -ne "" }

Write-Output 'creating shim...'
shim "$dest\bin\scoop.ps1" $false

success 'scoop was refreshed!'


================================================
FILE: bin/scoop.ps1
================================================
#Requires -Version 5
Set-StrictMode -Off

. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\buckets.ps1"
. "$PSScriptRoot\..\lib\commands.ps1"
. "$PSScriptRoot\..\lib\help.ps1"

$subCommand = $Args[0]

# for aliases where there's a local function, re-alias so the function takes precedence
$aliases = Get-Alias | Where-Object { $_.Options -notmatch 'ReadOnly|AllScope' } | ForEach-Object { $_.Name }
Get-ChildItem Function: | Where-Object -Property Name -In -Value $aliases | ForEach-Object {
    Set-Alias -Name $_.Name -Value Local:$($_.Name) -Scope Script
}

switch ($subCommand) {
    ({ $subCommand -in @($null, '-h', '--help', '/?') }) {
        exec 'help'
    }
    ({ $subCommand -in @('-v', '--version') }) {
        Write-Host 'Current Scoop version:'
        if (Test-GitAvailable -and (Test-Path "$PSScriptRoot\..\.git") -and (get_config SCOOP_BRANCH 'master') -ne 'master') {
            Invoke-Git -Path "$PSScriptRoot\.." -ArgumentList @('log', 'HEAD', '-1', '--oneline')
        } else {
            $version = Select-String -Pattern '^## \[(v[\d.]+)\].*?([\d-]+)$' -Path "$PSScriptRoot\..\CHANGELOG.md"
            Write-Host $version.Matches.Groups[1].Value -ForegroundColor Cyan -NoNewline
            Write-Host " - Released at $($version.Matches.Groups[2].Value)"
        }
        Write-Host ''

        Get-LocalBucket | ForEach-Object {
            $bucketLoc = Find-BucketDirectory $_ -Root
            if (Test-GitAvailable -and (Test-Path "$bucketLoc\.git")) {
                Write-Host "'$_' bucket:"
                Invoke-Git -Path $bucketLoc -ArgumentList @('log', 'HEAD', '-1', '--oneline')
                Write-Host ''
            }
        }
    }
    ({ $subCommand -in (commands) }) {
        [string[]]$arguments = $Args | Select-Object -Skip 1
        if ($null -ne $arguments -and $arguments[0] -in @('-h', '--help', '/?')) {
            exec 'help' @($subCommand)
        } else {
            exec $subCommand $arguments
        }
    }
    default {
        warn "scoop: '$subCommand' isn't a scoop command. See 'scoop help'."
        exit 1
    }
}


================================================
FILE: bin/test.ps1
================================================
. "$PSScriptRoot\..\test\bin\test.ps1"


================================================
FILE: bin/uninstall.ps1
================================================
<#
.SYNOPSIS
    Uninstall ALL scoop applications and scoop itself.
.PARAMETER global
    Global applications will be uninstalled.
.PARAMETER purge
    Persisted data will be deleted.
#>
param(
    [bool] $global,
    [bool] $purge
)

. "$PSScriptRoot\..\lib\core.ps1"
. "$PSScriptRoot\..\lib\system.ps1"
. "$PSScriptRoot\..\lib\install.ps1"
. "$PSScriptRoot\..\lib\shortcuts.ps1"
. "$PSScriptRoot\..\lib\versions.ps1"
. "$PSScriptRoot\..\lib\manifest.ps1"

if ($global -and !(is_admin)) {
    error 'You need admin rights to uninstall globally.'
    exit 1
}

if ($purge) {
    warn 'This will uninstall Scoop, all the programs that have been installed with Scoop and all persisted data!'
} else {
    warn 'This will uninstall Scoop and all the programs that have been installed with Scoop!'
}
$yn = Read-Host 'Are you sure? (yN)'
if ($yn -notlike 'y*') { exit }

$errors = $false

# Uninstall given app
function do_uninstall($app, $global) {
    $version = Select-CurrentVersion -AppName $app -Global:$global
    $dir = versiondir $app $version $global
    $manifest = installed_manifest $app $version $global
    $install = install_info $app $version $global
    $architecture = $install.architecture

    Write-Output "Uninstalling '$app'"
    Invoke-Installer -Path $dir -Manifest $manifest -ProcessorArchitecture $architecture -Uninstall
    rm_shims $app $manifest $global $architecture

    # If a junction was used during install, that will have been used
    # as the reference directory. Othewise it will just be the version
    # directory.
    $refdir = unlink_current (appdir $app $global)

    env_rm_path $manifest $refdir $global $architecture
    env_rm $manifest $global $architecture

    $appdir = appdir $app $global
    try {
        Remove-Item $appdir -Recurse -Force -ErrorAction Stop
    } catch {
        $errors = $true
        warn "Couldn't remove $(friendly_path $appdir): $_.Exception"
    }
}

function rm_dir($dir) {
    try {
        Remove-Item $dir -Recurse -Force -ErrorAction Stop
    } catch {
        abort "Couldn't remove $(friendly_path $dir): $_"
    }
}

# Remove all folders (except persist) inside given scoop directory.
function keep_onlypersist($directory) {
    Get-ChildItem $directory -Exclude 'persist' | ForEach-Object { rm_dir $_ }
}

# Run uninstallation for each app if necessary, continuing if there's
# a problem deleting a directory (which is quite likely)
if ($global) {
    installed_apps $true | ForEach-Object { # global apps
        do_uninstall $_ $true
    }
}

installed_apps $false | ForEach-Object { # local apps
    do_uninstall $_ $false
}

if ($errors) {
    abort 'Not all apps could be deleted. Try again or restart.'
}

if ($purge) {
    rm_dir $scoopdir
    if ($global) { rm_dir $globaldir }
} else {
    keep_onlypersist $scoopdir
    if ($global) { keep_onlypersist $globaldir }
}

Remove-Path -Path (shimdir $global) -Global:$global
if (get_config USE_ISOLATED_PATH) {
    Remove-Path -Path ('%' + $scoopPathEnvVar + '%') -Global:$global
}

success 'Scoop has been uninstalled.'


================================================
FILE: buckets.json
================================================
{
    "main": "https://github.com/ScoopInstaller/Main",
    "extras": "https://github.com/ScoopInstaller/Extras",
    "versions": "https://github.com/ScoopInstaller/Versions",
    "nirsoft": "https://github.com/ScoopInstaller/Nirsoft",
    "sysinternals": "https://github.com/niheaven/scoop-sysinternals",
    "php": "https://github.com/ScoopInstaller/PHP",
    "nerd-fonts": "https://github.com/matthewjberger/scoop-nerd-fonts",
    "nonportable": "https://github.com/ScoopInstaller/Nonportable",
    "java": "https://github.com/ScoopInstaller/Java",
    "games": "https://github.com/Calinou/scoop-games"
}


================================================
FILE: lib/autoupdate.ps1
================================================
# Must included with 'json.ps1'

function format_hash([String] $hash) {
    $hash = $hash.toLower()

    if ($hash -like 'sha256:*') {
        $hash = $hash.Substring(7)  # Remove prefix 'sha256:'
    }

    switch ($hash.Length) {
        32 { $hash = "md5:$hash" } # md5
        40 { $hash = "sha1:$hash" } # sha1
        64 { $hash = $hash } # sha256
        128 { $hash = "sha512:$hash" } # sha512
        default { $hash = $null }
    }
    return $hash
}

function find_hash_in_rdf([String] $url, [String] $basename) {
    $xml = $null
    try {
        # Download and parse RDF XML file
        $wc = New-Object Net.Webclient
        $wc.Headers.Add('Referer', (strip_filename $url))
        $wc.Headers.Add('User-Agent', (Get-UserAgent))
        $data = $wc.DownloadData($url)
        [xml]$xml = (Get-Encoding($wc)).GetString($data)
    } catch [System.Net.WebException] {
        Write-Host $_ -ForegroundColor DarkRed
        Write-Host "URL $url is not valid" -ForegroundColor DarkRed
        return $null
    }

    # Find file content
    $digest = $xml.RDF.Content | Where-Object { [String]$_.about -eq $basename }

    return format_hash $digest.sha256
}

function find_hash_in_textfile([String] $url, [Hashtable] $substitutions, [String] $regex) {
    $hashfile = $null

    $templates = @{
        '$md5'      = '([a-fA-F0-9]{32})'
        '$sha1'     = '([a-fA-F0-9]{40})'
        '$sha256'   = '([a-fA-F0-9]{64})'
        '$sha512'   = '([a-fA-F0-9]{128})'
        '$checksum' = '([a-fA-F0-9]{32,128})'
        '$base64'   = '([a-zA-Z0-9+\/=]{24,88})'
    }

    try {
        $wc = New-Object Net.Webclient
        $wc.Headers.Add('Referer', (strip_filename $url))
        $wc.Headers.Add('User-Agent', (Get-UserAgent))
        $data = $wc.DownloadData($url)
        $ms = New-Object System.IO.MemoryStream
        $ms.Write($data, 0, $data.Length)
        $ms.Seek(0, 0) | Out-Null
        if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
            $ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
        }
        $hashfile = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
    } catch [system.net.webexception] {
        Write-Host $_ -ForegroundColor DarkRed
        Write-Host "URL $url is not valid" -ForegroundColor DarkRed
        return
    }

    if ($regex.Length -eq 0) {
        $regex = '^\s*([a-fA-F0-9]+)\s*$'
    }

    $regex = substitute $regex $templates $false
    $regex = substitute $regex $substitutions $true
    if ($hashfile -match $regex) {
        debug $regex
        $hash = $matches[1] -replace '\s', ''
    }

    # convert base64 encoded hash values
    if ($hash -match '^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$') {
        $base64 = $matches[0]
        if (!($hash -match '^[a-fA-F0-9]+$') -and $hash.Length -notin @(32, 40, 64, 128)) {
            try {
                $hash = ([System.Convert]::FromBase64String($base64) | ForEach-Object { $_.ToString('x2') }) -join ''
            } catch {
                $hash = $hash
            }
        }
    }

    # find hash with filename in $hashfile
    if ($hash.Length -eq 0) {
        $filenameRegex = "([a-fA-F0-9]{32,128})[\x20\t]+.*`$basename(?:\s|$)|`$basename[\x20\t]+.*?([a-fA-F0-9]{32,128})"
        $filenameRegex = substitute $filenameRegex $substitutions $true
        if ($hashfile -match $filenameRegex) {
            debug $filenameRegex
            $hash = $matches[1]
        }
        $metalinkRegex = '<hash[^>]+>([a-fA-F0-9]{64})'
        if ($hashfile -match $metalinkRegex) {
            debug $metalinkRegex
            $hash = $matches[1]
        }
    }

    return format_hash $hash
}

function find_hash_in_json([String] $url, [Hashtable] $substitutions, [String] $jsonpath) {
    $json = $null

    try {
        $wc = New-Object Net.Webclient
        $wc.Headers.Add('Referer', (strip_filename $url))
        $wc.Headers.Add('User-Agent', (Get-UserAgent))
        $data = $wc.DownloadData($url)
        $ms = New-Object System.IO.MemoryStream
        $ms.Write($data, 0, $data.Length)
        $ms.Seek(0, 0) | Out-Null
        if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
            $ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
        }
        $json = (New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd()
    } catch [System.Net.WebException] {
        Write-Host $_ -ForegroundColor DarkRed
        Write-Host "URL $url is not valid" -ForegroundColor DarkRed
        return
    }
    debug $jsonpath
    $hash = json_path $json $jsonpath $substitutions
    if (!$hash) {
        $hash = json_path_legacy $json $jsonpath $substitutions
    }
    return format_hash $hash
}

function find_hash_in_xml([String] $url, [Hashtable] $substitutions, [String] $xpath) {
    $xml = $null

    try {
        $wc = New-Object Net.Webclient
        $wc.Headers.Add('Referer', (strip_filename $url))
        $wc.Headers.Add('User-Agent', (Get-UserAgent))
        $data = $wc.DownloadData($url)
        $ms = New-Object System.IO.MemoryStream
        $ms.Write($data, 0, $data.Length)
        $ms.Seek(0, 0) | Out-Null
        if ($data[0] -eq 0x1F -and $data[1] -eq 0x8B) {
            $ms = New-Object System.IO.Compression.GZipStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
        }
        $xml = [xml]((New-Object System.IO.StreamReader($ms, (Get-Encoding $wc))).ReadToEnd())
    } catch [system.net.webexception] {
        Write-Host $_ -ForegroundColor DarkRed
        Write-Host "URL $url is not valid" -ForegroundColor DarkRed
        return
    }

    # Replace placeholders
    if ($substitutions) {
        $xpath = substitute $xpath $substitutions
    }

    # Find all `significant namespace declarations` from the XML file
    $nsList = $xml.SelectNodes('//namespace::*[not(. = ../../namespace::*)]')
    # Then add them into the NamespaceManager
    $nsmgr = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
    $nsList | ForEach-Object {
        $nsmgr.AddNamespace($_.LocalName, $_.Value)
    }

    debug $xpath
    debug $nsmgr
    # Getting hash from XML, using XPath
    $hash = $xml.SelectSingleNode($xpath, $nsmgr).'#text'
    return format_hash $hash
}

function find_hash_in_headers([String] $url) {
    $hash = $null

    try {
        $req = [System.Net.WebRequest]::Create($url)
        $req.Referer = (strip_filename $url)
        $req.AllowAutoRedirect = $false
        $req.UserAgent = (Get-UserAgent)
        $req.Timeout = 2000
        $req.Method = 'HEAD'
        $res = $req.GetResponse()
        if (([int]$res.StatusCode -ge 300) -and ([int]$res.StatusCode -lt 400)) {
            if ($res.Headers['Digest'] -match 'SHA-256=([^,]+)' -or $res.Headers['Digest'] -match 'SHA=([^,]+)' -or $res.Headers['Digest'] -match 'MD5=([^,]+)') {
                $hash = ([System.Convert]::FromBase64String($matches[1]) | ForEach-Object { $_.ToString('x2') }) -join ''
                debug $hash
            }
        }
        $res.Close()
    } catch [System.Net.WebException] {
        Write-Host $_ -ForegroundColor DarkRed
        Write-Host "URL $url is not valid" -ForegroundColor DarkRed
        return
    }

    return format_hash $hash
}

function get_hash_for_app([String] $app, $config, [String] $version, [String] $url, [Hashtable] $substitutions) {
    $hash = $null

    $hashmode = $config.mode
    $basename = [System.Web.HttpUtility]::UrlDecode((url_remote_filename($url)))

    $substitutions = $substitutions.Clone()
    $substitutions.Add('$url', (strip_fragment $url))
    $substitutions.Add('$baseurl', (strip_filename (strip_fragment $url)).TrimEnd('/'))
    $substitutions.Add('$basename', $basename)
    $substitutions.Add('$urlNoExt', (strip_ext (strip_fragment $url)))
    $substitutions.Add('$basenameNoExt', (strip_ext $basename))

    debug $substitutions

    $hashfile_url = substitute $config.url $substitutions
    debug $hashfile_url
    if ($hashfile_url) {
        Write-Host 'Searching hash for ' -ForegroundColor DarkYellow -NoNewline
        Write-Host $basename -ForegroundColor Green -NoNewline
        Write-Host ' in ' -ForegroundColor DarkYellow -NoNewline
        Write-Host $hashfile_url -ForegroundColor Green
    }

    if ($hashmode.Length -eq 0 -and $config.url.Length -ne 0) {
        $hashmode = 'extract'
    }

    $jsonpath = ''
    if ($config.jp) {
        $jsonpath = $config.jp
        $hashmode = 'json'
    }
    if ($config.jsonpath) {
        $jsonpath = $config.jsonpath
        $hashmode = 'json'
    }
    $regex = ''
    if ($config.find) {
        $regex = $config.find
    }
    if ($config.regex) {
        $regex = $config.regex
    }

    $xpath = ''
    if ($config.xpath) {
        $xpath = $config.xpath
        $hashmode = 'xpath'
    }

    if (!$hashfile_url -and $url -match '^(?:.*fosshub.com\/).*(?:\/|\?dwl=)(?<filename>.*)$') {
        $hashmode = 'fosshub'
    }

    if (!$hashfile_url -and $url -match '(?:downloads\.)?sourceforge.net\/projects?\/(?<project>[^\/]+)\/(?:files\/)?(?<file>.*)') {
        $hashmode = 'sourceforge'
    }

    if (!$hashfile_url -and $url -match 'https:\/\/github\.com\/(?<owner>[^\/]+)\/(?<repo>[^\/]+)\/releases\/download\/[^\/]+\/[^\/]+') {
        $hashmode = 'github'
    }

    switch ($hashmode) {
        'extract' {
            $hash = find_hash_in_textfile $hashfile_url $substitutions $regex
        }
        'json' {
            $hash = find_hash_in_json $hashfile_url $substitutions $jsonpath
        }
        'xpath' {
            $hash = find_hash_in_xml $hashfile_url $substitutions $xpath
        }
        'rdf' {
            $hash = find_hash_in_rdf $hashfile_url $basename
        }
        'metalink' {
            $hash = find_hash_in_headers $url
            if (!$hash) {
                $hash = find_hash_in_textfile "$url.meta4" $substitutions
            }
        }
        'fosshub' {
            $hash = find_hash_in_textfile $url $substitutions ($matches.filename + '.*?"sha256":"([a-fA-F0-9]{64})"')
        }
        'sourceforge' {
            # change the URL because downloads.sourceforge.net doesn't have checksums
            $hashfile_url = (strip_filename (strip_fragment "https://sourceforge.net/projects/$($matches['project'])/files/$($matches['file'])")).TrimEnd('/')
            $hash = find_hash_in_textfile $hashfile_url $substitutions '"$basename":.*?"sha1":\s*"([a-fA-F0-9]{40})"'
        }
        'github' {
            $hashfile_url = "https://api.github.com/repos/$($matches['owner'])/$($matches['repo'])/releases"
            $hash = find_hash_in_json $hashfile_url $substitutions ("$..assets[?(@.browser_download_url == '" + $url + "')].digest")
        }
    }

    if ($hash) {
        # got one!
        Write-Host 'Found: ' -ForegroundColor DarkYellow -NoNewline
        Write-Host $hash -ForegroundColor Green -NoNewline
        Write-Host ' using ' -ForegroundColor DarkYellow -NoNewline
        Write-Host "$((Get-Culture).TextInfo.ToTitleCase($hashmode)) Mode" -ForegroundColor Green
        return $hash
    } elseif ($hashfile_url) {
        Write-Host -f DarkYellow "Could not find hash in $hashfile_url"
    }

    Write-Host 'Downloading ' -ForegroundColor DarkYellow -NoNewline
    Write-Host $basename -ForegroundColor Green -NoNewline
    Write-Host ' to compute hashes!' -ForegroundColor DarkYellow
    try {
        Invoke-CachedDownload $app $version $url $null $null $true
    } catch [system.net.webexception] {
        Write-Host $_ -ForegroundColor DarkRed
        Write-Host "URL $url is not valid" -ForegroundColor DarkRed
        return $null
    }
    $file = cache_path $app $version $url
    $hash = (Get-FileHash -Path $file -Algorithm SHA256).Hash.ToLower()
    Write-Host 'Computed hash: ' -ForegroundColor DarkYellow -NoNewline
    Write-Host $hash -ForegroundColor Green
    return $hash
}

function Update-ManifestProperty {
    <#
    .SYNOPSIS
        Update propert(y|ies) in manifest
    .DESCRIPTION
        Update selected propert(y|ies) to given version in manifest.
    .PARAMETER Manifest
        Manifest to be updated
    .PARAMETER Property
        Selected propert(y|ies) to be updated
    .PARAMETER AppName
        Software name
    .PARAMETER Version
        Given software version
    .PARAMETER Substitutions
        Hashtable of internal substitutable variables
    .OUTPUTS
        System.Boolean
            Flag that indicate if there are any changed properties
    #>
    [CmdletBinding(SupportsShouldProcess = $true)]
    [OutputType([Boolean])]
    param (
        [Parameter(Mandatory = $true, Position = 1)]
        [PSCustomObject]
        $Manifest,
        [Parameter(ValueFromPipeline = $true, Position = 2)]
        [String[]]
        $Property,
        [String]
        $AppName,
        [String]
        $Version,
        [Alias('Matches')]
        [HashTable]
        $Substitutions
    )
    begin {
        $hasManifestChanged = $false
    }
    process {
        foreach ($currentProperty in $Property) {
            if ($currentProperty -eq 'hash') {
                # Update hash
                if ($Manifest.hash) {
                    # Global
                    $newURL = substitute $Manifest.autoupdate.url $Substitutions
                    $newHash = HashHelper -AppName $AppName -Version $Version -HashExtraction $Manifest.autoupdate.hash -URL $newURL -Substitutions $Substitutions
                    $Manifest.hash, $hasPropertyChanged = PropertyHelper -Property $Manifest.hash -Value $newHash
                    $hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
                } else {
                    # Arch-spec
                    $Manifest.architecture | Get-Member -MemberType NoteProperty | ForEach-Object {
                        $arch = $_.Name
                        $newURL = substitute (arch_specific 'url' $Manifest.autoupdate $arch) $Substitutions
                        $newHash = HashHelper -AppName $AppName -Version $Version -HashExtraction (arch_specific 'hash' $Manifest.autoupdate $arch) -URL $newURL -Substitutions $Substitutions
                        $Manifest.architecture.$arch.hash, $hasPropertyChanged = PropertyHelper -Property $Manifest.architecture.$arch.hash -Value $newHash
                        $hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
                    }
                }
            } elseif ($Manifest.$currentProperty -and $Manifest.autoupdate.$currentProperty) {
                # Update other property (global)
                $autoupdateProperty = $Manifest.autoupdate.$currentProperty
                $newValue = substitute $autoupdateProperty $Substitutions
                if (($autoupdateProperty.GetType().Name -eq 'Object[]') -and ($autoupdateProperty.Length -eq 1)) {
                    # Make sure it's an array
                    $newValue = , $newValue
                }
                $Manifest.$currentProperty, $hasPropertyChanged = PropertyHelper -Property $Manifest.$currentProperty -Value $newValue
                $hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
            } elseif ($Manifest.architecture) {
                # Update other property (arch-spec)
                $Manifest.architecture | Get-Member -MemberType NoteProperty | ForEach-Object {
                    $arch = $_.Name
                    if ($Manifest.architecture.$arch.$currentProperty -and ($Manifest.autoupdate.architecture.$arch.$currentProperty -or $Manifest.autoupdate.$currentProperty)) {
                        $autoupdateProperty = @(arch_specific $currentProperty $Manifest.autoupdate $arch)
                        $newValue = substitute $autoupdateProperty $Substitutions
                        if (($autoupdateProperty.GetType().Name -eq 'Object[]') -and ($autoupdateProperty.Length -eq 1)) {
                            # Make sure it's an array
                            $newValue = , $newValue
                        }
                        $Manifest.architecture.$arch.$currentProperty, $hasPropertyChanged = PropertyHelper -Property $Manifest.architecture.$arch.$currentProperty -Value $newValue
                        $hasManifestChanged = $hasManifestChanged -or $hasPropertyChanged
                    }
                }
            }
        }
    }
    end {
        if ($Version -ne '' -and $Manifest.version -ne $Version) {
            $Manifest.version = $Version
            $hasManifestChanged = $true
        }
        return $hasManifestChanged
    }
}

function Get-VersionSubstitution {
    param (
        [String]
        $Version,
        [Hashtable]
        $CustomMatches
    )

    $firstPart = $Version.Split('-') | Select-Object -First 1
    $lastPart = $Version.Split('-') | Select-Object -Last 1
    $versionVariables = @{
        '$version'           = $Version
        '$dotVersion'        = ($Version -replace '[._-]', '.')
        '$underscoreVersion' = ($Version -replace '[._-]', '_')
        '$dashVersion'       = ($Version -replace '[._-]', '-')
        '$cleanVersion'      = ($Version -replace '[._-]', '')
        '$majorVersion'      = $firstPart.Split('.') | Select-Object -First 1
        '$minorVersion'      = $firstPart.Split('.') | Select-Object -Skip 1 -First 1
        '$patchVersion'      = $firstPart.Split('.') | Select-Object -Skip 2 -First 1
        '$buildVersion'      = $firstPart.Split('.') | Select-Object -Skip 3 -First 1
        '$preReleaseVersion' = $lastPart
    }
    if ($Version -match '(?<head>\d+\.\d+(?:\.\d+)?)(?<tail>.*)') {
        $versionVariables.Add('$matchHead', $Matches['head'])
        $versionVariables.Add('$matchTail', $Matches['tail'])
    }
    if ($CustomMatches) {
        $CustomMatches.GetEnumerator() | ForEach-Object {
            if ($_.Name -ne '0') {
                $versionVariables.Add('$match' + (Get-Culture).TextInfo.ToTitleCase($_.Name), $_.Value)
            }
        }
    }
    return $versionVariables
}

function Invoke-AutoUpdate {
    param (
        [String]
        $AppName,
        [String]
        $Path,
        [PSObject]
        $Manifest,
        [String]
        $Version,
        [Hashtable]
        $CustomMatches
    )

    Write-Host "Autoupdating $AppName" -ForegroundColor DarkCyan
    $substitutions = Get-VersionSubstitution $Version $CustomMatches

    # update properties
    $updatedProperties = @(@($Manifest.autoupdate.PSObject.Properties.Name) -ne 'architecture')
    if ($Manifest.autoupdate.architecture) {
        $updatedProperties += $Manifest.autoupdate.architecture.PSObject.Properties | ForEach-Object { $_.Value.PSObject.Properties.Name }
    }
    if ($updatedProperties -contains 'url') {
        $updatedProperties += 'hash'
    }
    $updatedProperties = $updatedProperties | Select-Object -Unique
    debug [$updatedProperties]
    $hasChanged = Update-ManifestProperty -Manifest $Manifest -Property $updatedProperties -AppName $AppName -Version $Version -Substitutions $substitutions

    if ($hasChanged) {
        # write file
        Write-Host "Writing updated $AppName manifest" -ForegroundColor DarkGreen
        # Accept unusual Unicode characters
        # 'Set-Content -Encoding ASCII' don't works in PowerShell 5
        # Wait for 'UTF8NoBOM' Encoding in PowerShell 7
        # $Manifest | ConvertToPrettyJson | Set-Content -Path (Join-Path $Path "$AppName.json") -Encoding UTF8NoBOM
        [System.IO.File]::WriteAllLines($Path, (ConvertToPrettyJson $Manifest))
        # notes
        $note = "`nUpdating note:"
        if ($Manifest.autoupdate.note) {
            $note += "`nno-arch: $($Manifest.autoupdate.note)"
            $hasNote = $true
        }
        if ($Manifest.autoupdate.architecture) {
            '64bit', '32bit', 'arm64' | ForEach-Object {
                if ($Manifest.autoupdate.architecture.$_.note) {
                    $note += "`n$_-arch: $($Manifest.autoupdate.architecture.$_.note)"
                    $hasNote = $true
                }
            }
        }
        if ($hasNote) {
            Write-Host $note -ForegroundColor DarkYellow
        }
    } else {
        # This if-else branch may not be in use.
        Write-Host "No updates for $AppName" -ForegroundColor DarkGray
    }
}

## Helper Functions

function PropertyHelper {
    <#
    .SYNOPSIS
        Helper of updating property
    .DESCRIPTION
        Update manifest property (String, Array or PSCustomObject).
    .PARAMETER Property
        Property to be updated
    .PARAMETER Value
        New property values
        Update line by line
    .OUTPUTS
        System.Object[]
            The first element is new property, the second element is change flag
    #>
    param (
        [Object]$Property,
        [Object]$Value
    )
    $hasChanged = $false
    if (@($Property).Length -lt @($Value).Length) {
        $Property = $Value
        $hasChanged = $true
    } else {
        switch ($Property.GetType().Name) {
            'String' {
                $Value = $Value -as [String]
                if ($null -ne $Value) {
                    $Property = $Value
                    $hasChanged = $true
                }
            }
            'Object[]' {
                $Value = @($Value)
                for ($i = 0; $i -lt $Value.Length; $i++) {
                    $Property[$i], $hasItemChanged = PropertyHelper -Property $Property[$i] -Value $Value[$i]
                    $hasChanged = $hasChanged -or $hasItemChanged
                }
            }
            'PSCustomObject' {
                if ($Value -is [PSObject]) {
                    foreach ($name in $Property.PSObject.Properties.Name) {
                        if ($Value.$name) {
                            $Property.$name, $hasItemChanged = PropertyHelper -Property $Property.$name -Value $Value.$name
                            $hasChanged = $hasChanged -or $hasItemChanged
                        }
                    }
                }
            }
        }
    }
    return $Property, $hasChanged
}

function HashHelper {
    <#
    .SYNOPSIS
        Helper of getting file hash(es)
    .DESCRIPTION
        Extract or calculate file hash(es).
        If hash extraction templates are less then URLs, the last template will be reused for the rest URLs.
    .PARAMETER AppName
        Software name
    .PARAMETER Version
        Given software version
    .PARAMETER HashExtraction
        Hash extraction template(s)
    .PARAMETER URL
        New download URL(s), used to calculate hash locally (fallback)
    .PARAMETER Substitutions
        Hashtable of internal substitutable variables
    .OUTPUTS
        System.String
            Hash value (single URL)
        System.String[]
            Hash values (multi URLs)
    #>
    param (
        [String]
        $AppName,
        [String]
        $Version,
        [PSObject[]]
        $HashExtraction,
        [String[]]
        $URL,
        [HashTable]
        $Substitutions
    )
    $hash = @()
    for ($i = 0; $i -lt $URL.Length; $i++) {
        if ($null -eq $HashExtraction) {
            $currentHashExtraction = $null
        } else {
            $currentHashExtraction = $HashExtraction[$i], $HashExtraction[-1] | Select-Object -First 1
        }
        $hash += get_hash_for_app $AppName $currentHashExtraction $Version $URL[$i] $Substitutions
        if ($null -eq $hash[$i]) {
            throw "Could not update $AppName, hash for $(url_remote_filename $URL[$i]) failed!"
        }
    }
    return $hash
}


================================================
FILE: lib/buckets.ps1
================================================
$bucketsdir = "$scoopdir\buckets"

function Find-BucketDirectory {
    <#
    .DESCRIPTION
        Return full path for bucket with given name.
        Main bucket will be returned as default.
    .PARAMETER Name
        Name of bucket.
    .PARAMETER Root
        Root folder of bucket repository will be returned instead of 'bucket' subdirectory (if exists).
    #>
    param(
        [string] $Name = 'main',
        [switch] $Root
    )

    # Handle info passing empty string as bucket ($install.bucket)
    if (($null -eq $Name) -or ($Name -eq '')) {
        $Name = 'main'
    }
    $bucket = "$bucketsdir\$Name"

    if ((Test-Path "$bucket\bucket") -and !$Root) {
        $bucket = "$bucket\bucket"
    }

    return $bucket
}

function bucketdir($name) {
    Show-DeprecatedWarning $MyInvocation 'Find-BucketDirectory'

    return Find-BucketDirectory $name
}

function known_bucket_repos {
    $json = "$PSScriptRoot\..\buckets.json"

    return Get-Content $json -Raw | ConvertFrom-Json -ErrorAction stop
}

function known_bucket_repo($name) {
    $buckets = known_bucket_repos
    $buckets.$name
}

function known_buckets {
    known_bucket_repos | ForEach-Object { $_.PSObject.Properties | Select-Object -Expand 'name' }
}

function apps_in_bucket($dir) {
    return (Get-ChildItem $dir -Filter '*.json' -Recurse).BaseName
}

function Get-LocalBucket {
    <#
    .SYNOPSIS
        List all local buckets.
    #>
    $bucketNames = [System.Collections.Generic.List[String]](Get-ChildItem -Path $bucketsdir -Directory).Name
    if ($null -eq $bucketNames) {
        return @() # Return a zero-length list instead of $null.
    } else {
        $knownBuckets = known_buckets
        for ($i = $knownBuckets.Count - 1; $i -ge 0 ; $i--) {
            $name = $knownBuckets[$i]
            if ($bucketNames.Contains($name)) {
                [void]$bucketNames.Remove($name)
                $bucketNames.Insert(0, $name)
            }
        }
        return $bucketNames
    }
}

function buckets {
    Show-DeprecatedWarning $MyInvocation 'Get-LocalBucket'

    return Get-LocalBucket
}

function Convert-RepositoryUri {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0, ValueFromPipeline = $true)]
        [AllowEmptyString()]
        [String] $Uri
    )

    process {
        # https://git-scm.com/docs/git-clone#_git_urls
        # https://regex101.com/r/xGmwRr/1
        if ($Uri -match '(?:@|/{1,3})(?:www\.|.*@)?(?<provider>[^/]+?)(?::\d+)?[:/](?<user>.+)/(?<repo>.+?)(?:\.git)?/?$') {
            $Matches.provider, $Matches.user, $Matches.repo -join '/'
        } else {
            error "$Uri is not a valid Git URL!"
            error "Please see https://git-scm.com/docs/git-clone#_git_urls for valid ones."
            return $null
        }
    }
}

function list_buckets {
    $buckets = @()
    Get-LocalBucket | ForEach-Object {
        $bucket = [Ordered]@{ Name = $_ }
        $path = Find-BucketDirectory $_ -Root
        if ((Test-Path (Join-Path $path '.git')) -and (Get-Command git -ErrorAction SilentlyContinue)) {
            $bucket.Source = Invoke-Git -Path $path -ArgumentList @('config', 'remote.origin.url')
            $bucket.Updated = Invoke-Git -Path $path -ArgumentList @('log', '--format=%aD', '-n', '1') | Get-Date
        } else {
            $bucket.Source = friendly_path $path
            $bucket.Updated = (Get-Item "$path\bucket" -ErrorAction SilentlyContinue).LastWriteTime
        }
        $bucket.Manifests = Get-ChildItem "$path\bucket" -Force -Recurse -ErrorAction SilentlyContinue |
                Measure-Object | Select-Object -ExpandProperty Count
        $buckets += [PSCustomObject]$bucket
    }
    ,$buckets
}

function add_bucket($name, $repo) {
    if (!(Test-GitAvailable)) {
        error "Git is required for buckets. Run 'scoop install git' and try again."
        return 1
    }

    $dir = Find-BucketDirectory $name -Root
    if (Test-Path $dir) {
        warn "The '$name' bucket already exists. To add this bucket again, first remove it by running 'scoop bucket rm $name'."
        return 2
    }

    $uni_repo = Convert-RepositoryUri -Uri $repo
    if ($null -eq $uni_repo) {
        return 1
    }
    foreach ($bucket in Get-LocalBucket) {
        if (Test-Path -Path "$bucketsdir\$bucket\.git") {
            $remote = Invoke-Git -Path "$bucketsdir\$bucket" -ArgumentList @('config', '--get', 'remote.origin.url')
            if ((Convert-RepositoryUri -Uri $remote) -eq $uni_repo) {
                warn "Bucket $bucket already exists for $repo"
                return 2
            }
        }
    }

    Write-Host 'Checking repo... ' -NoNewline
    $out = Invoke-Git -ArgumentList @('ls-remote', $repo) 2>&1
    if ($LASTEXITCODE -ne 0) {
        error "'$repo' doesn't look like a valid git repository`n`nError given:`n$out"
        return 1
    }
    ensure $bucketsdir | Out-Null
    $dir = ensure $dir
    $out = Invoke-Git -ArgumentList @('clone', $repo, $dir, '-q')
    if ($LASTEXITCODE -ne 0) {
        error "Failed to clone '$repo' to '$dir'.`n`nError given:`n$out`n`nPlease check the repository URL or network connection and try again."
        Remove-Item $dir -Recurse -Force -ErrorAction SilentlyContinue
        return 1
    }
    Write-Host 'OK'
    if (get_config USE_SQLITE_CACHE) {
        info 'Updating cache...'
        Set-ScoopDB -Path (Get-ChildItem (Find-BucketDirectory $name) -Filter '*.json' -Recurse).FullName
    }
    success "The $name bucket was added successfully."
    return 0
}

function rm_bucket($name) {
    $dir = Find-BucketDirectory $name -Root
    if (!(Test-Path $dir)) {
        error "'$name' bucket not found."
        return 1
    }

    Remove-Item $dir -Recurse -Force -ErrorAction Stop
    if (get_config USE_SQLITE_CACHE) {
        info 'Updating cache...'
        Remove-ScoopDBItem -Bucket $name
    }
    success "The $name bucket was removed successfully."
    return 0
}

function new_issue_msg($app, $bucket, $title, $body) {
    $app, $manifest, $bucket, $url = Get-Manifest "$bucket/$app"
    $url = known_bucket_repo $bucket
    $bucket_path = "$bucketsdir\$bucket"

    if (Test-Path $bucket_path) {
        $remote = Invoke-Git -Path $bucket_path -ArgumentList @('config', '--get', 'remote.origin.url')
        # Support ssh and http syntax
        # git@PROVIDER:USER/REPO.git
        # https://PROVIDER/USER/REPO.git
        $remote -match '(@|:\/\/)(?<provider>.+)[:/](?<user>.*)\/(?<repo>.*)(\.git)?$' | Out-Null
        $url = "https://$($Matches.Provider)/$($Matches.User)/$($Matches.Repo)"
    }

    if (!$url) { return 'Please contact the bucket maintainer!' }

    # Print only github repositories
    if ($url -like '*github*') {
        $title = [System.Web.HttpUtility]::UrlEncode("$app@$($manifest.version): $title")
        $body = [System.Web.HttpUtility]::UrlEncode($body)
        $url = $url -replace '\.git$', ''
        $url = "$url/issues/new?title=$title"
        if ($body) {
            $url += "&body=$body"
        }
    }

    $msg = "`nPlease try again or create a new issue by using the following link and paste your console output:"
    return "$msg`n$url"
}


================================================
FILE: lib/commands.ps1
================================================
# Description: Functions for managing commands and aliases.

## Functions for commands

function command_files {
    (Get-ChildItem "$PSScriptRoot\..\libexec") + (Get-ChildItem "$scoopdir\shims") |
    Where-Object 'scoop-.*?\.ps1$' -Property Name -Match
}

function commands {
    command_files | ForEach-Object { command_name $_ }
}

function command_name($filename) {
    $filename.name | Select-String 'scoop-(.*?)\.ps1$' | ForEach-Object { $_.matches[0].groups[1].value }
}

function command_path($cmd) {
    $cmd_path = "$PSScriptRoot\..\libexec\scoop-$cmd.ps1"

    # built in commands
    if (!(Test-Path $cmd_path)) {
        # get path from shim
        $shim_path = "$scoopdir\shims\scoop-$cmd.ps1"
        $line = ((Get-Content $shim_path) | Where-Object { $_.startswith('$path') })
        if ($line) {
            Invoke-Command ([scriptblock]::Create($line)) -NoNewScope
            $cmd_path = $path
        } else { $cmd_path = $shim_path }
    }

    $cmd_path
}

function exec($cmd, $arguments) {
    $cmd_path = command_path $cmd

    & $cmd_path @arguments
}

## Functions for aliases

function add_alias {
    param(
        [ValidateNotNullOrEmpty()]
        [string]$name,
        [ValidateNotNullOrEmpty()]
        [string]$command,
        [string]$description
    )

    $aliases = get_config ALIAS ([PSCustomObject]@{})
    if ($aliases.$name) {
        abort "Alias '$name' already exists."
    }

    $alias_script_name = "scoop-$name"
    $shimdir = shimdir $false
    if (Test-Path "$shimdir\$alias_script_name.ps1") {
        abort "File '$alias_script_name.ps1' already exists in shims directory."
    }
    $script = @(
        "# Summary: $description",
        "$command"
    ) -join "`n"
    try {
        $script | Out-UTF8File "$shimdir\$alias_script_name.ps1"
    } catch {
        abort $_.Exception
    }

    # Add the new alias to the config.
    $aliases | Add-Member -MemberType NoteProperty -Name $name -Value $alias_script_name
    set_config ALIAS $aliases | Out-Null
}

function rm_alias {
    param(
        [ValidateNotNullOrEmpty()]
        [string]$name
    )

    $aliases = get_config ALIAS ([PSCustomObject]@{})
    if (!$aliases.$name) {
        abort "Alias '$name' doesn't exist."
    }

    info "Removing alias '$name'..."
    if (Test-Path "$(shimdir $false)\scoop-$name.ps1") {
        Remove-Item "$(shimdir $false)\scoop-$name.ps1"
    }
    $aliases.PSObject.Properties.Remove($name)
    set_config ALIAS $aliases | Out-Null
}

function list_aliases {
    param(
        [bool]$verbose
    )

    $aliases = get_config ALIAS ([PSCustomObject]@{})
    $alias_info = $aliases.PSObject.Properties.Name | Where-Object { $_ } | ForEach-Object {
        # Mark the alias as <BROKEN>, if the alias script file does NOT exist.
        if (!(Test-Path "$(shimdir $false)\scoop-$_.ps1")) {
            [PSCustomObject]@{
                Name    = $_
                Command = '<BROKEN>'
            }
            return
        }
        $content = Get-Content (command_path $_)
        [PSCustomObject]@{
            Name    = $_
            Command = ($content | Select-Object -Skip 1).Trim()
            Summary = (summary $content).Trim()
        }
    }
    if (!$alias_info) {
        info 'No alias found.'
        return
    }
    $alias_info = $alias_info | Sort-Object Name
    $properties = @('Name', 'Command')
    if ($verbose) {
        $properties += 'Summary'
    }
    $alias_info | Select-Object $properties
}


================================================
FILE: lib/core.ps1
================================================
function Get-PESubsystem($filePath) {
    try {
        $fileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
        $binaryReader = [System.IO.BinaryReader]::new($fileStream)

        $fileStream.Seek(0x3C, [System.IO.SeekOrigin]::Begin) | Out-Null
        $peOffset = $binaryReader.ReadInt32()

        $fileStream.Seek($peOffset, [System.IO.SeekOrigin]::Begin) | Out-Null
        $fileHeaderOffset = $fileStream.Position

        $fileStream.Seek(18, [System.IO.SeekOrigin]::Current) | Out-Null
        $fileStream.Seek($fileHeaderOffset + 0x5C, [System.IO.SeekOrigin]::Begin) | Out-Null

        return $binaryReader.ReadInt16()
    } catch {
        return -1
    } finally {
        $binaryReader.Close()
        $fileStream.Close()
    }
}

function Set-PESubsystem($filePath, $targetSubsystem) {
    try {
        $fileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite)
        $binaryReader = [System.IO.BinaryReader]::new($fileStream)
        $binaryWriter = [System.IO.BinaryWriter]::new($fileStream)

        $fileStream.Seek(0x3C, [System.IO.SeekOrigin]::Begin) | Out-Null
        $peOffset = $binaryReader.ReadInt32()

        $fileStream.Seek($peOffset, [System.IO.SeekOrigin]::Begin) | Out-Null
        $fileHeaderOffset = $fileStream.Position

        $fileStream.Seek(18, [System.IO.SeekOrigin]::Current) | Out-Null
        $fileStream.Seek($fileHeaderOffset + 0x5C, [System.IO.SeekOrigin]::Begin) | Out-Null

        $binaryWriter.Write([System.Int16] $targetSubsystem)
    } catch {
        return $false
    } finally {
        $binaryReader.Close()
        $fileStream.Close()
    }
    return $true
}

function Optimize-SecurityProtocol {
    # .NET Framework 4.7+ has a default security protocol called 'SystemDefault',
    # which allows the operating system to choose the best protocol to use.
    # If SecurityProtocolType contains 'SystemDefault' (means .NET4.7+ detected)
    # and the value of SecurityProtocol is 'SystemDefault', just do nothing on SecurityProtocol,
    # 'SystemDefault' will use TLS 1.2 if the webrequest requires.
    $isNewerNetFramework = ([System.Enum]::GetNames([System.Net.SecurityProtocolType]) -contains 'SystemDefault')
    $isSystemDefault = ([System.Net.ServicePointManager]::SecurityProtocol.Equals([System.Net.SecurityProtocolType]::SystemDefault))

    # If not, change it to support TLS 1.2
    if (!($isNewerNetFramework -and $isSystemDefault)) {
        # Set to TLS 1.2 (3072). Ssl3, TLS 1.0, and 1.1 have been deprecated,
        # https://datatracker.ietf.org/doc/html/rfc8996
        [System.Net.ServicePointManager]::SecurityProtocol = 3072
    }
}

function Show-DeprecatedWarning {
    <#
    .SYNOPSIS
        Print deprecated warning for functions, which will be deleted in near future.
    .PARAMETER Invocation
        Invocation to identify location of line.
        Just pass $MyInvocation.
    .PARAMETER New
        New command name.
    #>
    param($Invocation, [String] $New)

    warn ('"{0}" will be deprecated. Please change your code/manifest to use "{1}"' -f $Invocation.MyCommand.Name, $New)
    Write-Host "      -> $($Invocation.PSCommandPath):$($Invocation.ScriptLineNumber):$($Invocation.OffsetInLine)" -ForegroundColor DarkGray
}

function load_cfg($file) {
    if(!(Test-Path $file)) {
        return $null
    }

    try {
        # ReadAllLines will detect the encoding of the file automatically
        # Ref: https://docs.microsoft.com/en-us/dotnet/api/system.io.file.readalllines?view=netframework-4.5
        $content = [System.IO.File]::ReadAllLines($file)
        return ($content | ConvertFrom-Json -ErrorAction Stop)
    } catch {
        Write-Host "ERROR loading $file`: $($_.exception.message)"
    }
}

function get_config($name, $default) {
    $name = $name.ToLowerInvariant()
    if($null -eq $scoopConfig.$name -and $null -ne $default) {
        return $default
    }
    return $scoopConfig.$name
}

function set_config {
    Param (
        [ValidateNotNullOrEmpty()]
        $name,
        $value
    )

    $name = $name.ToLowerInvariant()

    if ($null -eq $scoopConfig -or $scoopConfig.Count -eq 0) {
        ensure (Split-Path -Path $configFile) | Out-Null
        $scoopConfig = New-Object -TypeName PSObject
    }

    if ($value -eq [bool]::TrueString -or $value -eq [bool]::FalseString) {
        $value = [System.Convert]::ToBoolean($value)
    }

    # Initialize config's change
    Complete-ConfigChange -Name $name -Value $value

    if ($null -eq $scoopConfig.$name) {
        $scoopConfig | Add-Member -MemberType NoteProperty -Name $name -Value $value
    } else {
        $scoopConfig.$name = $value
    }

    if ($null -eq $value) {
        $scoopConfig.PSObject.Properties.Remove($name)
    }

    # Save config with UTF8NoBOM encoding
    ConvertTo-Json $scoopConfig | Out-UTF8File -FilePath $configFile
    return $scoopConfig
}

function Complete-ConfigChange {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string]
        $Name,
        [Parameter(Mandatory, Position = 1)]
        [AllowEmptyString()]
        [string]
        $Value
    )

    if ($Name -eq 'use_isolated_path') {
        $oldValue = get_config USE_ISOLATED_PATH
        if ($Value -eq $oldValue) {
            return
        } else {
            $currPathEnvVar = $scoopPathEnvVar
        }
        . "$PSScriptRoot\..\lib\system.ps1"

        if ($Value -eq $false -or $Value -eq '') {
            info 'Turn off Scoop isolated path... This may take a while, please wait.'
            $movedPath = Get-EnvVar -Name $currPathEnvVar
            if ($movedPath) {
                Add-Path -Path $movedPath -Quiet
                Remove-Path -Path ('%' + $currPathEnvVar + '%') -Quiet
                Set-EnvVar -Name $currPathEnvVar -Quiet
            }
            if (is_admin) {
                $movedPath = Get-EnvVar -Name $currPathEnvVar -Global
                if ($movedPath) {
                    Add-Path -Path $movedPath -Global -Quiet
                    Remove-Path -Path ('%' + $currPathEnvVar + '%') -Global -Quiet
                    Set-EnvVar -Name $currPathEnvVar -Global -Quiet
                }
            }
        } else {
            $newPathEnvVar = if ($Value -eq $true) {
                'SCOOP_PATH'
            } else {
                $Value.ToUpperInvariant()
            }
            info "Turn on Scoop isolated path ('$newPathEnvVar')... This may take a while, please wait."
            $movedPath = Remove-Path -Path "$scoopdir\apps\*" -TargetEnvVar $currPathEnvVar -Quiet -PassThru
            if ($movedPath) {
                Add-Path -Path $movedPath -TargetEnvVar $newPathEnvVar -Quiet
                Add-Path -Path ('%' + $newPathEnvVar + '%') -Quiet
                if ($currPathEnvVar -ne 'PATH') {
                    Remove-Path -Path ('%' + $currPathEnvVar + '%') -Quiet
                    Set-EnvVar -Name $currPathEnvVar -Quiet
                }
            }
            if (is_admin) {
                $movedPath = Remove-Path -Path "$globaldir\apps\*" -TargetEnvVar $currPathEnvVar -Global -Quiet -PassThru
                if ($movedPath) {
                    Add-Path -Path $movedPath -TargetEnvVar $newPathEnvVar -Global -Quiet
                    Add-Path -Path ('%' + $newPathEnvVar + '%') -Global -Quiet
                    if ($currPathEnvVar -ne 'PATH') {
                        Remove-Path -Path ('%' + $currPathEnvVar + '%') -Global -Quiet
                        Set-EnvVar -Name $currPathEnvVar -Global -Quiet
                    }
                }
            }
        }
    }

    if ($Name -eq 'use_sqlite_cache' -and $Value -eq $true) {
        if ((Get-DefaultArchitecture) -eq 'arm64') {
            abort 'SQLite cache is not supported on ARM64 platform.'
        }
        . "$PSScriptRoot\..\lib\database.ps1"
        . "$PSScriptRoot\..\lib\manifest.ps1"
        info 'Initializing SQLite cache in progress... This may take a while, please wait.'
        Set-ScoopDB
    }
}

function Invoke-Git {
    [CmdletBinding()]
    [OutputType([String])]
    param(
        [Parameter(Mandatory = $false, Position = 0)]
        [Alias('PSPath', 'Path')]
        [ValidateNotNullOrEmpty()]
        [String]
        $WorkingDirectory,
        [Parameter(Mandatory = $true, Position = 1)]
        [Alias('Args')]
        [String[]]
        $ArgumentList
    )

    $proxy = get_config PROXY
    $git = Get-HelperPath -Helper Git

    if ($WorkingDirectory) {
        $ArgumentList = @('-C', $WorkingDirectory) + $ArgumentList
    }

    if([String]::IsNullOrEmpty($proxy) -or $proxy -eq 'none')  {
        return & $git @ArgumentList
    }

    if($ArgumentList -Match '\b(clone|checkout|pull|fetch|ls-remote)\b') {
        $j = Start-Job -ScriptBlock {
            # convert proxy setting for git
            $proxy = $using:proxy
            if ($proxy -and $proxy.StartsWith('currentuser@')) {
                $proxy = $proxy.Replace('currentuser@', ':@')
            }
            $env:HTTPS_PROXY = $proxy
            $env:HTTP_PROXY = $proxy
            & $using:git @using:ArgumentList
        }
        $o = $j | Receive-Job -Wait -AutoRemoveJob
        return $o
    }

    return & $git @ArgumentList
}

function Invoke-GitLog {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory, ValueFromPipeline)]
        [String]$Path,
        [Parameter(Mandatory, ValueFromPipeline)]
        [String]$CommitHash,
        [String]$Name = ''
    )
    Process {
        if ($Name) {
            if ($Name.Length -gt 12) {
                $Name = "$($Name.Substring(0, 10)).."
            }
            $Name = "%Cgreen$($Name.PadRight(12, ' ').Substring(0, 12))%Creset "
        }
        Invoke-Git -Path $Path -ArgumentList @('--no-pager', 'log', '--color', '--no-decorate', "--grep='^(chore)'", '--invert-grep', '--abbrev=12', "--format=tformat: * %C(yellow)%h%Creset %<|(72,trunc)%s $Name%C(cyan)%cr%Creset", "$CommitHash..HEAD")
    }
}

# helper functions
function coalesce($a, $b) { if($a) { return $a } $b }

function is_admin {
    $admin = [security.principal.windowsbuiltinrole]::administrator
    $id = [security.principal.windowsidentity]::getcurrent()
    ([security.principal.windowsprincipal]($id)).isinrole($admin)
}

# messages
function abort($msg, [int] $exit_code=1) { write-host $msg -f red; exit $exit_code }
function error($msg) { write-host "ERROR $msg" -f darkred }
function warn($msg) {  write-host "WARN  $msg" -f darkyellow }
function info($msg) {  write-host "INFO  $msg" -f darkgray }
function debug($obj) {
    if ((get_config DEBUG $false) -ine 'true' -and $env:SCOOP_DEBUG -ine 'true') {
        return
    }

    $prefix = "DEBUG[$(Get-Date -UFormat %s)]"
    $param = $MyInvocation.Line.Replace($MyInvocation.InvocationName, '').Trim()
    $msg = $obj | Out-String -Stream

    if($null -eq $obj -or $null -eq $msg) {
        Write-Host "$prefix $param = " -f DarkCyan -NoNewline
        Write-Host '$null' -f DarkYellow -NoNewline
        Write-Host " -> $($MyInvocation.PSCommandPath):$($MyInvocation.ScriptLineNumber):$($MyInvocation.OffsetInLine)" -f DarkGray
        return
    }

    if($msg.GetType() -eq [System.Object[]]) {
        Write-Host "$prefix $param ($($obj.GetType()))" -f DarkCyan -NoNewline
        Write-Host " -> $($MyInvocation.PSCommandPath):$($MyInvocation.ScriptLineNumber):$($MyInvocation.OffsetInLine)" -f DarkGray
        $msg | Where-Object { ![String]::IsNullOrWhiteSpace($_) } |
            Select-Object -Skip 2 | # Skip headers
            ForEach-Object {
                Write-Host "$prefix $param.$($_)" -f DarkCyan
            }
    } else {
        Write-Host "$prefix $param = $($msg.Trim())" -f DarkCyan -NoNewline
        Write-Host " -> $($MyInvocation.PSCommandPath):$($MyInvocation.ScriptLineNumber):$($MyInvocation.OffsetInLine)" -f DarkGray
    }
}
function success($msg) { write-host $msg -f darkgreen }

function filesize($length) {
    $gb = [math]::pow(2, 30)
    $mb = [math]::pow(2, 20)
    $kb = [math]::pow(2, 10)

    if($length -gt $gb) {
        "{0:n1} GB" -f ($length / $gb)
    } elseif($length -gt $mb) {
        "{0:n1} MB" -f ($length / $mb)
    } elseif($length -gt $kb) {
        "{0:n1} KB" -f ($length / $kb)
    } else {
        if ($null -eq $length) {
            $length = 0
        }
        "$($length) B"
    }
}

# dirs
function basedir($global) { if($global) { return $globaldir } $scoopdir }
function appsdir($global) { "$(basedir $global)\apps" }
function shimdir($global) { "$(basedir $global)\shims" }
function modulesdir($global) { "$(basedir $global)\modules" }
function appdir($app, $global) { "$(appsdir $global)\$app" }
function versiondir($app, $version, $global) { "$(appdir $app $global)\$version" }

function currentdir($app, $global) {
    if (get_config NO_JUNCTION) {
        $version = Select-CurrentVersion -App $app -Global:$global
    } else {
        $version = 'current'
    }
    "$(appdir $app $global)\$version"
}

function persistdir($app, $global) { "$(basedir $global)\persist\$app" }
function usermanifestsdir { "$(basedir)\workspace" }
function usermanifest($app) { "$(usermanifestsdir)\$app.json" }
function cache_path($app, $version, $url) {
    $underscoredUrl = $url -replace '[^\w\.\-]+', '_'
    $filePath = Join-Path $cachedir "$app#$version#$underscoredUrl"

    # NOTE: Scoop cache files migration. Remove this 6 months after the feature ships.
    if (Test-Path $filePath) {
        return $filePath
    }

    $urlStream = [System.IO.MemoryStream]::new([System.Text.Encoding]::UTF8.GetBytes($url))
    $sha = (Get-FileHash -Algorithm SHA256 -InputStream $urlStream).Hash.ToLower().Substring(0, 7)
    $extension = [System.IO.Path]::GetExtension($url)
    $filePath = $filePath -replace "$underscoredUrl", "$sha$extension"

    return $filePath
}

# apps
function sanitary_path($path) { return [regex]::replace($path, "[/\\?:*<>|]", "") }
function installed($app, [Nullable[bool]]$global) {
    if ($null -eq $global) {
        return (installed $app $false) -or (installed $app $true)
    }
    # Dependencies of the format "bucket/dependency" install in a directory of form
    # "dependency". So we need to extract the bucket from the name and only give the app
    # name to is_directory
    $app = ($app -split '/|\\')[-1]
    return $null -ne (Select-CurrentVersion -AppName $app -Global:$global)
}
function installed_apps($global) {
    $di
Download .txt
gitextract_ros1r64f/

├── .editorconfig
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug_report.md
│   │   ├── Feature_request.md
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CHANGELOG.md
├── LICENSE
├── PSScriptAnalyzerSettings.psd1
├── README.md
├── appveyor.yml
├── bin/
│   ├── auto-pr.ps1
│   ├── checkhashes.ps1
│   ├── checkurls.ps1
│   ├── checkver.ps1
│   ├── describe.ps1
│   ├── formatjson.ps1
│   ├── install.ps1
│   ├── missing-checkver.ps1
│   ├── refresh.ps1
│   ├── scoop.ps1
│   ├── test.ps1
│   └── uninstall.ps1
├── buckets.json
├── lib/
│   ├── autoupdate.ps1
│   ├── buckets.ps1
│   ├── commands.ps1
│   ├── core.ps1
│   ├── database.ps1
│   ├── decompress.ps1
│   ├── depends.ps1
│   ├── description.ps1
│   ├── diagnostic.ps1
│   ├── download.ps1
│   ├── getopt.ps1
│   ├── help.ps1
│   ├── install.ps1
│   ├── json.ps1
│   ├── manifest.ps1
│   ├── psmodules.ps1
│   ├── shortcuts.ps1
│   ├── system.ps1
│   └── versions.ps1
├── libexec/
│   ├── scoop-alias.ps1
│   ├── scoop-bucket.ps1
│   ├── scoop-cache.ps1
│   ├── scoop-cat.ps1
│   ├── scoop-checkup.ps1
│   ├── scoop-cleanup.ps1
│   ├── scoop-config.ps1
│   ├── scoop-create.ps1
│   ├── scoop-depends.ps1
│   ├── scoop-download.ps1
│   ├── scoop-export.ps1
│   ├── scoop-help.ps1
│   ├── scoop-hold.ps1
│   ├── scoop-home.ps1
│   ├── scoop-import.ps1
│   ├── scoop-info.ps1
│   ├── scoop-install.ps1
│   ├── scoop-list.ps1
│   ├── scoop-prefix.ps1
│   ├── scoop-reset.ps1
│   ├── scoop-search.ps1
│   ├── scoop-shim.ps1
│   ├── scoop-status.ps1
│   ├── scoop-unhold.ps1
│   ├── scoop-uninstall.ps1
│   ├── scoop-update.ps1
│   ├── scoop-virustotal.ps1
│   └── scoop-which.ps1
├── schema.json
├── supporting/
│   ├── formats/
│   │   └── ScoopTypes.Format.ps1xml
│   ├── shims/
│   │   ├── 71/
│   │   │   ├── checksum.sha256
│   │   │   └── checksum.sha512
│   │   ├── kiennq/
│   │   │   ├── checksum.sha256
│   │   │   ├── checksum.sha512
│   │   │   └── version.txt
│   │   └── scoopcs/
│   │       ├── checksum.sha256
│   │       ├── checksum.sha512
│   │       └── version.txt
│   └── validator/
│       ├── .gitignore
│       ├── Scoop.Validator.cs
│       ├── bin/
│       │   ├── checksum.sha256
│       │   └── checksum.sha512
│       ├── build.ps1
│       ├── install.ps1
│       ├── packages.config
│       ├── update.ps1
│       ├── validator.cs
│       └── validator.csproj
└── test/
    ├── Import-Bucket-Tests.ps1
    ├── Scoop-00File.Tests.ps1
    ├── Scoop-00Linting.Tests.ps1
    ├── Scoop-Commands.Tests.ps1
    ├── Scoop-Config.Tests.ps1
    ├── Scoop-Core.Tests.ps1
    ├── Scoop-Decompress.Tests.ps1
    ├── Scoop-Depends.Tests.ps1
    ├── Scoop-Download.Tests.ps1
    ├── Scoop-GetOpts.Tests.ps1
    ├── Scoop-Install.Tests.ps1
    ├── Scoop-Manifest.Tests.ps1
    ├── Scoop-TestLib.ps1
    ├── Scoop-Versions.Tests.ps1
    ├── bin/
    │   ├── init.ps1
    │   └── test.ps1
    └── fixtures/
        ├── format/
        │   ├── formatted/
        │   │   ├── 1-easy.json
        │   │   ├── 2-whitespaces-mess.json
        │   │   ├── 3-array-with-single-and-multi.json
        │   │   └── 4-script-block.json
        │   └── unformatted/
        │       ├── 1-easy.json
        │       ├── 2-whitespaces-mess.json
        │       ├── 3-array-with-single-and-multi.json
        │       └── 4-script-block.json
        ├── is_directory/
        │   ├── i_am_a_directory/
        │   │   └── .gitkeep
        │   └── i_am_a_file.txt
        ├── manifest/
        │   ├── broken_schema.json
        │   ├── broken_wget.json
        │   ├── invalid_wget.json
        │   └── wget.json
        ├── movedir/
        │   ├── user/
        │   │   └── _tmp/
        │   │       ├── subdir/
        │   │       │   └── test.txt
        │   │       └── test.txt
        │   ├── user with 'quote/
        │   │   └── _tmp/
        │   │       ├── subdir/
        │   │       │   └── test.txt
        │   │       └── test.txt
        │   └── user with space/
        │       └── _tmp/
        │           ├── subdir/
        │           │   └── test.txt
        │           └── test.txt
        └── shim/
            ├── shim-test.ps1
            └── user with 'quote/
                └── shim-test.ps1
Download .txt
SYMBOL INDEX (13 symbols across 2 files)

FILE: supporting/validator/Scoop.Validator.cs
  class JsonParserException (line 11) | public class JsonParserException : Exception
    method JsonParserException (line 14) | public JsonParserException(string file, string message) : base(message...
    method JsonParserException (line 15) | public JsonParserException(string file, string message, Exception inne...
  class Validator (line 18) | public class Validator
    method ParseSchema (line 34) | private JSchema ParseSchema(string file)
    method ParseManifest (line 50) | private JObject ParseManifest(string file)
    method Validator (line 66) | public Validator(string schemaFile)
    method Validator (line 72) | public Validator(string schemaFile, bool ci)
    method Validate (line 79) | public bool Validate(string file)
    method Validate (line 85) | public bool Validate()
    method traverseErrors (line 131) | public void traverseErrors(IList<ValidationError> errors, int level = ...

FILE: supporting/validator/validator.cs
  class Program (line 9) | public class Program
    method Main (line 11) | public static int Main(string[] args)
Condensed preview — 134 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (642K chars).
[
  {
    "path": ".editorconfig",
    "chars": 536,
    "preview": "# EditorConfig (is awesome): http://EditorConfig.org\r\n\r\n# * top-most EditorConfig file\r\nroot = true\r\n\r\n# default style s"
  },
  {
    "path": ".gitattributes",
    "chars": 123,
    "preview": "# retain windows line-endings in case checked out on mac or linux\r\n* text eol=crlf\r\n*.exe -text\r\n*.zip -text\r\n*.dll -tex"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Bug_report.md",
    "chars": 1312,
    "preview": "---\r\nname: \"Bug Report\"\r\nabout: \"I am facing some problems.\"\r\ntitle: '[Bug] '\r\nlabels: \"bug\"\r\n\r\n---\r\n\r\n<!--\r\n  IMPORTANT"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Feature_request.md",
    "chars": 1023,
    "preview": "---\r\nname: \"Feature Request\"\r\nabout: \"I have a suggestion (and may want to implement it)!\"\r\ntitle: '[Feature] '\r\nlabels:"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 31,
    "preview": "blank_issues_enabled: false\r\n\r\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 1735,
    "preview": "<!-- Provide a general summary of your changes in the Title above -->\r\n<!-- To help with semantic versioning the PR titl"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 181,
    "preview": "---\r\n# ~/.github/dependabot.yml\r\nversion: 2\r\nupdates:\r\n  - package-ecosystem: \"github-actions\"\r\n    directory: \"/\" # == "
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 957,
    "preview": "name: Scoop Core CI Tests\r\n\r\non:\r\n  pull_request:\r\n  workflow_dispatch:\r\n\r\njobs:\r\n  test_powershell:\r\n    name: WindowsP"
  },
  {
    "path": ".gitignore",
    "chars": 132,
    "preview": "*.log\r\n.DS_Store\r\n._.DS_Store\r\nscoop.sublime-workspace\r\ntest/installer/tmp/*\r\ntest/tmp/*\r\n*~\r\nTestResults.xml\r\nsupportin"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 109,
    "preview": "{\r\n    \"recommendations\": [\r\n        \"EditorConfig.EditorConfig\",\r\n        \"ms-vscode.PowerShell\"\r\n    ]\r\n}\r\n"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 670,
    "preview": "// Configure PSScriptAnalyzer settings\r\n{\r\n    \"powershell.scriptAnalysis.settingsPath\": \"PSScriptAnalyzerSettings.psd1\""
  },
  {
    "path": "CHANGELOG.md",
    "chars": 82004,
    "preview": "## [v0.5.3](https://github.com/ScoopInstaller/Scoop/compare/v0.5.2...v0.5.3) - 2025-08-11\r\n\r\n### Features\r\n\r\n**autoupdat"
  },
  {
    "path": "LICENSE",
    "chars": 3559,
    "preview": "SPDX-License-Identifier: UNLICENSE or MIT\r\n\r\nINFORMATION ABOUT THIS PROJECT'S LICENSE (SHORT)\r\n========================="
  },
  {
    "path": "PSScriptAnalyzerSettings.psd1",
    "chars": 1281,
    "preview": "@{\r\n    # Only diagnostic records of the specified severity will be generated.\r\n    # Uncomment the following line if yo"
  },
  {
    "path": "README.md",
    "chars": 7904,
    "preview": "<h1 align=\"center\">Scoop</h1>\r\n\r\n<!--<img src=\"scoop.png\" alt=\"Long live Scoop!\"/>-->\r\n<p align=\"center\">\r\n        <a hr"
  },
  {
    "path": "appveyor.yml",
    "chars": 871,
    "preview": "version: \"{build}-{branch}\"\r\nbranches:\r\n  except:\r\n    - gh-pages\r\nbuild: false\r\ndeploy: false\r\nclone_depth: 2\r\nimage: V"
  },
  {
    "path": "bin/auto-pr.ps1",
    "chars": 7356,
    "preview": "<#\r\n.SYNOPSIS\r\n    Updates manifests and pushes them or creates pull-requests.\r\n.DESCRIPTION\r\n    Updates manifests and "
  },
  {
    "path": "bin/checkhashes.ps1",
    "chars": 6988,
    "preview": "<#\r\n.SYNOPSIS\r\n    Check if ALL urls inside manifest have correct hashes.\r\n.PARAMETER App\r\n    Manifest to be checked.\r\n"
  },
  {
    "path": "bin/checkurls.ps1",
    "chars": 4033,
    "preview": "<#\r\n.SYNOPSIS\r\n    List manifests which do not have valid URLs.\r\n.PARAMETER App\r\n    Manifest name to search.\r\n    Place"
  },
  {
    "path": "bin/checkver.ps1",
    "chars": 13864,
    "preview": "<#\r\n.SYNOPSIS\r\n    Check manifest for a newer version.\r\n.DESCRIPTION\r\n    Checks websites for newer versions using an (o"
  },
  {
    "path": "bin/describe.ps1",
    "chars": 1795,
    "preview": "<#\r\n.SYNOPSIS\r\n    Search for application description on homepage.\r\n.PARAMETER App\r\n    Manifest name to search.\r\n    Pl"
  },
  {
    "path": "bin/formatjson.ps1",
    "chars": 1070,
    "preview": "<#\r\n.SYNOPSIS\r\n    Format manifest.\r\n.PARAMETER App\r\n    Manifest to format.\r\n\r\n    Wildcards are supported.\r\n.PARAMETER"
  },
  {
    "path": "bin/install.ps1",
    "chars": 82,
    "preview": "#Requires -Version 5\r\nInvoke-RestMethod https://get.scoop.sh | Invoke-Expression\r\n"
  },
  {
    "path": "bin/missing-checkver.ps1",
    "chars": 1447,
    "preview": "<#\r\n.SYNOPSIS\r\n    Check if manifest contains checkver and autoupdate property.\r\n.PARAMETER App\r\n    Manifest name.\r\n   "
  },
  {
    "path": "bin/refresh.ps1",
    "chars": 602,
    "preview": "# for development, update the installed scripts to match local source\r\n. \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n\r\n$src = \"$PSS"
  },
  {
    "path": "bin/scoop.ps1",
    "chars": 2155,
    "preview": "#Requires -Version 5\r\nSet-StrictMode -Off\r\n\r\n. \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n. \"$PSScriptRoot\\..\\lib\\buckets.ps1\"\r\n. "
  },
  {
    "path": "bin/test.ps1",
    "chars": 40,
    "preview": ". \"$PSScriptRoot\\..\\test\\bin\\test.ps1\"\r\n"
  },
  {
    "path": "bin/uninstall.ps1",
    "chars": 3170,
    "preview": "<#\r\n.SYNOPSIS\r\n    Uninstall ALL scoop applications and scoop itself.\r\n.PARAMETER global\r\n    Global applications will b"
  },
  {
    "path": "buckets.json",
    "chars": 620,
    "preview": "{\r\n    \"main\": \"https://github.com/ScoopInstaller/Main\",\r\n    \"extras\": \"https://github.com/ScoopInstaller/Extras\",\r\n   "
  },
  {
    "path": "lib/autoupdate.ps1",
    "chars": 24262,
    "preview": "# Must included with 'json.ps1'\r\n\r\nfunction format_hash([String] $hash) {\r\n    $hash = $hash.toLower()\r\n\r\n    if ($hash "
  },
  {
    "path": "lib/buckets.ps1",
    "chars": 7390,
    "preview": "$bucketsdir = \"$scoopdir\\buckets\"\r\n\r\nfunction Find-BucketDirectory {\r\n    <#\r\n    .DESCRIPTION\r\n        Return full path"
  },
  {
    "path": "lib/commands.ps1",
    "chars": 3614,
    "preview": "# Description: Functions for managing commands and aliases.\r\n\r\n## Functions for commands\r\n\r\nfunction command_files {\r\n  "
  },
  {
    "path": "lib/core.ps1",
    "chars": 48435,
    "preview": "function Get-PESubsystem($filePath) {\r\n    try {\r\n        $fileStream = [System.IO.FileStream]::new($filePath, [System.I"
  },
  {
    "path": "lib/database.ps1",
    "chars": 12908,
    "preview": "# Description: Functions for interacting with the Scoop database cache\r\n\r\n<#\r\n.SYNOPSIS\r\n    Get SQLite .NET driver\r\n.DE"
  },
  {
    "path": "lib/decompress.ps1",
    "chars": 12972,
    "preview": "# Description: Functions for decompressing archives or installers\r\n\r\nfunction Invoke-Extraction {\r\n    param (\r\n        "
  },
  {
    "path": "lib/depends.ps1",
    "chars": 5233,
    "preview": "function Get-Dependency {\r\n    <#\r\n    .SYNOPSIS\r\n        Get app's dependencies (with apps attached at the end).\r\n    ."
  },
  {
    "path": "lib/description.ps1",
    "chars": 4425,
    "preview": "function find_description($url, $html, $redir = $false) {\r\n    $meta = meta_tags $html\r\n\r\n    # check <meta property=\"og"
  },
  {
    "path": "lib/diagnostic.ps1",
    "chars": 3058,
    "preview": "<#\r\nDiagnostic tests.\r\nReturn $true if the test passed, otherwise $false.\r\nUse 'warn' to highlight the issue, and follow"
  },
  {
    "path": "lib/download.ps1",
    "chars": 28517,
    "preview": "# Description: Functions for downloading files\r\n\r\n## Meta downloader\r\n\r\nfunction Invoke-ScoopDownload ($app, $version, $"
  },
  {
    "path": "lib/getopt.ps1",
    "chars": 2950,
    "preview": "# adapted from http://hg.python.org/cpython/file/2.7/Lib/getopt.py\r\n# argv:\r\n#    array of arguments\r\n# shortopts:\r\n#   "
  },
  {
    "path": "lib/help.ps1",
    "chars": 601,
    "preview": "function usage($text) {\r\n    $text | Select-String '(?m)^# Usage: ([^\\n]*)$' | ForEach-Object { \"Usage: \" + $_.matches[0"
  },
  {
    "path": "lib/install.ps1",
    "chars": 21014,
    "preview": "function nightly_version($quiet = $false) {\r\n    if (!$quiet) {\r\n        warn \"This is a nightly version. Downloaded fil"
  },
  {
    "path": "lib/json.ps1",
    "chars": 7168,
    "preview": "# Convert objects to pretty json\r\n# Only needed until PowerShell ConvertTo-Json will be improved https://github.com/Powe"
  },
  {
    "path": "lib/manifest.ps1",
    "chars": 8195,
    "preview": "function manifest_path($app, $bucket) {\r\n    (Get-ChildItem (Find-BucketDirectory $bucket) -Filter \"$(sanitary_path $app"
  },
  {
    "path": "lib/psmodules.ps1",
    "chars": 1852,
    "preview": "function install_psmodule($manifest, $dir, $global) {\r\n    $psmodule = $manifest.psmodule\r\n    if (!$psmodule) { return "
  },
  {
    "path": "lib/shortcuts.ps1",
    "chars": 2990,
    "preview": "# Creates shortcut for the app in the start menu\r\nfunction create_startmenu_shortcuts($manifest, $dir, $global, $arch) {"
  },
  {
    "path": "lib/system.ps1",
    "chars": 5378,
    "preview": "# System-related functions\r\n\r\n## Environment Variables\r\n\r\nfunction Publish-EnvVar {\r\n    if (-not ('Win32.NativeMethods'"
  },
  {
    "path": "lib/versions.ps1",
    "chars": 10880,
    "preview": "function Get-LatestVersion {\r\n    <#\r\n    .SYNOPSIS\r\n        Get latest version of app from manifest\r\n    .PARAMETER App"
  },
  {
    "path": "libexec/scoop-alias.ps1",
    "chars": 1707,
    "preview": "# Usage: scoop alias <subcommand> [options] [<args>]\r\n# Summary: Manage scoop aliases\r\n# Help: Available subcommands: ad"
  },
  {
    "path": "libexec/scoop-bucket.ps1",
    "chars": 2033,
    "preview": "# Usage: scoop bucket add|list|known|rm [<args>]\r\n# Summary: Manage Scoop buckets\r\n# Help: Add, list or remove buckets.\r"
  },
  {
    "path": "libexec/scoop-cache.ps1",
    "chars": 2304,
    "preview": "# Usage: scoop cache show|rm [app(s)]\r\n# Summary: Show or clear the download cache\r\n# Help: Scoop caches downloads so yo"
  },
  {
    "path": "libexec/scoop-cat.ps1",
    "chars": 994,
    "preview": "# Usage: scoop cat <app>\r\n# Summary: Show content of specified manifest.\r\n# Help: Show content of specified manifest.\r\n#"
  },
  {
    "path": "libexec/scoop-checkup.ps1",
    "chars": 2304,
    "preview": "# Usage: scoop checkup\r\n# Summary: Check for potential problems\r\n# Help: Performs a series of diagnostic tests to try to"
  },
  {
    "path": "libexec/scoop-cleanup.ps1",
    "chars": 3129,
    "preview": "# Usage: scoop cleanup <app> [options]\r\n# Summary: Cleanup apps by removing old versions\r\n# Help: 'scoop cleanup' cleans"
  },
  {
    "path": "libexec/scoop-config.ps1",
    "chars": 7287,
    "preview": "# Usage: scoop config [rm] name [value]\r\n# Summary: Get or set configuration values\r\n# Help: The scoop configuration fil"
  },
  {
    "path": "libexec/scoop-create.ps1",
    "chars": 1564,
    "preview": "# Usage: scoop create <url>\r\n# Summary: Create a custom app manifest\r\n# Help: Create your own custom app manifest\r\nparam"
  },
  {
    "path": "libexec/scoop-depends.ps1",
    "chars": 1015,
    "preview": "# Usage: scoop depends <app>\r\n# Summary: List dependencies for an app, in the order they'll be installed\r\n\r\n. \"$PSScript"
  },
  {
    "path": "libexec/scoop-download.ps1",
    "chars": 5346,
    "preview": "# Usage: scoop download <app> [options]\r\n# Summary: Download apps in the cache folder and verify hashes\r\n# Help: e.g. Th"
  },
  {
    "path": "libexec/scoop-export.ps1",
    "chars": 713,
    "preview": "# Usage: scoop export > scoopfile.json\r\n# Summary: Exports installed apps, buckets (and optionally configs) in JSON form"
  },
  {
    "path": "libexec/scoop-help.ps1",
    "chars": 971,
    "preview": "# Usage: scoop help <command>\r\n# Summary: Show help for a command\r\nparam($cmd)\r\n\r\nfunction print_help($cmd) {\r\n    $file"
  },
  {
    "path": "libexec/scoop-hold.ps1",
    "chars": 2050,
    "preview": "# Usage: scoop hold <apps>\r\n# Summary: Hold an app to disable updates\r\n# Help: To hold a user-scoped app:\r\n#      scoop "
  },
  {
    "path": "libexec/scoop-home.ps1",
    "chars": 652,
    "preview": "# Usage: scoop home <app>\r\n# Summary: Opens the app homepage\r\nparam($app)\r\n\r\n. \"$PSScriptRoot\\..\\lib\\versions.ps1\" # 'Se"
  },
  {
    "path": "libexec/scoop-import.ps1",
    "chars": 1908,
    "preview": "# Usage: scoop import <path/url to scoopfile.json>\r\n# Summary: Imports apps, buckets and configs from a Scoopfile in JSO"
  },
  {
    "path": "libexec/scoop-info.ps1",
    "chars": 9726,
    "preview": "# Usage: scoop info <app> [options]\r\n# Summary: Display information about an app\r\n# Help: Options:\r\n#   -v, --verbose   "
  },
  {
    "path": "libexec/scoop-install.ps1",
    "chars": 5327,
    "preview": "# Usage: scoop install <app> [options]\r\n# Summary: Install apps\r\n# Help: e.g. The usual way to install an app (uses your"
  },
  {
    "path": "libexec/scoop-list.ps1",
    "chars": 2309,
    "preview": "# Usage: scoop list [query]\r\n# Summary: List installed apps\r\n# Help: Lists all installed apps, or the apps matching the "
  },
  {
    "path": "libexec/scoop-prefix.ps1",
    "chars": 447,
    "preview": "# Usage: scoop prefix <app>\r\n# Summary: Returns the path to the specified app\r\nparam($app)\r\n\r\n. \"$PSScriptRoot\\..\\lib\\ve"
  },
  {
    "path": "libexec/scoop-reset.ps1",
    "chars": 3076,
    "preview": "# Usage: scoop reset <app>\r\n# Summary: Reset an app to resolve conflicts\r\n# Help: Used to resolve conflicts in favor of "
  },
  {
    "path": "libexec/scoop-search.ps1",
    "chars": 7326,
    "preview": "# Usage: scoop search <query>\r\n# Summary: Search available apps\r\n# Help: Searches for apps that are available to install"
  },
  {
    "path": "libexec/scoop-shim.ps1",
    "chars": 10137,
    "preview": "# Usage: scoop shim <subcommand> [<shim_name>...] [options] [other_args]\r\n# Summary: Manipulate Scoop shims\r\n# Help: Ava"
  },
  {
    "path": "libexec/scoop-status.ps1",
    "chars": 3316,
    "preview": "# Usage: scoop status\r\n# Summary: Show status and check for new app versions\r\n# Help: Options:\r\n#   -l, --local         "
  },
  {
    "path": "libexec/scoop-unhold.ps1",
    "chars": 1946,
    "preview": "# Usage: scoop unhold <app>\r\n# Summary: Unhold an app to enable updates\r\n# Help: To unhold a user-scoped app:\r\n#      sc"
  },
  {
    "path": "libexec/scoop-uninstall.ps1",
    "chars": 4929,
    "preview": "# Usage: scoop uninstall <app> [options]\r\n# Summary: Uninstall an app\r\n# Help: e.g. scoop uninstall git\r\n#\r\n# Options:\r\n"
  },
  {
    "path": "libexec/scoop-update.ps1",
    "chars": 19159,
    "preview": "# Usage: scoop update <app> [options]\r\n# Summary: Update apps, or Scoop itself\r\n# Help: 'scoop update' updates Scoop to "
  },
  {
    "path": "libexec/scoop-virustotal.ps1",
    "chars": 15863,
    "preview": "# Usage: scoop virustotal [* | app1 app2 ...] [options]\r\n# Summary: Look for app's hash or url on virustotal.com\r\n# Help"
  },
  {
    "path": "libexec/scoop-which.ps1",
    "chars": 496,
    "preview": "# Usage: scoop which <command>\r\n# Summary: Locate a shim/executable (similar to 'which' on Linux)\r\n# Help: Locate the pa"
  },
  {
    "path": "schema.json",
    "chars": 22868,
    "preview": "{\r\n    \"$id\": \"http://scoop.sh/draft/schema#\",\r\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\r\n    \"addition"
  },
  {
    "path": "supporting/formats/ScoopTypes.Format.ps1xml",
    "chars": 4127,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Configuration>\r\n    <ViewDefinitions>\r\n        <View>\r\n            <Name>ScoopA"
  },
  {
    "path": "supporting/shims/71/checksum.sha256",
    "chars": 76,
    "preview": "70d4690b8ac3b3f715f537cdea6e07a39fda4bc0347bf6b958e4f3ff2f0e04d4  shim.exe\r\n"
  },
  {
    "path": "supporting/shims/71/checksum.sha512",
    "chars": 140,
    "preview": "ecde07b32192846c4885cf4d2208eedc170765ea115ae49b81509fed0ce474e21064100bb2f3d815ee79f1c12463d32ef013d4182647eae71855cd18"
  },
  {
    "path": "supporting/shims/kiennq/checksum.sha256",
    "chars": 76,
    "preview": "140e3801d8adeda639a21b14e62b93a4c7d26b7a758421f43c82be59753be49b *shim.exe\r\n"
  },
  {
    "path": "supporting/shims/kiennq/checksum.sha512",
    "chars": 140,
    "preview": "59d9da9f9714003b915bcafbe1b41f53b121dde206ecc23984f62273e957766eece8d64ffc53011c328d3a2ad627aa0f4f7c39bbec8e7b64d0d2ee7b"
  },
  {
    "path": "supporting/shims/kiennq/version.txt",
    "chars": 8,
    "preview": "v3.1.2\r\n"
  },
  {
    "path": "supporting/shims/scoopcs/checksum.sha256",
    "chars": 76,
    "preview": "0116068768fc992fc536738396b33db3dafe6b0cf0e6f54f6d1aa8b0331f3cec *shim.exe\r\n"
  },
  {
    "path": "supporting/shims/scoopcs/checksum.sha512",
    "chars": 140,
    "preview": "d734c528e9f20581ed3c7aa71a458f7dff7e2780fa0c319ccb9c813cd8dbf656bd7e550b81d2aa3ee8775bff9a4e507bc0b25f075697405adca0f47d"
  },
  {
    "path": "supporting/shims/scoopcs/version.txt",
    "chars": 7,
    "preview": "1.1.0\r\n"
  },
  {
    "path": "supporting/validator/.gitignore",
    "chars": 11,
    "preview": "packages/\r\n"
  },
  {
    "path": "supporting/validator/Scoop.Validator.cs",
    "chars": 5403,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Text;\r\nusing Newtonsoft.Json;\r\nusing Ne"
  },
  {
    "path": "supporting/validator/bin/checksum.sha256",
    "chars": 349,
    "preview": "e1e27af7b07eeedf5ce71a9255f0422816a6fc5849a483c6714e1b472044fa9d *Newtonsoft.Json.dll\r\n7496d5349a123a6e3696085662b2ff17b"
  },
  {
    "path": "supporting/validator/bin/checksum.sha512",
    "chars": 605,
    "preview": "56eb7f070929b239642dab729537dde2c2287bdb852ad9e80b5358c74b14bc2b2dded910d0e3b6304ea27eb587e5f19db0a92e1cbae6a70fb20b4ef0"
  },
  {
    "path": "supporting/validator/build.ps1",
    "chars": 1668,
    "preview": "Param([Switch]$Fast)\r\nPush-Location $PSScriptRoot\r\n. \"$PSScriptRoot\\..\\..\\lib\\core.ps1\"\r\n. \"$PSScriptRoot\\..\\..\\lib\\inst"
  },
  {
    "path": "supporting/validator/install.ps1",
    "chars": 329,
    "preview": "# https://github.com/edymtt/nugetstandalone\r\n$destinationFolder = \"$PSScriptRoot\\packages\"\r\nif ((Test-Path -Path $destin"
  },
  {
    "path": "supporting/validator/packages.config",
    "chars": 363,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<packages>\r\n    <package id=\"Newtonsoft.Json\" version=\"13.0.3\" targetFramework="
  },
  {
    "path": "supporting/validator/update.ps1",
    "chars": 385,
    "preview": "# https://github.com/edymtt/nugetstandalone\r\n$destinationFolder = \"$PSScriptRoot\\packages\"\r\nif (!(Test-Path -Path $desti"
  },
  {
    "path": "supporting/validator/validator.cs",
    "chars": 2659,
    "preview": "using System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\n\r\nnam"
  },
  {
    "path": "supporting/validator/validator.csproj",
    "chars": 3227,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbui"
  },
  {
    "path": "test/Import-Bucket-Tests.ps1",
    "chars": 2235,
    "preview": "#Requires -Version 5.1\r\n#Requires -Modules @{ ModuleName = 'BuildHelpers'; ModuleVersion = '2.0.1' }\r\n#Requires -Modules"
  },
  {
    "path": "test/Scoop-00File.Tests.ps1",
    "chars": 6670,
    "preview": "param(\r\n    [String] $TestPath = \"$PSScriptRoot\\..\"\r\n)\r\n\r\nBeforeDiscovery {\r\n    $project_file_exclusions = @(\r\n        "
  },
  {
    "path": "test/Scoop-00Linting.Tests.ps1",
    "chars": 1230,
    "preview": "Describe 'PSScriptAnalyzer' -Tag 'Linter' {\r\n    BeforeDiscovery {\r\n        $scriptDir = @('.', 'bin', 'lib', 'libexec',"
  },
  {
    "path": "test/Scoop-Commands.Tests.ps1",
    "chars": 1392,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib"
  },
  {
    "path": "test/Scoop-Config.Tests.ps1",
    "chars": 3167,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n}\r\n\r\nDescribe 'config' -Tag"
  },
  {
    "path": "test/Scoop-Core.Tests.ps1",
    "chars": 14911,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib"
  },
  {
    "path": "test/Scoop-Decompress.Tests.ps1",
    "chars": 9607,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib"
  },
  {
    "path": "test/Scoop-Depends.Tests.ps1",
    "chars": 5392,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib"
  },
  {
    "path": "test/Scoop-Download.Tests.ps1",
    "chars": 1716,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib"
  },
  {
    "path": "test/Scoop-GetOpts.Tests.ps1",
    "chars": 3241,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\getopt.ps1\"\r\n}\r\n\r\nDescribe 'getopt' -T"
  },
  {
    "path": "test/Scoop-Install.Tests.ps1",
    "chars": 3651,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\core.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib"
  },
  {
    "path": "test/Scoop-Manifest.Tests.ps1",
    "chars": 4302,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\..\\lib\\json.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\manifest.ps1\"\r\n}\r\n\r\nDescribe 'JSON parse"
  },
  {
    "path": "test/Scoop-TestLib.ps1",
    "chars": 556,
    "preview": "# copies fixtures to a working directory\r\nfunction setup_working($name) {\r\n    $fixtures = \"$PSScriptRoot\\fixtures\\$name"
  },
  {
    "path": "test/Scoop-Versions.Tests.ps1",
    "chars": 5467,
    "preview": "BeforeAll {\r\n    . \"$PSScriptRoot\\Scoop-TestLib.ps1\"\r\n    . \"$PSScriptRoot\\..\\lib\\versions.ps1\"\r\n}\r\n\r\nDescribe 'versions"
  },
  {
    "path": "test/bin/init.ps1",
    "chars": 1161,
    "preview": "#Requires -Version 5.1\r\nWrite-Output \"PowerShell: $($PSVersionTable.PSVersion)\"\r\nWrite-Output 'Check and install testsui"
  },
  {
    "path": "test/bin/test.ps1",
    "chars": 4259,
    "preview": "#Requires -Version 5.1\r\n#Requires -Modules @{ ModuleName = 'BuildHelpers'; ModuleVersion = '2.0.1' }\r\n#Requires -Modules"
  },
  {
    "path": "test/fixtures/format/formatted/1-easy.json",
    "chars": 27,
    "preview": "{\r\n    \"bin\": \"single\"\r\n}\r\n"
  },
  {
    "path": "test/fixtures/format/formatted/2-whitespaces-mess.json",
    "chars": 306,
    "preview": "{\r\n    \"version\": \"0.5.18\",\r\n    \"url\": \"https://whatever\",\r\n    \"hash\": \"whatever\",\r\n    \"architecture\": {\r\n        \"64"
  },
  {
    "path": "test/fixtures/format/formatted/3-array-with-single-and-multi.json",
    "chars": 1564,
    "preview": "{\r\n    \"homepage\": \"http://www.7-zip.org/\",\r\n    \"description\": \"A multi-format file archiver with high compression rati"
  },
  {
    "path": "test/fixtures/format/formatted/4-script-block.json",
    "chars": 1549,
    "preview": "{\r\n    \"version\": \"1.0.6\",\r\n    \"description\": \"Rambox Pro. Free, Open Source and Cross Platform messaging and emailing "
  },
  {
    "path": "test/fixtures/format/unformatted/1-easy.json",
    "chars": 22,
    "preview": "{ \"bin\": [\"single\"]}\r\n"
  },
  {
    "path": "test/fixtures/format/unformatted/2-whitespaces-mess.json",
    "chars": 278,
    "preview": "{\r\n    \"version\": \"0.5.18\",\r\n    \"url\": \"https://whatever\",\r\n\r\n    \"hash\": \"whatever\",\r\n  \"architecture\": {\r\n  \t\t\t     \""
  },
  {
    "path": "test/fixtures/format/unformatted/3-array-with-single-and-multi.json",
    "chars": 1607,
    "preview": "{\r\n    \"homepage\": \"http://www.7-zip.org/\",\r\n    \"description\": \"A multi-format file archiver with high compression rati"
  },
  {
    "path": "test/fixtures/format/unformatted/4-script-block.json",
    "chars": 1637,
    "preview": "{\r\n    \"version\": \"1.0.6\",\r\n    \"description\": \"Rambox Pro. Free, Open Source and Cross Platform messaging and emailing "
  },
  {
    "path": "test/fixtures/is_directory/i_am_a_directory/.gitkeep",
    "chars": 37,
    "preview": "need some content to not fail tests\r\n"
  },
  {
    "path": "test/fixtures/is_directory/i_am_a_file.txt",
    "chars": 15,
    "preview": "dummy content\r\n"
  },
  {
    "path": "test/fixtures/manifest/broken_schema.json",
    "chars": 248,
    "preview": "{\r\n    \"$id\": \"http://scoop.sh/draft/schema#\",\r\n    \"$schema\": \"http://scoop.sh/draft/schema#\",\r\n    \"title\": \"scoop app"
  },
  {
    "path": "test/fixtures/manifest/broken_wget.json",
    "chars": 960,
    "preview": "{\r\n    \"homepage\": \"https://eternallybored.org/misc/wget/\",\r\n    \"license\": \"GPL3\",\r\n    \"version\": \"1.16.3\"\r\n    \"archi"
  },
  {
    "path": "test/fixtures/manifest/invalid_wget.json",
    "chars": 977,
    "preview": "{\r\n    \"homepage\": \"https://eternallybored.org/misc/wget/\",\r\n    \"randomproperty\": \"should fail\",\r\n    \"license\": \"GPL3\""
  },
  {
    "path": "test/fixtures/manifest/wget.json",
    "chars": 961,
    "preview": "{\r\n    \"homepage\": \"https://eternallybored.org/misc/wget/\",\r\n    \"license\": \"GPL3\",\r\n    \"version\": \"1.16.3\",\r\n    \"arch"
  },
  {
    "path": "test/fixtures/movedir/user/_tmp/subdir/test.txt",
    "chars": 17,
    "preview": "this is the one\r\n"
  },
  {
    "path": "test/fixtures/movedir/user/_tmp/test.txt",
    "chars": 9,
    "preview": "testing\r\n"
  },
  {
    "path": "test/fixtures/movedir/user with 'quote/_tmp/subdir/test.txt",
    "chars": 17,
    "preview": "this is the one\r\n"
  },
  {
    "path": "test/fixtures/movedir/user with 'quote/_tmp/test.txt",
    "chars": 9,
    "preview": "testing\r\n"
  },
  {
    "path": "test/fixtures/movedir/user with space/_tmp/subdir/test.txt",
    "chars": 17,
    "preview": "this is the one\r\n"
  },
  {
    "path": "test/fixtures/movedir/user with space/_tmp/test.txt",
    "chars": 9,
    "preview": "testing\r\n"
  },
  {
    "path": "test/fixtures/shim/shim-test.ps1",
    "chars": 17,
    "preview": "'Hello, world!'\r\n"
  },
  {
    "path": "test/fixtures/shim/user with 'quote/shim-test.ps1",
    "chars": 17,
    "preview": "'Hello, world!'\r\n"
  }
]

About this extraction

This page contains the full source code of the ScoopInstaller/Scoop GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 134 files (583.4 KB), approximately 159.1k tokens, and a symbol index with 13 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!