From 647bdddb559a71433578e01a95d1223c18279e63 Mon Sep 17 00:00:00 2001 From: onyx-and-iris Date: Sun, 15 Jun 2025 12:49:07 +0100 Subject: [PATCH] first commit --- .github/workflows/golang-ci.yml | 29 +++++++ .github/workflows/release.yml | 28 +++++++ .gitignore | 36 +++++++++ .golangci.yml | 54 +++++++++++++ .goreleaser.yaml | 53 +++++++++++++ LICENSE | 21 +++++ README.md | 51 ++++++++++++ Taskfile.yaml | 57 ++++++++++++++ cmd/context.go | 16 ++++ cmd/new.go | 108 +++++++++++++++++++++++++ cmd/root.go | 68 ++++++++++++++++ go.mod | 53 +++++++++++++ go.sum | 135 ++++++++++++++++++++++++++++++++ img/promptfilter.png | Bin 0 -> 2368 bytes img/selectionprompt.png | Bin 0 -> 10339 bytes main.go | 28 +++++++ 16 files changed, 737 insertions(+) create mode 100644 .github/workflows/golang-ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 .goreleaser.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Taskfile.yaml create mode 100644 cmd/context.go create mode 100644 cmd/new.go create mode 100644 cmd/root.go create mode 100644 go.mod create mode 100644 go.sum create mode 100755 img/promptfilter.png create mode 100755 img/selectionprompt.png create mode 100644 main.go diff --git a/.github/workflows/golang-ci.yml b/.github/workflows/golang-ci.yml new file mode 100644 index 0000000..a6aa5e6 --- /dev/null +++ b/.github/workflows/golang-ci.yml @@ -0,0 +1,29 @@ +name: CI + +on: + push: + branches: ['main'] + paths: + - '**.go' + pull_request: + branches: ['main'] + paths: + - '**.go' +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + timeout-minutes: 3 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.24' + - name: Install golangci-lint + run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + - name: Run golangci-lint + run: golangci-lint run ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..bafdbf0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: goreleaser + +on: + push: + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up Go + uses: actions/setup-go@v5 + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + distribution: goreleaser + version: '~> v2' + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a7188be --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# Generated by ignr-cli: github.com/onyx-and-iris/ignr-cli +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin/ + +# Test binary, built with `go test -c` +*.test + +# Code coverage profiles and other test artifacts +*.out +coverage.* +*.coverprofile +profile.cov + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + +# Editor/IDE +# .idea/ +# .vscode/ + +# End of ignr-cli diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..55de51c --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,54 @@ +run: + # timeout for analysis, e.g. 30s, 3m, default is 1m + timeout: 3m + # exclude test files + tests: true + +linters: + # Set to true runs only fast linters. + # Good option for 'lint on save', pre-commit hook or CI. + fast: true + + disable-all: true + + enable: + - gosimple + - govet + - ineffassign + - staticcheck + - unused + - gofmt + - gofumpt + - misspell + - unparam + - gosec + - asciicheck + - errname + - gci + - godot + - goimports + - revive + +linters-settings: + gofmt: + rewrite-rules: + - pattern: 'interface{}' + replacement: 'any' + - pattern: 'a[b:len(a)]' + replacement: 'a[b:]' + + misspell: + locale: UK + + errcheck: + check-type-assertions: true + +issues: + max-same-issues: 0 + max-issues-per-linter: 0 + exclude-use-default: false + exclude: + # gosec: Duplicated errcheck checks + - G104 + # gosec: integer overflow conversion int -> uint32 + - G115 diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..1d5e192 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,53 @@ +# This is an example .goreleaser.yml file with some sensible defaults. +# Make sure to check the documentation at https://goreleaser.com + +# The lines below are called `modelines`. See `:help modeline` +# Feel free to remove those if you don't want/need to use them. +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +# vim: set ts=2 sw=2 tw=0 fo=cnqoj + +version: 2 + +before: + hooks: + # You may remove this if you don't use go modules. + - go mod tidy + # you may remove this if you don't need go generate + - go generate ./... + +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + +archives: + - formats: ['tar.gz'] + # this name template makes the OS and Arch compatible with the results of `uname`. + name_template: >- + {{ .ProjectName }}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} + # use zip for windows archives + format_overrides: + - goos: windows + formats: ['zip'] + +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' + +release: + footer: >- + + --- + + Released by [GoReleaser](https://github.com/goreleaser/goreleaser). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..29058bb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright © 2025 onyx-and-iris + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6c5a0ab --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +![Windows](https://img.shields.io/badge/Windows-0078D6?style=for-the-badge&logo=windows&logoColor=white) +![Linux](https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black) +![macOS](https://img.shields.io/badge/mac%20os-000000?style=for-the-badge&logo=macos&logoColor=F0F0F0) + +# ignr-cli + +Simple no-frills .gitignore generator backed by the Github API. + +![Selection Prompt](./img/selectionprompt.png) + +## Install + +```console +go install github.com/onyx-and-iris/ignr-cli@latest +``` + +## Authentication + +You can run this tool without authenticating but requests will have a stricter rate limiting. + +If you prefer to authenticate you can pass a token in the following ways: + +*Flag* + +- --token/-t: Github API Token + +*Environment Variable* + +```bash +#!/usr/bin/env bash + +export GH_TOKEN= +``` + +## Commands + +### New + +Trigger the selection prompt. + +```console +ignr-cli new +``` + +The prompt filter can activated by pressing `/`: + +![Prompt Filter](./img/promptfilter.png) + +## Special Thanks + +- [Charm](https://github.com/charmbracelet) for their awesome CLI packages. diff --git a/Taskfile.yaml b/Taskfile.yaml new file mode 100644 index 0000000..4351341 --- /dev/null +++ b/Taskfile.yaml @@ -0,0 +1,57 @@ +version: '3' + +vars: + PROGRAM: ignr-cli + SHELL: '{{if eq .OS "Windows_NT"}}powershell{{end}}' + BIN_DIR: bin + VERSION: + sh: 'git describe --tags $(git rev-list --tags --max-count=1)' + + WINDOWS: '{{.BIN_DIR}}/{{.PROGRAM}}_windows_amd64.exe' + LINUX: '{{.BIN_DIR}}/{{.PROGRAM}}_linux_amd64' + +tasks: + default: + desc: Build the ignr-cli project + cmds: + - task: build + + build: + desc: Build the ignr-cli project + deps: [vet] + cmds: + - task: build-windows + - task: build-linux + + vet: + desc: Vet the code + deps: [fmt] + cmds: + - go vet ./... + + fmt: + desc: Fmt the code + cmds: + - go fmt ./... + + build-windows: + desc: Build the ignr-cli project for Windows + cmds: + - GOOS=windows GOARCH=amd64 go build -o {{.WINDOWS}} -ldflags="-X main.version={{.VERSION}}" + internal: true + + build-linux: + desc: Build the ignr-cli project for Linux + cmds: + - GOOS=linux GOARCH=amd64 go build -o {{.LINUX}} -ldflags="-X main.version={{.VERSION}}" + internal: true + + test: + desc: Run tests + cmds: + - go test ./... + + clean: + desc: Clean the build artifacts + cmds: + - '{{.SHELL}} rm -r {{.BIN_DIR}}' diff --git a/cmd/context.go b/cmd/context.go new file mode 100644 index 0000000..ecff9a6 --- /dev/null +++ b/cmd/context.go @@ -0,0 +1,16 @@ +package cmd + +import ( + "context" + + "github.com/google/go-github/v72/github" +) + +type contextKey string + +const clientKey contextKey = "client" + +func getClientFromContext(ctx context.Context) (*github.Client, bool) { + client, ok := ctx.Value(clientKey).(*github.Client) + return client, ok +} diff --git a/cmd/new.go b/cmd/new.go new file mode 100644 index 0000000..a2507be --- /dev/null +++ b/cmd/new.go @@ -0,0 +1,108 @@ +package cmd + +import ( + "context" + "errors" + "fmt" + "io" + "os" + + "github.com/charmbracelet/huh" + "github.com/charmbracelet/lipgloss" + "github.com/google/go-github/v72/github" + "github.com/spf13/cobra" +) + +const gitignoreFileName = ".gitignore" + +// newCmd represents the new command. +var newCmd = &cobra.Command{ + Use: "new", + Short: "Create a new .gitignore file", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + return runNewCommand(cmd, args) + }, +} + +func init() { + rootCmd.AddCommand(newCmd) +} + +// runNewCommand is the handler for the 'new' command. +// It retrieves available .gitignore templates from GitHub, prompts the user to select one, +// and writes the selected template to a new .gitignore file. +func runNewCommand(cmd *cobra.Command, _ []string) error { + client, ok := getClientFromContext(cmd.Context()) + if !ok { + return errors.New("failed to get GitHub client from context") + } + + templates, _, err := client.Gitignores.List(context.Background()) + if err != nil { + return fmt.Errorf("error listing gitignore templates: %w", err) + } + + var selection string + if err := runPrompt(templates, &selection); err != nil { + return fmt.Errorf("error running selection prompt: %w", err) + } + + content, _, err := client.Gitignores.Get(context.Background(), selection) + if err != nil { + return fmt.Errorf("error retrieving gitignore template '%s': %w", selection, err) + } + + f, err := os.OpenFile(gitignoreFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600) + if err != nil { + return fmt.Errorf("error opening file '%s': %w", gitignoreFileName, err) + } + defer f.Close() + + if err = commitGitignore(content, f); err != nil { + return fmt.Errorf("error committing gitignore file: %w", err) + } + + style := lipgloss.NewStyle(). + Bold(true). + Foreground(lipgloss.Color("#7D56F4")) // nolint: misspell + + fmt.Println(style.Render("Created"), selection, style.Render(".gitignore file ✓")) + + return nil +} + +// runPrompt is a helper function to run the selection prompt for .gitignore templates. +func runPrompt(templates []string, selection *string) error { + var options []huh.Option[string] + for _, template := range templates { + options = append(options, huh.NewOption(template, template)) + } + + selectionPrompt := huh.NewSelect[string](). + Title("Select a .gitignore template"). + Options(options...). + Value(selection) + + if err := selectionPrompt.Run(); err != nil { + return fmt.Errorf("error running selection prompt: %w", err) + } + return nil +} + +// commitGitignore writes the content of the selected gitignore template to the .gitignore file. +func commitGitignore(content *github.Gitignore, w io.Writer) error { + if _, err := fmt.Fprintf(w, "# Generated by ignr-cli: github.com/onyx-and-iris/ignr-cli\n"); err != nil { + return fmt.Errorf("error writing header to file '%s': %w", gitignoreFileName, err) + } + + if _, err := fmt.Fprintf(w, "%s", *content.Source); err != nil { + return fmt.Errorf("error writing to file '%s': %w", gitignoreFileName, err) + } + + if _, err := fmt.Fprintf(w, "\n# End of ignr-cli\n"); err != nil { + return fmt.Errorf("error writing footer to file '%s': %w", gitignoreFileName, err) + } + + return nil +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..c89f486 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,68 @@ +// Package cmd provides a command-line interface for generating .gitignore files. +package cmd + +import ( + "context" + "errors" + "fmt" + "runtime/debug" + "strings" + + "github.com/google/go-github/v72/github" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var version string // Version of the CLI, set during build time + +// rootCmd represents the base command when called without any subcommands. +var rootCmd = &cobra.Command{ + Use: "ignr-cli", + Short: "A command-line interface for generating .gitignore files", + Long: `ignr-cli is a command-line interface for generating .gitignore files. +It allows users to easily create and manage .gitignore files for various programming languages and frameworks. +You may also list available templates and generate .gitignore files based on those templates.`, + SilenceUsage: true, + PersistentPreRun: func(cmd *cobra.Command, _ []string) { + var client *github.Client + if !viper.IsSet("token") || viper.GetString("token") == "" { + client = github.NewClient(nil) + } else { + client = github.NewClient(nil).WithAuthToken(viper.GetString("token")) + } + ctx := context.WithValue(context.Background(), clientKey, client) + cmd.SetContext(ctx) + }, + RunE: func(cmd *cobra.Command, _ []string) error { + if cmd.Flags().Lookup("version").Changed { + if version == "" { + info, ok := debug.ReadBuildInfo() + if !ok { + return errors.New("unable to retrieve build information") + } + version = strings.Split(info.Main.Version, "-")[0] + } + fmt.Printf("ignr-cli version: %s\n", version) + return nil + } + + return cmd.Help() + }, +} + +func init() { + rootCmd.PersistentFlags().StringP("token", "t", "", "GitHub authentication token") + rootCmd.Flags().BoolP("version", "v", false, "Print the version of the CLI") + + viper.SetEnvPrefix("GH") + viper.AutomaticEnv() + viper.BindPFlag("token", rootCmd.PersistentFlags().Lookup("token")) +} + +// Execute adds all child commands to the root command and sets flags appropriately. +func Execute() error { + if err := rootCmd.Execute(); err != nil { + return err + } + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f7c6d29 --- /dev/null +++ b/go.mod @@ -0,0 +1,53 @@ +module github.com/onyx-and-iris/ignr-cli + +go 1.24.3 + +require ( + github.com/charmbracelet/huh v0.7.0 + github.com/charmbracelet/lipgloss v1.1.0 + github.com/google/go-github/v72 v72.0.0 + github.com/spf13/cobra v1.9.1 + github.com/spf13/viper v1.20.1 +) + +require ( + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/catppuccin/go v0.3.0 // indirect + github.com/charmbracelet/bubbles v0.21.0 // indirect + github.com/charmbracelet/bubbletea v1.3.4 // indirect + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect + github.com/charmbracelet/x/ansi v0.8.0 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13 // indirect + github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.23.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a2dbcd3 --- /dev/null +++ b/go.sum @@ -0,0 +1,135 @@ +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= +github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= +github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY= +github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= +github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= +github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= +github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI= +github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= +github.com/charmbracelet/huh v0.7.0 h1:W8S1uyGETgj9Tuda3/JdVkc3x7DBLZYPZc4c+/rnRdc= +github.com/charmbracelet/huh v0.7.0/go.mod h1:UGC3DZHlgOKHvHC07a5vHag41zzhpPFj34U92sOmyuk= +github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= +github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= +github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= +github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= +github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= +github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA= +github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4= +github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= +github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= +github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI= +github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/go-github/v72 v72.0.0 h1:FcIO37BLoVPBO9igQQ6tStsv2asG4IPcYFi655PPvBM= +github.com/google/go-github/v72 v72.0.0/go.mod h1:WWtw8GMRiL62mvIquf1kO3onRHeWWKmK01qdCY8c5fg= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/img/promptfilter.png b/img/promptfilter.png new file mode 100755 index 0000000000000000000000000000000000000000..b70dc61b245301d0f47b93df6a940874b9cec507 GIT binary patch literal 2368 zcmds3`#%$G8^4F}I989Phw#z?6RJ@;F3PFq5aw7Y*))XKLQYfRO=abj(}t4sArWEC z(m@Jyo~IV8WC$Z;nCzV&o_=}Xzu^7hzV7?_T;I><`h33M`+ME@Ehh&XSt%tc0D!EW z?FnZ9AYsDubxCny^fgG&5pEEivyCOF>De_UOvEr2_7(ut5vAA9Z4u^wgxPxH0FZmN zxgZ^(WfuUD9I`uM;Tq{P`#Cfa#Z&26a7=czuDSbCw;Cy9|8T*gTQogQqdC)O!nNVS z)L{#iDanNGU$gyw7G6-lsTFk(c_~L-(xIid4;VW^LMiLvGR!8&Iily zkCET!S0GHQ;A&^Dn!lPJ$;U|mKgg-=^J}_6k99Ct`i(Blv{fB{<~u#pX#eq9Nczw0O%+rolG?(dal&jQO4! zaF57=)FRe%eOh8qe^xW;@E)$vigJm^rQ&8!cO;v*UfVm-)#abtYppUJ%99f#Txa8G zyve1d4@*-+yGNz9^N3Ss45WAHZ2#MPe9u*FydcgJ4%M&h!|4D8<9N}HVZD&Sn+|F` zpRkyiV{ObvyVf2gn!Z!f3SN~AwikZ8S2=#} z+ma4y+*};kQpHW_{T6op3-DZ9J;qyK_Uh%ID~P4?_X?d=ierybbpvw4tNkFL*t98I zR)xtq)*S8+V}Cp|EieDWsnco}+bLLY-DJ8fjAZLD8G%3)p29Nvh*u{cb5}pH+3U){ z>0OLeWNT_1H@76Z5$#q00M*lc%Pzn=A|NM-f*30rgr+4T2duY+fdeT7QNrm>eWk_^ zwU>5>PHt4Hv$e{=hE z1PZ1C5%TlGx?W=DiWO0b!kBnk0UO>#%$c9#BzNwZ<3?HzNinF}oKwb?6D3?{`O{oR zsZU&NY90hed@C?mInEi13N9OpepT{5NdHu@M>49aqa|^hu-tmm- zIq#YT;B<6d`Y52eQ_U?QU?uqxB)WeTO%^k{o6(}XRnw!Afp#^1fB zf3iRB%~x*}*&OME;!w>WCk>b5%B&2hNF#gpcJQCo1_k%<2aO6Fb05ygUW`bBnypZI z`+?ZWLNx1(ZK7r8C#6nhjxk;?1T_`e28VMP&nt#@eA2hWraUV{V@H~Y3s*>q9OYST z&mDVo&5^C4V4oO_Wz=4+bP^$?r3@y7wyawh;^^t0VIh&V9Qs;Yc zzUde(;IW-aATD3@ZLsKDxv+fZXWjO>gSVHec#va+Eil%j2sPUxDXWRKw})J-V7zct z-5DZIc|rnjmu&_?>%s?WPFuF!(Qf{Z>+>Q7&d#=UnEZ*T`V){`y)1sV{P3 zsGb}RM{IO19)TkU7uIQ-Y$YJ(O+&N%r$4eOKMiwY-vk+t;zE}1rADC6FYEXZ%)K7q z$^39w9nM#Ye9Ble^l3qbGh)G3SBUhAX?t}_20f6{w0lwR&x^>j5`5>{J3}bh@u+~A z;3fkSmwZauh4HRyIHVx7KDn<|zPKONOfP&@=~^K%2hYJUi*iXu@b5DZvj5gcD!vvrq6VNvs4TR6 z5!SHvNJwB!)?0d%c!?l2`bIM5$-nJ204)?E9Z51y7Kai`heMLFUJArgx9i0ZcD^mG z7|M#9O&)w-(Sodc5Mi-B}wcR0idZt`0Db&uTJE! us07%*WAowM^zi?ly}vKV|1YFWAo@N?Fu1M|d0P1E0d`gnCu%JHuKx$Qenut$ literal 0 HcmV?d00001 diff --git a/img/selectionprompt.png b/img/selectionprompt.png new file mode 100755 index 0000000000000000000000000000000000000000..de2c066106ab1d9b9b288b7fa3f13059d7c0e218 GIT binary patch literal 10339 zcma)ic|4Ts-~UvH7NOHZ)>d_pl%;G#5<-@YF?NYecG(R^8!Aaz57~EP%{Ezvq>^>S zFpNDh_I(U9jNdh??{m)c{C=w+|TuN)Y%X49)Lg~>>4+3 z=tCg8?IDm|d-t(|GlF{dw&1YKU0?k=q_CZT3ViqjsjRIGfxHW6+q7Zl!zd4SX!-1_SP&oq9C9lpPGzc1J7aR*Vif4LKgSVrIBIHonj800ihh%ZPO&o3g~BO0dsoMN zbIC_^m7p}yT@c6zneD&O;ISdLCv(8Z<1bRcMDP6dm=^+hn7R*49TI%{A7A7Iu#{`X zvNmvnF9gE_Sfs&G0sRN_pb~Ib$@Hdbh{AAycXj6M{Q%WudS~)voO?Z9sb>(u2xAmd zGGG_8#cNj6l2At7EyJ`iA1ls~0&lLR?Sl|k34ZHv6CF#RDLT!5al`*2`ug6YX}@8V zj(FX&=hmWC&FpP|<}Im|?%3Lb;ZW|l>478fkb_7*(sbfcy5sO0pQvqQ_=@Z<2y*Z; zOZm-(c2T@>pg8m9~*lDb;<&X3AELctU~qfWj@++sIcAG3~J8BA}qFo z6I#wrWEo#Nl{-XXP2P6cnrRvJi4k=6H@~+P5@VgpX-RBxnHW>I-u%GB;15h{cxKtP zvMg%3Aji+`f|zU|QkLH?comSRyy}RQpjZn+Wf(@#LT6)~lhQ!kzBWuZ&PLUHZY^Ac z2av^tx9)0^H;2oq=2XTjxv9Zgf1(3ph+J2cM|-DuoK}|9sj}rdb_VLc(G`KtkG0&W z7o3BIZzB`?8Q)GNAAvkET|c&2ls)VfMf)xhv#k#B}Ml zW}OeYZW?WLd~0ky#KaeQQ)PRZ1-Gahyt;1Y|7YB(w@>^<_X9e zm*t!mr47V7|Fy&k$JP8;C;Dq{7cY4h)NNyiwnwj?!IK>Q7Ov!b7ZB-a-N{a5q+B3F z7`i#+j+!e9mRjvYMz6P>!UZe@*@jO>q+^G9Iy;b!t8{J{iXNi0R?C;z6{H)OvD}$Q z3*=5FE|~dfy40;WKT(m=FyzRES44-^KCc9 zTkwjDB>C_mmi_wQHMoX*fM#9W}Giiqh0n%*#F-P|UT;I!?jzab~*5 z#*-5xhXQB9%L@>c^n#Fxq{$5d%BHj5)B|me&IWJFnYxhK(H>L#nFaQKDuz*eYHC1e zVH;!+ZOBi7oZ8O;ky&{qoTEYOJ24|2h$ank3QZ*>`Hu2+x7DwxGdC5vq?G*Z>M$Q|YO4Cvb{zo~y>*~)ZJv%Wya%Ky6 z;&sLL1n26qXkc;O!eq*;#rPA@`=Pms0uz2pAIX0}PP+Oli+x`hT15~O{jSsK;j10V zT}LlU_2SR23sSE8QBeG!B8NL-m8f>vW&B^%VylNA+n}!3scJCj@l$w9uxO zXohH8@|M-9fb~67NSCRtkj}~$ONHLodUzD$QdgxxY;-20I5w%nW$yCqG3sJ{bwoxz z*|OIX|H5TaGS)-qUFwx>aGH8L@GI4<`uc?8qO7*#PD!LWFA9C%}Qa&xJ=9urd)Z`d=%o5yFxsnvF z_2yW};IuCh+5x4$n=Tzkov1CWM%_jf1Qh;QLDVLN7Hm5Bsm*;`i=icwI;w|~sBD3p z@3<#e@x%J(t4c1{>PvLc<);f^^wW4QsPuAxKiSk}O45>cWNW^MNFjw=fHk}|B^?NN zsL>(LXpC-4&TZgM%*s-UUJwXLz*J9VZ)igJC@XD!>9A#h>VK zoc0F*|G*Z`i1Xp6@fIRe4olyilLB0noZp?BzT;J z{f);73W2l<&#jFw4;ho0#IkjpnzBLhB95t8D*F4@;$ZS*Wb)nhBj8%?MnOXSg)k_V znow?ORgbhPOM|B|(*K-1XdUO(bxFgwo=$mD&n|agK(53H&c*X2NU5&bR ztmQY|?T_?@ z%$8h3G6XVmP_8y5=E79?Dnb)Iqg#GleCGQ$V`aFf$Ym4X^F(RAmWCGOVQdnRABQTE zy--8|&>w`Co@XZuZoxP23}k9O8Litv-h*JyjbrO5=2k4;{GSm1FKm}nQFgkn>V12D zIe*sY&261#_uY_(W45+>rO0ysXT=f17wu)Qaw++rOBk=%193Is;UUbfJ~J@C4L_rK z;%qLZEQ1HB-@cw8vUEBOdzwR0vdV5isLz03Lt?#2sq-Uv3R%6sIfS1U}c z%w-YwZ;v`=@G`~|-M+Mmk@&2d>1~o+Ij>`Hs|-ylrI!-YJkv;|{Sb%_@5w}nn`N9WpPvG9#dvcjhv&-OfmChcgw})uyoft*I7gh| zC&fL2AY`z z1*{8gB%ei|{qgz~Gbaw(vXtA@<$sAkpmXTqx$&btgkrU*Qe0}|Q}?_E*Yxa)Qc+R6 zg+LisD-}<6QGvB!mWCLYPdWoyQVDZg3E|GyRgv#Ak@Fv%Kt=f?X@6OnynjjH+>*MX zENh-{IyqSM^2|5YT~^UI`}FA;{GyLLW$LBU#lD0e!=v%<;4yfchN4=cEKXlT^-t$!)drGAq%wXFsWHup;2G2UWxW2ZNoyvA6uzzi zcS3yjVzYVDxHcW+U#o;fPT$m@xm9TxwWxEsyC4rGn?Iyn$?_=C?KjmDA!gXf$(6}w z4Ys$?C%<}&5 zNPA97Or=D=T0xpCChja;1S3r=OQ_D~@s^x*YT+0NTa6c+((%Oh9f_Sogb4!f@A@&| z`&71i;4!7+-cy}-))%~o2c3n%3Vm3*gi#0h0MY&@KB($}ul@}jiIXWYpw`5N5yN^I z0-zW$H>TTyt_^P96URe%93aoWZapL@^(r<|G^ih0>8w#{y~VPgD!eRAlUJIwz7NRT z{d+dd_0{)Og@^qWkgxptLfrSXl3co5gIJlfmZd^rv0T=`vNXHen!0C#M%#r?czJuR z_y_04U*gN>uYsr`9e*!b|F>I97w=!X)9pbKSstcizJZ*&brX}X`>Py7P@AkDKks(P&%LCWtvL}hAj)YVzz=UG!Mg)= zHIRgUNl$;BXdhg_03Q9c0t-bh3XCI6i}=ucAMHOjI3oY7Oxz6!H)NPEl$q$|xfGV% z5>HFRP7c2)iO+VK6^M^RC$RI}7aVg0`-;sYX4%M@v|ujMbX%UBkC;RTG237b<8=US zY;80(@VCfD?xJAW{UVsw`^k1qZNJgaaR#YXc{fNiJTq$-yihj`$Dq;GXOGBxn~ShO zEmtu11~6s5!|7nznhU7HdKlxE> z*6xKKdA9kpQJXV^u);ym%ohYPnq^eWj z1-`MIm2V@NNEl2(*ulq1h53&{t@=`>dkhvAjD_p6gS(5G6_Zq7w0;Y1?aKS%qK2xy zi|;e)5~%aeyB%<57T$`e8piivmd7GR3^EORs)=Xt>N9|4zpgBdD$jN6b+5ws+i8b= zx~E!l6|CkfD`lr!Q#Q%dGxaBELO`}e-C7Vh2?}<6V6T&@#s&_y_L^1t!g)EnA)Z$V zCATn>Oj$=nT-SSd_iemBI7$jP4mt{k24D4lx6)xVpg7OH>Lwc`Ei5fY9h?4aub?M} zJ_rg;dwz;-zov=)M>|%w^Qmis**YS}x_O5dvl9j1q$z8>eY2m&K>8PE(#E(QtE;H~PXD>D3R3cjh$HO^2pN7EAFJzAKei?=#h(~SP+2?L?d4@U(WJ_5vFJyW zz^)M+x@U~JhV;t6WfKgj@T7iI^xIiuZRqqC$p;rlVq7}-V6QVhY4|obgTKK;W>pS= z;rn~XxgifrzvjS`>+PE+M0A7l_C=Q8@yu58Kv>?kBHKH{bL!lRom8!`(a%WMEY=}a zVtMD(aTdv6;s;325_&QC9?-l9_g zS%?@75XVefbn94YZfM5RRRd!m;m|Jh`_))dMVI%Ft-^HtH@CKR488)n3oGAgW%yDhHua=$EVB^D> z)-RHu7M{(ZRn^`0&P+2=;jOuJ?pGG|eX5SA%k}RKsKB^6A$mT1?ui8BAGH2SD~JcJ zO*&CH-KN#QGyF()H=m0hv3TPoYBz^5js|t*;e+1jT=Zo?zsDl9Ps``Gd-;`0gmY+3wn+d89Z!3$r-!lTarg?)7f6NsMw6Nt3_14O%zucKaFoHZ6h(&1jtC^q(w)@LxsYN7$d zhGaj#4Yh{~(U1A6#vjc;)E(gTXD8S;VGlPHVRK8~l$_+$9JW>rb~@qo`JE_95IPS; z5dh+sr~c`I!T1OgpGO27!tH-jXUF%l{^!-bmB1L`amr%7Z{5RP!2-C(|C22T&T2Sm zNVaDrELHXhfO|q-#XTw_ABQ>nn*0oy&M0TPAL^Ab)?Y0Ctd<`*IbvS*ZTT6B5 zMSo7agF+qV)`QzqiN4VuD#n4y_$v9_IF=2SxAl~>%nGOy2au7R$3!GynLP3qbBM?P z9S&X{3|teA#$ggaX7D2|y1x{6GHQyM@irIj+Tev1tjszqDqS%9!CbaI<3P8$P-iK+ zw<@cCy2jGQ0v;w}n(+E8d>J;n@xX5oSb!t9dAON+AfFaY)T$^>t?HKBH1>WH07bwH z=bCxn|MfEtD^`6zOMxeB5#6D>nXR6g`P$J97RB&!EeHFv7e%}DWo?zHVDo)$1hbT1 z&WsGe6z$!0Ut@-%DAW~R8((rePm26Ed_rn|V3kcUhf5ZW{o$xBi*&zXXT;(5G&3Sy zW`C2W;Mj}Zd6rF+c!4W{fNQSH{C$iNu~owBAhNzv`R?6*NqzsV#&Jar%MXe7NV5NY1^&gIJE+n))CT8!UbMx+81{+KSI# zly}9B?SAM5=!0QdV*HxlVhzjgHh30;q936DJ>FaA!S_Gs!7~&GveqVni9sX^{=az8 zp9I0Cr!VHy2FCloepv#)Q*UTZvBleO?AxQ4)jJR&vVI|?`cH8F@20QZL!?STQ4r-n z;JH$n{w;xjep0fP&37y|=`n@_mcxG`0h?l9-xClwffUr8=C zkje_b0;m1RARLS_70|C^Qjm5 zZs(%tZ@91ctaQge`nE$br{0LO0d*?yyCw$Ream}VL+D2fq9M*BoJ~>^E6eqtArZ8djVQCOk20&DP`ai$h{mA|y0~ne2m}=uWn8HWy5nJc-8YApRW#-qURda!1k7cc0@8W8D_!?SXG}vK)zF)+ECHZh3v(oCX<;86R*{zH)I!C z!DC5XmF&^b+7M^zOj+rTb$QFW3)JR4@V)BMC0=mPVOS>*W$mfZEb!B0S5O4U|3_Ly zdSC?yM{3lKCt}RVH5jz9#}mrWdTopE8YvH8r_RCgfTAlmoRHJbz*(8?aB}?RB8-}J zG#^`t@gS;<>>zRYWzCjWI;G@|ulwLUQ45E(lQ->!mflS zWKMV}A5a_DlfQ99NAeFQimXiz+bcXfVP~)K+Cx`9%tx7!HE`#?`1-8Fe3#XyQeS)aN->svo?cR)U8Q z>x3Zm4S<$TTNzlJDyH~bEhItna*bRJoRHXnNl##&NRv_0A@1Sc$BV~G*HPu8#jN7% zb1egDu^bRc*JG237uz~jr3@^MpYiQV{o2v&MmN1yo-n3-q`@RnU zMkBo|z^kyiFFu+KOXy9v5Z9`L4LT_zD=f<^o^N7tLA&ccLys^-#dhFpVO-4SS;f`} zsvO@nXS`;wg2c^}+bUrlwX1t7=~d?dd3p=j%4F8oF%G&Yz%!Y+m(xtPcJ0Vd`}h3) z9iHTv%0#(;yTP8UkK?I~!n^(b&Qyn=glXt)!rMj%`p|+mxWzdM$s86x4aHZkQI!;* z`O@=Bht!lp1~x!FN#IapW#R%HVbJ}o^Mv1Hlg`%KwIv0hoqH8qhBqD-vx3ODcju=| zHdi1N?Vv9)$Y0TN6lbL%k2v6$Xc86fDYsy=o9#u;gg{@9kn8IsogoQ3*&93?<`H0`aSL}UEb_(ceC(d>>kYl1sBrdu?YsAprr0-ER@X?N8sx>pVT;Eg*5oL?)Q!7*bW)xEp<*-FR z4DUDg_UgPJ*&pd;GXOk4I2ZzAKA ztC81L133*ED|3UOg>k|bu(aCm(Z_lSuMNDjql#|ErD2Kp%gEyUg1zR|G8`ppxWOLD zj6IGA3KBlN$apUfQ1x@L5}$)e>jjO7pPnQ9+uv?eR?--3^n!#U&(njyCG`@FV^)u7 z_CEJITr=Q-A;|D)XY5JI)HKO_H43}fO$<=hBre?WkW=jJr3}?QW>g2ANzLn+BELE$ z(=E!VXR}84WtnZu??W+6c6;`+?E~H7AS>lIzO{pU9y7DofrsG;lC$z|v}~CC)nEDh z+3!uOLDR6Ir>g!j;Xwb~di_s#!7x zHcpxMzFz7uyLCvQHbL*Qya=4!P%_~_u-ynKMurrFAeP8%0v}7i3nNfrH<2J0@k}wlB zWo~E<;0YgXMf8Uh6I+wI4Sd?R%AvDUFT}1-`e^$ZPTg=g&Zc4wa@^Xez1A>&Uf?vK zN8V~I<*m`9J*nC(^(mg~rIDIw&7kRxm{XMj)E`Fa&1xabF-TKGaa&kG+fXKSPc!Dk zhb-Jm7v~RFC_K*8E%9qj8IvC$gb+2wQF6=<1!v89uxU}(63b_59zkXS_|FQ?mt?!UE+q|F8Z43d5@vy!1pnbhy)I03tf)H$W zGmVJjuduipy=ma61*+7;C;!C~)<|;TEsl{@CKa%57SnY|QOK3&){O6T3S>*0SmN2f zXW>P=Ag%#Z(;PTUq;R}8R%57s5!&4nFc6<<1X(611Lv$hfVkwDyU<@9s~`^)nG2m^4Gdd@x1 z>C`nQWa;#S&Ihld+(8xV=FE`poZ3Iz+2!x!Ebi@n>*57~a~*X2AmO+36eXG6nu#rV z(k_>1o02OSCslK$zoMW2yNl&a{@2v4<^h4R>PC?L!a z8*`YU@$g*fPHY_d=esEXYGnQVVwzBs)X*LsFa9A6_ckBVm%cQd*<%E=VtS|GaXy^6 zl&=o@U4b(>i?D=e$%NZNNDa$vegTrHknAb zNo}wwjUT?I^f22nHi5cf!dU((C(|US!Q>UayTq5PBlli}nzV;CwMTzkJ}IRZUcN>H z*O=+IzgpuM(wB4)RObWZ+u8W&y#+j}(Egswg6W*J5-mjUR1LeBmigV%6M=nn_;xLOS2}a&7u&ranQb*n@PMN0F;e6J-wR)dwR$U zG$x1XY6de*NWW5K;#MVFb{}MONykaECSRkUwbf0V$m1-V$rR(sJ7S!0y@hA52f+z! zbau=e<$|V}(aw?A*wa$XQo41B=+wKEa%G%GWK(LakQsST0@vxBX?Q}~fgSs{-ZI>H z8zK_0AoaO0riMG%(nl7(_Nw_!1=EBv3C1n<1U_nv)eypL6}4adf4%JVuK)uq<({)Nb;v`jIY>SOghPS=Q?w!?W)cwPhh}lU zrnK+*U%?AgBl(vdk-J^kge%+TV!<%&BBdyTL~L|NR?mJr@Hu$rrKw-Wql9Qqw_r}H zm3h-A5bcn5L7)%s>5NxJxjN^@b$^KxEdkvwNCGstfVOJ$BGm10y>2yzD=Vs~jOi-4 zl7Pbmes+h{aULA5|1V9J|8(bD1|nuI(vlMu}6(fK7ct#u741TY}1s-~$aqyIuo6 z1CLddX_uX}>B*V}=p)eN=`1poYfIK_&Z6B_7qUYHVX9)_Y~QR5K+Hup0P~xP8yF{V zeaWQ^F3|h+HEAN%d|Aoc`xls`j4|l%<+tXV#U5@KyZ7;lb@MS}3h0h8*D5|EC{Cji zc!Q&U1m~OHX?Z&v%KEEVNEGgPE`tBuUlNg@sZ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +package main + +import "github.com/onyx-and-iris/ignr-cli/cmd" + +func main() { + cmd.Execute() +}