[
  {
    "path": ".github/workflows/build.yaml",
    "content": "name: Build and Test\npermissions:\n  contents: read\n\non:\n  pull_request:\n    branches: [ master ]\n  push:\n    branches: [ master ]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Set up Go\n      uses: actions/setup-go@v4\n      with:\n        go-version: '1.23'\n\n    - name: Cache Go modules\n      uses: actions/cache@v3\n      with:\n        path: ~/go/pkg/mod\n        key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n        restore-keys: |\n          ${{ runner.os }}-go-\n\n    - name: Download dependencies\n      run: go mod download\n\n    - name: Verify dependencies\n      run: go mod verify\n\n    - name: Install Task\n      uses: arduino/setup-task@v2\n      with:\n        version: 3.x\n        repo-token: ${{ secrets.GITHUB_TOKEN }}\n\n    - name: Lint, Test, and Build\n      run: |\n        task ci\n\n  lint:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Set up Go\n      uses: actions/setup-go@v4\n      with:\n        go-version: '1.23'\n\n    - name: golangci-lint\n      uses: golangci/golangci-lint-action@v7\n      with:\n        version: latest\n        args: --timeout=5m\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL Advanced\"\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n  schedule:\n    - cron: '44 20 * * 3'\n\njobs:\n  analyze:\n    name: Analyze (${{ matrix.language }})\n    # Runner size impacts CodeQL analysis time. To learn more, please see:\n    #   - https://gh.io/recommended-hardware-resources-for-running-codeql\n    #   - https://gh.io/supported-runners-and-hardware-resources\n    #   - https://gh.io/using-larger-runners (GitHub.com only)\n    # Consider using larger runners or machines with greater resources for possible analysis time improvements.\n    runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}\n    permissions:\n      # required for all workflows\n      security-events: write\n\n      # required to fetch internal or private CodeQL packs\n      packages: read\n\n      # only required for workflows in private repositories\n      actions: read\n      contents: read\n\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n        - language: actions\n          build-mode: none\n        - language: go\n          build-mode: autobuild\n        # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'\n        # Use `c-cpp` to analyze code written in C, C++ or both\n        # Use 'java-kotlin' to analyze code written in Java, Kotlin or both\n        # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both\n        # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,\n        # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.\n        # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how\n        # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v4\n\n    # Add any setup steps before running the `github/codeql-action/init` action.\n    # This includes steps like installing compilers or runtimes (`actions/setup-node`\n    # or others). This is typically only required for manual builds.\n    # - name: Setup runtime (example)\n    #   uses: actions/setup-example@v1\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3\n      with:\n        languages: ${{ matrix.language }}\n        build-mode: ${{ matrix.build-mode }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n\n        # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs\n        # queries: security-extended,security-and-quality\n\n    # If the analyze step fails for one of the languages you are analyzing with\n    # \"We were unable to automatically build your code\", modify the matrix above\n    # to set the build mode to \"manual\" for that language. Then modify this step\n    # to build your code.\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun\n    - if: matrix.build-mode == 'manual'\n      shell: bash\n      run: |\n        echo 'If you are using a \"manual\" build mode for one or more of the' \\\n          'languages you are analyzing, replace this with the commands to build' \\\n          'your code, for example:'\n        echo '  make bootstrap'\n        echo '  make release'\n        exit 1\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v3\n      with:\n        category: \"/language:${{matrix.language}}\"\n"
  },
  {
    "path": ".github/workflows/release.yaml",
    "content": "name: goreleaser\n\non:\n  push:\n    tags:\n      - '*'\n\njobs:\n  goreleaser:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n          token: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Set up Go\n        uses: actions/setup-go@v4\n        with:\n          go-version: '1.24'\n\n      - name: Run GoReleaser\n        uses: goreleaser/goreleaser-action@v5\n        with:\n          distribution: goreleaser\n          version: '~> v2'\n          args: release --clean\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, built with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\n# Dependency directories (remove the comment below to include it)\n# vendor/\nkelp\nbuild/\ndist/\n\n# llm files\n.cursor\n.claude\n"
  },
  {
    "path": ".golangci.yml",
    "content": "version: \"2\"\nrun:\n  go: \"1.23\"\nlinters:\n  enable:\n    - gocritic\n    - gosec\n    - misspell\n    - revive\n  disable:\n    - errcheck\n  settings:\n    gosec:\n      excludes:\n        - G404\n    revive:\n      rules:\n        - name: exported\n          disabled: false\n        - name: unreachable-code\n          disabled: false\n        - name: unused-parameter\n          disabled: false\n  exclusions:\n    generated: lax\n    presets:\n      - comments\n      - common-false-positives\n      - legacy\n      - std-error-handling\n    rules:\n      - linters:\n          - gocritic\n          - gosec\n        path: _test\\.go\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\nissues:\n  max-issues-per-linter: 0\n  max-same-issues: 0\nformatters:\n  enable:\n    - gofmt\n    - goimports\n  exclusions:\n    generated: lax\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\n"
  },
  {
    "path": ".goreleaser.yaml",
    "content": "# GoReleaser configuration for kelp\nversion: 2\n\nproject_name: kelp\n\nbefore:\n  hooks:\n    - go mod tidy\n    - go generate ./...\n\nbuilds:\n  - env:\n      - CGO_ENABLED=0\n    goos:\n      - linux\n      - darwin\n    goarch:\n      - amd64\n      - arm64\n    main: .\n    binary: kelp\n    ldflags:\n      - -s -w\n      - -X main.version={{.Version}}\n      - -X main.commit={{.Commit}}\n      - -X main.date={{.Date}}\n    gcflags:\n      - all=-l\n      - ./dontoptimizeme=-N\n\narchives:\n  - formats: [tar.gz]\n    name_template: \"{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}\"\n    files:\n      - README.md\n      - LICENSE*\n\nchecksum:\n  name_template: \"checksums.txt\"\n\nchangelog:\n  sort: asc\n  use: github\n  filters:\n    exclude:\n      - \"^docs:\"\n      - \"^test:\"\n      - \"^ci:\"\n      - \"^chore:\"\n      - merge conflict\n      - Merge pull request\n      - Merge remote-tracking branch\n      - Merge branch\n  groups:\n    - title: \"🚀 New Features\"\n      regexp: \"^.*feat[(\\\\w)]*:+.*$\"\n      order: 0\n    - title: \"🐛 Bug Fixes\"\n      regexp: \"^.*fix[(\\\\w)]*:+.*$\"\n      order: 1\n    - title: \"📚 Documentation\"\n      regexp: \"^.*docs[(\\\\w)]*:+.*$\"\n      order: 2\n    - title: \"🔧 Improvements\"\n      regexp: \"^.*refactor[(\\\\w)]*:+.*$\"\n      order: 3\n    - title: \"Other Changes\"\n      order: 999\n\nrelease:\n  github:\n    owner: crhuber\n    name: kelp\n  draft: false\n  prerelease: auto\n  mode: replace\n  header: |\n    ## kelp {{ .Tag }}\n\n    This release includes kelp.\n\n    ### Installation\n\n    Download the appropriate binary for your platform and follow the installation instructions in the README.\n"
  },
  {
    "path": ".tool-versions",
    "content": "golang 1.24.0\n"
  },
  {
    "path": "README.md",
    "content": "# KELP\n<p align=\"center\">\n  <img height=\"150px\" src=\"./logo.png\"  alt=\"KELP\" title=\"KELP\">\n</p>\n\n## What is it\nA simple replacement for homebrew for installing binary packages on MacOS & Linux written in Go.\n\n## How Does it Work?\n\n1. It downloads a Github releases package matching your operating system and architecture to `~/.kelp/cache`\n2. It extracts any binary files to `~/.kelp/bin`\n3. It unquarantines the binary (mac)\n\nExample:\n\n```\nkelp update --install crumb\n🌐 Getting releases for crhuber/crumb:latest...\nLatest release v0.0.24. Kelp configured release v0.0.21.\n===> Installing crhuber/crumb:v0.0.24...\n🌐 Getting releases by tag v0.0.24...\n🍏 Finding assets to download...\n===> Downloading https://api.github.com/repos/crhuber/crumb/releases/assets/372978000...\nDownloading 100%\n📂 Extracting /Users/Craig/.kelp/cache/crumb_0.0.24_darwin_arm64.tar.gz\n🧐 Checking for binary files in extract...\n💾 Copying crumb to kelp bin...\n✅ Installed crumb !\n🛃 Unquarantining /Users/Craig/.kelp/bin/crumb..\n```\n\n## Why?\n\nI built Kelp to scratch my own itch:\n\n* No waiting for a formula to become available on homebrew\n* Keep all your computers up to date with a single installation manifest\n* No homebrew auto update\n* No bloat, no magic\n\nCouldn't this just be a bash script? Probably.\n\n## How To Install\n\nGo to the [releases](https://github.com/crhuber/kelp/releases) page. Download the latest release\n\nAdd kelp binary path to your PATH\n\n```\nexport PATH=~/.kelp/bin/:$PATH\n```\n\n## Quick Setup\n\n\n1. Initialize Kelp\n\n```\nkelp init\n```\n\n2. Add a new package\n\n```\nkelp add junegunn/fzf\n```\n\nTo use a specific version use the `-r` flag. Where `-r` is the github release version\n\n```\nkelp add junegunn/fzf -r 1.0.0\n```\n\n3. Install\n\n```\nkelp install fzf\n```\nor\n\n```\nkelp add junegunn/fzf --install\n```\n\n### Updating a Package\n\nUpdate\n\n```\nkelp update fzf\nkelp install fzf\n```\n\nUpdate and install\n\n```\nkelp update fzf --install\n```\n\n\nUpdate to a specific version\n\n```\nkelp set fzf -r v0.72.0\nkelp install fzf\n```\n\n## Configuration\n\n```\nGLOBAL OPTIONS:\n   --config string, -c string  path to kelp config file (default: \"/Users/Craig/.kelp/kelp.json\") [$KELP_CONFIG]\n   --verbose                   verbose output [$KELP_VERBOSE]\n```\n\n\n## Troubleshooting\n\n### What if the package I want is not on github releases?\n\nJust kelp add the link to the binary, ie:\n\n```\nkelp add hashicorp/terraform -r https://releases.hashicorp.com/terraform/0.11.13/terraform_0.11.13_darwin_amd64.zip\n```\n\nAlso supported are packages like `helm` that provide external non-github download links in the release description.\n\n### Increase logging level\n\nUse `--verbose` or set `KELP_VERBOSE=1` to get more information, expecially during the installation process.\n\n### Why wasnt my package installed ?\n\nKelp looks for binaries made for MacOS or Linux. If it cannot file a suitable binary for your machine architecture and operating system it will skip downloading it or wont extract it.\n\nUse inspect to open the cache and bin directories for your package\n\n```\nkelp inspect\n```\n\nTo see what binaries exist use:\n\n```\nkelp doctor\n```\n\nIf your binary has a different filename than the name of the Github project, kelp doctor may not find it. To give it a hint you can add the name of the binary to the kelp config\n\n```\nkelp set jira-cli -b \"jira\"`\n```\n\nTo see whats in your config use:\n\n```\nkelp ls\n```\n\n### Does it work for Linux?\n\nYes!\n\n### What if I'm rate limited by Github Api?\n\nSet a github token environment variable\n\n```\nexport GITHUB_TOKEN=\"XYZ\"\n```\n\n## Contributing\n\nIf you find bugs, please open an issue first. If you have feature requests, I may not honor it because this project is being built mostly to suit my personal workflow and preferences.\n"
  },
  {
    "path": "TODO.txt",
    "content": "- when file already exists in cache do a hash before skipping it\n- add post install hooks\n"
  },
  {
    "path": "Taskfile.yaml",
    "content": "version: '3'\n\nvars:\n  BINARY_NAME: kelp\n  BUILD_DIR: ./build\n  COVERAGE_DIR: ./coverage\n\ntasks:\n  default:\n    desc: Show available tasks\n    cmds:\n      - task --list\n\n  clean:\n    desc: Clean build artifacts and coverage reports\n    cmds:\n      - rm -rf {{.BUILD_DIR}}\n      - rm -rf {{.COVERAGE_DIR}}\n      - rm -f {{.BINARY_NAME}}\n      - rm -f coverage.out coverage.html\n\n  deps:\n    desc: Download and verify dependencies\n    cmds:\n      - go mod download\n      - go mod verify\n\n  build:\n    desc: Build the application\n    deps: [clean]\n    cmds:\n      - mkdir -p {{.BUILD_DIR}}\n      - go build -o {{.BUILD_DIR}}/{{.BINARY_NAME}} .\n\n  test:\n    desc: Run all tests\n    cmds:\n      - echo \"Running unit tests...\"\n      - go test -v ./...\n\n  test-unit:\n    desc: Run unit tests only\n    cmds:\n      - echo \"Running unit tests...\"\n      - go test -v ./... -run \"^Test\"\n\n  test-integration:\n    desc: Run integration tests only\n    cmds:\n      - echo \"Running integration tests...\"\n      - go test -v ./... -run \"Integration\"\n\n  test-coverage:\n    desc: Run tests with coverage report\n    cmds:\n      - mkdir -p {{.COVERAGE_DIR}}\n      - go test -v -cover -coverprofile={{.COVERAGE_DIR}}/coverage.out ./...\n      - go tool cover -html={{.COVERAGE_DIR}}/coverage.out -o {{.COVERAGE_DIR}}/coverage.html\n      - 'echo \"Coverage report generated: {{.COVERAGE_DIR}}/coverage.html\"'\n\n  test-coverage-text:\n    desc: Run tests with coverage report (text output)\n    cmds:\n      - go test -v -cover -coverprofile=coverage.out ./...\n      - go tool cover -func=coverage.out\n      - rm -f coverage.out\n\n  lint:\n    desc: Run linter\n    cmds:\n      - echo \"Running linter...\"\n      - go vet ./...\n      - go fmt ./...\n      - golangci-lint run --timeout=5m\n\n  lint-check:\n    desc: Check code formatting and linting\n    cmds:\n      - echo \"Checking code formatting...\"\n      - test -z \"$(go fmt ./...)\"\n      - go vet ./...\n\n  security:\n    desc: Run security scanner (requires gosec)\n    cmds:\n      - echo \"Running security scanner...\"\n      - gosec ./...\n    preconditions:\n      - sh: command -v gosec\n        msg: \"gosec is not installed. Run: go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest\"\n\n  ci:\n    desc: Run CI pipeline (lint, test, build)\n    cmds:\n      - task: lint-check\n      - task: test-coverage-text\n      - task: build\n\n  ci-full:\n    desc: Run full CI pipeline with benchmarks\n    cmds:\n      - task: deps\n      - task: lint-check\n      - task: test-coverage\n      - task: build\n\n  setup-dev:\n    desc: Setup development environment\n    cmds:\n      - echo \"Setting up development environment...\"\n      - go mod download\n      - go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest\n      - go install github.com/go-task/task/v3/cmd/task@latest\n      - echo \"Development environment setup complete!\"\n\n\n  test-race:\n    desc: Run tests with race detection\n    cmds:\n      - echo \"Running tests with race detection...\"\n      - go test -v -race ./...\n\n\n  release:\n    desc: Build release binaries for multiple platforms\n    deps: [clean, test-coverage-text, lint-check]\n    cmds:\n      - mkdir -p {{.BUILD_DIR}}/release\n      - echo \"Building release binaries...\"\n      - GOOS=darwin GOARCH=amd64 go build -o {{.BUILD_DIR}}/release/{{.BINARY_NAME}}-darwin-amd64 .\n      - GOOS=darwin GOARCH=arm64 go build -o {{.BUILD_DIR}}/release/{{.BINARY_NAME}}-darwin-arm64 .\n      - GOOS=linux GOARCH=amd64 go build -o {{.BUILD_DIR}}/release/{{.BINARY_NAME}}-linux-amd64 .\n      - GOOS=linux GOARCH=arm64 go build -o {{.BUILD_DIR}}/release/{{.BINARY_NAME}}-linux-arm64 .\n      - echo \"Release binaries built in {{.BUILD_DIR}}/release/\"\n"
  },
  {
    "path": "go.mod",
    "content": "module crhuber/kelp\n\ngo 1.23.0\n\ntoolchain go1.23.8\n\nrequire (\n\tgithub.com/gabriel-vasile/mimetype v1.4.12\n\tgithub.com/h2non/gock v1.2.0\n\tgithub.com/mholt/archives v0.1.4\n\tgithub.com/schollz/progressbar/v3 v3.19.0\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/urfave/cli/v3 v3.6.1\n)\n\nrequire (\n\tgithub.com/STARRY-S/zip v0.2.3 // indirect\n\tgithub.com/andybalholm/brotli v1.2.0 // indirect\n\tgithub.com/bodgit/plumbing v1.3.0 // indirect\n\tgithub.com/bodgit/sevenzip v1.6.1 // indirect\n\tgithub.com/bodgit/windows v1.0.1 // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect\n\tgithub.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect\n\tgithub.com/hashicorp/golang-lru/v2 v2.0.7 // indirect\n\tgithub.com/klauspost/compress v1.18.2 // indirect\n\tgithub.com/klauspost/pgzip v1.2.6 // indirect\n\tgithub.com/kr/pretty v0.3.1 // indirect\n\tgithub.com/mattn/go-runewidth v0.0.19 // indirect\n\tgithub.com/mikelolasagasti/xz v1.0.1 // indirect\n\tgithub.com/minio/minlz v1.0.1 // indirect\n\tgithub.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect\n\tgithub.com/nwaples/rardecode/v2 v2.1.1 // indirect\n\tgithub.com/pierrec/lz4/v4 v4.1.23 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/rivo/uniseg v0.4.7 // indirect\n\tgithub.com/sorairolake/lzip-go v0.3.8 // indirect\n\tgithub.com/spf13/afero v1.15.0 // indirect\n\tgithub.com/ulikunitz/xz v0.5.15 // indirect\n\tgo4.org v0.0.0-20230225012048-214862532bf5 // indirect\n\tgolang.org/x/sys v0.31.0 // indirect\n\tgolang.org/x/term v0.30.0 // indirect\n\tgolang.org/x/text v0.28.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4=\ngithub.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk=\ngithub.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=\ngithub.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=\ngithub.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU=\ngithub.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs=\ngithub.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4=\ngithub.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8=\ngithub.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4=\ngithub.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=\ngithub.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY=\ngithub.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=\ngithub.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=\ngithub.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=\ngithub.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=\ngithub.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=\ngithub.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=\ngithub.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=\ngithub.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=\ngithub.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=\ngithub.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=\ngithub.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=\ngithub.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=\ngithub.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=\ngithub.com/mholt/archives v0.1.4 h1:sU+/lLNgafUontWFv3AVwO8VUWye3rrtN6hgC2dU11c=\ngithub.com/mholt/archives v0.1.4/go.mod h1:I2ia+SQTtQHej9w1GZM/mz7qfdgQv+BHr3hEKqDcGuk=\ngithub.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0=\ngithub.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc=\ngithub.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A=\ngithub.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec=\ngithub.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=\ngithub.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=\ngithub.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=\ngithub.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=\ngithub.com/nwaples/rardecode/v2 v2.1.1 h1:OJaYalXdliBUXPmC8CZGQ7oZDxzX1/5mQmgn0/GASew=\ngithub.com/nwaples/rardecode/v2 v2.1.1/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw=\ngithub.com/pierrec/lz4/v4 v4.1.23 h1:oJE7T90aYBGtFNrI8+KbETnPymobAhzRrR8Mu8n1yfU=\ngithub.com/pierrec/lz4/v4 v4.1.23/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=\ngithub.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=\ngithub.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=\ngithub.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=\ngithub.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=\ngithub.com/schollz/progressbar/v3 v3.19.0 h1:Ea18xuIRQXLAUidVDox3AbwfUhD0/1IvohyTutOIFoc=\ngithub.com/schollz/progressbar/v3 v3.19.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=\ngithub.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik=\ngithub.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU=\ngithub.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=\ngithub.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=\ngithub.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=\ngithub.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=\ngithub.com/urfave/cli/v3 v3.6.1 h1:j8Qq8NyUawj/7rTYdBGrxcH7A/j7/G8Q5LhWEW4G3Mo=\ngithub.com/urfave/cli/v3 v3.6.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=\ngithub.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=\ngithub.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=\ngo4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=\ngolang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=\ngolang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=\ngolang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=\ngolang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"context\"\n\t\"crhuber/kelp/pkg/config\"\n\t\"crhuber/kelp/pkg/install\"\n\t\"crhuber/kelp/pkg/logging\"\n\t\"crhuber/kelp/pkg/types\"\n\t\"crhuber/kelp/pkg/utils\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/urfave/cli/v3\"\n)\n\nvar (\n\tversion = \"dev\"\n)\n\nfunc main() {\n\n\t// default config\n\tvar home, _ = os.UserHomeDir()\n\tvar KelpConf = filepath.Join(home, \"/.kelp/kelp.json\")\n\n\tif types.GetCapabilities() == nil {\n\t\tfmt.Println(\"Sorry, your OS is not yet supported.\")\n\t\tos.Exit(1)\n\t}\n\n\tapp := &cli.Command{\n\t\tName:    \"kelp\",\n\t\tVersion: version,\n\t\tFlags: []cli.Flag{\n\t\t\t&cli.StringFlag{\n\t\t\t\tName:    \"config\",\n\t\t\t\tAliases: []string{\"c\"},\n\t\t\t\tValue:   KelpConf,\n\t\t\t\tUsage:   \"path to kelp config file\",\n\t\t\t\tSources: cli.EnvVars(\"KELP_CONFIG\"),\n\t\t\t},\n\t\t\t&cli.BoolFlag{\n\t\t\t\tName:    \"verbose\",\n\t\t\t\tValue:   false,\n\t\t\t\tUsage:   \"verbose output\",\n\t\t\t\tSources: cli.EnvVars(\"KELP_VERBOSE\"),\n\t\t\t\tAction: func(_ context.Context, _ *cli.Command, val bool) error {\n\t\t\t\t\tlogging.SetLogVerbose(val)\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tCommands: []*cli.Command{\n\t\t\t{\n\t\t\t\tName:  \"add\",\n\t\t\t\tUsage: \"add a new package to config\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\tName:    \"release\",\n\t\t\t\t\t\tAliases: []string{\"r\"},\n\t\t\t\t\t\tValue:   \"latest\",\n\t\t\t\t\t\tUsage:   \"release for package\",\n\t\t\t\t\t},\n\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\tName:    \"install\",\n\t\t\t\t\t\tAliases: []string{\"i\"},\n\t\t\t\t\t\tValue:   false,\n\t\t\t\t\t\tUsage:   \"also install package\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\n\t\t\t\t\tproject := cmd.Args().First()\n\t\t\t\t\townerRepo := strings.Split(project, \"/\")\n\t\t\t\t\tif len(ownerRepo) < 2 {\n\t\t\t\t\t\treturn fmt.Errorf(\"use owner/repo format\")\n\t\t\t\t\t}\n\n\t\t\t\t\t// resolve release version\n\t\t\t\t\treleaseFlag := cmd.String(\"release\")\n\t\t\t\t\tvar actualRelease string\n\t\t\t\t\tif releaseFlag == \"latest\" {\n\t\t\t\t\t\t// Get the actual latest release version from GitHub\n\t\t\t\t\t\tlatestRelease, err := utils.GetGithubRelease(ownerRepo[0], ownerRepo[1], \"latest\")\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"failed to get latest release for %s/%s: %s\", ownerRepo[0], ownerRepo[1], err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tactualRelease = latestRelease.TagName\n\t\t\t\t\t} else {\n\t\t\t\t\t\tactualRelease = releaseFlag\n\t\t\t\t\t}\n\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\terr = kc.AddPackage(ownerRepo[0], ownerRepo[1], actualRelease)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\t// save config\n\t\t\t\t\terr = kc.Save()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// auto install\n\t\t\t\t\tif cmd.Bool(\"install\") {\n\t\t\t\t\t\terr = install.Install(ownerRepo[0], ownerRepo[1], actualRelease)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"browse\",\n\t\t\t\tUsage: \"browse to project github page\",\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\tproject := cmd.Args().First()\n\t\t\t\t\tif project == \"\" {\n\t\t\t\t\t\treturn errors.New(\"project argument required\")\n\t\t\t\t\t}\n\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tp, err := kc.GetPackage(project)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\tconfig.Browse(p.Owner, p.Repo)\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"doctor\",\n\t\t\t\tUsage: \"checks if packages are installed properly\",\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\tkc.Doctor()\n\t\t\t\t\treturn nil\n\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"get\",\n\t\t\t\tUsage: \"get package details\",\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\n\t\t\t\t\tproject := cmd.Args().First()\n\t\t\t\t\tif project == \"\" {\n\t\t\t\t\t\treturn errors.New(\"project argument required\")\n\t\t\t\t\t}\n\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tp, err := kc.GetPackage(project)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tfmt.Printf(\"[%s/%s]\\n\", p.Owner, p.Repo)\n\t\t\t\t\tfmt.Printf(\"Release: %s\\n\", p.Release)\n\t\t\t\t\tfmt.Printf(\"Description: %s\\n\", p.Description)\n\t\t\t\t\tfmt.Printf(\"Url: https://github.com/%s/%s\\n\", p.Owner, p.Repo)\n\t\t\t\t\tfmt.Printf(\"Binary: %s\\n\", p.Binary)\n\t\t\t\t\tfmt.Printf(\"Updated At: %s\\n\", p.UpdatedAt)\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"init\",\n\t\t\t\tUsage: \"initialize kelp\",\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\terr := config.Initialize(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"inspect\",\n\t\t\t\tUsage: \"inspect kelp bin directory\",\n\t\t\t\tAction: func(_ context.Context, _ *cli.Command) error {\n\t\t\t\t\tconfig.Inspect()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"install\",\n\t\t\t\tUsage: \"install kelp package\",\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\tproject := cmd.Args().First()\n\t\t\t\t\tif project == \"\" {\n\t\t\t\t\t\treturn errors.New(\"project argument required\")\n\t\t\t\t\t}\n\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\tkp, err := kc.GetPackage(project)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\terr = install.Install(kp.Owner, kp.Repo, kp.Release)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"list\",\n\t\t\t\tAliases: []string{\"ls\"},\n\t\t\t\tUsage:   \"list kelp packages\",\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\tkc.List()\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:    \"remove\",\n\t\t\t\tAliases: []string{\"rm\"},\n\t\t\t\tUsage:   \"remove a package from config and disk\",\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\tproject := cmd.Args().First()\n\t\t\t\t\tif project == \"\" {\n\t\t\t\t\t\treturn errors.New(\"project argument required\")\n\t\t\t\t\t}\n\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\tkp, err := kc.GetPackage(project)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// remove from config\n\t\t\t\t\terr = kc.RemovePackage(kp.Repo)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// save config\n\t\t\t\t\terr = kc.Save()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error saving: %s\", err)\n\t\t\t\t\t}\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"set\",\n\t\t\t\tUsage: \"set package configuration in config\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\tName:    \"release\",\n\t\t\t\t\t\tAliases: []string{\"r\"},\n\t\t\t\t\t\tValue:   \"latest\",\n\t\t\t\t\t\tUsage:   \"release for package\",\n\t\t\t\t\t},\n\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\tName:    \"description\",\n\t\t\t\t\t\tAliases: []string{\"d\"},\n\t\t\t\t\t\tValue:   \"\",\n\t\t\t\t\t\tUsage:   \"description of package\",\n\t\t\t\t\t},\n\t\t\t\t\t&cli.StringFlag{\n\t\t\t\t\t\tName:    \"binary\",\n\t\t\t\t\t\tAliases: []string{\"b\"},\n\t\t\t\t\t\tValue:   \"\",\n\t\t\t\t\t\tUsage:   \"alias of binary\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\tproject := cmd.Args().First()\n\t\t\t\t\tif project == \"\" {\n\t\t\t\t\t\treturn errors.New(\"project argument required\")\n\t\t\t\t\t}\n\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\terr = kc.SetPackage(project, cmd.String(\"release\"), cmd.String(\"description\"), cmd.String(\"binary\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\t// save config\n\t\t\t\t\terr = kc.Save()\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tName:  \"update\",\n\t\t\t\tUsage: \"update kelp package in config\",\n\t\t\t\tFlags: []cli.Flag{\n\t\t\t\t\t&cli.BoolFlag{\n\t\t\t\t\t\tName:    \"install\",\n\t\t\t\t\t\tAliases: []string{\"i\"},\n\t\t\t\t\t\tValue:   false,\n\t\t\t\t\t\tUsage:   \"also install package\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tAction: func(_ context.Context, cmd *cli.Command) error {\n\t\t\t\t\tproject := cmd.Args().First()\n\t\t\t\t\tif project == \"\" {\n\t\t\t\t\t\treturn errors.New(\"project argument required\")\n\t\t\t\t\t}\n\n\t\t\t\t\t// load config\n\t\t\t\t\tkc, err := config.Load(cmd.String(\"config\"))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\t\t\t\t\tkp, err := kc.GetPackage(project)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// handle http packages\n\t\t\t\t\tif strings.HasPrefix(kp.Release, \"http\") {\n\t\t\t\t\t\treturn errors.New(\"update functionality not supported for http packages\")\n\t\t\t\t\t}\n\n\t\t\t\t\tghr, err := utils.GetGithubRelease(kp.Owner, kp.Repo, \"latest\")\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif ghr.TagName == kp.Release {\n\t\t\t\t\t\tlogging.LogInfo(\"Latest release %s already matches release %s in kelp config\", ghr.TagName, kp.Release)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\tlogging.LogInfo(\"Latest release %s. Kelp configured release %s. Update config [y/n] ? : \", ghr.TagName, kp.Release)\n\n\t\t\t\t\tvar confirmation string\n\t\t\t\t\tconfirmation = strings.TrimSpace(confirmation)\n\t\t\t\t\tconfirmation = strings.ToLower(confirmation)\n\n\t\t\t\t\t// Taking input from user\n\t\t\t\t\tfmt.Scanln(&confirmation)\n\t\t\t\t\tif confirmationUpper := strings.ToUpper(confirmation); confirmationUpper == \"Y\" || confirmationUpper == \"YES\" {\n\t\t\t\t\t\terr = kc.SetPackage(kp.Repo, ghr.TagName, \"\", \"\")\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// save config\n\t\t\t\t\t\terr = kc.Save()\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"%s\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// auto install\n\t\t\t\t\tif cmd.Bool(\"install\") {\n\t\t\t\t\t\terr = install.Install(kp.Owner, kp.Repo, ghr.TagName)\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tif err := app.Run(context.Background(), os.Args); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n"
  },
  {
    "path": "pkg/config/config.go",
    "content": "package config\n\nimport (\n\t\"crhuber/kelp/pkg/logging\"\n\t\"crhuber/kelp/pkg/types\"\n\t\"crhuber/kelp/pkg/utils\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"time\"\n)\n\nvar home, _ = os.UserHomeDir()\n\nvar KelpDir = filepath.Join(home, \"/.kelp/\")\nvar KelpBin = filepath.Join(home, \"/.kelp/bin/\")\nvar KelpCache = filepath.Join(home, \"/.kelp/cache/\")\n\ntype KelpConfig struct {\n\tPath     string `json:\"-\"`\n\tPackages []KelpPackage\n}\ntype KelpPackage struct {\n\tOwner       string    `json:\"Owner\"`\n\tRepo        string    `json:\"Repo\"`\n\tRelease     string    `json:\"Release\"`\n\tUpdatedAt   time.Time `json:\"UpdatedAt\"`\n\tDescription string    `json:\"Description\"`\n\tBinary      string    `json:\"Binary\"`\n}\n\nfunc (kc *KelpConfig) Pop(index int) []KelpPackage {\n\treturn append(kc.Packages[:index], kc.Packages[index+1:]...)\n}\n\nfunc (kc *KelpConfig) GetPackage(repo string) (*KelpPackage, error) {\n\tparts := strings.Split(repo, \"/\")\n\t// Check if there is an owner part since some projects have the same repo name\n\t// like cli\n\tif len(parts) > 1 {\n\t\t// If there is an owner, get the more specific project first\n\t\tfor _, kp := range kc.Packages {\n\t\t\tif kp.Owner == parts[0] && kp.Repo == parts[1] {\n\t\t\t\treturn &kp, nil\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor _, kp := range kc.Packages {\n\t\t\tif kp.Repo == repo {\n\t\t\t\treturn &kp, nil\n\t\t\t}\n\t\t}\n\t}\n\treturn nil, errors.New(\"package not found in config, try adding it first\")\n}\n\nfunc Load(path string) (*KelpConfig, error) {\n\tbs, _ := os.ReadFile(path)\n\tkc := KelpConfig{}\n\terr := json.Unmarshal(bs, &kc.Packages)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkc.Path = path\n\treturn &kc, nil\n}\n\nfunc (kc *KelpConfig) Save() error {\n\tbs, _ := json.MarshalIndent(kc.Packages, \"\", \" \")\n\terr := os.WriteFile(kc.Path, bs, 0600)\n\tif err != nil {\n\t\treturn err\n\t}\n\tlogging.LogInfo(\"Config saved.\")\n\treturn nil\n}\n\nfunc (kc *KelpConfig) RemovePackage(repo string) error {\n\tfor i, kp := range kc.Packages {\n\t\tif kp.Repo == repo {\n\t\t\tkc.Packages = kc.Pop(i)\n\t\t\tlogging.LogInfo(\"Package %s removed\\n\", repo)\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn errors.New(\"package not found in config\")\n}\n\nfunc (kc *KelpConfig) AddPackage(owner, repo, release string) error {\n\n\tfor _, p := range kc.Packages {\n\t\tif p.Owner == owner && p.Repo == repo {\n\t\t\treturn fmt.Errorf(\"package already exists in config\")\n\t\t}\n\t}\n\n\t// append a new item\n\tkp := KelpPackage{\n\t\tOwner:     owner,\n\t\tRepo:      repo,\n\t\tRelease:   release,\n\t\tUpdatedAt: time.Now(),\n\t}\n\tkc.Packages = append(kc.Packages, kp)\n\tlogging.LogDebug(\"Config added for %s/%s\", owner, repo)\n\n\treturn nil\n}\n\nfunc (kc *KelpConfig) UpdatePackage(repo string) (string, error) {\n\tfor _, p := range kc.Packages {\n\t\tif p.Repo == repo {\n\t\t\tghr, err := utils.GetGithubRelease(p.Owner, p.Repo, \"latest\")\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", err\n\t\t\t}\n\t\t\treturn ghr.TagName, nil\n\t\t}\n\t}\n\treturn \"\", errors.New(\"package not found in config\")\n}\n\nfunc (kc *KelpConfig) SetPackage(repo, release, description, binary string) error {\n\tfor i, p := range kc.Packages {\n\t\tif p.Repo == repo {\n\t\t\tif release != \"\" {\n\t\t\t\tkc.Packages[i].Release = release\n\t\t\t\tkc.Packages[i].UpdatedAt = time.Now()\n\t\t\t}\n\t\t\tif description != \"\" {\n\t\t\t\tkc.Packages[i].Description = description\n\t\t\t}\n\t\t\tif binary != \"\" {\n\t\t\t\tkc.Packages[i].Binary = binary\n\t\t\t}\n\t\t\tlogging.LogDebug(\"Config set for %s\", repo)\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (kc *KelpConfig) List() {\n\tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)\n\n\t// sort by date\n\tsort.Slice(kc.Packages, func(i, j int) bool {\n\t\treturn kc.Packages[i].UpdatedAt.Before(kc.Packages[j].UpdatedAt)\n\t})\n\n\tfor _, pkg := range kc.Packages {\n\n\t\t// Format the timestamp in a more human-friendly way\n\t\thumanFriendlyTimestamp := pkg.UpdatedAt.Format(\"Jan 2 2006\")\n\t\tif humanFriendlyTimestamp == \"Jan 1 0001\" {\n\t\t\thumanFriendlyTimestamp = \"\"\n\t\t}\n\t\trelease := \"\"\n\t\tif strings.HasPrefix(pkg.Release, \"http\") {\n\t\t\t// Define the regex pattern to extract version numbers\n\t\t\tpattern := `[/v-]([\\d.]+)`\n\t\t\t// Compile the regex pattern\n\t\t\tre := regexp.MustCompile(pattern)\n\t\t\tmatch := re.FindStringSubmatch(pkg.Release)\n\t\t\tif len(match) > 1 {\n\t\t\t\trelease = fmt.Sprintf(\"%s (https)\", match[1])\n\t\t\t} else {\n\t\t\t\trelease = \"unknown (https)\"\n\t\t\t}\n\t\t} else {\n\t\t\trelease = pkg.Release\n\t\t}\n\n\t\tfmt.Fprintf(w, \"%s/%s\\t%s\\t%s\\n\", pkg.Owner, pkg.Repo, release, humanFriendlyTimestamp)\n\t}\n\tw.Flush()\n}\n\nfunc Initialize(path string) error {\n\tif !utils.DirExists(KelpDir) {\n\t\tlogging.LogDebug(\"Creating Kelp dir...\")\n\t\terr := os.Mkdir(KelpDir, 0777)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif !utils.DirExists(KelpCache) {\n\t\tlogging.LogDebug(\"Creating Kelp cache...\")\n\t\terr := os.Mkdir(KelpCache, 0777)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif !utils.DirExists(KelpBin) {\n\t\tlogging.LogDebug(\"Creating Kelp bin...\")\n\t\terr := os.Mkdir(KelpBin, 0777)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\t// create empty config\n\tkp := KelpPackage{\n\t\tOwner:       \"crhuber\",\n\t\tRepo:        \"kelp\",\n\t\tRelease:     \"latest\",\n\t\tUpdatedAt:   time.Now(),\n\t\tDescription: \"Simple homebrew alternative\",\n\t}\n\tkc := KelpConfig{\n\t\tPath:     path,\n\t\tPackages: []KelpPackage{kp},\n\t}\n\n\tif !utils.FileExists(path) {\n\t\tlogging.LogDebug(\"Creating Kelp config file...\")\n\t\terr := kc.Save()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tlogging.LogDebug(\"Skipping Kelp config file creation since one alredy exists...\")\n\t}\n\n\tlogging.LogInfo(\"🌱 Kelp Initialized!\")\n\tlogging.LogInfo(\"🗒  Add Kelp to your path by running: \\nexport PATH=%s:$PATH >> ~/.bash_profile\\n\", KelpBin)\n\treturn nil\n}\n\nfunc Inspect() {\n\tvar err error\n\tswitch types.GetOS() {\n\tcase types.Darwin:\n\t\terr = exec.Command(\"open\", KelpDir).Start()\n\tcase types.Linux:\n\t\terr = exec.Command(\"xdg-open\", KelpDir).Start()\n\tdefault:\n\t\terr = fmt.Errorf(\"unsupported platform\")\n\t}\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc Browse(owner, repo string) {\n\tvar err error\n\turl := fmt.Sprintf(\"https://github.com/%s/%s\", owner, repo)\n\tlogging.LogDebug(\"Opening %s\\n\", url)\n\n\tswitch types.GetOS() {\n\tcase types.Darwin:\n\t\terr = exec.Command(\"open\", url).Start()\n\tcase types.Linux:\n\t\terr = exec.Command(\"xdg-open\", url).Start()\n\tdefault:\n\t\terr = fmt.Errorf(\"unsupported platform\")\n\t}\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n\nfunc (kc *KelpConfig) Doctor() {\n\tw := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)\n\tfor _, p := range kc.Packages {\n\t\t// check alias first\n\t\tvar binary string\n\t\tif p.Binary != \"\" {\n\t\t\tbinary = p.Binary\n\t\t} else {\n\t\t\tbinary = p.Repo\n\t\t}\n\n\t\tstatus := \"\"\n\t\tpath, err := commandExists(binary)\n\t\tif err != nil {\n\t\t\tstatus = \"❌ Binary not found\"\n\t\t} else {\n\t\t\tif strings.HasPrefix(path, KelpBin) {\n\t\t\t\tstatus = \"✅ Installed\"\n\t\t\t} else {\n\t\t\t\tstatus = \"⛔️ Installed outside kelp\"\n\t\t\t}\n\t\t}\n\t\tlogging.LogInfo(\"%s\\t%s\\n\", binary, status)\n\t}\n\tw.Flush()\n}\n\nfunc commandExists(cmd string) (string, error) {\n\treturn exec.LookPath(cmd)\n}\n"
  },
  {
    "path": "pkg/install/install.go",
    "content": "package install\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"crhuber/kelp/pkg/config\"\n\t\"crhuber/kelp/pkg/logging\"\n\t\"crhuber/kelp/pkg/types\"\n\t\"crhuber/kelp/pkg/utils\"\n\n\t\"github.com/gabriel-vasile/mimetype\"\n\t\"github.com/mholt/archives\"\n\t\"github.com/schollz/progressbar/v3\"\n)\n\nfunc Install(owner, repo, release string) error {\n\t// handle http packages\n\ttempdir, _ := os.MkdirTemp(\"\", \"kelp\")\n\tdefer os.RemoveAll(tempdir)\n\n\tvar downloadPath string\n\n\tif strings.HasPrefix(release, \"http\") {\n\t\turlsplit := strings.SplitAfter(release, \"/\")\n\t\tfilename := urlsplit[len(urlsplit)-1]\n\t\tdownloadPath = filepath.Join(config.KelpCache, filename)\n\t\terr := downloadFile(downloadPath, release)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tasset, err := downloadGithubRelease(owner, repo, release)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdownloadPath = filepath.Join(config.KelpCache, asset.Name)\n\t}\n\terr := extractPackage(downloadPath, tempdir)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdestinations := installBinary(tempdir)\n\tif types.IsDarwin() {\n\t\tfor _, d := range destinations {\n\t\t\tunquarantineFile(d)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc unquarantineFile(filepath string) error {\n\tlogging.LogInfo(\"🛃 Unquarantining %s...\\n\", filepath)\n\tcmd := exec.Command(\"xattr\", \"-d\", \"com.apple.quarantine\", filepath)\n\treturn cmd.Run()\n}\n\n// downloadFile downloads files\nfunc downloadFile(filepath string, url string) error {\n\tlogging.LogInfo(\"===> Downloading %s...\\n\", url)\n\tlogging.LogDebug(\"To: %s...\\n\", filepath)\n\n\t// Get the data\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\t// set headers for github auth\n\tif ghToken := os.Getenv(\"GITHUB_TOKEN\"); ghToken != \"\" {\n\t\tlogging.LogDebug(\"Using Github token in http request\")\n\t\treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Bearer %s\", ghToken))\n\t}\n\treq.Header.Set(\"Accept\", \"application/octet-stream\")\n\tresp, err := http.DefaultClient.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"\\ninvalid HTTP status: %v\", resp.StatusCode)\n\t}\n\tdefer resp.Body.Close()\n\n\t// Create the file\n\tout, err := os.Create(filepath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer out.Close()\n\n\t// Write the body to file\n\tbar := progressbar.DefaultBytes(\n\t\tresp.ContentLength,\n\t\t\"Downloading\",\n\t)\n\t_, err = io.Copy(io.MultiWriter(out, bar), resp.Body)\n\treturn err\n}\n\nfunc extractPackage(downloadPath, tempDir string) error {\n\tlogging.LogInfo(\"📂 Extracting %s\\n\", downloadPath)\n\n\t// Handle dmg files\n\tif strings.HasSuffix(downloadPath, \".dmg\") {\n\t\treturn errors.New(\"kelp does not support dmg files\")\n\t}\n\n\t// Open the file\n\tfile, err := os.Open(downloadPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not open file: %w\", err)\n\t}\n\tdefer file.Close()\n\n\t// Try to identify archive format\n\tctx := context.Background()\n\tformat, stream, err := archives.Identify(ctx, downloadPath, file)\n\tif err != nil {\n\t\t// Not a recognized archive — treat as raw binary\n\t\tlogging.LogDebug(\"File is not a recognized archive format. Treating as raw binary.\")\n\t\tcleanName := cleanBinaryName(filepath.Base(downloadPath))\n\t\tdestPath := filepath.Join(tempDir, cleanName)\n\t\tif copyErr := utils.CopyFile(downloadPath, destPath); copyErr != nil {\n\t\t\treturn fmt.Errorf(\"could not copy binary to temp dir: %w\", copyErr)\n\t\t}\n\t\tos.Chmod(destPath, 0o755)\n\t\treturn nil\n\t}\n\n\t// Check if the format supports extraction\n\textractor, ok := format.(archives.Extractor)\n\tif !ok {\n\t\treturn fmt.Errorf(\"archive format does not support extraction\")\n\t}\n\n\t// Extract all files to destination directory\n\terr = extractor.Extract(ctx, stream, func(_ context.Context, f archives.FileInfo) error {\n\t\treturn extractFile(f, tempDir)\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"extraction failed: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// cleanBinaryName strips OS/arch suffixes from binary filenames.\n// For example, \"direnv.darwin-arm64\" becomes \"direnv\".\nfunc cleanBinaryName(name string) string {\n\tosNames := []string{\"darwin\", \"linux\", \"macos\", \"windows\"}\n\tarchNames := []string{\"arm64\", \"aarch64\", \"amd64\", \"x86_64\", \"x64\"}\n\tlower := strings.ToLower(name)\n\tfor _, osName := range osNames {\n\t\tfor _, arch := range archNames {\n\t\t\tfor _, sep := range []string{\"-\", \"_\"} {\n\t\t\t\t// os-arch: direnv.darwin-arm64\n\t\t\t\tsuffix := \".\" + osName + sep + arch\n\t\t\t\tif strings.HasSuffix(lower, suffix) {\n\t\t\t\t\treturn name[:len(name)-len(suffix)]\n\t\t\t\t}\n\t\t\t\t// arch-os: direnv.arm64-darwin\n\t\t\t\tsuffix = \".\" + arch + sep + osName\n\t\t\t\tif strings.HasSuffix(lower, suffix) {\n\t\t\t\t\treturn name[:len(name)-len(suffix)]\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn name\n}\n\n// Helper function to extract a single file\nfunc extractFile(f archives.FileInfo, destDir string) error {\n\textractPath := filepath.Join(destDir, f.NameInArchive)\n\n\tif f.IsDir() {\n\t\treturn os.MkdirAll(extractPath, f.Mode())\n\t}\n\n\tif err := os.MkdirAll(filepath.Dir(extractPath), 0o755); err != nil {\n\t\treturn err\n\t}\n\n\trc, err := f.Open()\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer rc.Close()\n\n\toutFile, err := os.OpenFile(extractPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, f.Mode())\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer outFile.Close()\n\n\t_, err = io.Copy(outFile, rc)\n\treturn err\n}\n\nfunc installBinary(tempDir string) []string {\n\tlogging.LogInfo(\"🧐 Checking for binary files in extract...\")\n\tfiles, err := utils.FilePathWalkDir(tempDir)\n\tif err != nil {\n\t\tlog.Panic(\"Could not walk directory\")\n\t}\n\tdestinations := []string{}\n\tosCap := types.GetCapabilities()\n\tvar foundLibs []string\n\tfor _, file := range files {\n\t\tmime, _ := mimetype.DetectFile(string(file))\n\t\t// only install binary files\n\t\tswitch mime.String() {\n\t\tcase osCap.ExecutableMime:\n\t\t\tdestinations = append(destinations, copyToKelpBin(file))\n\t\tcase osCap.SharedLibrary:\n\t\t\tsplits := strings.SplitAfter(file, \"/\")\n\t\t\tfileName := splits[len(splits)-1]\n\t\t\tlogging.LogDebug(\"Shared/Static Library file %s found in extract.\\n\", fileName)\n\t\t\tfoundLibs = append(foundLibs, file)\n\t\tdefault:\n\t\t\tlogging.LogDebug(\"Skipping non executable file: %v - %v\\n\", file, mime.String())\n\t\t}\n\t}\n\tif len(destinations) == 0 { // if no binary was found in extract, then filter shared libararies\n\t\tif len(foundLibs) == 1 {\n\t\t\tdestinations = append(destinations, copyToKelpBin(foundLibs[0]))\n\t\t} else {\n\t\t\tvar filteredLibs []string\n\t\t\tfor _, currentLib := range foundLibs {\n\t\t\t\tif !strings.HasPrefix(currentLib, \"lib\") && !strings.HasSuffix(currentLib, \"dynlib\") {\n\t\t\t\t\tfilteredLibs = append(filteredLibs, currentLib)\n\t\t\t\t} else {\n\t\t\t\t\tmime, _ := mimetype.DetectFile(string(currentLib))\n\t\t\t\t\tlogging.LogDebug(\"Skipping non executable file: %v - %v\\n\", currentLib, mime.String())\n\t\t\t\t}\n\t\t\t}\n\t\t\tif len(filteredLibs) == 1 {\n\t\t\t\tdestinations = append(destinations, copyToKelpBin(filteredLibs[0]))\n\t\t\t} else {\n\t\t\t\tfor _, currentUnrecognizedLib := range filteredLibs {\n\t\t\t\t\tmime, _ := mimetype.DetectFile(string(currentUnrecognizedLib))\n\t\t\t\t\tlogging.LogDebug(\"Skipping non executable file: %v - %v\\n\", currentUnrecognizedLib, mime.String())\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn destinations\n}\n\nfunc copyToKelpBin(file string) string {\n\tsplits := strings.SplitAfter(file, \"/\")\n\tfileName := splits[len(splits)-1]\n\tlogging.LogDebug(\"Binary file %s found in extract.\\n\", fileName)\n\tdestination := filepath.Join(config.KelpBin, fileName)\n\tlogging.LogInfo(\"💾 Copying %v to kelp bin...\\n\", fileName)\n\tutils.CopyFile(file, destination)\n\tlogging.LogInfo(\"✅ Installed %v !\\n\", fileName)\n\treturn destination\n}\n\nfunc downloadGithubRelease(owner, repo, release string) (*types.Asset, error) {\n\tlogging.LogInfo(\"===> Installing %s/%s:%s...\\n\", owner, repo, release)\n\tghr, err := utils.GetGithubRelease(owner, repo, release)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlogging.LogInfo(\"🍏 Finding assets to download...\")\n\tdownloadableAsset, err := ghr.FindBestAsset(types.GetCapabilities())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdownloadPath := filepath.Join(config.KelpCache, downloadableAsset.Name)\n\tif utils.FileExists(downloadPath) {\n\t\tlogging.LogDebug(\"File %v already exists in cache, skipping download.\\n\", downloadableAsset.Name)\n\t} else {\n\t\terr := downloadFile(downloadPath, downloadableAsset.URL)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\treturn downloadableAsset, nil\n}\n"
  },
  {
    "path": "pkg/install/install_test.go",
    "content": "package install\n\nimport \"testing\"\n\nfunc TestCleanBinaryName(t *testing.T) {\n\ttests := []struct {\n\t\tinput string\n\t\twant  string\n\t}{\n\t\t{\"direnv.darwin-arm64\", \"direnv\"},\n\t\t{\"direnv.darwin-amd64\", \"direnv\"},\n\t\t{\"direnv.linux-arm64\", \"direnv\"},\n\t\t{\"direnv.linux-amd64\", \"direnv\"},\n\t\t{\"tool.darwin_arm64\", \"tool\"},\n\t\t{\"tool.linux_amd64\", \"tool\"},\n\t\t{\"tool.arm64-darwin\", \"tool\"},\n\t\t{\"tool.amd64-linux\", \"tool\"},\n\t\t{\"tool.macos-arm64\", \"tool\"},\n\t\t{\"tool.windows-x86_64\", \"tool\"},\n\t\t{\"tool.linux-aarch64\", \"tool\"},\n\t\t{\"tool.darwin-x64\", \"tool\"},\n\t\t// No matching suffix — returned as-is\n\t\t{\"mybinary\", \"mybinary\"},\n\t\t{\"archive.tar.gz\", \"archive.tar.gz\"},\n\t\t{\"tool.v1.2.3\", \"tool.v1.2.3\"},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.input, func(t *testing.T) {\n\t\t\tgot := cleanBinaryName(tt.input)\n\t\t\tif got != tt.want {\n\t\t\t\tt.Errorf(\"cleanBinaryName(%q) = %q, want %q\", tt.input, got, tt.want)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "pkg/logging/logging.go",
    "content": "package logging\n\nimport \"log\"\n\nvar logVerbose = false\n\nfunc SetLogVerbose(verbose bool) {\n\tlogVerbose = verbose\n}\n\nfunc LogDebug(message string, args ...any) {\n\tif logVerbose {\n\t\tlog.Printf(message, args...)\n\t}\n}\n\nfunc LogInfo(message string, args ...any) {\n\tlog.Printf(message, args...)\n}\n\nfunc init() {\n\t// set log output to the simplest as possible, without anything but the message\n\tlog.SetFlags(0)\n}\n"
  },
  {
    "path": "pkg/rm/rm.go",
    "content": "package rm\n\nimport (\n\t\"crhuber/kelp/pkg/config\"\n\t\"crhuber/kelp/pkg/logging\"\n\t\"crhuber/kelp/pkg/utils\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc RemoveBinary(binary string) error {\n\tbinaryPath := filepath.Join(config.KelpBin, binary)\n\tif utils.FileExists(binaryPath) {\n\t\tlogging.LogInfo(\"Removing binary %s...\", binary)\n\t\treturn os.Remove(binaryPath)\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "pkg/types/github.go",
    "content": "package types\n\nimport (\n\t\"crhuber/kelp/pkg/logging\"\n\t\"errors\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Asset represents a downloadable asset from a Github release\ntype Asset struct {\n\tURL                string    `json:\"url\"`\n\tID                 int       `json:\"id\"`\n\tName               string    `json:\"name\"`\n\tLabel              string    `json:\"label\"`\n\tContentType        string    `json:\"content_type\"`\n\tState              string    `json:\"state\"`\n\tSize               int       `json:\"size\"`\n\tDownloadCount      int       `json:\"download_count\"`\n\tCreatedAt          time.Time `json:\"created_at\"`\n\tUpdatedAt          time.Time `json:\"updated_at\"`\n\tBrowserDownloadURL string    `json:\"browser_download_url\"`\n}\n\n// GithubRelease represents a Github release\ntype GithubRelease struct {\n\tURL             string    `json:\"url\"`\n\tAssetsURL       string    `json:\"assets_url\"`\n\tUploadURL       string    `json:\"upload_url\"`\n\tHTMLURL         string    `json:\"html_url\"`\n\tID              int       `json:\"id\"`\n\tTagName         string    `json:\"tag_name\"`\n\tTargetCommitish string    `json:\"target_commitish\"`\n\tName            string    `json:\"name\"`\n\tDraft           bool      `json:\"draft\"`\n\tPrerelease      bool      `json:\"prerelease\"`\n\tCreatedAt       time.Time `json:\"created_at\"`\n\tPublishedAt     time.Time `json:\"published_at\"`\n\tAssets          []Asset   `json:\"assets\"`\n\tBody            string    `json:\"body\"`\n}\n\n// methods\n\nfunc (a *Asset) isDownloadableExtension() bool {\n\tdownLoadableExtension := []string{\".zip\", \".tar\", \".gz\", \".xz\", \".dmg\", \".pkg\", \".tgz\", \".bz2\"}\n\tfor _, word := range downLoadableExtension {\n\t\tresult := strings.HasSuffix(a.BrowserDownloadURL, word)\n\t\tif result {\n\t\t\treturn result\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (a *Asset) isChecksumFile() bool {\n\tchecksumExtension := []string{\".asc\", \".sha256.asc\", \".sha512.asc\", \".sha256sum.asc\", \".sha512sum.asc\", \".sha1.asc\", \".md5.asc\"}\n\tfor _, word := range checksumExtension {\n\t\tif strings.HasSuffix(a.BrowserDownloadURL, word) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (a *Asset) hasNoExtension() bool {\n\tbdu := strings.SplitAfter(a.BrowserDownloadURL, \"/\")\n\tfilename := bdu[len(bdu)-1]\n\treturn !strings.Contains(filename, \".\")\n}\n\n// IsMacAsset checks if the download url contains \"mac\", \"macos\", \"darwin\", \"osx\", \"apple\" and returns true if so\nfunc (a *Asset) isMacAsset() bool {\n\tmacIdentifiers := []string{\"mac\", \"macos\", \"darwin\", \"osx\", \"apple\"}\n\n\tfor _, word := range macIdentifiers {\n\t\tresult := strings.Contains(strings.ToLower(a.BrowserDownloadURL), word)\n\t\tif result {\n\t\t\treturn result\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (a *Asset) isLinuxAsset() bool {\n\tmacIdentifiers := []string{\"linux\"}\n\n\tfor _, word := range macIdentifiers {\n\t\tresult := strings.Contains(strings.ToLower(a.BrowserDownloadURL), word)\n\t\tif result {\n\t\t\treturn result\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (a *Asset) isSameOS(capabilities *Capabilities) bool {\n\tswitch capabilities.OS {\n\tcase Darwin:\n\t\treturn a.isMacAsset()\n\tcase Linux:\n\t\treturn a.isLinuxAsset()\n\t}\n\treturn false\n}\n\nfunc (a *Asset) isSameArchitecture(capabilities *Capabilities) bool {\n\tlowerURL := strings.ToLower(a.BrowserDownloadURL)\n\n\t// First check if the URL contains the exact arch name\n\tif strings.Contains(lowerURL, strings.ToLower(capabilities.Arch)) {\n\t\treturn true\n\t}\n\n\t// Then handle architecture aliases\n\tswitch capabilities.Arch {\n\tcase \"amd64\":\n\t\treturn strings.Contains(lowerURL, \"x86_64\")\n\tcase \"arm64\":\n\t\treturn strings.Contains(lowerURL, \"arm64\") || strings.Contains(lowerURL, \"aarch64\")\n\tdefault:\n\t\treturn false\n\t}\n}\n\nconst (\n\tMIN_ASSET_SCORE = 6 // minimum score for an asset to be considered suitable for download\n)\n\nfunc (a *Asset) EvaluateSuitability(capabilities *Capabilities) int {\n\tassetScore := 0\n\tif a.isSameOS(capabilities) {\n\t\tassetScore += 4\n\t}\n\tif a.isSameArchitecture(capabilities) {\n\t\tassetScore += 3\n\t}\n\tif a.isDownloadableExtension() {\n\t\tassetScore += 2\n\t}\n\tif a.hasNoExtension() {\n\t\tassetScore += 1\n\t}\n\tif a.isChecksumFile() {\n\t\tassetScore -= 10\n\t}\n\treturn assetScore\n}\n\nfunc (a *Asset) RealFilename() string {\n\tif a.Name != \"\" {\n\t\treturn a.Name\n\t}\n\turl := a.URL\n\tif url == \"\" {\n\t\turl = a.BrowserDownloadURL\n\t}\n\tfilename := strings.Split(url, \"/\")\n\treturn filename[len(filename)-1]\n}\n\n// A data structure to hold key/value pairs\ntype Pair struct {\n\tKey   int\n\tValue int\n}\n\n// A slice of pairs that implements sort.Interface to sort by values\ntype PairList []Pair\n\nfunc (p PairList) Len() int           { return len(p) }\nfunc (p PairList) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }\nfunc (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value }\n\nfunc (ghr *GithubRelease) FindBestAsset(capabilities *Capabilities) (*Asset, error) {\n\tvar bestAsset Asset\n\n\tassetScores := map[int]int{}\n\tfor index, asset := range ghr.Assets {\n\t\tif assetScore := asset.EvaluateSuitability(capabilities); assetScore >= MIN_ASSET_SCORE {\n\t\t\tlogging.LogDebug(\"Found suitable candidate %v for download. Score: %v\", asset.RealFilename(), assetScore)\n\t\t\tassetScores[index] = assetScore\n\t\t}\n\t}\n\tif len(assetScores) == 0 {\n\t\t// inspect the release body for links to downloadable assets\n\t\tlinks := ghr.inspectLinksInReleaseBody()\n\t\t// create a list of assets from the links and evaluate them\n\t\tassetsFromBodyScores := map[int]int{}\n\t\tassetLinks := make([]Asset, len(links))\n\t\tfor index, link := range links {\n\t\t\tfilename := strings.Split(link, \"/\")\n\t\t\trealFilename := filename[len(filename)-1]\n\t\t\ta := Asset{\n\t\t\t\tBrowserDownloadURL: link,\n\t\t\t\tURL:                link,\n\t\t\t\tName:               realFilename,\n\t\t\t}\n\t\t\tassetLinks[index] = a\n\t\t\tif assetScore := a.EvaluateSuitability(capabilities); assetScore >= MIN_ASSET_SCORE {\n\t\t\t\tlogging.LogDebug(\"Found suitable candidate %v for download in release body. Score: %v\", realFilename, assetScore)\n\t\t\t\tassetsFromBodyScores[index] = assetScore\n\t\t\t}\n\t\t}\n\t\tif len(assetsFromBodyScores) == 0 {\n\t\t\treturn nil, errors.New(\"no suitable candidates found in release body\")\n\t\t}\n\t\t// sort the map by value of score.\n\t\thighest := getHighestScore(assetsFromBodyScores)\n\t\tbestAsset = assetLinks[highest.Key]\n\t} else {\n\t\t// sort the map by value of score.\n\t\thighest := getHighestScore(assetScores)\n\t\tbestAsset = ghr.Assets[highest.Key]\n\t}\n\n\tlogging.LogDebug(\"Adding highest ranked asset %v to download queue.\", bestAsset.RealFilename())\n\treturn &bestAsset, nil\n}\n\nfunc getHighestScore(assetScores map[int]int) Pair {\n\t// sort the map by value of score.\n\tassetsByScore := make(PairList, len(assetScores))\n\ti := 0\n\tfor k, v := range assetScores {\n\t\tassetsByScore[i] = Pair{k, v}\n\t\ti++\n\t}\n\tsort.Sort(assetsByScore)\n\t// return highest\n\treturn assetsByScore[len(assetsByScore)-1]\n}\n\nfunc (ghr *GithubRelease) inspectLinksInReleaseBody() []string {\n\tconst (\n\t\tNAME_REGEXP      = `([a-z][a-z0-9_-]+?)`\n\t\tARCH_REGEXP      = `[._-](amd64|x86_64|x64|arm64|aarch64)`\n\t\tOS_REGEXP        = `[._-]((unknown[._-])?(linux|linux-gnu|linux-musl))|((apple[._-])?(darwin|macos|osx))`\n\t\tVERSION_REGEXP   = `([_-]v?[0-9.]+)?`\n\t\tSUFFIX_REGEXP    = `([_-][a-z0-9_-]+)?`\n\t\tEXTENSION_REGEXP = `(\\.zip|\\.tar\\.gz|\\.gz|\\.tgz|\\.tar\\.xz|\\.txz|\\.tar\\.bz2|\\.tbz)?`\n\t\tREGEXP           = NAME_REGEXP + VERSION_REGEXP + \"(\" + OS_REGEXP + ARCH_REGEXP + \"|\" + ARCH_REGEXP + OS_REGEXP + \")\" + SUFFIX_REGEXP + EXTENSION_REGEXP\n\t)\n\tre := regexp.MustCompile(`https:\\/\\/[a-z0-9.\\/]+\\/` + REGEXP)\n\tmatches := re.FindAllString(ghr.Body, -1)\n\t// remove duplicates\n\tsort.Strings(matches)\n\t// remove duplicates\n\tseen := make(map[string]bool)\n\tresult := make([]string, 0)\n\tfor _, item := range matches {\n\t\tif !seen[item] {\n\t\t\tseen[item] = true\n\t\t\tresult = append(result, item)\n\t\t}\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "pkg/types/github_test.go",
    "content": "package types\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestEvalAssetSuitabilityDarwin(t *testing.T) {\n\tt.Parallel()\n\t// pluto_4.2.0_darwin_amd64.tar.gz = 9\n\t// ruplacer-osx = 6\n\t// croc_9.2.0_macOS-64bit.tar.gz = 7\n\t// conftest_0.28.1_Darwin_x86_64.tar.gz = 7\n\t// conftest_0.28.1_Darwin_arm64.tar.gz = 6\n\t// pandoc-2.14.2-macOS.pkg = 6\n\t// direnv.darwin-amd64 =8\n\tosCap := &Capabilities{\n\t\tOS:             Darwin,\n\t\tExecutableMime: \"application/x-mach-binary\",\n\t\tArch:           \"arm64\",\n\t}\n\tasset := Asset{\n\t\tBrowserDownloadURL: \"https://github.com/foo/bar/releases/download/v1.0/direnv.darwin-arm64\",\n\t}\n\trequire.Equal(t, 7, asset.EvaluateSuitability(osCap))\n\t// pluto_4.2.0_darwin_amd64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/pluto_4.2.0_darwin_arm64.tar.gz\"\n\trequire.Equal(t, 9, asset.EvaluateSuitability(osCap))\n\t// ruplacer-osx\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/ruplacer-osx\"\n\trequire.Equal(t, 5, asset.EvaluateSuitability(osCap))\n\t// croc_9.2.0_macOS-64bit.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/croc_9.2.0_macOS-64bit.tar.gz\"\n\trequire.Equal(t, 6, asset.EvaluateSuitability(osCap))\n\t// conftest_0.28.1_Darwin_x86_64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/conftest_0.28.1_Darwin_x86_64.tar.gz\"\n\trequire.Equal(t, 6, asset.EvaluateSuitability(osCap))\n\t// conftest_0.28.1_Darwin_arm64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/conftest_0.28.1_Darwin_arm64.tar.gz\"\n\trequire.Equal(t, 9, asset.EvaluateSuitability(osCap))\n\t// pandoc-2.14.2-macOS.pkg\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/pandoc-2.14.2-macOS.pkg\"\n\trequire.Equal(t, 6, asset.EvaluateSuitability(osCap))\n\t// gopass-1.15.11-darwin-amd64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/gopass-1.15.11-darwin-amd64.tar.gz\"\n\trequire.Equal(t, 6, asset.EvaluateSuitability(osCap))\n\t// gopass-1.15.11-darwin-arm64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/gopass-1.15.11-darwin-arm64.tar.gz\"\n\trequire.Equal(t, 9, asset.EvaluateSuitability(osCap))\n}\n\nfunc TestEvalAssetSuitabilityLinux(t *testing.T) {\n\tt.Parallel()\n\t// pluto_4.2.0_darwin_amd64.tar.gz = 9\n\t// ruplacer-osx = 6\n\t// croc_9.2.0_macOS-64bit.tar.gz = 7\n\t// conftest_0.28.1_Darwin_x86_64.tar.gz = 7\n\t// conftest_0.28.1_Darwin_arm64.tar.gz = 6\n\t// pandoc-2.14.2-macOS.pkg = 6\n\t// direnv.darwin-amd64 =8\n\t// helm-v4.0.4-linux-arm64.tar.gz.asc <0\n\tosCap := &Capabilities{\n\t\tOS:             Linux,\n\t\tExecutableMime: \"asdf\",\n\t\tArch:           \"amd64\",\n\t}\n\tasset := Asset{\n\t\tBrowserDownloadURL: \"https://github.com/foo/bar/releases/download/v1.0/direnv.linux-amd64\",\n\t}\n\trequire.Equal(t, 7, asset.EvaluateSuitability(osCap))\n\t// pluto_4.2.0_darwin_amd64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/pluto_4.2.0_linux_amd64.tar.gz\"\n\trequire.Equal(t, 9, asset.EvaluateSuitability(osCap))\n\t// ruplacer-osx\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/ruplacer-linux\"\n\trequire.Equal(t, 5, asset.EvaluateSuitability(osCap))\n\t// croc_9.2.0_macOS-64bit.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/croc_9.2.0_linuX-64bit.tar.gz\"\n\trequire.Equal(t, 6, asset.EvaluateSuitability(osCap))\n\t// conftest_0.28.1_Darwin_x86_64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/conftest_0.28.1_Linux_x86_64.tar.gz\"\n\trequire.Equal(t, 9, asset.EvaluateSuitability(osCap))\n\t// conftest_0.28.1_Darwin_arm64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/conftest_0.28.1_Linux_arm64.tar.gz\"\n\trequire.Equal(t, 6, asset.EvaluateSuitability(osCap))\n\t// pandoc-2.14.2-macOS.pkg\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/pandoc-2.14.2-linux.pkg\"\n\trequire.Equal(t, 6, asset.EvaluateSuitability(osCap))\n\t// gopass-1.15.11-darwin-amd64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/gopass-1.15.11-linux-arm64.tar.gz\"\n\trequire.Equal(t, 6, asset.EvaluateSuitability(osCap))\n\t// gopass-1.15.11-darwin-arm64.tar.gz\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/gopass-1.15.11-linux-amd64.tar.gz\"\n\trequire.Equal(t, 9, asset.EvaluateSuitability(osCap))\n\t// helm-v4.0.4-linux-arm64.tar.gz.asc\n\tasset.BrowserDownloadURL = \"https://github.com/foo/bar/releases/download/v1.0/helm-v4.0.4-linux-arm64.tar.gz.asc\"\n\trequire.Less(t, asset.EvaluateSuitability(osCap), 0)\n}\n\nfunc TestFindGithubReleaseMacAssets(t *testing.T) {\n\tt.Parallel()\n\tvar assets []Asset\n\tasset1 := Asset{\n\t\tBrowserDownloadURL: \"https://github.com/trufflesecurity/trufflehog/releases/download/v3.60.1/trufflehog_3.60.1_linux_amd64.tar.gz\",\n\t}\n\tasset2 := Asset{\n\t\tBrowserDownloadURL: \"https://github.com/trufflesecurity/trufflehog/releases/download/v3.60.1/trufflehog_3.60.1_linux_arm64.tar.gz\",\n\t}\n\tassets = append(assets, asset1, asset2)\n\n\tghr := GithubRelease{\n\t\tAssets: assets,\n\t}\n\n\tcapAMD64 := &Capabilities{\n\t\tOS:   Linux,\n\t\tArch: \"amd64\",\n\t}\n\tcapARM64 := &Capabilities{\n\t\tOS:   Linux,\n\t\tArch: \"arm64\",\n\t}\n\tdownloadableAsset, _ := ghr.FindBestAsset(capAMD64)\n\trequire.Equal(t, asset1, *downloadableAsset)\n\n\tdownloadableAsset, _ = ghr.FindBestAsset(capARM64)\n\trequire.Equal(t, asset2, *downloadableAsset)\n}\n\nfunc TestGetHighestScore(t *testing.T) {\n\tt.Parallel()\n\tassetScores := map[int]int{}\n\tassetScores[0] = 6\n\tassetScores[1] = 8\n\tassetScores[2] = 1\n\tassetScores[3] = 9\n\tassetScores[4] = 3\n\tassetsByScore := getHighestScore(assetScores)\n\trequire.Equal(t, assetsByScore.Value, assetScores[3])\n}\n\nfunc TestInspectLinksInReleaseBody(t *testing.T) {\n\tt.Parallel()\n\tfilename := filepath.Join(\"..\", \"..\", \"testdata\", \"helm-latest.json\")\n\tjsonBytes, err := os.ReadFile(filename)\n\tif err != nil {\n\t\tt.Fatal(\"error reading testdata: \", err)\n\t}\n\tghr := GithubRelease{}\n\tif err := json.Unmarshal(jsonBytes, &ghr); err != nil {\n\t\tt.Fatal(\"error unmarshalling testdata: \", err)\n\t}\n\tasset, err := ghr.FindBestAsset(&Capabilities{\n\t\tOS:   Linux,\n\t\tArch: \"amd64\",\n\t})\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"helm-v4.0.4-linux-amd64.tar.gz\", asset.Name)\n\trequire.Contains(t, asset.BrowserDownloadURL, \"get.helm.sh\")\n}\n"
  },
  {
    "path": "pkg/types/os.go",
    "content": "package types\n\nimport (\n\t\"runtime\"\n)\n\ntype OS int\n\nconst (\n\tDarwin OS = iota\n\tLinux\n)\n\nfunc IsDarwin() bool {\n\treturn runtime.GOOS == \"darwin\"\n}\n\nfunc IsLinux() bool {\n\treturn runtime.GOOS == \"linux\"\n}\n\ntype Capabilities struct {\n\tOS             OS\n\tExecutableMime string\n\tSharedLibrary  string\n\tArch           string\n}\n\nfunc GetOS() OS {\n\tif runtime.GOOS == \"darwin\" {\n\t\treturn Darwin\n\t}\n\tif runtime.GOOS == \"linux\" {\n\t\treturn Linux\n\t}\n\treturn -1\n}\n\nvar current *Capabilities\n\nfunc GetCapabilities() *Capabilities {\n\tif current != nil {\n\t\treturn current\n\t}\n\n\tswitch runtime.GOOS {\n\tcase \"darwin\":\n\t\tcurrent = &Capabilities{OS: Darwin, ExecutableMime: \"application/x-mach-binary\", SharedLibrary: \"application/x-sharedlib\"}\n\tcase \"linux\":\n\t\tcurrent = &Capabilities{OS: Linux, ExecutableMime: \"application/x-executable\", SharedLibrary: \"application/x-sharedlib\"}\n\t}\n\tcurrent.Arch = runtime.GOARCH\n\treturn current\n}\n"
  },
  {
    "path": "pkg/utils/utils.go",
    "content": "package utils\n\nimport (\n\t\"crhuber/kelp/pkg/logging\"\n\t\"crhuber/kelp/pkg/types\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\nfunc DirExists(dir string) bool {\n\tinfo, err := os.Stat(dir)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn info.IsDir()\n}\n\nfunc FileExists(filename string) bool {\n\tinfo, err := os.Stat(filename)\n\treturn !os.IsNotExist(err) && !info.IsDir()\n}\n\nfunc FilePathWalkDir(root string) ([]string, error) {\n\tvar files []string\n\terr := filepath.Walk(root, func(path string, info os.FileInfo, _ error) error {\n\t\tif !info.IsDir() {\n\t\t\tfiles = append(files, path)\n\t\t}\n\t\treturn nil\n\t})\n\treturn files, err\n}\n\nfunc CopyFile(source, destination string) error {\n\tfrom, err := os.Open(source)\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tdefer from.Close()\n\n\tto, err := os.OpenFile(destination, os.O_RDWR|os.O_CREATE, 0744)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer to.Close()\n\n\t_, err = io.Copy(to, from)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}\n\nfunc GetGithubRelease(owner, repo, release string) (*types.GithubRelease, error) {\n\tvar url string\n\tif release == \"latest\" {\n\t\tlogging.LogInfo(\"🌐 Getting releases for %s/%s:%s...\", owner, repo, release)\n\t\turl = fmt.Sprintf(\"https://api.github.com/repos/%s/%s/releases/%s\", owner, repo, release)\n\n\t} else {\n\t\t// try by tag\n\t\tlogging.LogInfo(\"🌐 Getting releases by tag %s...\", release)\n\t\turl = fmt.Sprintf(\"https://api.github.com/repos/%s/%s/releases/tags/%s\", owner, repo, release)\n\t}\n\n\t// create client\n\tclient := &http.Client{}\n\treq, err := http.NewRequest(\"GET\", url, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// set headers for github auth\n\tghToken := os.Getenv(\"GITHUB_TOKEN\")\n\tif ghToken != \"\" {\n\t\tlogging.LogDebug(\"Using Github token in http request\")\n\t\treq.Header.Set(\"Authorization\", fmt.Sprintf(\"Bearer %s\", ghToken))\n\t}\n\n\t// make request\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"invalid HTTP status: %v\", resp.StatusCode)\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tghr := types.GithubRelease{}\n\tif err := json.Unmarshal(body, &ghr); err != nil {\n\t\treturn nil, err\n\t}\n\treturn &ghr, nil\n}\n"
  },
  {
    "path": "pkg/utils/utils_test.go",
    "content": "package utils\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/h2non/gock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestGetGithubRelease(t *testing.T) {\n\tdefer gock.Off()\n\n\tfilename := filepath.Join(\"..\", \"..\", \"testdata\", \"helm-latest.json\")\n\tjsonBytes, err := os.ReadFile(filename)\n\tif err != nil {\n\t\tt.Fatal(\"error reading testdata: \", err)\n\t}\n\tgock.New(\"https://api.github.com\").\n\t\tGet(\"/repos/helm/helm/releases/latest\").\n\t\tReply(200).\n\t\tJSON(jsonBytes)\n\tghr, err := GetGithubRelease(\"helm\", \"helm\", \"latest\")\n\trequire.NoError(t, err)\n\trequire.Equal(t, \"v4.0.4\", ghr.TagName)\n}\n"
  },
  {
    "path": "testdata/helm-latest.json",
    "content": "{\n  \"url\": \"https://api.github.com/repos/helm/helm/releases/270052681\",\n  \"assets_url\": \"https://api.github.com/repos/helm/helm/releases/270052681/assets\",\n  \"upload_url\": \"https://uploads.github.com/repos/helm/helm/releases/270052681/assets{?name,label}\",\n  \"html_url\": \"https://github.com/helm/helm/releases/tag/v4.0.4\",\n  \"id\": 270052681,\n  \"author\": {\n    \"login\": \"scottrigby\",\n    \"id\": 407675,\n    \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n    \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n    \"gravatar_id\": \"\",\n    \"url\": \"https://api.github.com/users/scottrigby\",\n    \"html_url\": \"https://github.com/scottrigby\",\n    \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n    \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n    \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n    \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n    \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n    \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n    \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n    \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n    \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n    \"type\": \"User\",\n    \"user_view_type\": \"public\",\n    \"site_admin\": false\n  },\n  \"node_id\": \"RE_kwDOApspmc4QGK1J\",\n  \"tag_name\": \"v4.0.4\",\n  \"target_commitish\": \"main\",\n  \"name\": \"Helm v4.0.4\",\n  \"draft\": false,\n  \"immutable\": false,\n  \"prerelease\": false,\n  \"created_at\": \"2025-12-13T01:05:06Z\",\n  \"updated_at\": \"2025-12-13T01:23:13Z\",\n  \"published_at\": \"2025-12-13T01:22:50Z\",\n  \"assets\": [\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071815\",\n      \"id\": 328071815,\n      \"node_id\": \"RA_kwDOApspmc4TjfqH\",\n      \"name\": \"helm-v4.0.4-darwin-amd64.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:943463856d9a7da8abfdb6421e2b7bef3197565b32ecea04bfb0a93fa15db2fe\",\n      \"download_count\": 266,\n      \"created_at\": \"2025-12-13T01:23:08Z\",\n      \"updated_at\": \"2025-12-13T01:23:08Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-darwin-amd64.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071822\",\n      \"id\": 328071822,\n      \"node_id\": \"RA_kwDOApspmc4TjfqO\",\n      \"name\": \"helm-v4.0.4-darwin-amd64.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:5c0fcfab9868357ab5f540c6d470c3cf0c9373ab33d353f56914ba1731b656be\",\n      \"download_count\": 170,\n      \"created_at\": \"2025-12-13T01:23:08Z\",\n      \"updated_at\": \"2025-12-13T01:23:08Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-darwin-amd64.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071823\",\n      \"id\": 328071823,\n      \"node_id\": \"RA_kwDOApspmc4TjfqP\",\n      \"name\": \"helm-v4.0.4-darwin-amd64.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:1db897efd998fcadc5edd249a828b5d0401d6c2bd643828d9c528f607362e458\",\n      \"download_count\": 172,\n      \"created_at\": \"2025-12-13T01:23:08Z\",\n      \"updated_at\": \"2025-12-13T01:23:08Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-darwin-amd64.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071827\",\n      \"id\": 328071827,\n      \"node_id\": \"RA_kwDOApspmc4TjfqT\",\n      \"name\": \"helm-v4.0.4-darwin-arm64.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:fd44bbc3d2b875ad61713fd13de0dff34864d5c52381c7247bd1dfbebbc7316a\",\n      \"download_count\": 187,\n      \"created_at\": \"2025-12-13T01:23:08Z\",\n      \"updated_at\": \"2025-12-13T01:23:09Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-darwin-arm64.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071832\",\n      \"id\": 328071832,\n      \"node_id\": \"RA_kwDOApspmc4TjfqY\",\n      \"name\": \"helm-v4.0.4-darwin-arm64.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:538510d78f375c6b2ef7d7b87ce33ee279680c32a670a33317c5c7a71228eee0\",\n      \"download_count\": 147,\n      \"created_at\": \"2025-12-13T01:23:08Z\",\n      \"updated_at\": \"2025-12-13T01:23:09Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-darwin-arm64.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071835\",\n      \"id\": 328071835,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqb\",\n      \"name\": \"helm-v4.0.4-darwin-arm64.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:6f6b2b3704ba05d7357563868335155f0d4b2852f430b57bd167486ee8b481b9\",\n      \"download_count\": 153,\n      \"created_at\": \"2025-12-13T01:23:09Z\",\n      \"updated_at\": \"2025-12-13T01:23:09Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-darwin-arm64.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071838\",\n      \"id\": 328071838,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqe\",\n      \"name\": \"helm-v4.0.4-linux-386.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:02fa09a1e5f6f40b33e1fe7a8e404cced85f47480c3d272f4d75f297afe64b8f\",\n      \"download_count\": 219,\n      \"created_at\": \"2025-12-13T01:23:09Z\",\n      \"updated_at\": \"2025-12-13T01:23:09Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-386.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071840\",\n      \"id\": 328071840,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqg\",\n      \"name\": \"helm-v4.0.4-linux-386.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:ced78ed6756b7820b764b9487e7bee13d259ce8d943a1b6ad27f478b1bf019ed\",\n      \"download_count\": 164,\n      \"created_at\": \"2025-12-13T01:23:09Z\",\n      \"updated_at\": \"2025-12-13T01:23:09Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-386.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071842\",\n      \"id\": 328071842,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqi\",\n      \"name\": \"helm-v4.0.4-linux-386.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:b33b73be03e14589873a63b59a01ddd2f75d63d6783b206abcf1ca3a29f9359d\",\n      \"download_count\": 166,\n      \"created_at\": \"2025-12-13T01:23:09Z\",\n      \"updated_at\": \"2025-12-13T01:23:09Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-386.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071844\",\n      \"id\": 328071844,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqk\",\n      \"name\": \"helm-v4.0.4-linux-amd64.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:37184ca689c09c8fbe67801b3c0c6da602013f84514f18a5da40351fb16e716d\",\n      \"download_count\": 6591,\n      \"created_at\": \"2025-12-13T01:23:09Z\",\n      \"updated_at\": \"2025-12-13T01:23:09Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-amd64.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071849\",\n      \"id\": 328071849,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqp\",\n      \"name\": \"helm-v4.0.4-linux-amd64.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:970ce8c0f959eb632867991e769ac0bcd8121bce15c4960f89d4cfe369268b03\",\n      \"download_count\": 6101,\n      \"created_at\": \"2025-12-13T01:23:09Z\",\n      \"updated_at\": \"2025-12-13T01:23:10Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-amd64.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071850\",\n      \"id\": 328071850,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqq\",\n      \"name\": \"helm-v4.0.4-linux-amd64.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:d3255c9bb0a7a12fa18998ba2b0bb0f1704c0fea07bf45c8a078274376bfebe0\",\n      \"download_count\": 205,\n      \"created_at\": \"2025-12-13T01:23:10Z\",\n      \"updated_at\": \"2025-12-13T01:23:10Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-amd64.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071851\",\n      \"id\": 328071851,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqr\",\n      \"name\": \"helm-v4.0.4-linux-arm.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:3bfc27ba402781a4ebd20a2afddca7ec31f3ae0ef66317f769ae9c4840cd03cd\",\n      \"download_count\": 146,\n      \"created_at\": \"2025-12-13T01:23:10Z\",\n      \"updated_at\": \"2025-12-13T01:23:10Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-arm.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071853\",\n      \"id\": 328071853,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqt\",\n      \"name\": \"helm-v4.0.4-linux-arm.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:b7d7ed2334381758e159154c649b4045bca08c8aff72caf22ced967e2e10746d\",\n      \"download_count\": 137,\n      \"created_at\": \"2025-12-13T01:23:10Z\",\n      \"updated_at\": \"2025-12-13T01:23:10Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-arm.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071856\",\n      \"id\": 328071856,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqw\",\n      \"name\": \"helm-v4.0.4-linux-arm.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:98694fe87b905ca078bc844dd1e9b6ed8bf73e761fda33fcb11acfb0fdd4a56f\",\n      \"download_count\": 139,\n      \"created_at\": \"2025-12-13T01:23:10Z\",\n      \"updated_at\": \"2025-12-13T01:23:10Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-arm.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071858\",\n      \"id\": 328071858,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqy\",\n      \"name\": \"helm-v4.0.4-linux-arm64.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:29f58b92bc616ff27a96157c89f4c71b44ad74ff2b93225ef7e5bf6f04ca6444\",\n      \"download_count\": 1328,\n      \"created_at\": \"2025-12-13T01:23:10Z\",\n      \"updated_at\": \"2025-12-13T01:23:10Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-arm64.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071859\",\n      \"id\": 328071859,\n      \"node_id\": \"RA_kwDOApspmc4Tjfqz\",\n      \"name\": \"helm-v4.0.4-linux-arm64.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:85c2c1b29af5020aee6f865830ca7c78535582c08961e442c3841edfc4ae9bc6\",\n      \"download_count\": 1305,\n      \"created_at\": \"2025-12-13T01:23:10Z\",\n      \"updated_at\": \"2025-12-13T01:23:10Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-arm64.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071868\",\n      \"id\": 328071868,\n      \"node_id\": \"RA_kwDOApspmc4Tjfq8\",\n      \"name\": \"helm-v4.0.4-linux-arm64.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:7008fa1fe790ce223945651da31dec9e2147412ee6c77ffe9dfdb3a36e1fdde0\",\n      \"download_count\": 133,\n      \"created_at\": \"2025-12-13T01:23:10Z\",\n      \"updated_at\": \"2025-12-13T01:23:11Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-arm64.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071876\",\n      \"id\": 328071876,\n      \"node_id\": \"RA_kwDOApspmc4TjfrE\",\n      \"name\": \"helm-v4.0.4-linux-loong64.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:6494e3aa743c4e7e18cc9d7f5afdadbc6798a5a0e8fc63dd2285b3a951982481\",\n      \"download_count\": 143,\n      \"created_at\": \"2025-12-13T01:23:11Z\",\n      \"updated_at\": \"2025-12-13T01:23:11Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-loong64.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071889\",\n      \"id\": 328071889,\n      \"node_id\": \"RA_kwDOApspmc4TjfrR\",\n      \"name\": \"helm-v4.0.4-linux-loong64.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:8ae2f601edf1110027f54459dc40130a4395308bcdf75ec17a68f40b7706169a\",\n      \"download_count\": 143,\n      \"created_at\": \"2025-12-13T01:23:11Z\",\n      \"updated_at\": \"2025-12-13T01:23:11Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-loong64.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071891\",\n      \"id\": 328071891,\n      \"node_id\": \"RA_kwDOApspmc4TjfrT\",\n      \"name\": \"helm-v4.0.4-linux-loong64.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:51fc79563532f1e3949bdf3b254f2d3c255dc8b79b399fd94262b675e97d20d8\",\n      \"download_count\": 144,\n      \"created_at\": \"2025-12-13T01:23:11Z\",\n      \"updated_at\": \"2025-12-13T01:23:11Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-loong64.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071892\",\n      \"id\": 328071892,\n      \"node_id\": \"RA_kwDOApspmc4TjfrU\",\n      \"name\": \"helm-v4.0.4-linux-ppc64le.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:61848dd0d2c20ad62145b89adc9ddcf7bb3d26bb486292662b6593a210645720\",\n      \"download_count\": 51,\n      \"created_at\": \"2025-12-13T01:23:11Z\",\n      \"updated_at\": \"2025-12-13T01:23:11Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-ppc64le.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071894\",\n      \"id\": 328071894,\n      \"node_id\": \"RA_kwDOApspmc4TjfrW\",\n      \"name\": \"helm-v4.0.4-linux-ppc64le.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:7c5eb882502e657db2ea23d08974021f1d6585a2fd6acc8e7e2c9d2c65910f3a\",\n      \"download_count\": 54,\n      \"created_at\": \"2025-12-13T01:23:11Z\",\n      \"updated_at\": \"2025-12-13T01:23:11Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-ppc64le.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071897\",\n      \"id\": 328071897,\n      \"node_id\": \"RA_kwDOApspmc4TjfrZ\",\n      \"name\": \"helm-v4.0.4-linux-ppc64le.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:ab546edb11ea05ad21b3a10ed94c289c8cd1e91be856914bcda68feb30a74bc5\",\n      \"download_count\": 51,\n      \"created_at\": \"2025-12-13T01:23:11Z\",\n      \"updated_at\": \"2025-12-13T01:23:11Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-ppc64le.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071898\",\n      \"id\": 328071898,\n      \"node_id\": \"RA_kwDOApspmc4Tjfra\",\n      \"name\": \"helm-v4.0.4-linux-riscv64.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:91c1382737e7426f51c25e3643e24cd1e2c53a79d6564105b657dfc9ec33dcde\",\n      \"download_count\": 142,\n      \"created_at\": \"2025-12-13T01:23:11Z\",\n      \"updated_at\": \"2025-12-13T01:23:12Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-riscv64.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071899\",\n      \"id\": 328071899,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrb\",\n      \"name\": \"helm-v4.0.4-linux-riscv64.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:a9d3b44f24caafa628ace829f96043f13bebfe19635134bd3e81aa16a51809dc\",\n      \"download_count\": 141,\n      \"created_at\": \"2025-12-13T01:23:12Z\",\n      \"updated_at\": \"2025-12-13T01:23:12Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-riscv64.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071900\",\n      \"id\": 328071900,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrc\",\n      \"name\": \"helm-v4.0.4-linux-riscv64.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:f6ec68ffd30bf9b01083699097e67353eea81bba60164ba7c4d561f6bdce25e9\",\n      \"download_count\": 144,\n      \"created_at\": \"2025-12-13T01:23:12Z\",\n      \"updated_at\": \"2025-12-13T01:23:12Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-riscv64.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071901\",\n      \"id\": 328071901,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrd\",\n      \"name\": \"helm-v4.0.4-linux-s390x.tar.gz.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:699c5924c1ca2d02229e43f3f0120ad98a74007e52e9eae82cd54e0f30adb098\",\n      \"download_count\": 52,\n      \"created_at\": \"2025-12-13T01:23:12Z\",\n      \"updated_at\": \"2025-12-13T01:23:12Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-s390x.tar.gz.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071902\",\n      \"id\": 328071902,\n      \"node_id\": \"RA_kwDOApspmc4Tjfre\",\n      \"name\": \"helm-v4.0.4-linux-s390x.tar.gz.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:72348b11c9e2c4868fd201a15657f4049f9c91c5cc51df5c0f2d7efb2eee7bd9\",\n      \"download_count\": 49,\n      \"created_at\": \"2025-12-13T01:23:12Z\",\n      \"updated_at\": \"2025-12-13T01:23:12Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-s390x.tar.gz.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071903\",\n      \"id\": 328071903,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrf\",\n      \"name\": \"helm-v4.0.4-linux-s390x.tar.gz.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:c6c42a06b3d02ee3b45f74ae7799dcddfdb3d626d8447f0bfa915ae96d5d8394\",\n      \"download_count\": 51,\n      \"created_at\": \"2025-12-13T01:23:12Z\",\n      \"updated_at\": \"2025-12-13T01:23:12Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-linux-s390x.tar.gz.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071904\",\n      \"id\": 328071904,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrg\",\n      \"name\": \"helm-v4.0.4-windows-amd64.zip.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:eb6d3871d204f77552c6e6783eec76b7182df3bd3ab60c4b95a34e6e73eba409\",\n      \"download_count\": 340,\n      \"created_at\": \"2025-12-13T01:23:12Z\",\n      \"updated_at\": \"2025-12-13T01:23:12Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-windows-amd64.zip.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071905\",\n      \"id\": 328071905,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrh\",\n      \"name\": \"helm-v4.0.4-windows-amd64.zip.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:afd5bccf1a5ae673e7e765dc358e19f4a1ecc1a33b8bf1fedd8c04e085788779\",\n      \"download_count\": 181,\n      \"created_at\": \"2025-12-13T01:23:12Z\",\n      \"updated_at\": \"2025-12-13T01:23:12Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-windows-amd64.zip.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071906\",\n      \"id\": 328071906,\n      \"node_id\": \"RA_kwDOApspmc4Tjfri\",\n      \"name\": \"helm-v4.0.4-windows-amd64.zip.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:a813554ad03442e5b2ce6bd53ec6dd71c27b06f6bec449d1f5ebf2091d38db19\",\n      \"download_count\": 161,\n      \"created_at\": \"2025-12-13T01:23:12Z\",\n      \"updated_at\": \"2025-12-13T01:23:13Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-windows-amd64.zip.sha256sum.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071907\",\n      \"id\": 328071907,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrj\",\n      \"name\": \"helm-v4.0.4-windows-arm64.zip.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:63cfea9ba48829939f459ade799583247955116dd3bcaae7eecb4ca575aca933\",\n      \"download_count\": 166,\n      \"created_at\": \"2025-12-13T01:23:13Z\",\n      \"updated_at\": \"2025-12-13T01:23:13Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-windows-arm64.zip.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071909\",\n      \"id\": 328071909,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrl\",\n      \"name\": \"helm-v4.0.4-windows-arm64.zip.sha256.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:463780016e11b617f87a9c79b20513c61a0ddc9c27ebb42ee267c5a2e4654fed\",\n      \"download_count\": 128,\n      \"created_at\": \"2025-12-13T01:23:13Z\",\n      \"updated_at\": \"2025-12-13T01:23:13Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-windows-arm64.zip.sha256.asc\"\n    },\n    {\n      \"url\": \"https://api.github.com/repos/helm/helm/releases/assets/328071910\",\n      \"id\": 328071910,\n      \"node_id\": \"RA_kwDOApspmc4Tjfrm\",\n      \"name\": \"helm-v4.0.4-windows-arm64.zip.sha256sum.asc\",\n      \"label\": null,\n      \"uploader\": {\n        \"login\": \"scottrigby\",\n        \"id\": 407675,\n        \"node_id\": \"MDQ6VXNlcjQwNzY3NQ==\",\n        \"avatar_url\": \"https://avatars.githubusercontent.com/u/407675?v=4\",\n        \"gravatar_id\": \"\",\n        \"url\": \"https://api.github.com/users/scottrigby\",\n        \"html_url\": \"https://github.com/scottrigby\",\n        \"followers_url\": \"https://api.github.com/users/scottrigby/followers\",\n        \"following_url\": \"https://api.github.com/users/scottrigby/following{/other_user}\",\n        \"gists_url\": \"https://api.github.com/users/scottrigby/gists{/gist_id}\",\n        \"starred_url\": \"https://api.github.com/users/scottrigby/starred{/owner}{/repo}\",\n        \"subscriptions_url\": \"https://api.github.com/users/scottrigby/subscriptions\",\n        \"organizations_url\": \"https://api.github.com/users/scottrigby/orgs\",\n        \"repos_url\": \"https://api.github.com/users/scottrigby/repos\",\n        \"events_url\": \"https://api.github.com/users/scottrigby/events{/privacy}\",\n        \"received_events_url\": \"https://api.github.com/users/scottrigby/received_events\",\n        \"type\": \"User\",\n        \"user_view_type\": \"public\",\n        \"site_admin\": false\n      },\n      \"content_type\": \"application/octet-stream\",\n      \"state\": \"uploaded\",\n      \"size\": 833,\n      \"digest\": \"sha256:4f27866327d78cca9bcafd836796bec8a0c79b15ac48a8001607593913a635ce\",\n      \"download_count\": 129,\n      \"created_at\": \"2025-12-13T01:23:13Z\",\n      \"updated_at\": \"2025-12-13T01:23:13Z\",\n      \"browser_download_url\": \"https://github.com/helm/helm/releases/download/v4.0.4/helm-v4.0.4-windows-arm64.zip.sha256sum.asc\"\n    }\n  ],\n  \"tarball_url\": \"https://api.github.com/repos/helm/helm/tarball/v4.0.4\",\n  \"zipball_url\": \"https://api.github.com/repos/helm/helm/zipball/v4.0.4\",\n  \"body\": \"Helm v4.0.4 is a security fix for a Go CVE in the previous tag. This patch release rebuilds the Helm `v4.0.2` release with the latest Go toolchain, to fix the Go CVE. Users are encouraged to upgrade. Note that tag v4.0.3 was skipped due to a build failure.\\r\\n\\r\\nThe community keeps growing, and we'd love to see you there!\\r\\n\\r\\n- Join the discussion in [Kubernetes Slack](https://kubernetes.slack.com):\\r\\n  -  for questions and just to hang out\\r\\n  -  for discussing PRs, code, and bugs\\r\\n- Hang out at the Public Developer Call: Thursday, 9:30 Pacific via [Zoom](https://zoom.us/j/696660622)\\r\\n- Test, debug, and contribute charts: [ArtifactHub/packages](https://artifacthub.io/packages/search?kind=0)\\r\\n\\r\\n## Installation and Upgrading\\r\\n\\r\\nDownload Helm v4.0.4. The common platform binaries are here:\\r\\n\\r\\n- [MacOS amd64](https://get.helm.sh/helm-v4.0.4-darwin-amd64.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-darwin-amd64.tar.gz.sha256sum) / 73bcfd6ab000fdc95acf9fe1c59e8e47179426a653e45ae485889869d4a00523)\\r\\n- [MacOS arm64](https://get.helm.sh/helm-v4.0.4-darwin-arm64.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-darwin-arm64.tar.gz.sha256sum) / a7ea99937a9679b3935fa0a2b70e577aa1ea84e5856e7c0821ca6ffa064ea976)\\r\\n- [Linux amd64](https://get.helm.sh/helm-v4.0.4-linux-amd64.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-linux-amd64.tar.gz.sha256sum) / 29454bc351f4433e66c00f5d37841627cbbcc02e4c70a6d796529d355237671c)\\r\\n- [Linux arm](https://get.helm.sh/helm-v4.0.4-linux-arm.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-linux-arm.tar.gz.sha256sum) / 9255732e31b5aa5ee7b55be8497eea4723e3dfb08a63c37603ae0d15a9a9d82c)\\r\\n- [Linux arm64](https://get.helm.sh/helm-v4.0.4-linux-arm64.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-linux-arm64.tar.gz.sha256sum) / 16b88acc6503d646b7537a298e7389bef469c5cc9ebadf727547abe9f6a35903)\\r\\n- [Linux i386](https://get.helm.sh/helm-v4.0.4-linux-386.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-linux-386.tar.gz.sha256sum) / e6dbf45313bab48e51a2b7a5f3271a19bb3d8b9f07b4bb48ba342389d902af53)\\r\\n- [Linux loong64](https://get.helm.sh/helm-v4.0.4-linux-loong64.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-linux-loong64.tar.gz.sha256sum) / ﻿<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?><Error><Code>BlobNotFound</Code><Message>The specified blob does not exist.\\r\\nRequestId:11673868-901e-003e-10cd-6b624b000000\\r\\nTime:2025-12-13T01:15:26.0922049Z</Message></Error>)\\r\\n- [Linux ppc64le](https://get.helm.sh/helm-v4.0.4-linux-ppc64le.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-linux-ppc64le.tar.gz.sha256sum) / c108d181a0e29dadf281fbb4f4a0e0f2149922b119ec745ced1a5ae6f0918703)\\r\\n- [Linux s390x](https://get.helm.sh/helm-v4.0.4-linux-s390x.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-linux-s390x.tar.gz.sha256sum) / cdf172c59379f0a3fe1db4743c16f122745fdaaebb2fbbfa40ce5722a4787717)\\r\\n- [Linux riscv64](https://get.helm.sh/helm-v4.0.4-linux-riscv64.tar.gz) ([checksum](https://get.helm.sh/helm-v4.0.4-linux-riscv64.tar.gz.sha256sum) / 2cf1c77d993bf5386e85249007bdaf38358d2516b18454212206a81b132e1330)\\r\\n- [Windows amd64](https://get.helm.sh/helm-v4.0.4-windows-amd64.zip) ([checksum](https://get.helm.sh/helm-v4.0.4-windows-amd64.zip.sha256sum) / 135bffadd3c87aff8856e06efb366bea2a48ac4d1742d73af80250410246f14d)\\r\\n- [Windows arm64](https://get.helm.sh/helm-v4.0.4-windows-arm64.zip) ([checksum](https://get.helm.sh/helm-v4.0.4-windows-arm64.zip.sha256sum) / b65d05f15260e78311f463773f54fe68f6d74444b3c3e84cecf270cdb927cd8a)\\r\\n\\r\\nThis release was signed with `208D D36E D5BB 3745 A167 43A4 C7C6 FBB5 B91C 1155` and can be found at @scottrigby [keybase account](https://keybase.io/r6by). Please use the attached signatures for verifying this release using `gpg`.\\r\\n\\r\\nThe [Quickstart Guide](https://helm.sh/docs/intro/quickstart/) will get you going from there. For **upgrade instructions** or detailed installation notes, check the [install guide](https://helm.sh/docs/intro/install/). You can also use a [script to install](https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3) on any system with `bash`.\\r\\n\\r\\n## What's Next\\r\\n\\r\\n- 3.19.5 and 4.0.5 are the next patch releases and will be on January 14, 2026\\r\\n- 3.20.0 and 4.1.0 is the next minor releases and will be on January 21, 2026\\r\\n\\r\\n## Changelog\\r\\n\\r\\n- Bump v4.0.2 CVE deps cd700e0627b8d9a4997a7ab2bc3b712d0de4dcd3 (George Jenkins)\\r\\n- Use latest patch release of Go in releases 9db13ee5c343196f642c568a03e58d3221b324d6 (Matt Farina)\",\n  \"reactions\": {\n    \"url\": \"https://api.github.com/repos/helm/helm/releases/270052681/reactions\",\n    \"total_count\": 8,\n    \"+1\": 8,\n    \"-1\": 0,\n    \"laugh\": 0,\n    \"hooray\": 0,\n    \"confused\": 0,\n    \"heart\": 0,\n    \"rocket\": 0,\n    \"eyes\": 0\n  },\n  \"mentions_count\": 1\n}\n"
  }
]