Compare commits

...

23 commits

Author SHA1 Message Date
Thomas Buckley-Houston cb3ddd533f build: release v1.8.3
* Bump fast-json-patch and web-ext in /webext by @dependabot in https://github.com/browsh-org/browsh/pull/461
* Bump loader-utils from 2.0.2 to 2.0.4 in /webext by @dependabot in https://github.com/browsh-org/browsh/pull/453
* remove unnecessary RUN command by @lpmi-13 in https://github.com/browsh-org/browsh/pull/466
* Bump http-cache-semantics from 4.1.0 to 4.1.1 in /webext by @dependabot in https://github.com/browsh-org/browsh/pull/467
* fix: Golang install: use "amd64" for "x86_64" by @tombh in https://github.com/browsh-org/browsh/pull/463
* feat: Use log/slog for logging to file or stdout by @ananthb in https://github.com/browsh-org/browsh/pull/493
* feat: Structured log messages by @ananthb in https://github.com/browsh-org/browsh/pull/494
* chore: Clean up SETUP guides by @ananthb in https://github.com/browsh-org/browsh/pull/495
* chore: Remove manual install steps by @ananthb in https://github.com/browsh-org/browsh/pull/496
* fix: If debug is false discard logs by @ananthb in https://github.com/browsh-org/browsh/pull/497
* [Fix] Firefox inspecting logic on Windows by @Dragon1573 in https://github.com/browsh-org/browsh/pull/502
* feat: Add json schema (#505) by @Freed-Wu in https://github.com/browsh-org/browsh/pull/510

* @lpmi-13 made their first contribution in https://github.com/browsh-org/browsh/pull/466
* @ananthb made their first contribution in https://github.com/browsh-org/browsh/pull/493
* @Dragon1573 made their first contribution in https://github.com/browsh-org/browsh/pull/502
* @Freed-Wu made their first contribution in https://github.com/browsh-org/browsh/pull/510
2024-01-29 15:57:44 -03:00
Wu Zhenyu 200aec095d feat: Add json schema (#505) 2024-01-21 14:27:20 -03:00
是蓝兔哟~ 8bca0f17ee
[Fix] Firefox inspecting logic on Windows (#502)
* Fix (firefox_windows.go): Release resources

It seems `defer` keyword is using to release and close some resources.
It should be added to `getFirefoxPath` function.

Signed-off-by: Dragon1573 <49941141+Dragon1573@users.noreply.github.com>

* Fix (firefox_windows.go): Registry path

For Mozilla Firefox Stable edition, it's incorrect in `getFirefoxPath` function.

Signed-off-by: Dragon1573 <49941141+Dragon1573@users.noreply.github.com>

* Fix (firefox_windows.go): Registry Value

Signed-off-by: Dragon1573 <49941141+Dragon1573@users.noreply.github.com>

* Update (firefox_windows.go): Reformat code

Advices from GitHub Workflows, try fix this using GitHub Web.

---------

Signed-off-by: Dragon1573 <49941141+Dragon1573@users.noreply.github.com>
2023-12-24 07:37:17 -05:00
Ananth Bhaskararaman d7fb6e1045 fix: If debug is false discard logs
The slog change logged to stderr if debug was false.
This screwed up the UI.
2023-12-12 07:50:40 -05:00
Ananth Bhaskararaman 65344c3f80 chore: Remove manual install steps 2023-12-12 07:50:21 -05:00
Ananth Bhaskararaman f9c6fcf4cc chore: Clean up SETUP guides 2023-12-09 18:59:59 -05:00
Ananth Bhaskararaman c191b34201 feat: Structured log messages
Log messages have been re-written with structured fields.

Also, important Go depenedencies like x/sys and errors packages have
been updated.

Github actions have also been updated.
2023-12-09 13:17:50 -05:00
Ananth Bhaskararaman f93a4d12cf feat: Use log/slog for logging to file or stdout
Switched to Go1.21 to use the log/slog package for strutctured logging.

TODO: Log messages that are stringifying objects can now use strutctured
output.

TODO: Customise log levels for different messages.

Fix tests
2023-12-08 19:09:08 -05:00
Thomas Buckley-Houston d32ae0ba5a fix: Golang install: use "amd64" for "x86_64" 2023-02-02 18:38:32 -05:00
dependabot[bot] 1d4211ceb0 Bump http-cache-semantics from 4.1.0 to 4.1.1 in /webext
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-02 18:38:13 -05:00
Adam Leskis 0cef277365 remove unnecessary RUN command
WORKDIR already runs "mkdir -p" under the hood, so we don't need to add this extra command (and layer) to the Dockerfile.
2023-02-02 18:37:35 -05:00
dependabot[bot] acaa7d6459 Bump loader-utils from 2.0.2 to 2.0.4 in /webext
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 2.0.2 to 2.0.4.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v2.0.4/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v2.0.2...v2.0.4)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-02 18:36:52 -05:00
dependabot[bot] 51eaefba13 Bump fast-json-patch and web-ext in /webext
Bumps [fast-json-patch](https://github.com/Starcounter-Jack/JSON-Patch) to 3.1.1 and updates ancestor dependency [web-ext](https://github.com/mozilla/web-ext). These dependencies need to be updated together.


Updates `fast-json-patch` from 2.2.1 to 3.1.1
- [Release notes](https://github.com/Starcounter-Jack/JSON-Patch/releases)
- [Commits](https://github.com/Starcounter-Jack/JSON-Patch/compare/v2.2.1...3.1.1)

Updates `web-ext` from 7.1.1 to 7.5.0
- [Release notes](https://github.com/mozilla/web-ext/releases)
- [Commits](https://github.com/mozilla/web-ext/compare/7.1.1...7.5.0)

---
updated-dependencies:
- dependency-name: fast-json-patch
  dependency-type: indirect
- dependency-name: web-ext
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-02 18:36:19 -05:00
Thomas Buckley-Houston 010b8531f6
chore: Release v1.8.2 2023-01-30 21:08:02 -05:00
Thomas Buckley-Houston ffe3b6510e
chore: Bump version v1.8.1 2023-01-30 20:58:08 -05:00
Samveen 1591cf8e6a [scripts/misc.bash]Remove hard-coded arch in golang download, and use build platform arch instead. 2023-01-30 09:03:55 -05:00
Samveen b389228682 Use Debian's firefox-esr instead of the standalone Mozilla build 2023-01-30 09:03:55 -05:00
Thomas Buckley-Houston a547ac71fd
ci: Run Github Actions for PRs as well as pushes 2023-01-30 07:19:06 -05:00
Thomas Buckley-Houston 7e68247557 Use ENTRYPOINT instead of CMD in Dockerfile
Fixes #346
2022-07-25 22:46:58 -04:00
Thomas Buckley-Houston 277ede9a60
ci: Also push Docker image 'latest' tag 2022-07-21 12:30:57 -04:00
Thomas Buckley-Houston 3bc427f416 devops: Update release process for Github 2022-07-20 15:22:12 -04:00
Thomas Buckley-Houston 87bf16dd20 devops: Update Docker process for releasing 2022-07-20 15:22:12 -04:00
Thomas Buckley-Houston 0ef4e64f93 chore: Update README 2022-07-20 15:22:12 -04:00
33 changed files with 1994 additions and 1988 deletions

View file

@ -1,5 +1,5 @@
name: Lint
on: [push]
on: [push, pull_request]
jobs:
lint:
@ -13,11 +13,11 @@ jobs:
with:
fetch-depth: 0
- name: Setup go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.18.x
go-version: 1.21.x
- name: Setup node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16

View file

@ -1,30 +1,32 @@
name: Test/Release
on: [push]
name: Test-Release
on: [push, pull_request]
jobs:
test_maybe_release:
name: Test (then release if new version)
tests:
name: "Tests (webextension, interfacer: unit, tty, http-server)"
runs-on: ubuntu-latest
env:
GOPATH: ${{ github.workspace }}
GOBIN: ${{ github.workspace }}/bin
outputs:
is_new_version: ${{ steps.check_versions.outputs.is_new_version }}
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.18.x
go-version-file: 'interfacer/go.mod'
- name: Setup node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16
node-version-file: '.nvmrc'
- name: Install Firefox
uses: browser-actions/setup-firefox@latest
with:
firefox-version: 102.0.1 # TODO: Use same version in Dockerfile
firefox-version: 102.0.1
- run: firefox --version
# Web extension tests
@ -33,14 +35,13 @@ jobs:
- name: Web extension tests
run: npm test
working-directory: ./webext
- run: npm run build_webextension
working-directory: ./webext
# Interfacer tests
- name: Build
run: go build ./cmd/browsh
working-directory: ./interfacer
- name: Interfacer tests setup
run: |
touch interfacer/src/browsh/browsh.xpi
cd webext
npm run build:dev
- name: Unit tests
run: go test -v $(find src/browsh -name '*.go' | grep -v windows)
working-directory: ./interfacer
@ -51,16 +52,72 @@ jobs:
if: ${{ failure() }}
run: cat ./interfacer/test/tty/debug.log || echo "No log file"
- name: HTTP Server tests
run: go test test/http-server/*.go -v -ginkgo.slowSpecThreshold=30 -ginkgo.flakeAttempts=3
working-directory: ./interfacer
uses: nick-fields/retry@v2
with:
max_attempts: 3
retry_on: error
timeout_minutes: 15
command: |
cd interfacer
go test test/http-server/*.go -v -ginkgo.slowSpecThreshold=30 -ginkgo.flakeAttempts=3
- name: HTTP Server debug log
if: ${{ failure() }}
run: cat ./interfacer/test/http-server/debug.log || echo "No log file"
# Release
- name: Check for new version
id: check_versions
run: ./ctl.sh github_actions_output_version_status
- name: Release
if: contains(steps.check_versions.outputs.is_new_version, 'true')
release:
name: Release
runs-on: ubuntu-latest
needs: tests
if: github.ref == 'refs/heads/master' && contains(needs.tests.outputs.is_new_version, 'true')
env:
GOPATH: ${{ github.workspace }}
GOBIN: ${{ github.workspace }}/bin
MDN_KEY: ${{ secrets.MDN_KEY }}
DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Setup Deploy Keys
uses: webfactory/ssh-agent@v0.5.4
with:
# Note that these private keys depend on having an ssh-keygen'd comment with the
# Git remote URL. This is because Github Actions use the *first* matching private
# key and fails if it doesn't match. webfactory/ssh-agent
ssh-private-key: |
${{ secrets.HOMEBREW_DEPLOY_KEY }}
${{ secrets.WWW_DEPLOY_KEY }}
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup node
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
- name: Setup go
uses: actions/setup-go@v3
with:
go-version-file: 'interfacer/go.mod'
- run: npm ci
working-directory: ./webext
- name: Binary Release
run: ./ctl.sh release
- name: Push new tag
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
tags: true
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: tombh
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
- name: Docker Release
run: ./ctl.sh docker_release
- name: Update Homebrew Tap
run: ./ctl.sh update_homebrew_tap_with_new_version
- name: Update Browsh Website
run: ./ctl.sh update_browsh_website_with_new_version

11
.gitignore vendored
View file

@ -12,3 +12,14 @@ webext/node_modules
webext/dist/*
dist
*.xpi
# This is because of an odd permissions quirk on Github Actions. I can't seem to find a
# way to delete these files in CI, so let's just ignore them. Otherwise Goreleaser complains
# about a dirty working tree.
/pkg
/bin
# Goreleaser needs to upload the webextension as an extra file in the release. But it doesn't
# like Git to be in a dirty state. Also Goreleaser is run at PWD ./interfacer, so we can't
# reference the webextension with something like ../webext/...
interfacer/browsh-*.xpi

View file

@ -1,4 +1,4 @@
FROM bitnami/minideb:stretch as build
FROM bitnami/minideb:bullseye as build
RUN install_packages \
curl \
@ -13,68 +13,69 @@ RUN install_packages \
libssl-dev \
pkg-config \
libprotobuf-dev \
make
make \
bzip2
# Install Golang
# Helper scripts
WORKDIR /build
ADD .git .git
ADD .github .github
ADD scripts scripts
ADD ctl.sh .
# Install Golang and Browsh
ENV GOROOT=/go
ENV GOPATH=/go-home
ENV PATH=$GOROOT/bin:$GOPATH/bin:$PATH
RUN curl -L -o go.tar.gz https://dl.google.com/go/go1.9.2.linux-amd64.tar.gz
RUN mkdir -p $GOPATH/bin
RUN tar -C / -xzf go.tar.gz
ENV BASE=$GOPATH/src/browsh/interfacer
WORKDIR $BASE
ADD interfacer $BASE
# Build Browsh
RUN $BASE/contrib/build_browsh.sh
WORKDIR $BASE
RUN /build/ctl.sh install_golang $BASE
RUN /build/ctl.sh build_browsh_binary $BASE
###########################
# Actual final Docker image
###########################
FROM bitnami/minideb:stretch
FROM bitnami/minideb:bullseye
ENV HOME=/app
WORKDIR /app
WORKDIR $HOME
COPY --from=build /go-home/src/browsh/interfacer/browsh /app/browsh
COPY --from=build /go-home/src/browsh/interfacer/browsh /app/bin/browsh
RUN install_packages \
xvfb \
libgtk-3-0 \
curl \
ca-certificates \
bzip2 \
libdbus-glib-1-2 \
procps
procps \
libasound2 \
libxtst6 \
firefox-esr
# Block ads, etc. This includes porn just because this image is also used on the
# public SSH demo: `ssh brow.sh`.
RUN curl -o /etc/hosts https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn-social/hosts
RUN curl \
-o /etc/hosts \
https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews-gambling-porn-social/hosts
# Don't use root
RUN useradd -m user --home /app
RUN chown user:user /app
USER user
# Setup Firefox
ENV PATH="${HOME}/bin/firefox:${PATH}"
ADD .travis.yml .
ADD interfacer/contrib/setup_firefox.sh .
RUN ./setup_firefox.sh
RUN rm setup_firefox.sh && rm .travis.yml
ENV PATH="${HOME}/bin:${HOME}/bin/firefox:${PATH}"
# Firefox behaves quite differently to normal on its first run, so by getting
# that over and done with here when there's no user to be dissapointed means
# that all future runs will be consistent.
RUN TERM=xterm script \
--return \
-c "/app/browsh" \
-c "/app/bin/browsh" \
/dev/null \
>/dev/null & \
sleep 10
CMD ["/app/browsh"]
ENTRYPOINT ["/app/bin/browsh"]

View file

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/browsh-org/browsh.svg?branch=master)](https://travis-ci.org/browsh-org/browsh) [![Follow @brow_sh](https://img.shields.io/twitter/follow/brow_sh.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=brow_sh)
[![Follow @brow_sh](https://img.shields.io/twitter/follow/brow_sh.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=brow_sh)
![Browsh Logo](https://www.brow.sh/assets/images/browsh-header.jpg)
@ -35,8 +35,8 @@ is running somewhere else on mains electricity.
## Installation
Download a binary from the [releases](https://github.com/browsh-org/browsh/releases) (~7MB).
You will need to have [Firefox 63](https://www.mozilla.org/en-US/firefox/new/) (or higher) already installed.
Download a binary from the [releases](https://github.com/browsh-org/browsh/releases) (~11MB).
You will need to have [Firefox](https://www.mozilla.org/en-US/firefox/new/) already installed.
Or download and run the Docker image (~230MB) with:
`docker run --rm -it browsh/browsh`
@ -48,47 +48,18 @@ browser.
For full documentation click [here](https://www.brow.sh/docs/introduction/).
## Contributing
To setup a development environment you will need NodeJS and Golang installed. If you get stuck
setting up your environment, take a look in `.travis.yml`, it has to setup everything
from scratch for every push to GitHub.
_Note that some of these instructions may be out of date (July 2022)_
I'd recommend [nvm](https://github.com/creationix/nvm) for NodeJS - note that
`nvm install` will automatically parse the `.nvmrc` version in this repo to get
the correct NodeJS version. For Golang it's probably best to just use your OS's
package manager. The current Golang version being used is stored in `.travis.yml`.
For generic Linux systems you can follow [this guide](https://github.com/browsh-org/browsh/blob/master/SETUP_DEV_LINUX.md) on how to setup a build environment, that you may be able to adapt for other systems as well.
You'll then need to install the project dependencies. For the webextension, just
run: `npm install` inside the `webext/` folder. For the CLI client you will first
need to install `dep`, there is a script for this in `interfacer/contrib/setup_dep.sh`.
I don't fully understand Golang's best practices, but it seems you are forced to
keep your Go project's code under `$GOPATH/src`, you might be able to get away
with symlinks. Anyway, to install the dependencies use: `dep ensure` inside the
`interfacer/` folder.
Windows users can follow [this guide](https://github.com/browsh-org/browsh/blob/master/SETUP_DEV_WIN.md) in order to set up a build environment.
Then the ideal setup for development is:
* have Webpack watch the JS code so that it rebuilds automatically:
`webpack --watch`
* run the CLI client without giving it the responsibility to launch Firefox:
`go run ./interfacer/src/main.go --firefox.use-existing --debug`
* have Mozilla's handy `web-ext` tool run Firefox and reinstall the
webextension every time webpack rebuilds it: (in `webext/dist`)
`web-ext run --verbose`
For generic Linux systems you can follow [this guide](https://github.com/browsh-org/browsh/blob/master/contrib/setup_linux_build_environment.md) on how to setup a build environment, that you may be able to adapt for other systems as well.
Windows users can follow [this guide](https://github.com/browsh-org/browsh/blob/master/contrib/setup_windows_build_environment.md) in order to set up a build environment.
Mac users may follow [this guide](https://github.com/browsh-org/browsh/blob/master/contrib/setup_mac_build_environment.md) that goes through the steps of setting up a build environment.
Mac users may follow [this guide](https://github.com/browsh-org/browsh/blob/master/SETUP_DEV_OSX.md) that goes through the steps of setting up a build environment.
### Communication
Questions about Brow.sh? Stuck trying to resolve a tricky issue? Connect with the Brow.sh community on [Gitter](https://gitter.im/browsh)!
## Building a Browsh release
If you'd like to build Browsh for a new package manager, or for any other reason,
you can use the script at `interfacer/contrib/build_browsh.sh` as a guide. Note
you won't be able to build the web extension as Mozilla only allows one canonical
version of web extensions per version number. So the build script downloads the
official web extension `.xpi` file from the Mozilla archives.
Questions about Brow.sh? Stuck trying to resolve a tricky issue? Try:
- [Github Discussions](https://github.com/browsh-org/browsh/discussions)
- [Gitter](https://gitter.im/browsh)
## Tests

View file

@ -1,86 +1,19 @@
# How to setup the build environment for browsh on a generic Linux system
This guide was made for x86-64 based Linux systems. You may try to adapt it to other systems.
In this guide, it is assumed that you can't install the required go, nodejs and firefox versions from your distribution's repositories.
In case they are available, you should try to install go, nodejs and firefox using your distribution's package manager.
## Installing golang
Get the latest amd64 binary for Linux on the [golang download page](https://golang.org/dl/).
Extract to `/usr/local` with:
```
$ tar -C /usr/local -xzf go1.11.linux-amd64.tar.gz
```
Add `/usr/local/go/bin` to your `PATH` in `~/.profile`
## Installing nodejs/npm
Go to the [nodejs download page](https://nodejs.org/download) and select the LTS version of the Linux x86 64bit binaries.
```
$ mkdir /usr/local/lib/nodejs
$ VERSION=v8.11.4
$ DISTRO=linux-x64
$ tar -xJvf node-$VERSION-$DISTRO.tar.xz -C /usr/local/lib/nodejs
$ mv /usr/local/lib/nodejs/node-$VERSION-$DISTRO /usr/local/lib/nodejs/node-$VERSION
```
Edit your `~/.profile` to add `/usr/local/lib/nodejs/node-v8.11.4/bin` to your `PATH`, then reload your profile:
```
$ source ~/.profile
```
Create symlinks for *node* and *npm*:
```
$ sudo ln -s /usr/local/lib/nodejs/node-$VERSION/bin/node /usr/local/bin/node
$ sudo ln -s /usr/local/lib/nodejs/node-$VERSION/bin/npm /usr/local/bin/npm
```
Install Go, Node.js, and Firefox using your system's package manager.
**Browsh requires Version 57 or higher.**
Now you should be able to call the *go* and *node* binaries:
```
$ go version
$ node --version
```shell
go version
node --version
```
## Installing webpack and webpack-cli
## Install webpack, webpack-cli, & web-ext
(`--no-audit` is used to get around errors, may not be needed)
```
$ npm install -g --no-audit webpack
$ npm install -g webpack-cli
```
## Installing web-ext
(`--no-audit` is used to get around errors, may not be needed)
```
$ npm install -g --ignore-scripts web-ext
```
## Installing Firefox
You may install *firefox* from your distribution's repositories. **Version 57 or higher is required.**
### Installing firefox from mozilla's binaries
See `interfacer/contrib/setup_firefox.sh` for reference.
```
$ export FIREFOX_VERSION=60.0
$ mkdir -p $HOME/bin
$ pushd $HOME/bin
$ curl -L -o firefox.tar.bz2 https://ftp.mozilla.org/pub/firefox/releases/$FIREFOX_VERSION/linux-x86_64/en-US/firefox-$FIREFOX_VERSION.tar.bz2
$ bzip2 -d firefox.tar.bz2
$ tar xf firefox.tar
$ popd
```shell
npm install -g webpack webpack-cli web-ext
```
## Cloning the browsh repository
@ -89,58 +22,58 @@ It's assumed that you already have *git* installed.
Run this anywhere you want:
```
$ git clone https://github.com/browsh-org/browsh.git
```shell
git clone https://github.com/browsh-org/browsh.git
```
## Setting up the build environment in the cloned repository
### Setting up dependencies
### Setting up dependencies
```shell
browsh=/path/to/browsh
cd "$browsh/webext"
npm run get-gobindata
npm install
npm run build
diff -u <(echo -n) <(gofmt -d ./)
./node_modules/.bin/prettier --list-different "{src,test}/**/*.js"
```
$ REPO_ROOT=/path/to/browsh
$ cd $REPO_ROOT/webext
$ source ~/.nvm/nvm.sh # this is optional
$ npm run get-gobindata
$ npm install
$ npm run build
$ diff -u <(echo -n) <(gofmt -d ./)
$ ./node_modules/.bin/prettier --list-different "{src,test}/**/*.js"
```
### Building browsh
```
$ cd $REPO_ROOT/interfacer
$ go build -o browsh src/main.go
```shell
cd "$browsh/interfacer"
go build -o browsh src/main.go
```
### Building the web extension
In `$REPO_ROOT/webext`:
In `$browsh/webext`:
```
$ webpack --watch
```shell
webpack --watch
```
This will continuously watch for changes made to the web extension and rebuild it.
## Run firefox and the webextension
In `$REPO_ROOT/webext/dist`:
In `$browsh/webext/dist`:
```
$ web-ext run --verbose --firefox path/to/firefox
```shell
web-ext run --verbose --firefox path/to/firefox
```
## Run browsh
```
$ cd $REPO_ROOT/interfacer
$ go run ./cmd/browsh --firefox.use-existing --debug
```shell
cd "$browsh/interfacer"
go run ./cmd/browsh --firefox.use-existing --debug
```
Or after building:
```
$ ./browsh --firefox.use-existing --debug
```shell
./browsh --firefox.use-existing --debug
```

View file

@ -1,90 +1,88 @@
# How to setup Browsh's build system for Mac
If you just want to try Browsh, you can use [Homebrew](https://brew.sh/) (check out the [installation page](https://www.brow.sh/docs/installation/) at the [official site](https://www.brow.sh/)).
If you want to try Browsh, you can use [Homebrew](https://brew.sh/).
Check out the [installation page](https://www.brow.sh/docs/installation/) at the
[official site](https://www.brow.sh/)).
## Installations
You need Go, Firefox and Node.js to run Browsh.
### Install Go
Follow the [installation guide](https://golang.org/doc/install) (you can use an installer).
#### Ensure your GOPATH is set
```sh
$ echo $GOPATH
/Users/uesr_name/go
$ # anywhere is ok, but make sure it's not none
```
#### Ensure you have `$GOPATH/src` and `$GOPATH/bin` folders
If you're not sure if you have these folders, run:
```sh
$ mkdir "$GOPATH/src"
$ mkdir "$GOPATH/bin"
```
### Install Firefox
Follow the official [guide](https://support.mozilla.org/en-US/kb/how-download-and-install-firefox-mac) to install Firefox.
Follow the official [guide](https://support.mozilla.org/en-US/kb/how-download-and-install-firefox-mac)
to install Firefox.
#### Include Firefox to your PATH
The `firefox` executable is probably at `/Applications/Firefox.app/Contents/MacOS`. You need to add it to your `PATH` so that Browsh can create new instances of Firefox.
The `firefox` executable is probably at `/Applications/Firefox.app/Contents/MacOS`.
You need to add it to your `PATH` so that Browsh can create new instances of Firefox.
### Install Node.js
Follow the [official downloading page](https://nodejs.org/en/download/).
> v8.11.4. is currently recommended for working with Browsh (?)
Use Nodejs > v8.11.4 with Browsh.
#### Install web-ext globally
It's a Mozilla's handy tool for working with Firefox web extensions:
```sh
$ npm install -g web-ext
It's a Mozilla tool for working with Firefox web extensions:
```shell
npm install -g web-ext
```
## Setting up your Browsh
### Clone Browsh
Fork Browsh to your Github account. Clone it to `$GOPATH/src`.
Fork Browsh to your Github account.
Clone it to a directory of your choice.
We will refer to this directory as `$browsh` for the rest of the guide.
### Install NPM packages
```shell
$ cd "$GOPATH/src/browsh/webext"
$ npm install
cd "$browsh/webext"
npm install
```
### Run the build script
```sh
$ cd "$GOPATH/src/browsh"
$ # install several required package"
$ ./interfacer/contrib/build_browsh.sh
cd "$browsh"
# install required package"
./interfacer/contrib/build_browsh.sh
```
## Running Browsh from source
Now that you have all of the required dependencies installed, we can run Browsh. Open three terminals and do the follows:
Now that you have the required dependencies installed, we can run Browsh.
Open three terminals and do the following:
### Terminal 1 (builds JavaScript)
```sh
$ cd "$GOPATH/src/browsh/webext"
$ # create a dist folder inside the webext folder.
$ npx webpack --watch
cd "$browsh/webext
# create a dist folder inside the webext folder.
npx webpack --watch
```
### Terminal 2 (handles Firefox web extension)
```sh
$ # the dist folder is created in the first terminal
$ cd "$GOPATH/src/browsh/webext/dist"
$ # create a dist folder inside the webext folder.
$ npx webpack --watch
mkdir "$browsh/webext/dist"
cd "$browsh/webext/dist"
npx webpack --watch
```
### Terminal 3 (Displays Browsh)
```sh
$ cd "$GOPATH/src/browsh/interfacer"
$ go run ./cmd/browsh/main.go --firefox.use-existing --debug
cd "$browsh/interfacer"
go run ./cmd/browsh/main.go --firefox.use-existing --debug
```

View file

@ -1,8 +1,11 @@
# How to set up the build environment for Browsh on Windows
This guide is for those who want to set up the build environment on Windows Command Prompt or Powershell. Since some of the shell scripts are needed to set up the environment, you can just use **Git Bash** to run these scripts.
This guide is for those who want to set up the build environment on Windows
Command Prompt or Powershell.
Setup depends on running shell scripts. You can use **Git Bash** to run those scripts.
## Setting up Go, NodeJs, and GOPATH
Download and install Go for Windows at [Go download page](https://golang.org/dl/).
Download and install NodeJs for Windows at [NodeJs download page](https://nodejs.org/en/download/)
@ -10,17 +13,24 @@ Download and install NodeJs for Windows at [NodeJs download page](https://nodejs
Using Command Prompt or Powershell:
Create a go workspace:
> mkdir go
> cd go
```shell
mkdir go
cd go
```
Set GOPATH to current directory.
> set GOPATH=%cd%
```shell
set GOPATH=%cd%
```
Create subdirectories bin and src within your go directory:
> mkdir bin
> mkdir src
```shell
mkdir bin
mkdir src
```
Add %GOPATH%/bin to your PATH.
@ -29,44 +39,63 @@ Add %GOPATH%/bin to your PATH.
Download and install Chocolatey package manager at [Chocolatey download page](https://chocolatey.org/install).
Using chocolatey package manager run:
> choco install dep
```shell
choco install dep
```
## Installing webpack, web-ext, and Firefox
> npm install -g --no-audit webpack
> npm install -g --ignore-scripts web-ext
```shell
npm install -g --no-audit webpack
npm install -g --ignore-scripts web-ext
```
Download and install Firefox for Windows at [Firefox download page](https://www.mozilla.org/en-US/firefox/new/).
Note: **Version 57 or higher is required.**
Note: **Browsh requires Firefox versions 57 or higher.**
## Cloning the browsh repository
Navigate to GOPATH/src and run:
> git clone https://github.com/browsh-org/browsh.git
Navigate to GOPATH/src and run:
```shell
git clone https://github.com/browsh-org/browsh.git
```
## Setting up dependencies
Navigate to browsh/webext and run:
> npm install
```shell
npm install
```
## Building browsh with Git Bash
Using Git Bash, navigate to browsh/interfacer/contrib and run:
> ./build_browsh.sh
```shell
./build_browsh.sh
```
## Running browsh
Using three Command Prompts or Powershells:
Navigate to GOPATH/browsh and run:
> go run ./interfacer/src/main.go --firefox.use-existing --debug
```shell
go run ./interfacer/src/main.go --firefox.use-existing --debug
```
Navigate to browsh/webext and run:
> webpack --watch
```shell
webpack --watch
```
Navigate to browsh/webext/dist and run:
> web-ext run --verbose
```shell
web-ext run --verbose
```

10
ctl.sh
View file

@ -1,11 +1,12 @@
#!/bin/env bash
#!/usr/bin/env bash
set -e
function_to_run=$1
export PROJECT_ROOT && PROJECT_ROOT=$(git rev-parse --show-toplevel)
export PROJECT_ROOT
export GORELEASER_VERSION=1.10.2
export GOBINDATA_VERSION=3.23.0
PROJECT_ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
function _includes_path {
echo "$PROJECT_ROOT"/scripts
@ -26,4 +27,7 @@ if [[ $(type -t "$function_to_run") != function ]]; then
fi
shift
pushd "$PROJECT_ROOT" || _panic
"$function_to_run" "$@"
popd || _panic

View file

@ -57,15 +57,14 @@ nfpms:
brews:
- name: browsh
tap:
owner: browsh-org
name: homebrew-browsh
commit_author:
name: Goreleaser Bot care of Github Actions
email: ci@github.com
homepage: "https://www.brow.sh"
description: "The modern, text-based browser"
caveats: "You need Firefox 57 or newer to run Browsh"
# We do the upload manually because Goreleaser doesn't support Deploy Keys and Github
# doesn't support repo-specific Access Tokens 🙄
skip_upload: true
release:
extra_files:
- glob: ./webext/dist/web-ext-artifacts/browsh-{{ Env.BROWSH_VERSION }}-an+fx.xpi
- glob: ./browsh-*.xpi

View file

@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -ex
if [ ! -f .travis.yml ]; then
PROJECT_ROOT=$(git rev-parse --show-toplevel)
else
PROJECT_ROOT=.
fi
line=$(grep 'firefox: "' < $PROJECT_ROOT/.travis.yml)
version=$(echo $line | grep -o '".*"' | cut -d " " -f 1 | sed 's/"//g')
# Firefox is needed both for testing in Travis and embedding in the Docker
# image used by the Browsh as a Service platform. So we need to be able to
# give a specific and consistent version pin.
FIREFOX_VERSION=$version
mkdir -p $HOME/bin
pushd $HOME/bin
curl -L -o firefox.tar.bz2 https://ftp.mozilla.org/pub/firefox/releases/$FIREFOX_VERSION/linux-x86_64/en-US/firefox-$FIREFOX_VERSION.tar.bz2
bzip2 -d firefox.tar.bz2
tar xf firefox.tar
popd
firefox --version

View file

@ -1,42 +1,45 @@
module github.com/browsh-org/browsh/interfacer
go 1.18
go 1.21
require (
github.com/NYTimes/gziphandler v1.1.1
github.com/gdamore/tcell v1.4.0
github.com/go-errors/errors v1.4.2
github.com/gorilla/websocket v1.5.0
github.com/go-errors/errors v1.5.1
github.com/gorilla/websocket v1.5.1
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.19.0
github.com/onsi/gomega v1.30.0
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.12.0
github.com/spf13/viper v1.18.1
github.com/ulule/limiter v2.2.2+incompatible
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8
golang.org/x/sys v0.15.0
)
require (
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gdamore/encoding v1.0.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.2 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/afero v1.9.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.4.0 // indirect
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/ini.v1 v1.66.6 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View file

@ -1,535 +1,181 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
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.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
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/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw=
github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/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/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w=
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y=
github.com/spf13/afero v1.9.0 h1:sFSLUHgxdnN32Qy38hK3QkYBFXZj9DKjVjCUCtD7juY=
github.com/spf13/afero v1.9.0/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
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.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM=
github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs=
github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/ulule/limiter v2.2.2+incompatible h1:1lk9jesmps1ziYHHb4doL7l5hFkYYYA3T8dkNyw7ffY=
github.com/ulule/limiter v2.2.2+incompatible/go.mod h1:VJx/ZNGmClQDS5F6EmsGqK8j3jz1qJYZ6D9+MdAD+kw=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0=
golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View file

@ -3,7 +3,8 @@ package browsh
import (
"encoding/base64"
"fmt"
"io/ioutil"
"io"
"log/slog"
"net/url"
"os"
"os/exec"
@ -44,40 +45,18 @@ var (
)
func setupLogging() {
dir, err := os.Getwd()
if err != nil {
Shutdown(err)
}
logfile = fmt.Sprintf(filepath.Join(dir, "debug.log"))
fmt.Println("Logging to: " + logfile)
if _, err := os.Stat(logfile); err == nil {
os.Truncate(logfile, 0)
}
if err != nil {
Shutdown(err)
}
}
// Log for general purpose logging
// TODO: accept generic types
func Log(msg string) {
if !*isDebug {
return
}
if viper.GetBool("http-server-mode") && !IsTesting {
fmt.Println(msg)
} else {
f, oErr := os.OpenFile(logfile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if oErr != nil {
Shutdown(oErr)
out := io.Discard
if *isDebug {
dir, err := os.Getwd()
if err != nil {
Shutdown(err)
}
defer f.Close()
msg = msg + "\n"
if _, wErr := f.WriteString(msg); wErr != nil {
Shutdown(wErr)
logfile = fmt.Sprintf(filepath.Join(dir, "debug.log"))
if out, err = os.OpenFile(logfile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644); err != nil {
Shutdown(err)
}
}
slog.SetDefault(slog.New(slog.NewTextHandler(out, nil)))
}
// Initialise browsh
@ -85,41 +64,42 @@ func Initialise() {
if IsTesting {
*isDebug = true
}
if *isDebug {
setupLogging()
}
setupLogging()
loadConfig()
}
// Shutdown tries its best to cleanly shutdown browsh and the associated browser
func Shutdown(err error) {
if *isDebug {
if e, ok := err.(*errors.Error); ok {
Log(fmt.Sprintf(e.ErrorStack()))
} else {
Log(err.Error())
}
msg := "shutting down"
var e *errors.Error
if errors.As(err, &e) {
slog.Error(msg, "errorStack", e.ErrorStack())
} else {
slog.Error(msg, "error", err)
}
exitCode := 0
if screen != nil {
screen.Fini()
}
if err.Error() != "normal" {
exitCode := 0
if !errors.Is(err, errNormalExit) {
exitCode = 1
println(err.Error())
}
os.Exit(exitCode)
}
func Log(message string) {
}
func saveScreenshot(base64String string) {
dec, err := base64.StdEncoding.DecodeString(base64String)
if err != nil {
Shutdown(err)
}
file, err := ioutil.TempFile(os.TempDir(), "browsh-screenshot")
file, err := os.CreateTemp("", "browsh-screenshot")
if err != nil {
Shutdown(err)
}
defer file.Close()
if _, err := file.Write(dec); err != nil {
Shutdown(err)
}
@ -132,7 +112,6 @@ func saveScreenshot(base64String string) {
}
message := "Screenshot saved to " + fullPath
sendMessageToWebExtension("/status," + message)
file.Close()
}
// Shell provides nice and easy shell commands
@ -142,9 +121,13 @@ func Shell(command string) string {
parts = parts[1:]
out, err := exec.Command(head, parts...).CombinedOutput()
if err != nil {
errorMessge := fmt.Sprintf(
"Browsh tried to run `%s` but failed with: %s", command, string(out))
Shutdown(errors.New(errorMessge))
err := fmt.Errorf(
"Browsh tried to run `%s` but failed with: %s, err: %w",
command,
string(out),
err,
)
Shutdown(err)
}
return strings.TrimSpace(string(out))
}
@ -154,9 +137,14 @@ func TTYStart(injectedScreen tcell.Screen) {
screen = injectedScreen
setupTcell()
writeString(1, 0, logo, tcell.StyleDefault)
writeString(0, 15, "Starting Browsh v"+browshVersion+", the modern text-based web browser.", tcell.StyleDefault)
writeString(
0,
15,
"Starting Browsh v"+browshVersion+", the modern text-based web browser.",
tcell.StyleDefault,
)
StartFirefox()
Log("Starting Browsh CLI client")
slog.Info("Starting Browsh CLI client")
go readStdin()
startWebSocketServer()
}

View file

@ -3,6 +3,7 @@ package browsh
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"strings"
@ -30,15 +31,15 @@ func startWebSocketServer() {
serverMux := http.NewServeMux()
serverMux.HandleFunc("/", webSocketServer)
port := viper.GetString("browsh.websocket-port")
Log("Starting websocket server...")
slog.Info("Starting websocket server...")
if netErr := http.ListenAndServe(":"+port, serverMux); netErr != nil {
Shutdown(errors.New(fmt.Errorf("Error starting websocket server: %v", netErr)))
Shutdown(fmt.Errorf("Error starting websocket server: %w", netErr))
}
}
func sendMessageToWebExtension(message string) {
if !IsConnectedToWebExtension {
Log("Webextension not connected. Message not sent: " + message)
slog.Info("Webextension not connected. Message not sent", "message", message)
return
}
stdinChannel <- message
@ -53,12 +54,12 @@ func webSocketReader(ws *websocket.Conn) {
handleWebextensionCommand(message)
if err != nil {
if websocket.IsCloseError(err, websocket.CloseGoingAway) {
Log("Socket reader detected that the browser closed the websocket")
slog.Info("Socket reader detected that the browser closed the websocket")
triggerSocketWriterClose()
return
}
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
Log("Socket reader detected that the connection unexpectedly dissapeared")
slog.Error("Socket reader detected that the connection unexpectedly dissapeared")
triggerSocketWriterClose()
return
}
@ -89,7 +90,7 @@ func handleWebextensionCommand(message []byte) {
case "/screenshot":
saveScreenshot(parts[1])
default:
Log("WEBEXT: " + string(message))
slog.Info("WEBEXT", "message", string(message))
}
}
@ -102,13 +103,13 @@ func handleRawFrameTextCommands(parts []string) {
Shutdown(err)
}
if incoming.RequestID != "" {
Log("Raw text for " + incoming.RequestID)
slog.Info("Raw text for", "RequestID", incoming.RequestID)
rawTextRequests.store(incoming.RequestID, incoming.RawJSON)
} else {
Log("Raw text but no associated request ID")
slog.Info("Raw text but no associated request ID")
}
} else {
Log("WEBEXT: " + strings.Join(parts[0:], ","))
slog.Info("WEBEXT", "command", strings.Join(parts[0:], ","))
}
}
@ -117,7 +118,8 @@ func handleRawFrameTextCommands(parts []string) {
// automatically notice until it actually needs to send something. So we force that
// by sending this NOOP text.
// TODO: There's a potential race condition because new connections share the same
// Go channel. So we need to setup a new channel for every connection.
//
// Go channel. So we need to setup a new channel for every connection.
func triggerSocketWriterClose() {
stdinChannel <- "BROWSH CLIENT FORCING CLOSE OF WEBSOCKET WRITER"
}
@ -128,12 +130,12 @@ func webSocketWriter(ws *websocket.Conn) {
defer ws.Close()
for {
message = <-stdinChannel
Log(fmt.Sprintf("TTY sending: %s", message))
slog.Info("TTY sending", "message", message)
if err := ws.WriteMessage(websocket.TextMessage, []byte(message)); err != nil {
if err == websocket.ErrCloseSent {
Log("Socket writer detected that the browser closed the websocket")
if errors.Is(err, websocket.ErrCloseSent) {
slog.Info("Socket writer detected that the browser closed the websocket")
} else {
Log("Socket writer detected unexpected closure of websocket")
slog.Error("Socket writer detected unexpected closure of websocket", "error", err)
}
return
}
@ -141,7 +143,7 @@ func webSocketWriter(ws *websocket.Conn) {
}
func webSocketServer(w http.ResponseWriter, r *http.Request) {
Log("Incoming web request from browser")
slog.Info("Incoming web request from browser")
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
Shutdown(err)

View file

@ -3,6 +3,7 @@ package browsh
import (
"bytes"
"fmt"
"log/slog"
"os"
"path/filepath"
"strings"
@ -15,7 +16,7 @@ import (
var (
configFilename = "config.toml"
isDebug = pflag.Bool("debug", false, "Log to ./debug.log")
isDebug = pflag.Bool("debug", false, "slog.Info to ./debug.log")
timeLimit = pflag.Int("time-limit", 0, "Kill Browsh after the specified number of seconds")
_ = pflag.Bool("http-server-mode", false, "Run as an HTTP service")
@ -79,20 +80,18 @@ func setDefaults() {
func loadConfig() {
dir := getConfigDir()
fullPath := filepath.Join(dir, configFilename)
Log("Looking in " + fullPath + " for config.")
slog.Info("Looking in " + fullPath + " for config.")
viper.SetConfigType("toml")
viper.SetConfigName(strings.Trim(configFilename, ".toml"))
viper.AddConfigPath(dir)
viper.AddConfigPath(".")
setDefaults()
// First load the sample config in case the user hasn't updated any new fields
err := viper.ReadConfig(bytes.NewBuffer([]byte(configSample)))
if err != nil {
if err := viper.ReadConfig(bytes.NewBuffer([]byte(configSample))); err != nil {
panic(fmt.Errorf("Config file error: %s \n", err))
}
// Then load the users own config file, overwriting the sample config
err = viper.MergeInConfig()
if err != nil {
if err := viper.MergeInConfig(); err != nil {
panic(fmt.Errorf("Config file error: %s \n", err))
}
viper.BindPFlags(pflag.CommandLine)

View file

@ -5,7 +5,8 @@ import (
"embed"
"encoding/json"
"fmt"
"io/ioutil"
"io/fs"
"log/slog"
"net"
"os"
"os/exec"
@ -59,7 +60,7 @@ var (
)
func startHeadlessFirefox() {
Log("Starting Firefox in headless mode")
slog.Info("Starting Firefox in headless mode")
checkIfFirefoxIsAlreadyRunning()
firefoxPath := ensureFirefoxBinary()
ensureFirefoxVersion(firefoxPath)
@ -69,11 +70,11 @@ func startHeadlessFirefox() {
}
profile := viper.GetString("firefox.profile")
if profile != "browsh-default" {
Log("Using profile: " + profile)
slog.Info("Using Firefox profile", "profile", profile)
args = append(args, "-P", profile)
} else {
profilePath := getFirefoxProfilePath()
Log("Using default profile at: " + profilePath)
slog.Info("Using default profile", "path", profilePath)
args = append(args, "--profile", profilePath)
}
firefoxProcess := exec.Command(firefoxPath, args...)
@ -87,7 +88,7 @@ func startHeadlessFirefox() {
}
in := bufio.NewScanner(stdout)
for in.Scan() {
Log("FF-CONSOLE: " + in.Text())
slog.Info("FF-CONSOLE", "stdout", in.Text())
}
}
@ -114,10 +115,13 @@ func ensureFirefoxBinary() string {
path = getFirefoxPath()
}
}
Log("Using Firefox at: " + path)
if _, err := os.Stat(path); os.IsNotExist(err) {
Shutdown(errors.New("Firefox binary not found: " + path))
if _, err := os.Stat(path); err != nil {
if errors.Is(err, fs.ErrNotExist) {
err = errors.New("Firefox binary not found: " + path)
}
Shutdown(err)
}
slog.Info("Using Firefox", "path", path)
return path
}
@ -155,12 +159,12 @@ func versionOrdinal(version string) string {
// because I haven't been able to recreate the way `web-ext` injects an unsigned
// extension.
func startWERFirefox() {
Log("Attempting to start headless Firefox with `web-ext`")
slog.Info("Attempting to start headless Firefox with `web-ext`")
if IsConnectedToWebExtension {
Shutdown(errors.New("There appears to already be an existing Web Extension connection"))
}
checkIfFirefoxIsAlreadyRunning()
var rootDir = Shell("git rev-parse --show-toplevel")
rootDir := Shell("git rev-parse --show-toplevel")
args := []string{
"run",
"--firefox=" + rootDir + "/webext/contrib/firefoxheadless.sh",
@ -185,9 +189,9 @@ func startWERFirefox() {
strings.Contains(in.Text(), "dbus") {
continue
}
Log("FF-CONSOLE: " + in.Text())
slog.Info("FF-CONSOLE", "stdout", in.Text())
}
Log("WER Firefox unexpectedly closed")
slog.Info("WER Firefox unexpectedly closed")
}
// Connect to Firefox's Marionette service.
@ -206,7 +210,7 @@ func firefoxMarionette() {
conn net.Conn
)
connected := false
Log("Attempting to connect to Firefox Marionette")
slog.Info("Attempting to connect to Firefox Marionette")
start := time.Now()
for time.Since(start) < 30*time.Second {
conn, err = net.Dial("tcp", "127.0.0.1:2828")
@ -230,15 +234,15 @@ func firefoxMarionette() {
sendFirefoxCommand("WebDriver:NewSession", map[string]interface{}{})
}
// Install the Browsh extension that was bundled with `go-bindata` under
// `webextension.go`.
func installWebextension() {
data, err := browshXpi.ReadFile("browsh.xpi")
if err != nil {
Shutdown(err)
}
path := path.Join(os.TempDir(), "browsh-webext-addon")
ioutil.WriteFile(path, []byte(data), 0644)
if err := os.WriteFile(path, []byte(data), 0644); err != nil {
Shutdown(err)
}
args := map[string]interface{}{"path": path}
sendFirefoxCommand("Addon:Install", args)
}
@ -264,14 +268,14 @@ func readMarionette() {
buffer := make([]byte, 4096)
count, err := marionette.Read(buffer)
if err != nil {
Log("Error reading from Marionette connection")
slog.Error("Error reading from Marionette connection", "error", err)
return
}
Log("FF-MRNT: " + string(buffer[:count]))
slog.Info("FF-MRNT", "buffer", string(buffer[:count]))
}
func sendFirefoxCommand(command string, args map[string]interface{}) {
Log("Sending `" + command + "` to Firefox Marionette")
slog.Info("Sending command to Firefox Marionette", "command", command, "args", args)
fullCommand := []interface{}{0, ffCommandCount, command, args}
marshalled, _ := json.Marshal(fullCommand)
message := fmt.Sprintf("%d:%s", len(marshalled), marshalled)

View file

@ -4,6 +4,7 @@ package browsh
import (
"fmt"
"log/slog"
"strings"
"github.com/go-errors/errors"
@ -16,14 +17,16 @@ func getFirefoxPath() string {
k, err := registry.OpenKey(
registry.LOCAL_MACHINE,
`Software\Mozilla\`+flavor+` `+versionString+`\bin`,
`Software\Mozilla\`+flavor+`\`+versionString+`\Main`,
registry.QUERY_VALUE)
if err != nil {
Shutdown(errors.New("Error reading Windows registry: " + fmt.Sprintf("%s", err)))
Shutdown(fmt.Errorf("Error reading Windows registry: %w", err))
}
defer k.Close()
path, _, err := k.GetStringValue("PathToExe")
if err != nil {
Shutdown(errors.New("Error reading Windows registry: " + fmt.Sprintf("%s", err)))
Shutdown(fmt.Errorf("Error reading Windows registry: %w", err))
}
return path
@ -37,22 +40,22 @@ func getWindowsFirefoxVersionString() string {
`Software\Mozilla\`+flavor,
registry.QUERY_VALUE)
if err != nil {
Shutdown(errors.New("Error reading Windows registry: " + fmt.Sprintf("%s", err)))
Shutdown(fmt.Errorf("Error reading Windows registry: %w", err))
}
defer k.Close()
versionString, _, err := k.GetStringValue("")
versionString, _, err := k.GetStringValue("CurrentVersion")
if err != nil {
Shutdown(errors.New("Error reading Windows registry: " + fmt.Sprintf("%s", err)))
Shutdown(fmt.Errorf("Error reading Windows registry: %w", err))
}
Log("Windows registry Firefox version: " + versionString)
slog.Info("Windows registry Firefox", "version", versionString)
return versionString
}
func getFirefoxFlavor() string {
var flavor = "null"
flavor := "null"
k, err := registry.OpenKey(
registry.LOCAL_MACHINE,
`Software\Mozilla\Mozilla Firefox`,

View file

@ -3,6 +3,7 @@ package browsh
import (
"encoding/json"
"fmt"
"log/slog"
"unicode"
"github.com/gdamore/tcell"
@ -78,7 +79,9 @@ func parseJSONFrameText(jsonString string) {
Shutdown(err)
}
if !isTabPresent(incoming.Meta.TabID) {
Log(fmt.Sprintf("Not building frame for non-existent tab ID: %d", incoming.Meta.TabID))
slog.Info(
fmt.Sprintf("Not building frame for non-existent tab ID: %d", incoming.Meta.TabID),
)
return
}
Tabs[incoming.Meta.TabID].frame.buildFrameText(incoming)
@ -100,7 +103,7 @@ func parseJSONFramePixels(jsonString string) {
Shutdown(err)
}
if !isTabPresent(incoming.Meta.TabID) {
Log(fmt.Sprintf("Not building frame for non-existent tab ID: %d", incoming.Meta.TabID))
slog.Warn("Not building frame for non-existent tab ID", "TabID", incoming.Meta.TabID)
return
}
if len(Tabs[incoming.Meta.TabID].frame.text) == 0 {
@ -139,7 +142,7 @@ func (f *frame) resetCells() {
func (f *frame) isIncomingFrameTextValid(incoming incomingFrameText) bool {
if len(incoming.Text) == 0 {
Log("Not parsing zero-size text frame")
slog.Warn("Not parsing zero-size text frame")
return false
}
return true
@ -224,7 +227,7 @@ func (f *frame) populateFramePixels(incoming incomingFramePixels) {
func (f *frame) isIncomingFramePixelsValid(incoming incomingFramePixels) bool {
if len(incoming.Colours) == 0 {
Log("Not parsing zero-size text frame")
slog.Warn("Not parsing zero-size text frame")
return false
}
return true

View file

@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/url"
"regexp"
@ -69,7 +70,7 @@ func HTTPServerStart() {
IsHTTPServerMode = true
StartFirefox()
go startWebSocketServer()
Log("Starting Browsh HTTP server")
slog.Info("Starting Browsh HTTP server")
bind := viper.GetString("http-server.bind")
port := viper.GetString("http-server.port")
serverMux := http.NewServeMux()
@ -120,7 +121,7 @@ func (h *slashFix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func handleHTTPServerRequest(w http.ResponseWriter, r *http.Request) {
var message string
var isErrored bool
var start = time.Now().Format(time.RFC3339)
start := time.Now().Format(time.RFC3339)
urlForBrowsh, _ := url.PathUnescape(strings.TrimPrefix(r.URL.Path, "/"))
urlForBrowsh, isErrored = deRecurseURL(urlForBrowsh)
if isErrored {
@ -147,7 +148,7 @@ func handleHTTPServerRequest(w http.ResponseWriter, r *http.Request) {
return
}
}
Log(r.Header.Get("User-Agent"))
slog.Info("Handling request", "User-Agent", r.Header.Get("User-Agent"))
if isKubeReadinessProbe(r.Header.Get("User-Agent")) {
io.WriteString(w, "healthy")
return
@ -228,7 +229,7 @@ func isProductionHTTP(r *http.Request) bool {
// 'HTML' mode returns some basic HTML tags for things like anchor links.
// 'DOM' mode returns a simple dump of the DOM.
func getRawTextMode(r *http.Request) string {
var mode = "HTML"
mode := "HTML"
if strings.Contains(r.Host, "text.") {
mode = "PLAIN"
}

View file

@ -16,6 +16,8 @@ var (
uiHeight = 2
// IsMonochromeMode decides whether to render the TTY in full colour or monochrome
IsMonochromeMode = false
errNormalExit = errors.New("normal")
)
func setupTcell() {
@ -110,7 +112,7 @@ func quitBrowsh() {
if !viper.GetBool("firefox.use-existing") {
quitFirefox()
}
Shutdown(errors.New("normal"))
Shutdown(errNormalExit)
}
func toggleMonochromeMode() {
@ -227,7 +229,7 @@ func handleTTYResize() {
// that have changed.
func renderCurrentTabWindow() {
var currentCell cell
var styling = tcell.StyleDefault
styling := tcell.StyleDefault
var runeChars []rune
width, height := screen.Size()
if CurrentTab == nil || CurrentTab.frame.cells == nil {

View file

@ -1,20 +1,20 @@
package browsh
import (
"log/slog"
"github.com/gdamore/tcell"
"github.com/spf13/viper"
)
var (
urlInputBox = inputBox{
X: 0,
Y: 1,
Height: 1,
text: nil,
FgColour: [3]int32{255, 255, 255},
bgColour: [3]int32{-1, -1, -1},
}
)
var urlInputBox = inputBox{
X: 0,
Y: 1,
Height: 1,
text: nil,
FgColour: [3]int32{255, 255, 255},
bgColour: [3]int32{-1, -1, -1},
}
// Render tabs, URL bar, status messages, etc
func renderUI() {
@ -28,7 +28,7 @@ func renderUI() {
func writeString(x, y int, str string, style tcell.Style) {
xOriginal := x
if viper.GetBool("http-server-mode") {
Log(str)
slog.Info(str)
return
}
for _, c := range str {

View file

@ -1,3 +1,3 @@
package browsh
var browshVersion = "1.6.4"
var browshVersion = "1.8.3"

View file

@ -2,18 +2,20 @@ package test
import (
"fmt"
"io/ioutil"
"io"
"log/slog"
"net/http"
"time"
ginkgo "github.com/onsi/ginkgo"
"github.com/browsh-org/browsh/interfacer/src/browsh"
ginkgo "github.com/onsi/ginkgo"
"github.com/spf13/viper"
)
var staticFileServerPort = "4444"
var rootDir = browsh.Shell("git rev-parse --show-toplevel")
var (
staticFileServerPort = "4444"
rootDir = browsh.Shell("git rev-parse --show-toplevel")
)
func startStaticFileServer() {
serverMux := http.NewServeMux()
@ -59,7 +61,7 @@ func getPath(path string, mode string) string {
panic(fmt.Sprintf("%s", err))
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
contents, err := io.ReadAll(response.Body)
if err != nil {
fmt.Printf("%s", err)
panic(fmt.Sprintf("%s", err))
@ -78,9 +80,9 @@ var _ = ginkgo.BeforeEach(func() {
browsh.ResetTabs()
waitUntilConnectedToWebExtension(15 * time.Second)
browsh.IsMonochromeMode = false
browsh.Log("\n---------")
browsh.Log(ginkgo.CurrentGinkgoTestDescription().FullTestText)
browsh.Log("---------")
slog.Info("\n---------")
slog.Info(ginkgo.CurrentGinkgoTestDescription().FullTestText)
slog.Info("---------")
})
var _ = ginkgo.BeforeSuite(func() {

View file

@ -2,6 +2,7 @@ package test
import (
"fmt"
"log/slog"
"net/http"
"os"
"path/filepath"
@ -9,24 +10,41 @@ import (
"time"
"unicode/utf8"
"github.com/browsh-org/browsh/interfacer/src/browsh"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/terminfo"
ginkgo "github.com/onsi/ginkgo"
gomega "github.com/onsi/gomega"
"github.com/browsh-org/browsh/interfacer/src/browsh"
"github.com/spf13/viper"
)
var staticFileServerPort = "4444"
var simScreen tcell.SimulationScreen
var startupWait = 60 * time.Second
var perTestTimeout = 2000 * time.Millisecond
var rootDir = browsh.Shell("git rev-parse --show-toplevel")
var testSiteURL = "http://localhost:" + staticFileServerPort
var ti *terminfo.Terminfo
var dir, _ = os.Getwd()
var framesLogFile = fmt.Sprintf(filepath.Join(dir, "frames.log"))
var (
staticFileServerPort = "4444"
simScreen tcell.SimulationScreen
startupWait = 60 * time.Second
perTestTimeout = 2000 * time.Millisecond
rootDir = browsh.Shell("git rev-parse --show-toplevel")
testSiteURL = "http://localhost:" + staticFileServerPort
ti *terminfo.Terminfo
framesLogFileName string
frameLogger *slog.Logger
)
func init() {
dir, err := os.Getwd()
if err != nil {
panic(err)
}
framesLogFileName = fmt.Sprintf(filepath.Join(dir, "frames.log"))
framesLogFile, err := os.OpenFile(framesLogFileName,
os.O_CREATE|os.O_TRUNC|os.O_WRONLY,
0o644,
)
if err != nil {
panic(err)
}
frameLogger = slog.New(slog.NewTextHandler(framesLogFile, nil))
}
func initTerm() {
// The tests check for true colour RGB values. The only downside to forcing true colour
@ -39,8 +57,8 @@ func initTerm() {
// GetFrame returns the current Browsh frame's text
func GetFrame() string {
var frame, log string
var line = 0
var styleDefault = ti.TParm(ti.SetFgBg, int(tcell.ColorWhite), int(tcell.ColorBlack))
line := 0
styleDefault := ti.TParm(ti.SetFgBg, int(tcell.ColorWhite), int(tcell.ColorBlack))
width, _ := simScreen.Size()
cells, _, _ := simScreen.GetContents()
for _, element := range cells {
@ -53,25 +71,12 @@ func GetFrame() string {
line = 0
}
}
writeFrameLog("================================================")
writeFrameLog(ginkgo.CurrentGinkgoTestDescription().FullTestText)
writeFrameLog("================================================\n")
log = "\n" + log + styleDefault
writeFrameLog(log)
frameLogger.Info("================================================")
frameLogger.Info(ginkgo.CurrentGinkgoTestDescription().FullTestText)
frameLogger.Info("================================================\n")
return frame
}
func writeFrameLog(log string) {
f, err := os.OpenFile(framesLogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
panic(err)
}
defer f.Close()
if _, err = f.WriteString(log); err != nil {
panic(err)
}
}
// Trigger the key definition specified by name
func triggerUserKeyFor(name string) {
key := viper.GetStringSlice(name)
@ -228,11 +233,10 @@ func initBrowsh() {
browsh.IsTesting = true
simScreen = tcell.NewSimulationScreen("UTF-8")
browsh.Initialise()
}
func stopFirefox() {
browsh.Log("Attempting to kill all firefox processes")
slog.Info("Attempting to kill all firefox processes")
browsh.IsConnectedToWebExtension = false
browsh.Shell(rootDir + "/webext/contrib/firefoxheadless.sh kill")
time.Sleep(500 * time.Millisecond)
@ -243,19 +247,19 @@ func runeCount(text string) int {
}
var _ = ginkgo.BeforeEach(func() {
browsh.Log("Attempting to restart WER Firefox...")
slog.Info("Attempting to restart WER Firefox...")
stopFirefox()
browsh.ResetTabs()
browsh.StartFirefox()
sleepUntilPageLoad(startupWait)
browsh.IsMonochromeMode = false
browsh.Log("\n---------")
browsh.Log(ginkgo.CurrentGinkgoTestDescription().FullTestText)
browsh.Log("---------")
slog.Info("\n---------")
slog.Info(ginkgo.CurrentGinkgoTestDescription().FullTestText)
slog.Info("---------")
})
var _ = ginkgo.BeforeSuite(func() {
os.Truncate(framesLogFile, 0)
os.Truncate(framesLogFileName, 0)
initTerm()
initBrowsh()
stopFirefox()

View file

@ -1,7 +1,23 @@
#!/usr/bin/env bash
function build_webextension() {
local NODE_BIN=$PROJECT_ROOT/webext/node_modules/.bin
export XPI_PATH="$PROJECT_ROOT"/interfacer/src/browsh/browsh.xpi
export XPI_SOURCE_DIR=$PROJECT_ROOT/webext/dist/web-ext-artifacts
export NODE_BIN=$PROJECT_ROOT/webext/node_modules/.bin
MDN_USER="user:13243312:78"
function versioned_xpi_file() {
echo "$XPI_SOURCE_DIR/browsh-$(browsh_version).xpi"
}
# You'll want to use this with `go run ./cmd/browsh --debug --firefox.use-existing`
function build_webextension_watch() {
"$NODE_BIN"/web-ext run \
--firefox contrib/firefoxheadless.sh \
--verbose
}
function build_webextension_production() {
local version && version=$(browsh_version)
cd "$PROJECT_ROOT"/webext && "$NODE_BIN"/webpack
cd "$PROJECT_ROOT"/webext/dist && rm ./*.map
@ -13,36 +29,65 @@ function build_webextension() {
"$NODE_BIN"/web-ext build --overwrite-dest
ls -alh web-ext-artifacts
version=$(browsh_version)
webextension_sign
local source_file && source_file=$(versioned_xpi_file)
local source_file
local source_dir=$PROJECT_ROOT/webext/dist/web-ext-artifacts
local bundle_file=$PROJECT_ROOT/interfacer/src/browsh/browsh.xpi
echo "Bundling $source_file to $XPI_PATH"
cp -f "$source_file" "$XPI_PATH"
if [ "$BROWSH_ENV" == "RELEASE" ]; then
# The signed version. There can only be one canonical XPI for each semantic
# version.
source_file="$source_dir/browsh-$version-an+fx.xpi"
echo "Making extra copy for Goreleaser to put in Github release:"
local goreleaser_pwd="$PROJECT_ROOT"/interfacer/
cp -a "$source_file" "$goreleaser_pwd"
ls -alh "$goreleaser_pwd"
}
# It is possible to use unsigned webextensions in Firefox but it requires that Firefox
# uses problematically insecure config. I know it's a hassle having to jump through all
# these signing hoops, but I think it's better to use a standard Firefox configuration.
# Moving away from the webextension alltogether is another story, but something I'm still
# thinking about.
#
# NB: There can only be one canonical XPI for each semantic version.
#
# shellcheck disable=2120
function webextension_sign() {
local use_existing=$1
if [ "$use_existing" == "" ]; then
"$NODE_BIN"/web-ext sign --api-key "$MDN_USER" --api-secret "$MDN_KEY"
_rename_built_xpi
else
# TODO: This doesn't currently work with the Marionettte `tempAddon`
# installation method. Just use `web-ext run` and Browsh's `use-existing-ff`
# flag - which is better anyway as it auto-reloads the extension when files
# change. NB: If you fix this, don't forget to change the filename loaded
# by `Asset()` in `main.go`.
# In development/testing, we want to be able to bundle the webextension
# frequently without having to resort to version bumps.
source_file="$source_dir/browsh-$version.zip"
echo "Skipping signing, downloading existing webextension"
local base="https://github.com/browsh-org/browsh/releases/download"
curl -L \
-o "$(versioned_xpi_file)" \
"$base/v$LATEST_TAGGED_VERSION/browsh-$LATEST_TAGGED_VERSION.xpi"
fi
}
echo "Bundling $source_file to $bundle_file"
cp -f "$source_file" "$bundle_file"
function _rename_built_xpi() {
pushd "$XPI_SOURCE_DIR" || _panic
local xpi_file
xpi_file="$(
find ./*.xpi \
-printf "%T@ %f\n" |
sort |
cut -d' ' -f2 |
tail -n1
)"
cp -a "$xpi_file" "$(versioned_xpi_file)"
popd || _panic
}
function bundle_production_webextension() {
local version && version=$(browsh_version)
local base='https://github.com/browsh-org/browsh/releases/download'
local release_url="$base/v$version/browsh-$version-an.fx.xpi"
local xpi_file=$PROJECT_ROOT/interfacer/src/browsh/browsh.xpi
curl -L -o "$xpi_file" "$release_url"
local release_url="$base/v$version/browsh-$version.xpi"
echo "Downloading webextension from: $release_url"
curl -L -o "$XPI_PATH" "$release_url"
local size && size=$(wc -c <"$XPI_PATH")
if [ "$size" -lt 500 ]; then
echo "XPI size seems too small: $size"
_panic "Problem downloading latest webextension XPI"
fi
cp -a "$XPI_PATH" "$(versioned_xpi_file)"
}

View file

@ -1,7 +1,23 @@
#!/bin/env bash
#!/usr/bin/env bash
# shellcheck disable=2120
function _panic() {
local message=$1
echo >&2 "$message"
exit 1
}
function _md5() {
local path=$1
md5sum "$path" | cut -d' ' -f1
}
function pushd() {
# shellcheck disable=2119
command pushd "$@" >/dev/null || _panic
}
function popd() {
# shellcheck disable=2119
command popd "$@" >/dev/null || _panic
}

39
scripts/docker.bash Normal file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env bash
function docker_image_name() {
_export_versions
echo browsh/browsh:v"$BROWSH_VERSION"
}
function docker_build() {
local og_xpi && og_xpi=$(versioned_xpi_file)
[ ! -f "$og_xpi" ] && _panic "Can't find latest webextension build: $og_xpi"
[ ! -f "$XPI_PATH" ] && _panic "Can't find bundleable browsh.xpi: $XPI_PATH"
if [ "$(_md5 "$og_xpi")" != "$(_md5 "$XPI_PATH")" ]; then
_panic "XPI file's MD5 does not match original XPI file's MD5"
fi
docker build -t "$(docker_image_name)" .
}
function is_docker_logged_in() {
docker system info | grep -E 'Username|Registry'
}
function docker_login() {
docker login docker.io \
-u tombh \
-p "$DOCKER_ACCESS_TOKEN"
}
function docker_tag_latest() {
local latest=browsh/browsh:latest
docker tag "$(docker_image_name)" "$latest"
docker push "$latest"
}
function docker_release() {
! is_docker_logged_in && try_docker_login
docker_build
docker push "$(docker_image_name)"
docker_tag_latest
}

View file

@ -1,4 +1,4 @@
#!/bin/env bash
#!/usr/bin/env bash
function golang_lint_check() {
pushd "$PROJECT_ROOT"/interfacer || _panic
@ -15,3 +15,52 @@ function prettier_fix() {
prettier --write '{src,test}/**/*.js'
popd || _panic
}
function parse_firefox_version_from_ci_config() {
local line && line=$(grep 'firefox-version:' <"$PROJECT_ROOT"/.github/workflows/main.yml)
local version && version=$(echo "$line" | tr -s ' ' | cut -d ' ' -f 3)
[ "$version" = "" ] && _panic "Couldn't parse Firefox version"
echo -n "$version"
}
function install_firefox() {
local version && version=$(parse_firefox_version_from_ci_config)
local destination=/tmp
echo "Installing Firefox v$version to $destination..."
mkdir -p "$destination"
pushd "$destination" || _panic
curl -L -o firefox.tar.bz2 \
"https://ftp.mozilla.org/pub/firefox/releases/$version/linux-x86_64/en-US/firefox-$version.tar.bz2"
bzip2 -d firefox.tar.bz2
tar xf firefox.tar
popd || _panic
}
function parse_golang_version_from_go_mod() {
local path=$1
[ "$path" = "" ] && _panic "Path to Golang interfacer code not passed"
local line && line=$(grep '^go ' <"$path"/go.mod)
local version && version=$(echo "$line" | tr -s ' ' | cut -d ' ' -f 2)
[ "$(echo "$version" | tr -s ' ')" == "" ] && _panic "Couldn't parse Golang version"
echo -n "$version"
}
function install_golang() {
local path=$1
[ "$path" = "" ] && _panic "Path to Golang interfacer code not passed"
local version && version=$(parse_golang_version_from_go_mod "$path")
[ "$GOPATH" = "" ] && _panic "GOPATH not set"
[ "$GOROOT" = "" ] && _panic "GOROOT not set"
GOARCH=$(uname -m)
[[ $GOARCH == aarch64 ]] && GOARCH=arm64
[[ $GOARCH == x86_64 ]] && GOARCH=amd64
url=https://dl.google.com/go/go"$version".linux-"$GOARCH".tar.gz
echo "Installing Golang ($url)... to $GOROOT"
curl -L \
-o go.tar.gz \
"$url"
mkdir -p "$GOPATH"/bin
mkdir -p "$GOROOT"
tar -C "$GOROOT/.." -xzf go.tar.gz
go version
}

View file

@ -1,4 +1,4 @@
#!/bin/env bash
#!/usr/bin/env bash
export BROWSH_VERSION
export LATEST_TAGGED_VERSION
@ -8,8 +8,12 @@ function _goreleaser_production() {
echo "Installing \`goreleaser'..."
go install github.com/goreleaser/goreleaser@v"$GORELEASER_VERSION"
fi
pushd "$PROJECT_ROOT"/interfacer/src || _panic
goreleaser release
pushd "$PROJECT_ROOT"/interfacer || _panic
_export_versions
[ "$BROWSH_VERSION" = "" ] && _panic "BROWSH_VERSION unset (goreleaser needs it)"
goreleaser release \
--config "$PROJECT_ROOT"/goreleaser.yml \
--rm-dist
popd || _panic
}
@ -21,9 +25,9 @@ function _export_versions() {
}
function _parse_browsh_version() {
version_file=$PROJECT_ROOT/interfacer/src/browsh/version.go
line=$(grep 'browshVersion' <"$version_file")
version=$(echo "$line" | grep -o '".*"' | sed 's/"//g')
local version_file=$PROJECT_ROOT/interfacer/src/browsh/version.go
local line && line=$(grep 'browshVersion' <"$version_file")
local version && version=$(echo "$line" | grep -o '".*"' | sed 's/"//g')
echo -n "$version"
}
@ -39,7 +43,7 @@ function _tag_on_version_change() {
echo_versions
if ! _is_new_version; then
echo "Not running release as there's no new version."
echo "Not tagging as there's no new version."
exit 0
fi
@ -47,15 +51,13 @@ function _tag_on_version_change() {
git show v"$BROWSH_VERSION" --quiet
git config --global user.email "ci@github.com"
git config --global user.name "Github Actions"
# `/dev/null` needed to prevent Github token appearing in logs
git push --tags --quiet https://"$GITHUB_TOKEN"@github.com/browsh-org/browsh >/dev/null 2>&1
git add --all
git reset --hard v"$BROWSH_VERSION"
}
function echo_versions() {
_export_versions
echo "Browsh Golang version: $BROWSH_VERSION"
echo "Browsh binary version: $BROWSH_VERSION"
echo "Git latest tag: $LATEST_TAGGED_VERSION"
}
@ -72,21 +74,35 @@ function github_actions_output_version_status() {
echo "::set-output name=is_new_version::$status"
}
function npm_build_release() {
function webext_build_release() {
pushd "$PROJECT_ROOT"/webext || _panic
BROWSH_ENV=RELEASE npm run build_webextension
build_webextension_production
popd || _panic
}
function update_browsh_website_with_new_version() {
_export_versions
local remote="git@github.com:browsh-org/www.brow.sh.git"
pushd /tmp || _panic
git clone https://github.com/browsh-org/www.brow.sh.git
cd www.brow.sh || exit 1
git clone "$remote"
cd www.brow.sh || _panic
echo "latest_version: $BROWSH_VERSION" >_data/browsh.yml
git add _data/browsh.yml
git commit -m "Github Actions: updated Browsh version to $BROWSH_VERSION"
# `/dev/null` needed to prevent Github token appearing in logs
git push --quiet https://"$GITHUB_TOKEN"@github.com/browsh-org/www.brow.sh >/dev/null 2>&1
git push "$remote"
popd || _panic
}
function update_homebrew_tap_with_new_version() {
_export_versions
local remote="git@github.com:browsh-org/homebrew-browsh.git"
pushd /tmp || _panic
git clone "$remote"
cd homebrew-browsh || _panic
cp -f "$PROJECT_ROOT"/interfacer/dist/browsh.rb browsh.rb
git add browsh.rb
git commit -m "Github Actions: updated to $BROWSH_VERSION"
git push "$remote"
popd || _panic
}
@ -99,9 +115,23 @@ function goreleaser_local_only() {
popd || _panic
}
function build_browsh_binary() {
# Requires $path argument because it's used in the Dockerfile where the GOROOT is
# outside .git/
local path=$1
pushd "$path" || _panic
local webextension="src/browsh/browsh.xpi"
[ ! -f "$webextension" ] && _panic "browsh.xpi not present"
md5sum "$webextension"
go build ./cmd/browsh
echo "Freshly built \`browsh' version: $(./browsh --version 2>&1)"
popd || _panic
}
function release() {
npm_build_release
[ "$(git rev-parse --abbrev-ref HEAD)" != "master" ] && _panic "Not releasing unless on the master branch"
webext_build_release
build_browsh_binary "$PROJECT_ROOT"/interfacer
_tag_on_version_change
_goreleaser_production
update_browsh_website_with_new_version
}

View file

@ -0,0 +1,154 @@
{
"$id": "https://json.schemastore.org/browsh-schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"$comment": "https://www.brow.sh/docs/config/",
"properties": {
"browsh_supporter": {
"default": "♥",
"enum": ["I have shown my support for Browsh", "♥"],
"description": "By showing your support you can disable the app's branding and nags to donate",
"type": "string"
},
"startup-url": {
"description": "The page to show at startup. Browsh will fail to boot if this URL is not accessible",
"type": "string"
},
"default_search_engine_base": {
"default": "https://www.google.com/search?q=",
"description": "The base query when a non-URL is entered into the URL bar",
"type": "string"
},
"mobile_user_agent": {
"default": "Mozilla/5.0 (Android 7.0; Mobile; rv:54.0) Gecko/58.0 Firefox/58.0",
"description": "The mobile user agent for forcing web pages to use their mobile layout",
"type": "string"
},
"browsh": {
"description": "Browsh internals",
"properties": {
"websocket-port": {
"default": 3334,
"type": "integer"
},
"use_experimental_text_visibility": {
"description": "Possibly better handling of overlapping text in web pages. If a page seems to have text that shouldn't be visible, if it should be behind another element for example, then this experimental feature should help. It can also be toggled in-browser with F6",
"default": false,
"type": "boolean"
},
"custom_css": {
"description": "Custom CSS to apply to all loaded tabs",
"type": "string"
}
},
"type": "object"
},
"firefox": {
"properties": {
"path": {
"default": "firefox",
"description": "The path to your Firefox binary",
"type": "string"
},
"profile": {
"default": "browsh-default",
"description": "Browsh has its own profile, separate from the normal user's. But you can change that",
"type": "string"
},
"use-existing": {
"default": false,
"description": "Don't let Browsh launch Firefox, but make it try to connect to an existing one. Note it will need to have been launched with the '--marionette' flag",
"type": "boolean"
},
"with-gui": {
"default": "with-gui",
"description": "Launch Firefox in with its visible GUI window. Useful for setting up the Browsh profile.",
"type": "string"
},
"preferences": {
"items": {
"type": "string"
},
"description": "Config that you might usually set through Firefox's 'about:config' page Note that string must be wrapped in quotes",
"type": "array"
}
},
"tty": {
"properties": {
"small_pixel_frame_rate": {
"default": "250",
"description": "The time in milliseconds between requesting a new TTY-sized pixel frame. This is essentially the frame rate for graphics. Lower values make for smoother animations and feedback, but also increases the CPU load",
"type": "integer"
}
},
"type": "object"
},
"http-server": {
"properties": {
"port": {
"default": 4333,
"type": "integer"
},
"bind": {
"default": "0.0.0.0",
"type": "string"
},
"render_delay": {
"default": 100,
"description": "The time to wait in milliseconds after the DOM is ready before trying to parse and render the page's text. Too soon and text risks not being parsed, too long and you wait unnecessarily",
"type": "integer"
},
"timeout": {
"default": 30,
"description": "The length of time in seconds to wait before aborting the page load",
"type": "integer"
},
"columns": {
"default": 100,
"description": "The dimensions of a char-based window onto a webpage. The columns are ultimately the width of the final text",
"type": "string"
},
"rows": {
"default": 30,
"description": "Whereas the rows represent the height of the original web page made visible to the original browser window. So the number of rows can effect things like how far down a web page images are lazy-loaded",
"type": "string"
},
"jpeg_compression": {
"default": 0.9,
"description": "The amount of lossy JPG compression to apply to the background image of HTML pages",
"type": "string"
},
"rate-limit": {
"default": "100000000-M",
"description": "Rate limit. For syntax, see: https://github.com/ulule/limiter",
"type": "string"
},
"blocked-domains": {
"items": {
"type": "string"
},
"description": "Blocking is useful if the HTTP server is made public. All values are evaluated as regular expressions",
"type": "array"
},
"blocked-user-agents": {
"items": {
"type": "string"
},
"description": "Blocking is useful if the HTTP server is made public. All values are evaluated as regular expressions",
"type": "array"
},
"header": {
"description": "HTML snippets to show at top and bottom of final page",
"type": "string"
},
"footer": {
"description": "HTML snippets to show at top and bottom of final page",
"type": "string"
}
}
},
"type": "object"
}
},
"title": "JSON schema for browsh",
"type": "object"
}

2104
webext/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,8 @@
{
"type": "module",
"scripts": {
"build_webextension": "../ctl.sh build_webextension",
"build:dev": "webpack",
"build:watch": "webpack --watch",
"lint": "prettier --list-different '{src,test}/**/*.js'",
"test": "NODE_PATH=src:test mocha"
},
@ -22,7 +23,7 @@
"prettier": "2.7.1",
"sinon": "^14.0.0",
"strip-ansi": "^7.0.1",
"web-ext": "^7.1.1",
"web-ext": "^7.5.0",
"webpack": "^5.73.0",
"webpack-cli": "^4.10.0"
},