diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c9e919e9a..e963bd17e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -182,4 +182,4 @@ jobs: docker buildx create --name builder --use docker buildx inspect --bootstrap docker buildx ls - bash ./docker/ci/x86_64/docker_push.sh latest + bash ./docker/ci/x86_64/docker_push.sh latest "${{ github.event.release.tag_name }}" diff --git a/README.md b/README.md index f601919f3..74ab1301c 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Stash can run over HTTPS with some additional work. First you must generate a S This command would need customizing for your environment. [This link](https://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl) might be useful. -Once you have a certificate and key file name them `stash.crt` and `stash.key` and place them in the `~/.stash` directory. Stash detects these and starts up using HTTPS rather than HTTP. +Once you have a certificate and key file name them `stash.crt` and `stash.key` and place them in the same directory as the `config.yml` file, or the `~/.stash` directory. Stash detects these and starts up using HTTPS rather than HTTP. # Customization diff --git a/docker/ci/x86_64/Dockerfile b/docker/ci/x86_64/Dockerfile index 3c6e79497..9eb5d57d4 100644 --- a/docker/ci/x86_64/Dockerfile +++ b/docker/ci/x86_64/Dockerfile @@ -11,7 +11,7 @@ RUN if [ "$TARGETPLATFORM" = "linux/arm/v6" ]; then BIN=stash-pi; \ ENV DEBIAN_FRONTEND=noninteractive RUN apt update && apt install -y python3 python-is-python3 python3-requests python3-requests-toolbelt python3-lxml python3-pip && pip3 install cloudscraper FROM ubuntu:20.04 as app -run apt update && apt install -y python3 python-is-python3 python3-requests python3-requests-toolbelt python3-lxml ffmpeg && rm -rf /var/lib/apt/lists/* +run apt update && apt install -y python3 python-is-python3 python3-requests python3-requests-toolbelt python3-lxml python3-mechanicalsoup ffmpeg && rm -rf /var/lib/apt/lists/* COPY --from=prep /stash /usr/bin/ COPY --from=prep /usr/local/lib/python3.8/dist-packages /usr/local/lib/python3.8/dist-packages diff --git a/docker/ci/x86_64/docker_push.sh b/docker/ci/x86_64/docker_push.sh index 25008c476..8d638e0f7 100644 --- a/docker/ci/x86_64/docker_push.sh +++ b/docker/ci/x86_64/docker_push.sh @@ -1,8 +1,14 @@ #!/bin/bash -DOCKER_TAG=$1 +DOCKER_TAGS="" + +for TAG in "$@" +do + DOCKER_TAGS="$DOCKER_TAGS -t stashapp/stash:$TAG" +done + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin # must build the image from dist directory -docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push --output type=image,name=stashapp/stash:$DOCKER_TAG,push=true -f docker/ci/x86_64/Dockerfile dist/ +docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push $DOCKER_TAGS -f docker/ci/x86_64/Dockerfile dist/ diff --git a/go.mod b/go.mod index 3148b721c..08de5b6be 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,8 @@ require ( github.com/disintegration/imaging v1.6.0 github.com/fvbommel/sortorder v1.0.2 github.com/go-chi/chi v4.0.2+incompatible - github.com/gobuffalo/packr/v2 v2.0.2 + github.com/gobuffalo/logger v1.0.4 // indirect + github.com/gobuffalo/packr/v2 v2.8.1 github.com/golang-migrate/migrate/v4 v4.3.1 github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.2.0 @@ -21,24 +22,27 @@ require ( github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jmoiron/sqlx v1.2.0 github.com/json-iterator/go v1.1.9 - github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 // indirect + github.com/karrick/godirwalk v1.16.1 // indirect github.com/mattn/go-sqlite3 v1.14.6 github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007 github.com/remeh/sizedwaitgroup v1.0.0 github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac github.com/rs/cors v1.6.0 github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f - github.com/sirupsen/logrus v1.4.2 + github.com/sirupsen/logrus v1.8.1 + github.com/spf13/afero v1.2.0 // indirect github.com/spf13/pflag v1.0.3 github.com/spf13/viper v1.7.0 github.com/stretchr/testify v1.5.1 - github.com/tidwall/gjson v1.6.0 + github.com/tidwall/gjson v1.8.1 + github.com/tidwall/pretty v1.2.0 // indirect github.com/vektah/gqlparser/v2 v2.0.1 github.com/vektra/mockery/v2 v2.2.1 - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb - golang.org/x/net v0.0.0-20200822124328-c89045814202 - golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 + golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c + golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect golang.org/x/tools v0.0.0-20200915031644-64986481280e // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/yaml.v2 v2.3.0 diff --git a/go.sum b/go.sum index 6c673e170..8e5faa378 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.31.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.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= 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= @@ -13,18 +11,13 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= -dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= -dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= github.com/99designs/gqlgen v0.12.2 h1:aOdpsiCycFtCnAv8CAI1exnKrIDHMqtMzQoXeTziY4o= github.com/99designs/gqlgen v0.12.2/go.mod h1:7zdGo6ry9u1YBp/qlb2uxSU5Mt2jQKLcBETQiKk+Bxo= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= 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/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -33,13 +26,10 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953 h1:+iPJDL28FxZhEdtJ9qykrMt/oDiOvlzTa0zV06nUcFM= github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953/go.mod h1:kaTsk10p2hJWwrB2t7vMsk1lXj9KAHaDYRtJQiB+Ick= -github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= -github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0= github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs= github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM= github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= -github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/anacrolix/dms v1.2.2 h1:0mk2/DXNqa5KDDbaLgFPf3oMV6VCGdFNh3d/gt4oafM= @@ -51,12 +41,10 @@ github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xop github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M= github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0= github.com/antchfx/xpath v1.1.6 h1:6sVh6hB5T6phw1pFpHRQ+C4bd8sNI+O58flqtg7h0R0= github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= -github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= @@ -71,18 +59,12 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/chromedp/cdproto v0.0.0-20200116234248-4da64dd111ac/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g= -github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c h1:qM1xzKK8kc93zKPkxK4iqtjksqDDrU6g9wGnr30jyLo= -github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c/go.mod h1:E6LPWRdIJc11h/di5p0rwvRmUYbhGpBEH7ZbPfzDIOE= github.com/chromedp/cdproto v0.0.0-20210526005521-9e51b9051fd0/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/cdproto v0.0.0-20210622022015-fe1827b46b84 h1:Xxl4imt7LA3SbkrlIH5mm+mbzsv0tpHomLASTPINlvQ= github.com/chromedp/cdproto v0.0.0-20210622022015-fe1827b46b84/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= -github.com/chromedp/chromedp v0.5.3 h1:F9LafxmYpsQhWQBdCs+6Sret1zzeeFyHS5LkRF//Ffg= -github.com/chromedp/chromedp v0.5.3/go.mod h1:YLdPtndaHQ4rCpSpBG+IPpy9JvX0VD+7aaLxYgYj28w= github.com/chromedp/chromedp v0.7.3 h1:FvgJICfjvXtDX+miuMUY0NHuY8zQvjS/TcEQEG6Ldzs= github.com/chromedp/chromedp v0.7.3/go.mod h1:9gC521Yzgrk078Ulv6KIgG7hJ2x9aWrxMBBobTFk30A= github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic= @@ -90,14 +72,11 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= -github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/corona10/goimagehash v1.0.3 h1:NZM518aKLmoNluluhfHGxT3LGOnrojrxhGn63DR/CZA= @@ -134,24 +113,17 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= @@ -165,229 +137,20 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gobuffalo/attrs v0.0.0-20190219185331-f338c9388485/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY= -github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4= -github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs= -github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4= -github.com/gobuffalo/buffalo-plugins v1.4.3/go.mod h1:uCzTY0woez4nDMdQjkcOYKanngeUVRO2HZi7ezmAjWY= -github.com/gobuffalo/buffalo-plugins v1.5.1/go.mod h1:jbmwSZK5+PiAP9cC09VQOrGMZFCa/P0UMlIS3O12r5w= -github.com/gobuffalo/buffalo-plugins v1.6.4/go.mod h1:/+N1aophkA2jZ1ifB2O3Y9yGwu6gKOVMtUmJnbg+OZI= -github.com/gobuffalo/buffalo-plugins v1.6.5/go.mod h1:0HVkbgrVs/MnPZ/FOseDMVanCTm2RNcdM0PuXcL1NNI= -github.com/gobuffalo/buffalo-plugins v1.6.7/go.mod h1:ZGZRkzz2PiKWHs0z7QsPBOTo2EpcGRArMEym6ghKYgk= -github.com/gobuffalo/buffalo-plugins v1.6.9/go.mod h1:yYlYTrPdMCz+6/+UaXg5Jm4gN3xhsvsQ2ygVatZV5vw= -github.com/gobuffalo/buffalo-plugins v1.6.11/go.mod h1:eAA6xJIL8OuynJZ8amXjRmHND6YiusVAaJdHDN1Lu8Q= -github.com/gobuffalo/buffalo-plugins v1.8.2/go.mod h1:9te6/VjEQ7pKp7lXlDIMqzxgGpjlKoAcAANdCgoR960= -github.com/gobuffalo/buffalo-plugins v1.8.3/go.mod h1:IAWq6vjZJVXebIq2qGTLOdlXzmpyTZ5iJG5b59fza5U= -github.com/gobuffalo/buffalo-plugins v1.9.4/go.mod h1:grCV6DGsQlVzQwk6XdgcL3ZPgLm9BVxlBmXPMF8oBHI= -github.com/gobuffalo/buffalo-plugins v1.10.0/go.mod h1:4osg8d9s60txLuGwXnqH+RCjPHj9K466cDFRl3PErHI= -github.com/gobuffalo/buffalo-plugins v1.11.0 h1:yZ6USaSdAKpogRS8DZJgeG7/CTPGmyhplwifphmmegw= -github.com/gobuffalo/buffalo-plugins v1.11.0/go.mod h1:rtIvAYRjYibgmWhnjKmo7OadtnxuMG5ZQLr25ozAzjg= -github.com/gobuffalo/buffalo-plugins v1.12.0 h1:5rvYQ7mwfPwUW9zqcMd9ahWtPVOOouMKZjv88q45Z7c= -github.com/gobuffalo/buffalo-plugins v1.12.0/go.mod h1:kw4Mj2vQXqe4X5TI36PEQgswbL30heGQwJEeDKd1v+4= -github.com/gobuffalo/buffalo-pop v1.0.5/go.mod h1:Fw/LfFDnSmB/vvQXPvcXEjzP98Tc+AudyNWUBWKCwQ8= -github.com/gobuffalo/depgen v0.0.0-20190219190223-ba8c93fa0c2c/go.mod h1:CE/HUV4vDCXtJayRf6WoMWgezb1yH4QHg8GNK8FL0JI= -github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc= -github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobuffalo/envy v1.6.6/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobuffalo/envy v1.6.7/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobuffalo/envy v1.6.8/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobuffalo/envy v1.6.9/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= -github.com/gobuffalo/envy v1.6.10/go.mod h1:X0CFllQjTV5ogsnUrg+Oks2yTI+PU2dGYBJOEI2D1Uo= -github.com/gobuffalo/envy v1.6.11/go.mod h1:Fiq52W7nrHGDggFPhn2ZCcHw4u/rqXkqo+i7FB6EAcg= -github.com/gobuffalo/envy v1.6.12 h1:zkhss8DXz/pty2HAyA8BnvWMTYxo4gjd4+WCnYovoxY= -github.com/gobuffalo/envy v1.6.12/go.mod h1:qJNrJhKkZpEW0glh5xP2syQHH5kgdmgsKss2Kk8PTP0= -github.com/gobuffalo/envy v1.6.13/go.mod h1:w9DJppgl51JwUFWWd/M/6/otrPtWV3WYMa+NNLunqKA= -github.com/gobuffalo/envy v1.6.15 h1:OsV5vOpHYUpP7ZLS6sem1y40/lNX1BZj+ynMiRi21lQ= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/events v1.0.3/go.mod h1:Txo8WmqScapa7zimEQIwgiJBvMECMe9gJjsKNPN3uZw= -github.com/gobuffalo/events v1.0.7/go.mod h1:z8txf6H9jWhQ5Scr7YPLWg/cgXBRj8Q4uYI+rsVCCSQ= -github.com/gobuffalo/events v1.0.8/go.mod h1:A5KyqT1sA+3GJiBE4QKZibse9mtOcI9nw8gGrDdqYGs= -github.com/gobuffalo/events v1.1.3/go.mod h1:9yPGWYv11GENtzrIRApwQRMYSbUgCsZ1w6R503fCfrk= -github.com/gobuffalo/events v1.1.4/go.mod h1:09/YRRgZHEOts5Isov+g9X2xajxdvOAcUuAHIX/O//A= -github.com/gobuffalo/events v1.1.5/go.mod h1:3YUSzgHfYctSjEjLCWbkXP6djH2M+MLaVRzb4ymbAK0= -github.com/gobuffalo/events v1.1.7/go.mod h1:6fGqxH2ing5XMb3EYRq9LEkVlyPGs4oO/eLzh+S8CxY= -github.com/gobuffalo/events v1.1.8/go.mod h1:UFy+W6X6VbCWS8k2iT81HYX65dMtiuVycMy04cplt/8= -github.com/gobuffalo/events v1.1.9 h1:ukq5ys/h0TuiX7eLJyZBD1dJOy0r19JTEYmgXKG9j+Y= -github.com/gobuffalo/events v1.1.9/go.mod h1:/0nf8lMtP5TkgNbzYxR6Bl4GzBy5s5TebgNTdRfRbPM= -github.com/gobuffalo/events v1.2.0 h1:YovlMNcwNTfIm/3OdB+KemDOm8yUz4XIH+4kbMhGXWw= -github.com/gobuffalo/events v1.2.0/go.mod h1:pxvpvsKXKZNPtHuIxUV3K+g+KP5o4forzaeFj++bh68= -github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc= -github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.0.0-20181002182613-4571df4b1daf/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.0.0-20181007231023-ae7ed6bfe683/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.0.0-20181018182602-fd24a256709f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.0.0-20181019110701-3d6f0b585514/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.0.0-20181024204909-8f6be1a8c6c2/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.0.0-20181104133451-1f6e9779237a/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328/go.mod h1:0HvNbHdfh+WOvDSIASqJOSxTOWSxCCUF++k/Y53v9rI= -github.com/gobuffalo/flect v0.0.0-20181210151238-24a2b68e0316/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= -github.com/gobuffalo/flect v0.0.0-20190104192022-4af577e09bf2/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk= -github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794 h1:HZOs07hF3AmoaUj4HJQHV5RqfOuGnPZI7aFcireIrww= -github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794/go.mod h1:397QT6v05LkZkn07oJXXT6y9FCfwC8Pug0WA2/2mE9k= -github.com/gobuffalo/flect v0.1.0 h1:EJvbvZlo9exJk5UK02lz5pTs3XEpIM5/4o691KfvtkM= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g= -github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= -github.com/gobuffalo/genny v0.0.0-20181005145118-318a41a134cc/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= -github.com/gobuffalo/genny v0.0.0-20181007153042-b8de7d566757/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= -github.com/gobuffalo/genny v0.0.0-20181012161047-33e5f43d83a6/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= -github.com/gobuffalo/genny v0.0.0-20181017160347-90a774534246/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA= -github.com/gobuffalo/genny v0.0.0-20181024195656-51392254bf53/go.mod h1:o9GEH5gn5sCKLVB5rHFC4tq40rQ3VRUzmx6WwmaqISE= -github.com/gobuffalo/genny v0.0.0-20181025145300-af3f81d526b8/go.mod h1:uZ1fFYvdcP8mu0B/Ynarf6dsGvp7QFIpk/QACUuFUVI= -github.com/gobuffalo/genny v0.0.0-20181027191429-94d6cfb5c7fc/go.mod h1:x7SkrQQBx204Y+O9EwRXeszLJDTaWN0GnEasxgLrQTA= -github.com/gobuffalo/genny v0.0.0-20181027195209-3887b7171c4f/go.mod h1:JbKx8HSWICu5zyqWOa0dVV1pbbXOHusrSzQUprW6g+w= -github.com/gobuffalo/genny v0.0.0-20181106193839-7dcb0924caf1/go.mod h1:x61yHxvbDCgQ/7cOAbJCacZQuHgB0KMSzoYcw5debjU= -github.com/gobuffalo/genny v0.0.0-20181107223128-f18346459dbe/go.mod h1:utQD3aKKEsdb03oR+Vi/6ztQb1j7pO10N3OBoowRcSU= -github.com/gobuffalo/genny v0.0.0-20181114215459-0a4decd77f5d/go.mod h1:kN2KZ8VgXF9VIIOj/GM0Eo7YK+un4Q3tTreKOf0q1ng= -github.com/gobuffalo/genny v0.0.0-20181119162812-e8ff4adce8bb/go.mod h1:BA9htSe4bZwBDJLe8CUkoqkypq3hn3+CkoHqVOW718E= -github.com/gobuffalo/genny v0.0.0-20181127225641-2d959acc795b/go.mod h1:l54xLXNkteX/PdZ+HlgPk1qtcrgeOr3XUBBPDbH+7CQ= -github.com/gobuffalo/genny v0.0.0-20181128191930-77e34f71ba2a/go.mod h1:FW/D9p7cEEOqxYA71/hnrkOWm62JZ5ZNxcNIVJEaWBU= -github.com/gobuffalo/genny v0.0.0-20181203165245-fda8bcce96b1/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= -github.com/gobuffalo/genny v0.0.0-20181203201232-849d2c9534ea/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= -github.com/gobuffalo/genny v0.0.0-20181206121324-d6fb8a0dbe36/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM= -github.com/gobuffalo/genny v0.0.0-20181207164119-84844398a37d/go.mod h1:y0ysCHGGQf2T3vOhCrGHheYN54Y/REj0ayd0Suf4C/8= -github.com/gobuffalo/genny v0.0.0-20181211165820-e26c8466f14d/go.mod h1:sHnK+ZSU4e2feXP3PA29ouij6PUEiN+RCwECjCTB3yM= -github.com/gobuffalo/genny v0.0.0-20190104222617-a71664fc38e7/go.mod h1:QPsQ1FnhEsiU8f+O0qKWXz2RE4TiDqLVChWkBuh1WaY= -github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5 h1:boQS3dA9PxhyufJEWIILrG6pJQbDnpwP2rFyvWacdoY= -github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5/go.mod h1:CIaHCrSIuJ4il6ka3Hub4DR4adDrGoXGEEt2FbBxoIo= -github.com/gobuffalo/genny v0.0.0-20190124191459-3310289fa4b4/go.mod h1:yIRqxhZV2sAzb+B3iPUMLauTRrYP8tJUlZ1zV9teKik= -github.com/gobuffalo/genny v0.0.0-20190131150032-1045e97d19fb/go.mod h1:yIRqxhZV2sAzb+B3iPUMLauTRrYP8tJUlZ1zV9teKik= -github.com/gobuffalo/genny v0.0.0-20190131190646-008a76242145/go.mod h1:NJvPZJxb9M4z790P6N2SMZKSUYpASpEvLuUWnHGKzb4= -github.com/gobuffalo/genny v0.0.0-20190219203444-c95082806342 h1:ewzWZ+TT9/3wYSnUPQRU7YFzqWAx4dgUXdgvJVTVLCA= -github.com/gobuffalo/genny v0.0.0-20190219203444-c95082806342/go.mod h1:3BLT+Vs94EEz3fKR8WWOkYpL6c1tdJcZUNCe3LZAnvQ= -github.com/gobuffalo/gitgen v0.0.0-20190219185555-91c2c5f0aad5/go.mod h1:ZzGIrxBvCJEluaU4i3CN0GFlu1Qmb3yK8ziV02evJ1E= -github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I= -github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY= -github.com/gobuffalo/github_flavored_markdown v1.0.7/go.mod h1:w93Pd9Lz6LvyQXEG6DktTPHkOtCbr+arAD5mkwMzXLI= -github.com/gobuffalo/gogen v0.0.0-20190219194924-d32a17ad9761/go.mod h1:v47C8sid+ZM2qK+YpQ2MGJKssKAqyTsH1wl/pTCPdz8= -github.com/gobuffalo/gogen v0.0.0-20190224213239-1c6076128bbc h1:GjmMs2PLx+rH9In421AR1RkHV5AG9lLnRpIPhWauvoI= -github.com/gobuffalo/gogen v0.0.0-20190224213239-1c6076128bbc/go.mod h1:tQqPADZKflmJCR4FHRHYNPP79cXPICyxUiUHyhuXtqg= -github.com/gobuffalo/httptest v1.0.2/go.mod h1:7T1IbSrg60ankme0aDLVnEY0h056g9M1/ZvpVThtB7E= -github.com/gobuffalo/licenser v0.0.0-20180924033006-eae28e638a42/go.mod h1:Ubo90Np8gpsSZqNScZZkVXXAo5DGhTb+WYFIjlnog8w= -github.com/gobuffalo/licenser v0.0.0-20181025145548-437d89de4f75/go.mod h1:x3lEpYxkRG/XtGCUNkio+6RZ/dlOvLzTI9M1auIwFcw= -github.com/gobuffalo/licenser v0.0.0-20181027200154-58051a75da95/go.mod h1:BzhaaxGd1tq1+OLKObzgdCV9kqVhbTulxOpYbvMQWS0= -github.com/gobuffalo/licenser v0.0.0-20181109171355-91a2a7aac9a7/go.mod h1:m+Ygox92pi9bdg+gVaycvqE8RVSjZp7mWw75+K5NPHk= -github.com/gobuffalo/licenser v0.0.0-20181128165715-cc7305f8abed/go.mod h1:oU9F9UCE+AzI/MueCKZamsezGOOHfSirltllOVeRTAE= -github.com/gobuffalo/licenser v0.0.0-20181203160806-fe900bbede07/go.mod h1:ph6VDNvOzt1CdfaWC+9XwcBnlSTBz2j49PBwum6RFaU= -github.com/gobuffalo/licenser v0.0.0-20181211173111-f8a311c51159/go.mod h1:ve/Ue99DRuvnTaLq2zKa6F4KtHiYf7W046tDjuGYPfM= -github.com/gobuffalo/logger v0.0.0-20181022175615-46cfb361fc27/go.mod h1:8sQkgyhWipz1mIctHF4jTxmJh1Vxhp7mP8IqbljgJZo= -github.com/gobuffalo/logger v0.0.0-20181027144941-73d08d2bb969/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= -github.com/gobuffalo/logger v0.0.0-20181027193913-9cf4dd0efe46/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8= -github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17/go.mod h1:oNErH0xLe+utO+OW8ptXMSA5DkiSEDW1u3zGIt8F9Ew= -github.com/gobuffalo/logger v0.0.0-20181117211126-8e9b89b7c264/go.mod h1:5etB91IE0uBlw9k756fVKZJdS+7M7ejVhmpXXiSFj0I= -github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c h1:Z/ppYX6EtPEysbW4VEGz2dO+4F4VTthWp2sWRUCANdU= -github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c/go.mod h1:+HxKANrR9VGw9yN3aOAppJKvhO05ctDi63w4mDnKv2U= -github.com/gobuffalo/logger v0.0.0-20190224201004-be78ebfea0fa h1:26mAf6lQ2m1PSrYlsC16sFAaocXAM+jnCkpj3qKmDmU= -github.com/gobuffalo/logger v0.0.0-20190224201004-be78ebfea0fa/go.mod h1:+HxKANrR9VGw9yN3aOAppJKvhO05ctDi63w4mDnKv2U= -github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw= -github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.1 h1:JRuTiZzDEZhBHkFiHTxJkYRT6CbYuL0K/rn+1byJoEA= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/meta v0.0.0-20181018155829-df62557efcd3/go.mod h1:XTTOhwMNryif3x9LkTTBO/Llrveezd71u3quLd0u7CM= -github.com/gobuffalo/meta v0.0.0-20181018192820-8c6cef77dab3/go.mod h1:E94EPzx9NERGCY69UWlcj6Hipf2uK/vnfrF4QD0plVE= -github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a/go.mod h1:YDAKBud2FP7NZdruCSlmTmDOZbVSa6bpK7LJ/A/nlKg= -github.com/gobuffalo/meta v0.0.0-20181114191255-b130ebedd2f7/go.mod h1:K6cRZ29ozr4Btvsqkjvg5nDFTLOgTqf03KA70Ks0ypE= -github.com/gobuffalo/meta v0.0.0-20181127070345-0d7e59dd540b/go.mod h1:RLO7tMvE0IAKAM8wny1aN12pvEKn7EtkBLkUZR00Qf8= -github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d h1:cP3lJDiGboBok8q6axF0rqWjlg/MOCfgjuwuNp5TlhE= -github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d/go.mod h1:KKsH44nIK2gA8p0PJmRT9GvWJUdphkDUA8AJEvFWiqM= -github.com/gobuffalo/meta v0.0.0-20190121163014-ecaa953cbfb3 h1:JzhweLavqD8ZNLOIBRvE5IPyp+sw/wYQmL9c5XwZuHI= -github.com/gobuffalo/meta v0.0.0-20190121163014-ecaa953cbfb3/go.mod h1:KLfkGnS+Tucc+iTkUcAUBtxpwOJGfhw2pHRLddPxMQY= -github.com/gobuffalo/mw-basicauth v1.0.3/go.mod h1:dg7+ilMZOKnQFHDefUzUHufNyTswVUviCBgF244C1+0= -github.com/gobuffalo/mw-contenttype v0.0.0-20180802152300-74f5a47f4d56/go.mod h1:7EvcmzBbeCvFtQm5GqF9ys6QnCxz2UM1x0moiWLq1No= -github.com/gobuffalo/mw-csrf v0.0.0-20180802151833-446ff26e108b/go.mod h1:sbGtb8DmDZuDUQoxjr8hG1ZbLtZboD9xsn6p77ppcHo= -github.com/gobuffalo/mw-forcessl v0.0.0-20180802152810-73921ae7a130/go.mod h1:JvNHRj7bYNAMUr/5XMkZaDcw3jZhUZpsmzhd//FFWmQ= -github.com/gobuffalo/mw-i18n v0.0.0-20180802152014-e3060b7e13d6/go.mod h1:91AQfukc52A6hdfIfkxzyr+kpVYDodgAeT5cjX1UIj4= -github.com/gobuffalo/mw-paramlogger v0.0.0-20181005191442-d6ee392ec72e/go.mod h1:6OJr6VwSzgJMqWMj7TYmRUqzNe2LXu/W1rRW4MAz/ME= -github.com/gobuffalo/mw-tokenauth v0.0.0-20181001105134-8545f626c189/go.mod h1:UqBF00IfKvd39ni5+yI5MLMjAf4gX7cDKN/26zDOD6c= -github.com/gobuffalo/packd v0.0.0-20181027182251-01ad393492c8/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= -github.com/gobuffalo/packd v0.0.0-20181027190505-aafc0d02c411/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= -github.com/gobuffalo/packd v0.0.0-20181027194105-7ae579e6d213/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc= -github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= -github.com/gobuffalo/packd v0.0.0-20181104210303-d376b15f8e96/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= -github.com/gobuffalo/packd v0.0.0-20181111195323-b2e760a5f0ff/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= -github.com/gobuffalo/packd v0.0.0-20181114190715-f25c5d2471d7/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI= -github.com/gobuffalo/packd v0.0.0-20181124090624-311c6248e5fb/go.mod h1:Foenia9ZvITEvG05ab6XpiD5EfBHPL8A6hush8SJ0o8= -github.com/gobuffalo/packd v0.0.0-20181207120301-c49825f8f6f4/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= -github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687 h1:uZ+G4JprR0UEq0aHZs+6eP7TEZuFfrIkmQWejIBV/QQ= -github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= -github.com/gobuffalo/packd v0.0.0-20190224160250-d04dd98aca5b h1:QlU2UkP7c/XJ994sM1Z8YN9tHsKeIOp7dyMqiLvyNt0= -github.com/gobuffalo/packd v0.0.0-20190224160250-d04dd98aca5b/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA= -github.com/gobuffalo/packr v1.13.7/go.mod h1:KkinLIn/n6+3tVXMwg6KkNvWwVsrRAz4ph+jgpk3Z24= -github.com/gobuffalo/packr v1.15.0/go.mod h1:t5gXzEhIviQwVlNx/+3SfS07GS+cZ2hn76WLzPp6MGI= -github.com/gobuffalo/packr v1.15.1/go.mod h1:IeqicJ7jm8182yrVmNbM6PR4g79SjN9tZLH8KduZZwE= -github.com/gobuffalo/packr v1.19.0/go.mod h1:MstrNkfCQhd5o+Ct4IJ0skWlxN8emOq8DsoT1G98VIU= -github.com/gobuffalo/packr v1.20.0/go.mod h1:JDytk1t2gP+my1ig7iI4NcVaXr886+N0ecUga6884zw= -github.com/gobuffalo/packr v1.21.0 h1:p2ujcDJQp2QTiYWcI0ByHbr/gMoCouok6M0vXs/yTYQ= -github.com/gobuffalo/packr v1.21.0/go.mod h1:H00jGfj1qFKxscFJSw8wcL4hpQtPe1PfU2wa6sg/SR0= -github.com/gobuffalo/packr/v2 v2.0.0-rc.8/go.mod h1:y60QCdzwuMwO2R49fdQhsjCPv7tLQFR0ayzxxla9zes= -github.com/gobuffalo/packr/v2 v2.0.0-rc.9/go.mod h1:fQqADRfZpEsgkc7c/K7aMew3n4aF1Kji7+lIZeR98Fc= -github.com/gobuffalo/packr/v2 v2.0.0-rc.10/go.mod h1:4CWWn4I5T3v4c1OsJ55HbHlUEKNWMITG5iIkdr4Px4w= -github.com/gobuffalo/packr/v2 v2.0.0-rc.11/go.mod h1:JoieH/3h3U4UmatmV93QmqyPUdf4wVM9HELaHEu+3fk= -github.com/gobuffalo/packr/v2 v2.0.0-rc.12/go.mod h1:FV1zZTsVFi1DSCboO36Xgs4pzCZBjB/tDV9Cz/lSaR8= -github.com/gobuffalo/packr/v2 v2.0.0-rc.13/go.mod h1:2Mp7GhBFMdJlOK8vGfl7SYtfMP3+5roE39ejlfjw0rA= -github.com/gobuffalo/packr/v2 v2.0.0-rc.14/go.mod h1:06otbrNvDKO1eNQ3b8hst+1010UooI2MFg+B2Ze4MV8= -github.com/gobuffalo/packr/v2 v2.0.0-rc.15 h1:vSmYcMO6CtuNQvMSbEJeIJlaeZzz2zoxGLTy8HrDh80= -github.com/gobuffalo/packr/v2 v2.0.0-rc.15/go.mod h1:IMe7H2nJvcKXSF90y4X1rjYIRlNMJYCxEhssBXNZwWs= -github.com/gobuffalo/packr/v2 v2.0.0/go.mod h1:7McfLpSxaPUoSQm7gYpTZRQSK63mX8EKzzYSEFKvfkM= -github.com/gobuffalo/packr/v2 v2.0.1/go.mod h1:tp5/5A2e67F1lUGTiNadtA2ToP045+mvkWzaqMCsZr4= -github.com/gobuffalo/packr/v2 v2.0.2 h1:Rlh39nDGlfG0wGSrfFi72JknkNdjRpEr44ZFymEOY80= -github.com/gobuffalo/packr/v2 v2.0.2/go.mod h1:6Y+2NY9cHDlrz96xkJG8bfPwLlCdJVS/irhNJmwD7kM= -github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush v3.7.21+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush v3.7.22+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush v3.7.23+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush v3.7.30+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush v3.7.31+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush v3.7.32+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush v3.7.33+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plushgen v0.0.0-20181128164830-d29dcb966cb2/go.mod h1:r9QwptTFnuvSaSRjpSp4S2/4e2D3tJhARYbvEBcKSb4= -github.com/gobuffalo/plushgen v0.0.0-20181203163832-9fc4964505c2/go.mod h1:opEdT33AA2HdrIwK1aibqnTJDVVKXC02Bar/GT1YRVs= -github.com/gobuffalo/plushgen v0.0.0-20181207152837-eedb135bd51b/go.mod h1:Lcw7HQbEVm09sAQrCLzIxuhFbB3nAgp4c55E+UlynR0= -github.com/gobuffalo/plushgen v0.0.0-20190104222512-177cd2b872b3/go.mod h1:tYxCozi8X62bpZyKXYHw1ncx2ZtT2nFvG42kuLwYjoc= -github.com/gobuffalo/pop v4.8.2+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= -github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= -github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= -github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= -github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= -github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= -github.com/gobuffalo/release v1.0.52/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug= -github.com/gobuffalo/release v1.0.53/go.mod h1:FdF257nd8rqhNaqtDWFGhxdJ/Ig4J7VcS3KL7n/a+aA= -github.com/gobuffalo/release v1.0.54/go.mod h1:Pe5/RxRa/BE8whDpGfRqSI7D1a0evGK1T4JDm339tJc= -github.com/gobuffalo/release v1.0.61/go.mod h1:mfIO38ujUNVDlBziIYqXquYfBF+8FDHUjKZgYC1Hj24= -github.com/gobuffalo/release v1.0.72/go.mod h1:NP5NXgg/IX3M5XmHmWR99D687/3Dt9qZtTK/Lbwc1hU= -github.com/gobuffalo/release v1.1.1/go.mod h1:Sluak1Xd6kcp6snkluR1jeXAogdJZpFFRzTYRs/2uwg= -github.com/gobuffalo/release v1.1.3/go.mod h1:CuXc5/m+4zuq8idoDt1l4va0AXAn/OSs08uHOfMVr8E= -github.com/gobuffalo/release v1.1.6/go.mod h1:18naWa3kBsqO0cItXZNJuefCKOENpbbUIqRL1g+p6z0= -github.com/gobuffalo/shoulders v1.0.1/go.mod h1:V33CcVmaQ4gRUmHKwq1fiTXuf8Gp/qjQBUL5tHPmvbA= -github.com/gobuffalo/syncx v0.0.0-20181120191700-98333ab04150/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f h1:S5EeH1reN93KR0L6TQvkRpu9YggCYXrUqFh1iEgvdC0= -github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gobuffalo/tags v2.0.11+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= -github.com/gobuffalo/tags v2.0.14+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= -github.com/gobuffalo/tags v2.0.15+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= -github.com/gobuffalo/uuid v2.0.3+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= -github.com/gobuffalo/uuid v2.0.4+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= -github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= -github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM= -github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc= -github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM= +github.com/gobuffalo/logger v1.0.4 h1:HFJRqL7AmL4QNvQb9Grss9sDz+3u02VBgAoR03A7q4o= +github.com/gobuffalo/logger v1.0.4/go.mod h1:/GRUdWb+gM3shxj0P5jiV6ecVS3X0aboJvl+hBu0HeE= +github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM= +github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI= +github.com/gobuffalo/packr/v2 v2.8.1 h1:tkQpju6i3EtMXJ9uoF5GT6kB+LMTimDWD8Xvbz6zDVA= +github.com/gobuffalo/packr/v2 v2.8.1/go.mod h1:c/PLlOuTU+p3SybaJATW3H6lX/iK7xEz5OeMf+NnJpg= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gobwas/ws v1.1.0-rc.5 h1:QOAag7FoBaBYYHRqzqkhhd8fq5RTubvI4v3Ft/gDVVQ= github.com/gobwas/ws v1.1.0-rc.5/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= -github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -395,22 +158,18 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/golang-migrate/migrate/v4 v4.3.1 h1:3eR1NY+pplX+m6yJ1fQf5dFWX3fBgUtZfDiaS/kJVu4= github.com/golang-migrate/migrate/v4 v4.3.1/go.mod h1:mJ89KBgbXmM3P49BqOxRL3riNF/ATlg5kMhm17GA0dE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= 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/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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= @@ -425,33 +184,25 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi 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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= -github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/h2non/filetype v1.0.8 h1:le8gpf+FQA0/DlDABbtisA1KiTS0Xi+YSC/E8yY3Y14= github.com/h2non/filetype v1.0.8/go.mod h1:isekKqOuhMj+s/7r3rIeTErIRy4Rub5uBWHfvMusLMU= @@ -471,7 +222,6 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -487,16 +237,11 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -509,78 +254,46 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= -github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= -github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= -github.com/karrick/godirwalk v1.7.8 h1:VfG72pyIxgtC7+3X9CMHI0AOl4LwyRAg98WAgsvffi8= -github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/karrick/godirwalk v1.15.8/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= +github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 h1:V0an7KRw92wmJysvFvtqtKMAPmvS5O0jtB0nYo6t+gs= -github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08/go.mod h1:dFWs1zEqDjFtnBXsd1vPOZaLsESovai349994nHx3e0= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= -github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= -github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= -github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c= -github.com/markbates/going v1.0.3/go.mod h1:fQiT6v6yQar9UD6bd/D4Z5Afbk9J6BBVBtLiyY4gp2o= -github.com/markbates/grift v1.0.4/go.mod h1:wbmtW74veyx+cgfwFhlnnMWqhoz55rnHR47oMXzsyVs= -github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c= -github.com/markbates/inflect v1.0.0/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88= -github.com/markbates/inflect v1.0.1/go.mod h1:uv3UVNBe5qBIfCm8O8Q+DW+S1EopeyINj+Ikhc7rnCk= -github.com/markbates/inflect v1.0.3/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= -github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= -github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2 h1:JgVTCPf0uBVcUSWpyXmGpgOc62nK5HWUBKAGc3Qqa5k= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc= -github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= +github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= +github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= +github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc= -github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w= github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg= github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -591,40 +304,30 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mongodb/mongo-go-driver v0.3.0/go.mod h1:NK/HWDIIZkaYsnYa0hmtP443T5ELr0KDecmIioVuuyU= -github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007 h1:Ohgj9L0EYOgXxkDp+bczlMBiulwmqYzQpvQNUdtt3oc= github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007/go.mod h1:wKCOWMb6iNlvKiOToY2cNuaovSXvIiv1zDi9QDR7aGQ= -github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= -github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= @@ -632,25 +335,21 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -661,21 +360,14 @@ github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNC github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.1.0 h1:g0fH8RicVgNl+zVZDCDfbdWxAWoAEJyI7I3TZYXFiig= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2 h1:J7U/N7eRtzjhs26d6GqMh2HBuXP8/Z64Densiiieafo= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8= github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -683,77 +375,40 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= -github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= -github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= -github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk= github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= -github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= -github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= -github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= -github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= -github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= -github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= -github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= -github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= -github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= -github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= -github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= -github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= -github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= -github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= -github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= -github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= -github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.0 h1:O9FblXGxoTc51M+cqr74Bm2Tmt4PvkA5iu/j8HrkNuY= github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= -github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= @@ -762,27 +417,23 @@ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 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 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= -github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= -github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= -github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/gjson v1.8.1 h1:8j5EE9Hrh3l9Od1OIEDAb7IpezNA20UdRngNAj5N0WU= +github.com/tidwall/gjson v1.8.1/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= -github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg= @@ -805,42 +456,23 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181024171144-74cb1d3d52f4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc h1:F5tKCVGp+MUAHhKp5MZtGqAlGX3+oCsiL1Q629FL90M= -golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/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= @@ -848,11 +480,9 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk= golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 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= @@ -865,29 +495,17 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc 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.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/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-20180816102801-aaf60122140d/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-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -897,122 +515,74 @@ golang.org/x/net v0.0.0-20190415214537-1da14a5a36f2/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/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-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 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-20190620200207-3b0461eec859/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-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/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-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/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-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= 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 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= 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-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/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-20180921163948-d47a0f339242/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181022134430-8a28ead16f52/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181024145615-5cd93ef61a7c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026064943-731415f00dce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190116161447-11f53e031339 h1:g/Jesu8+QLnA0CPzF3E1pURg0Byr7i6jLoX5sqjcAh0= -golang.org/x/sys v0.0.0-20190116161447-11f53e031339/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-20190222072716-a9d3bda3a223/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-20190415145633-3fd5a3612ccd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190426135247-a129542de9ae h1:mQLHiymj/JXKnnjc62tb7nD5pZLs940/sXJu+Xp3DBA= golang.org/x/sys v0.0.0-20190426135247-a129542de9ae/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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181008205924-a2b3f7f249e9/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181013182035-5e66757b835f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181024171208-a2dc47679d30/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181026183834-f60e5f99f081/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181107215632-34b416bd17b3/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181114190951-94339b83286c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181119130350-139d099f6620/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181127195227-b4e97c0ed882/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181127232545-e782529d0ddd/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181203210056-e5f3ab76ea4b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181205224935-3576414c54a4/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181206194817-bcd4e47d0288/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181207183836-8bc39b988060/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181212172921-837e80568c09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190102213336-ca9055ed7d04/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190104182027-498d95493402/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/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-20190118193359-16909d206f00 h1:6OmoTtlNJlHuWNIjTEyUtMBHrryp8NRuf/XtnC7MmXM= -golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190124004107-78ee07aa9465/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6 h1:iZgcI2DDp6zW5v9Z/5+f0NuqoxNdmzg4hivjk2WLXpY= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190131142011-8dbcc66f33bb/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206221403-44bcb96178d3/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190219185102-9394956cfdc5/go.mod h1:E6PF97AdD6v0s+fPshSmumCW1S1Ne85RbPQxELkKa44= -golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 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= @@ -1021,7 +591,6 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425222832-ad9eeb80039a/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd h1:oMEQDWVXVNpceQoVd1JN3CQ7LYJJzs5qWqZIUcxXHHw= golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/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= @@ -1033,11 +602,9 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM= golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e h1:ssd5ulOvVWlh4kDSUF2SqzmMeWfjmwDXM+uGw/aQjRE= +golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3 h1:OjYQxZBKJFs+sJbHkvSGIKNMkZXDJQ9JsMpebGhkafI= golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200915031644-64986481280e h1:tfSNPIxC48Azhz4nLSPskz/yE9R6ftFRK8pfgfqWUAc= golang.org/x/tools v0.0.0-20200915031644-64986481280e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= @@ -1045,14 +612,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T 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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -1061,19 +624,12 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn 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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= -google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1083,44 +639,33 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 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/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 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.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= 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/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/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 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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= @@ -1129,5 +674,3 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k= -sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= -sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/graphql/documents/data/config.graphql b/graphql/documents/data/config.graphql index 878f53298..7912bee00 100644 --- a/graphql/documents/data/config.graphql +++ b/graphql/documents/data/config.graphql @@ -32,6 +32,7 @@ fragment ConfigGeneralData on ConfigGeneralResult { galleryExtensions excludes imageExcludes + customPerformerImageLocation scraperUserAgent scraperCertCheck scraperCDPPath @@ -55,6 +56,7 @@ fragment ConfigInterfaceData on ConfigInterfaceResult { language slideshowDelay handyKey + funscriptOffset } fragment ConfigDLNAData on ConfigDLNAResult { @@ -64,6 +66,13 @@ fragment ConfigDLNAData on ConfigDLNAResult { interfaces } +fragment ConfigScrapingData on ConfigScrapingResult { + scraperUserAgent + scraperCertCheck + scraperCDPPath + excludeTagPatterns +} + fragment ConfigData on ConfigResult { general { ...ConfigGeneralData @@ -74,4 +83,7 @@ fragment ConfigData on ConfigResult { dlna { ...ConfigDLNAData } + scraping { + ...ConfigScrapingData + } } diff --git a/graphql/documents/data/scrapers.graphql b/graphql/documents/data/scrapers.graphql index f9fa5a879..b84fabfc9 100644 --- a/graphql/documents/data/scrapers.graphql +++ b/graphql/documents/data/scrapers.graphql @@ -23,6 +23,7 @@ fragment ScrapedPerformerData on ScrapedPerformer { death_date hair_color weight + remote_site_id } fragment ScrapedScenePerformerData on ScrapedScenePerformer { diff --git a/graphql/documents/data/studio.graphql b/graphql/documents/data/studio.graphql index a9515c32d..68ec86f82 100644 --- a/graphql/documents/data/studio.graphql +++ b/graphql/documents/data/studio.graphql @@ -5,23 +5,14 @@ fragment StudioData on Studio { url parent_studio { id - checksum name url image_path - scene_count - image_count - gallery_count } child_studios { id - checksum name - url image_path - scene_count - image_count - gallery_count } image_path scene_count diff --git a/graphql/documents/mutations/config.graphql b/graphql/documents/mutations/config.graphql index 5d3e0e734..149d9bf28 100644 --- a/graphql/documents/mutations/config.graphql +++ b/graphql/documents/mutations/config.graphql @@ -24,6 +24,12 @@ mutation ConfigureDLNA($input: ConfigDLNAInput!) { } } +mutation ConfigureScraping($input: ConfigScrapingInput!) { + configureScraping(input: $input) { + ...ConfigScrapingData + } +} + mutation GenerateAPIKey($input: GenerateAPIKeyInput!) { generateAPIKey(input: $input) } diff --git a/graphql/documents/queries/misc.graphql b/graphql/documents/queries/misc.graphql index 0816d39f5..b8b4871d1 100644 --- a/graphql/documents/queries/misc.graphql +++ b/graphql/documents/queries/misc.graphql @@ -41,6 +41,7 @@ query Stats { stats { scene_count, scenes_size, + scenes_duration, image_count, images_size, gallery_count, diff --git a/graphql/schema/schema.graphql b/graphql/schema/schema.graphql index 5ac192854..c0ba269ef 100644 --- a/graphql/schema/schema.graphql +++ b/graphql/schema/schema.graphql @@ -212,6 +212,7 @@ type Mutation { configureGeneral(input: ConfigGeneralInput!): ConfigGeneralResult! configureInterface(input: ConfigInterfaceInput!): ConfigInterfaceResult! configureDLNA(input: ConfigDLNAInput!): ConfigDLNAResult! + configureScraping(input: ConfigScrapingInput!): ConfigScrapingResult! """Generate and set (or clear) API key""" generateAPIKey(input: GenerateAPIKeyInput!): String! diff --git a/graphql/schema/types/config.graphql b/graphql/schema/types/config.graphql index d9c3ae52c..63fd730c5 100644 --- a/graphql/schema/types/config.graphql +++ b/graphql/schema/types/config.graphql @@ -89,12 +89,14 @@ input ConfigGeneralInput { excludes: [String!] """Array of file regexp to exclude from Image Scans""" imageExcludes: [String!] + """Custom Performer Image Location""" + customPerformerImageLocation: String """Scraper user agent string""" - scraperUserAgent: String + scraperUserAgent: String @deprecated(reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead") """Scraper CDP path. Path to chrome executable or remote address""" - scraperCDPPath: String + scraperCDPPath: String @deprecated(reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead") """Whether the scraper should check for invalid certificates""" - scraperCertCheck: Boolean! + scraperCertCheck: Boolean @deprecated(reason: "use mutation ConfigureScraping(input: ConfigScrapingInput) instead") """Stash-box instances used for tagging""" stashBoxes: [StashBoxInput!]! } @@ -162,12 +164,14 @@ type ConfigGeneralResult { excludes: [String!]! """Array of file regexp to exclude from Image Scans""" imageExcludes: [String!]! + """Custom Performer Image Location""" + customPerformerImageLocation: String """Scraper user agent string""" - scraperUserAgent: String + scraperUserAgent: String @deprecated(reason: "use ConfigResult.scraping instead") """Scraper CDP path. Path to chrome executable or remote address""" - scraperCDPPath: String + scraperCDPPath: String @deprecated(reason: "use ConfigResult.scraping instead") """Whether the scraper should check for invalid certificates""" - scraperCertCheck: Boolean! + scraperCertCheck: Boolean! @deprecated(reason: "use ConfigResult.scraping instead") """Stash-box instances used for tagging""" stashBoxes: [StashBox!]! } @@ -196,6 +200,8 @@ input ConfigInterfaceInput { slideshowDelay: Int """Handy Connection Key""" handyKey: String + """Funscript Time Offset""" + funscriptOffset: Int } type ConfigInterfaceResult { @@ -222,6 +228,8 @@ type ConfigInterfaceResult { slideshowDelay: Int """Handy Connection Key""" handyKey: String + """Funscript Time Offset""" + funscriptOffset: Int } input ConfigDLNAInput { @@ -244,11 +252,34 @@ type ConfigDLNAResult { interfaces: [String!]! } +input ConfigScrapingInput { + """Scraper user agent string""" + scraperUserAgent: String + """Scraper CDP path. Path to chrome executable or remote address""" + scraperCDPPath: String + """Whether the scraper should check for invalid certificates""" + scraperCertCheck: Boolean! + """Tags blacklist during scraping""" + excludeTagPatterns: [String!] +} + +type ConfigScrapingResult { + """Scraper user agent string""" + scraperUserAgent: String + """Scraper CDP path. Path to chrome executable or remote address""" + scraperCDPPath: String + """Whether the scraper should check for invalid certificates""" + scraperCertCheck: Boolean! + """Tags blacklist during scraping""" + excludeTagPatterns: [String!]! +} + """All configuration settings""" type ConfigResult { general: ConfigGeneralResult! interface: ConfigInterfaceResult! dlna: ConfigDLNAResult! + scraping: ConfigScrapingResult! } """Directory structure of a path""" diff --git a/graphql/schema/types/filters.graphql b/graphql/schema/types/filters.graphql index 18bcc9dff..989b95863 100644 --- a/graphql/schema/types/filters.graphql +++ b/graphql/schema/types/filters.graphql @@ -28,6 +28,11 @@ enum ResolutionEnum { "8k", EIGHT_K } +input ResolutionCriterionInput { + value: ResolutionEnum! + modifier: CriterionModifier! +} + input PerformerFilterType { AND: PerformerFilterType OR: PerformerFilterType @@ -126,7 +131,7 @@ input SceneFilterType { """Filter by o-counter""" o_counter: IntCriterionInput """Filter by resolution""" - resolution: ResolutionEnum + resolution: ResolutionCriterionInput """Filter by duration (in seconds)""" duration: IntCriterionInput """Filter to only include scenes which have markers. `true` or `false`""" @@ -215,7 +220,7 @@ input GalleryFilterType { """Filter by organized""" organized: Boolean """Filter by average image resolution""" - average_resolution: ResolutionEnum + average_resolution: ResolutionCriterionInput """Filter to only include galleries with this studio""" studios: HierarchicalMultiCriterionInput """Filter to only include galleries with these tags""" @@ -282,7 +287,7 @@ input ImageFilterType { """Filter by o-counter""" o_counter: IntCriterionInput """Filter by resolution""" - resolution: ResolutionEnum + resolution: ResolutionCriterionInput """Filter to only include images missing this property""" is_missing: String """Filter to only include images with this studio""" @@ -322,6 +327,10 @@ enum CriterionModifier { MATCHES_REGEX, """NOT MATCHES REGEX""" NOT_MATCHES_REGEX, + """>= AND <=""" + BETWEEN, + """< OR >""" + NOT_BETWEEN, } input StringCriterionInput { @@ -331,6 +340,7 @@ input StringCriterionInput { input IntCriterionInput { value: Int! + value2: Int modifier: CriterionModifier! } diff --git a/graphql/schema/types/scene.graphql b/graphql/schema/types/scene.graphql index a1ec113d7..734b5f596 100644 --- a/graphql/schema/types/scene.graphql +++ b/graphql/schema/types/scene.graphql @@ -125,7 +125,8 @@ type FindScenesResultType { input SceneParserInput { ignoreWords: [String!], whitespaceCharacters: String, - capitalizeTitle: Boolean + capitalizeTitle: Boolean, + ignoreOrganized: Boolean } type SceneMovieID { diff --git a/graphql/schema/types/scraped-performer.graphql b/graphql/schema/types/scraped-performer.graphql index db6c216a3..2ae1b5a8a 100644 --- a/graphql/schema/types/scraped-performer.graphql +++ b/graphql/schema/types/scraped-performer.graphql @@ -25,6 +25,7 @@ type ScrapedPerformer { death_date: String hair_color: String weight: String + remote_site_id: String } input ScrapedPerformerInput { @@ -51,4 +52,5 @@ input ScrapedPerformerInput { death_date: String hair_color: String weight: String + remote_site_id: String } \ No newline at end of file diff --git a/graphql/schema/types/stats.graphql b/graphql/schema/types/stats.graphql index d127871f2..fcadd54a7 100644 --- a/graphql/schema/types/stats.graphql +++ b/graphql/schema/types/stats.graphql @@ -1,6 +1,7 @@ type StatsResultType { scene_count: Int! scenes_size: Float! + scenes_duration: Float! image_count: Int! images_size: Float! gallery_count: Int! diff --git a/pkg/api/images.go b/pkg/api/images.go index 013df4be3..e38fb6aeb 100644 --- a/pkg/api/images.go +++ b/pkg/api/images.go @@ -1,49 +1,67 @@ package api import ( - "math/rand" "strings" "github.com/gobuffalo/packr/v2" + "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/utils" ) -var performerBox *packr.Box -var performerBoxMale *packr.Box +type imageBox struct { + box *packr.Box + files []string +} + +func newImageBox(box *packr.Box) *imageBox { + return &imageBox{ + box: box, + files: box.List(), + } +} + +var performerBox *imageBox +var performerBoxMale *imageBox +var performerBoxCustom *imageBox func initialiseImages() { - performerBox = packr.New("Performer Box", "../../static/performer") - performerBoxMale = packr.New("Male Performer Box", "../../static/performer_male") + performerBox = newImageBox(packr.New("Performer Box", "../../static/performer")) + performerBoxMale = newImageBox(packr.New("Male Performer Box", "../../static/performer_male")) + initialiseCustomImages() } -func getRandomPerformerImage(gender string) ([]byte, error) { - var box *packr.Box - switch strings.ToUpper(gender) { - case "FEMALE": - box = performerBox - case "MALE": - box = performerBoxMale - default: - box = performerBox - +func initialiseCustomImages() { + customPath := config.GetInstance().GetCustomPerformerImageLocation() + if customPath != "" { + logger.Debugf("Loading custom performer images from %s", customPath) + // We need to set performerBoxCustom at runtime, as this is a custom path, and store it in a pointer. + performerBoxCustom = newImageBox(packr.Folder(customPath)) + } else { + performerBoxCustom = nil } - imageFiles := box.List() - index := rand.Intn(len(imageFiles)) - return box.Find(imageFiles[index]) } -func getRandomPerformerImageUsingName(name, gender string) ([]byte, error) { - var box *packr.Box - switch strings.ToUpper(gender) { - case "FEMALE": - box = performerBox - case "MALE": - box = performerBoxMale - default: - box = performerBox +func getRandomPerformerImageUsingName(name, gender, customPath string) ([]byte, error) { + var box *imageBox + // If we have a custom path, we should return a new box in the given path. + if performerBoxCustom != nil && len(performerBoxCustom.files) > 0 { + box = performerBoxCustom } - imageFiles := box.List() + + if box == nil { + switch strings.ToUpper(gender) { + case "FEMALE": + box = performerBox + case "MALE": + box = performerBoxMale + default: + box = performerBox + } + } + + imageFiles := box.files index := utils.IntFromString(name) % uint64(len(imageFiles)) - return box.Find(imageFiles[index]) + return box.box.Find(imageFiles[index]) } diff --git a/pkg/api/resolver.go b/pkg/api/resolver.go index 07534fc1e..ed15a1d21 100644 --- a/pkg/api/resolver.go +++ b/pkg/api/resolver.go @@ -138,6 +138,7 @@ func (r *queryResolver) Stats(ctx context.Context) (*models.StatsResultType, err tagsQB := repo.Tag() scenesCount, _ := scenesQB.Count() scenesSize, _ := scenesQB.Size() + scenesDuration, _ := scenesQB.Duration() imageCount, _ := imageQB.Count() imageSize, _ := imageQB.Size() galleryCount, _ := galleryQB.Count() @@ -149,6 +150,7 @@ func (r *queryResolver) Stats(ctx context.Context) (*models.StatsResultType, err ret = models.StatsResultType{ SceneCount: scenesCount, ScenesSize: scenesSize, + ScenesDuration: scenesDuration, ImageCount: imageCount, ImagesSize: imageSize, GalleryCount: galleryCount, diff --git a/pkg/api/resolver_model_scene.go b/pkg/api/resolver_model_scene.go index 89f1ed8ae..5d909f6b5 100644 --- a/pkg/api/resolver_model_scene.go +++ b/pkg/api/resolver_model_scene.go @@ -67,12 +67,12 @@ func (r *sceneResolver) File(ctx context.Context, obj *models.Scene) (*models.Sc bitrate := int(obj.Bitrate.Int64) return &models.SceneFileType{ Size: &obj.Size.String, - Duration: &obj.Duration.Float64, + Duration: handleFloat64(obj.Duration.Float64), VideoCodec: &obj.VideoCodec.String, AudioCodec: &obj.AudioCodec.String, Width: &width, Height: &height, - Framerate: &obj.Framerate.Float64, + Framerate: handleFloat64(obj.Framerate.Float64), Bitrate: &bitrate, }, nil } diff --git a/pkg/api/resolver_mutation_configure.go b/pkg/api/resolver_mutation_configure.go index 7154ff219..4eb477731 100644 --- a/pkg/api/resolver_mutation_configure.go +++ b/pkg/api/resolver_mutation_configure.go @@ -167,6 +167,11 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co c.Set(config.CreateGalleriesFromFolders, input.CreateGalleriesFromFolders) + if input.CustomPerformerImageLocation != nil { + c.Set(config.CustomPerformerImageLocation, *input.CustomPerformerImageLocation) + initialiseCustomImages() + } + refreshScraperCache := false if input.ScraperUserAgent != nil { c.Set(config.ScraperUserAgent, input.ScraperUserAgent) @@ -178,7 +183,9 @@ func (r *mutationResolver) ConfigureGeneral(ctx context.Context, input models.Co refreshScraperCache = true } - c.Set(config.ScraperCertCheck, input.ScraperCertCheck) + if input.ScraperCertCheck != nil { + c.Set(config.ScraperCertCheck, input.ScraperCertCheck) + } if input.StashBoxes != nil { if err := c.ValidateStashBoxes(input.StashBoxes); err != nil { @@ -253,6 +260,10 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input models. c.Set(config.HandyKey, *input.HandyKey) } + if input.FunscriptOffset != nil { + c.Set(config.FunscriptOffset, *input.FunscriptOffset) + } + if err := c.Write(); err != nil { return makeConfigInterfaceResult(), err } @@ -291,6 +302,35 @@ func (r *mutationResolver) ConfigureDlna(ctx context.Context, input models.Confi return makeConfigDLNAResult(), nil } +func (r *mutationResolver) ConfigureScraping(ctx context.Context, input models.ConfigScrapingInput) (*models.ConfigScrapingResult, error) { + c := config.GetInstance() + + refreshScraperCache := false + if input.ScraperUserAgent != nil { + c.Set(config.ScraperUserAgent, input.ScraperUserAgent) + refreshScraperCache = true + } + + if input.ScraperCDPPath != nil { + c.Set(config.ScraperCDPPath, input.ScraperCDPPath) + refreshScraperCache = true + } + + if input.ExcludeTagPatterns != nil { + c.Set(config.ScraperExcludeTagPatterns, input.ExcludeTagPatterns) + } + + c.Set(config.ScraperCertCheck, input.ScraperCertCheck) + if refreshScraperCache { + manager.GetInstance().RefreshScraperCache() + } + if err := c.Write(); err != nil { + return makeConfigScrapingResult(), err + } + + return makeConfigScrapingResult(), nil +} + func (r *mutationResolver) GenerateAPIKey(ctx context.Context, input models.GenerateAPIKeyInput) (string, error) { c := config.GetInstance() diff --git a/pkg/api/resolver_query_configuration.go b/pkg/api/resolver_query_configuration.go index a3e226073..27aaac925 100644 --- a/pkg/api/resolver_query_configuration.go +++ b/pkg/api/resolver_query_configuration.go @@ -39,6 +39,7 @@ func makeConfigResult() *models.ConfigResult { General: makeConfigGeneralResult(), Interface: makeConfigInterfaceResult(), Dlna: makeConfigDLNAResult(), + Scraping: makeConfigScrapingResult(), } } @@ -49,45 +50,48 @@ func makeConfigGeneralResult() *models.ConfigGeneralResult { maxTranscodeSize := config.GetMaxTranscodeSize() maxStreamingTranscodeSize := config.GetMaxStreamingTranscodeSize() + customPerformerImageLocation := config.GetCustomPerformerImageLocation() + scraperUserAgent := config.GetScraperUserAgent() scraperCDPPath := config.GetScraperCDPPath() return &models.ConfigGeneralResult{ - Stashes: config.GetStashPaths(), - DatabasePath: config.GetDatabasePath(), - GeneratedPath: config.GetGeneratedPath(), - ConfigFilePath: config.GetConfigFilePath(), - ScrapersPath: config.GetScrapersPath(), - CachePath: config.GetCachePath(), - CalculateMd5: config.IsCalculateMD5(), - VideoFileNamingAlgorithm: config.GetVideoFileNamingAlgorithm(), - ParallelTasks: config.GetParallelTasks(), - PreviewAudio: config.GetPreviewAudio(), - PreviewSegments: config.GetPreviewSegments(), - PreviewSegmentDuration: config.GetPreviewSegmentDuration(), - PreviewExcludeStart: config.GetPreviewExcludeStart(), - PreviewExcludeEnd: config.GetPreviewExcludeEnd(), - PreviewPreset: config.GetPreviewPreset(), - MaxTranscodeSize: &maxTranscodeSize, - MaxStreamingTranscodeSize: &maxStreamingTranscodeSize, - APIKey: config.GetAPIKey(), - Username: config.GetUsername(), - Password: config.GetPasswordHash(), - MaxSessionAge: config.GetMaxSessionAge(), - LogFile: &logFile, - LogOut: config.GetLogOut(), - LogLevel: config.GetLogLevel(), - LogAccess: config.GetLogAccess(), - VideoExtensions: config.GetVideoExtensions(), - ImageExtensions: config.GetImageExtensions(), - GalleryExtensions: config.GetGalleryExtensions(), - CreateGalleriesFromFolders: config.GetCreateGalleriesFromFolders(), - Excludes: config.GetExcludes(), - ImageExcludes: config.GetImageExcludes(), - ScraperUserAgent: &scraperUserAgent, - ScraperCertCheck: config.GetScraperCertCheck(), - ScraperCDPPath: &scraperCDPPath, - StashBoxes: config.GetStashBoxes(), + Stashes: config.GetStashPaths(), + DatabasePath: config.GetDatabasePath(), + GeneratedPath: config.GetGeneratedPath(), + ConfigFilePath: config.GetConfigFilePath(), + ScrapersPath: config.GetScrapersPath(), + CachePath: config.GetCachePath(), + CalculateMd5: config.IsCalculateMD5(), + VideoFileNamingAlgorithm: config.GetVideoFileNamingAlgorithm(), + ParallelTasks: config.GetParallelTasks(), + PreviewAudio: config.GetPreviewAudio(), + PreviewSegments: config.GetPreviewSegments(), + PreviewSegmentDuration: config.GetPreviewSegmentDuration(), + PreviewExcludeStart: config.GetPreviewExcludeStart(), + PreviewExcludeEnd: config.GetPreviewExcludeEnd(), + PreviewPreset: config.GetPreviewPreset(), + MaxTranscodeSize: &maxTranscodeSize, + MaxStreamingTranscodeSize: &maxStreamingTranscodeSize, + APIKey: config.GetAPIKey(), + Username: config.GetUsername(), + Password: config.GetPasswordHash(), + MaxSessionAge: config.GetMaxSessionAge(), + LogFile: &logFile, + LogOut: config.GetLogOut(), + LogLevel: config.GetLogLevel(), + LogAccess: config.GetLogAccess(), + VideoExtensions: config.GetVideoExtensions(), + ImageExtensions: config.GetImageExtensions(), + GalleryExtensions: config.GetGalleryExtensions(), + CreateGalleriesFromFolders: config.GetCreateGalleriesFromFolders(), + Excludes: config.GetExcludes(), + ImageExcludes: config.GetImageExcludes(), + CustomPerformerImageLocation: &customPerformerImageLocation, + ScraperUserAgent: &scraperUserAgent, + ScraperCertCheck: config.GetScraperCertCheck(), + ScraperCDPPath: &scraperCDPPath, + StashBoxes: config.GetStashBoxes(), } } @@ -105,6 +109,7 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult { language := config.GetLanguage() slideshowDelay := config.GetSlideshowDelay() handyKey := config.GetHandyKey() + scriptOffset := config.GetFunscriptOffset() return &models.ConfigInterfaceResult{ MenuItems: menuItems, @@ -119,6 +124,7 @@ func makeConfigInterfaceResult() *models.ConfigInterfaceResult { Language: &language, SlideshowDelay: &slideshowDelay, HandyKey: &handyKey, + FunscriptOffset: &scriptOffset, } } @@ -132,3 +138,17 @@ func makeConfigDLNAResult() *models.ConfigDLNAResult { Interfaces: config.GetDLNAInterfaces(), } } + +func makeConfigScrapingResult() *models.ConfigScrapingResult { + config := config.GetInstance() + + scraperUserAgent := config.GetScraperUserAgent() + scraperCDPPath := config.GetScraperCDPPath() + + return &models.ConfigScrapingResult{ + ScraperUserAgent: &scraperUserAgent, + ScraperCertCheck: config.GetScraperCertCheck(), + ScraperCDPPath: &scraperCDPPath, + ExcludeTagPatterns: config.GetScraperExcludeTagPatterns(), + } +} diff --git a/pkg/api/routes_performer.go b/pkg/api/routes_performer.go index 7e50c4551..1940e0dfe 100644 --- a/pkg/api/routes_performer.go +++ b/pkg/api/routes_performer.go @@ -7,6 +7,7 @@ import ( "github.com/go-chi/chi" "github.com/stashapp/stash/pkg/manager" + "github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/utils" ) @@ -39,7 +40,7 @@ func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) { } if len(image) == 0 || defaultParam == "true" { - image, _ = getRandomPerformerImageUsingName(performer.Name.String, performer.Gender.String) + image, _ = getRandomPerformerImageUsingName(performer.Name.String, performer.Gender.String, config.GetInstance().GetCustomPerformerImageLocation()) } utils.ServeImage(image, w, r) diff --git a/pkg/api/server.go b/pkg/api/server.go index ee9063287..823dae457 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -27,7 +27,6 @@ import ( "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/manager" "github.com/stashapp/stash/pkg/manager/config" - "github.com/stashapp/stash/pkg/manager/paths" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/session" "github.com/stashapp/stash/pkg/utils" @@ -286,34 +285,31 @@ func Start() { displayAddress := displayHost + ":" + strconv.Itoa(c.GetPort()) address := c.GetHost() + ":" + strconv.Itoa(c.GetPort()) - if tlsConfig := makeTLSConfig(); tlsConfig != nil { - httpsServer := &http.Server{ - Addr: address, - Handler: r, - TLSConfig: tlsConfig, - } + tlsConfig, err := makeTLSConfig(c) + if err != nil { + // assume we don't want to start with a broken TLS configuration + panic(fmt.Errorf("error loading TLS config: %s", err.Error())) + } - go func() { - printVersion() - printLatestVersion() - logger.Infof("stash is listening on " + address) + server := &http.Server{ + Addr: address, + Handler: r, + TLSConfig: tlsConfig, + } + + go func() { + printVersion() + printLatestVersion() + logger.Infof("stash is listening on " + address) + + if tlsConfig != nil { logger.Infof("stash is running at https://" + displayAddress + "/") - logger.Error(httpsServer.ListenAndServeTLS("", "")) - }() - } else { - server := &http.Server{ - Addr: address, - Handler: r, - } - - go func() { - printVersion() - printLatestVersion() - logger.Infof("stash is listening on " + address) + logger.Error(server.ListenAndServeTLS("", "")) + } else { logger.Infof("stash is running at http://" + displayAddress + "/") logger.Error(server.ListenAndServe()) - }() - } + } + }() } func printVersion() { @@ -328,27 +324,44 @@ func GetVersion() (string, string, string) { return version, githash, buildstamp } -func makeTLSConfig() *tls.Config { - cert, err := ioutil.ReadFile(paths.GetSSLCert()) - if err != nil { - return nil +func makeTLSConfig(c *config.Instance) (*tls.Config, error) { + c.InitTLS() + certFile, keyFile := c.GetTLSFiles() + + if certFile == "" && keyFile == "" { + // assume http configuration + return nil, nil } - key, err := ioutil.ReadFile(paths.GetSSLKey()) + // ensure both files are present + if certFile == "" { + return nil, errors.New("SSL certificate file must be present if key file is present") + } + + if keyFile == "" { + return nil, errors.New("SSL key file must be present if certificate file is present") + } + + cert, err := ioutil.ReadFile(certFile) if err != nil { - return nil + return nil, fmt.Errorf("error reading SSL certificate file %s: %s", certFile, err.Error()) + } + + key, err := ioutil.ReadFile(keyFile) + if err != nil { + return nil, fmt.Errorf("error reading SSL key file %s: %s", keyFile, err.Error()) } certs := make([]tls.Certificate, 1) certs[0], err = tls.X509KeyPair(cert, key) if err != nil { - return nil + return nil, fmt.Errorf("error parsing key pair: %s", err.Error()) } tlsConfig := &tls.Config{ Certificates: certs, } - return tlsConfig + return tlsConfig, nil } type contextKey struct { diff --git a/pkg/api/types.go b/pkg/api/types.go index f786c3968..9af592806 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -1,7 +1,19 @@ package api +import "math" + // An enum https://golang.org/ref/spec#Iota const ( create = iota // 0 update = iota // 1 ) + +// #1572 - Inf and NaN values cause the JSON marshaller to fail +// Return nil for these values +func handleFloat64(v float64) *float64 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil + } + + return &v +} diff --git a/pkg/ffmpeg/downloader.go b/pkg/ffmpeg/downloader.go index e99716cbf..da5b2dbaf 100644 --- a/pkg/ffmpeg/downloader.go +++ b/pkg/ffmpeg/downloader.go @@ -16,17 +16,6 @@ import ( "github.com/stashapp/stash/pkg/utils" ) -func findInPaths(paths []string, baseName string) string { - for _, p := range paths { - filePath := filepath.Join(p, baseName) - if exists, _ := utils.FileExists(filePath); exists { - return filePath - } - } - - return "" -} - func GetPaths(paths []string) (string, string) { var ffmpegPath, ffprobePath string @@ -38,10 +27,10 @@ func GetPaths(paths []string) (string, string) { // Check if ffmpeg exists in the config directory if ffmpegPath == "" { - ffmpegPath = findInPaths(paths, getFFMPEGFilename()) + ffmpegPath = utils.FindInPaths(paths, getFFMPEGFilename()) } if ffprobePath == "" { - ffprobePath = findInPaths(paths, getFFProbeFilename()) + ffprobePath = utils.FindInPaths(paths, getFFProbeFilename()) } return ffmpegPath, ffprobePath diff --git a/pkg/manager/checksum.go b/pkg/manager/checksum.go index a545008b6..bc41ddfe1 100644 --- a/pkg/manager/checksum.go +++ b/pkg/manager/checksum.go @@ -4,7 +4,6 @@ import ( "context" "errors" - "github.com/spf13/viper" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/models" @@ -26,16 +25,12 @@ func setInitialMD5Config(txnManager models.TransactionManager) { usingMD5 := count != 0 defaultAlgorithm := models.HashAlgorithmOshash - if usingMD5 { defaultAlgorithm = models.HashAlgorithmMd5 } - // TODO - this should use the config instance - viper.SetDefault(config.VideoFileNamingAlgorithm, defaultAlgorithm) - viper.SetDefault(config.CalculateMD5, usingMD5) - config := config.GetInstance() + config.SetChecksumDefaultValues(defaultAlgorithm, usingMD5) if err := config.Write(); err != nil { logger.Errorf("Error while writing configuration file: %s", err.Error()) } diff --git a/pkg/manager/config/config.go b/pkg/manager/config/config.go index 618fdcdcf..c412880ca 100644 --- a/pkg/manager/config/config.go +++ b/pkg/manager/config/config.go @@ -9,6 +9,9 @@ import ( "runtime" "strings" + "sync" + //"github.com/sasha-s/go-deadlock" // if you have deadlock issues + "golang.org/x/crypto/bcrypt" "github.com/spf13/viper" @@ -95,6 +98,7 @@ const ScrapersPath = "scrapers_path" const ScraperUserAgent = "scraper_user_agent" const ScraperCertCheck = "scraper_cert_check" const ScraperCDPPath = "scraper_cdp_path" +const ScraperExcludeTagPatterns = "scraper_exclude_tag_patterns" // stash-box options const StashBoxes = "stash_boxes" @@ -120,6 +124,7 @@ var defaultMenuItems = []string{"scenes", "images", "movies", "markers", "galler const SoundOnPreview = "sound_on_preview" const WallShowTitle = "wall_show_title" +const CustomPerformerImageLocation = "custom_performer_image_location" const MaximumLoopDuration = "maximum_loop_duration" const AutostartVideo = "autostart_video" const ShowStudioAsText = "show_studio_as_text" @@ -127,6 +132,7 @@ const CSSEnabled = "cssEnabled" const WallPlayback = "wall_playback" const SlideshowDelay = "slideshow_delay" const HandyKey = "handy_key" +const FunscriptOffset = "funscript_offset" // DLNA options const DLNAServerName = "dlna.server_name" @@ -151,18 +157,13 @@ func (e MissingConfigError) Error() string { return fmt.Sprintf("missing the following mandatory settings: %s", strings.Join(e.missingFields, ", ")) } -func HasTLSConfig() bool { - ret, _ := utils.FileExists(paths.GetSSLCert()) - if ret { - ret, _ = utils.FileExists(paths.GetSSLKey()) - } - - return ret -} - type Instance struct { cpuProfilePath string isNewSystem bool + certFile string + keyFile string + sync.RWMutex + //deadlock.RWMutex // for deadlock testing/issues } var instance *Instance @@ -179,9 +180,31 @@ func (i *Instance) IsNewSystem() bool { } func (i *Instance) SetConfigFile(fn string) { + i.Lock() + defer i.Unlock() viper.SetConfigFile(fn) } +func (i *Instance) InitTLS() { + configDirectory := i.GetConfigPath() + tlsPaths := []string{ + configDirectory, + paths.GetStashHomeDirectory(), + } + + i.certFile = utils.FindInPaths(tlsPaths, "stash.crt") + i.keyFile = utils.FindInPaths(tlsPaths, "stash.key") +} + +func (i *Instance) GetTLSFiles() (certFile, keyFile string) { + return i.certFile, i.keyFile +} + +func (i *Instance) HasTLSConfig() bool { + certFile, keyFile := i.GetTLSFiles() + return certFile != "" && keyFile != "" +} + // GetCPUProfilePath returns the path to the CPU profile file to output // profiling info to. This is set only via a commandline flag. Returns an // empty string if not set. @@ -190,6 +213,8 @@ func (i *Instance) GetCPUProfilePath() string { } func (i *Instance) Set(key string, value interface{}) { + i.Lock() + defer i.Unlock() viper.Set(key, value) } @@ -203,11 +228,15 @@ func (i *Instance) SetPassword(value string) { } func (i *Instance) Write() error { + i.Lock() + defer i.Unlock() return viper.WriteConfig() } // GetConfigFile returns the full path to the used configuration file. func (i *Instance) GetConfigFile() string { + i.RLock() + defer i.RUnlock() return viper.ConfigFileUsed() } @@ -224,6 +253,8 @@ func (i *Instance) GetDefaultDatabaseFilePath() string { } func (i *Instance) GetStashPaths() []*models.StashConfig { + i.RLock() + defer i.RUnlock() var ret []*models.StashConfig if err := viper.UnmarshalKey(Stash, &ret); err != nil || len(ret) == 0 { // fallback to legacy format @@ -241,30 +272,44 @@ func (i *Instance) GetStashPaths() []*models.StashConfig { } func (i *Instance) GetConfigFilePath() string { + i.RLock() + defer i.RUnlock() return viper.ConfigFileUsed() } func (i *Instance) GetCachePath() string { + i.RLock() + defer i.RUnlock() return viper.GetString(Cache) } func (i *Instance) GetGeneratedPath() string { + i.RLock() + defer i.RUnlock() return viper.GetString(Generated) } func (i *Instance) GetMetadataPath() string { + i.RLock() + defer i.RUnlock() return viper.GetString(Metadata) } func (i *Instance) GetDatabasePath() string { + i.RLock() + defer i.RUnlock() return viper.GetString(Database) } func (i *Instance) GetJWTSignKey() []byte { + i.RLock() + defer i.RUnlock() return []byte(viper.GetString(JWTSignKey)) } func (i *Instance) GetSessionStoreKey() []byte { + i.RLock() + defer i.RUnlock() return []byte(viper.GetString(SessionStoreKey)) } @@ -277,14 +322,20 @@ func (i *Instance) GetDefaultScrapersPath() string { } func (i *Instance) GetExcludes() []string { + i.RLock() + defer i.RUnlock() return viper.GetStringSlice(Exclude) } func (i *Instance) GetImageExcludes() []string { + i.RLock() + defer i.RUnlock() return viper.GetStringSlice(ImageExclude) } func (i *Instance) GetVideoExtensions() []string { + i.RLock() + defer i.RUnlock() ret := viper.GetStringSlice(VideoExtensions) if ret == nil { ret = defaultVideoExtensions @@ -293,6 +344,8 @@ func (i *Instance) GetVideoExtensions() []string { } func (i *Instance) GetImageExtensions() []string { + i.RLock() + defer i.RUnlock() ret := viper.GetStringSlice(ImageExtensions) if ret == nil { ret = defaultImageExtensions @@ -301,6 +354,8 @@ func (i *Instance) GetImageExtensions() []string { } func (i *Instance) GetGalleryExtensions() []string { + i.RLock() + defer i.RUnlock() ret := viper.GetStringSlice(GalleryExtensions) if ret == nil { ret = defaultGalleryExtensions @@ -309,10 +364,14 @@ func (i *Instance) GetGalleryExtensions() []string { } func (i *Instance) GetCreateGalleriesFromFolders() bool { + i.RLock() + defer i.RUnlock() return viper.GetBool(CreateGalleriesFromFolders) } func (i *Instance) GetLanguage() string { + i.RLock() + defer i.RUnlock() ret := viper.GetString(Language) // default to English @@ -326,12 +385,16 @@ func (i *Instance) GetLanguage() string { // IsCalculateMD5 returns true if MD5 checksums should be generated for // scene video files. func (i *Instance) IsCalculateMD5() bool { + i.RLock() + defer i.RUnlock() return viper.GetBool(CalculateMD5) } // GetVideoFileNamingAlgorithm returns what hash algorithm should be used for // naming generated scene video files. func (i *Instance) GetVideoFileNamingAlgorithm() models.HashAlgorithm { + i.RLock() + defer i.RUnlock() ret := viper.GetString(VideoFileNamingAlgorithm) // default to oshash @@ -343,22 +406,30 @@ func (i *Instance) GetVideoFileNamingAlgorithm() models.HashAlgorithm { } func (i *Instance) GetScrapersPath() string { + i.RLock() + defer i.RUnlock() return viper.GetString(ScrapersPath) } func (i *Instance) GetScraperUserAgent() string { + i.RLock() + defer i.RUnlock() return viper.GetString(ScraperUserAgent) } // GetScraperCDPPath gets the path to the Chrome executable or remote address // to an instance of Chrome. func (i *Instance) GetScraperCDPPath() string { + i.RLock() + defer i.RUnlock() return viper.GetString(ScraperCDPPath) } // GetScraperCertCheck returns true if the scraper should check for insecure // certificates when fetching an image or a page. func (i *Instance) GetScraperCertCheck() bool { + i.RLock() + defer i.RUnlock() ret := true if viper.IsSet(ScraperCertCheck) { ret = viper.GetBool(ScraperCertCheck) @@ -367,7 +438,20 @@ func (i *Instance) GetScraperCertCheck() bool { return ret } +func (i *Instance) GetScraperExcludeTagPatterns() []string { + i.RLock() + defer i.RUnlock() + var ret []string + if viper.IsSet(ScraperExcludeTagPatterns) { + ret = viper.GetStringSlice(ScraperExcludeTagPatterns) + } + + return ret +} + func (i *Instance) GetStashBoxes() []*models.StashBox { + i.RLock() + defer i.RUnlock() var boxes []*models.StashBox viper.UnmarshalKey(StashBoxes, &boxes) return boxes @@ -381,34 +465,48 @@ func (i *Instance) GetDefaultPluginsPath() string { } func (i *Instance) GetPluginsPath() string { + i.RLock() + defer i.RUnlock() return viper.GetString(PluginsPath) } func (i *Instance) GetHost() string { + i.RLock() + defer i.RUnlock() return viper.GetString(Host) } func (i *Instance) GetPort() int { + i.RLock() + defer i.RUnlock() return viper.GetInt(Port) } func (i *Instance) GetExternalHost() string { + i.RLock() + defer i.RUnlock() return viper.GetString(ExternalHost) } // GetPreviewSegmentDuration returns the duration of a single segment in a // scene preview file, in seconds. func (i *Instance) GetPreviewSegmentDuration() float64 { + i.RLock() + defer i.RUnlock() return viper.GetFloat64(PreviewSegmentDuration) } // GetParallelTasks returns the number of parallel tasks that should be started // by scan or generate task. func (i *Instance) GetParallelTasks() int { + i.RLock() + defer i.RUnlock() return viper.GetInt(ParallelTasks) } func (i *Instance) GetParallelTasksWithAutoDetection() int { + i.RLock() + defer i.RUnlock() parallelTasks := viper.GetInt(ParallelTasks) if parallelTasks <= 0 { parallelTasks = (runtime.NumCPU() / 4) + 1 @@ -417,11 +515,15 @@ func (i *Instance) GetParallelTasksWithAutoDetection() int { } func (i *Instance) GetPreviewAudio() bool { + i.RLock() + defer i.RUnlock() return viper.GetBool(PreviewAudio) } // GetPreviewSegments returns the amount of segments in a scene preview file. func (i *Instance) GetPreviewSegments() int { + i.RLock() + defer i.RUnlock() return viper.GetInt(PreviewSegments) } @@ -432,6 +534,8 @@ func (i *Instance) GetPreviewSegments() int { // in the preview. If the value is suffixed with a '%' character (for example // '2%'), then it is interpreted as a proportion of the total video duration. func (i *Instance) GetPreviewExcludeStart() string { + i.RLock() + defer i.RUnlock() return viper.GetString(PreviewExcludeStart) } @@ -441,12 +545,16 @@ func (i *Instance) GetPreviewExcludeStart() string { // when generating previews. If the value is suffixed with a '%' character, // then it is interpreted as a proportion of the total video duration. func (i *Instance) GetPreviewExcludeEnd() string { + i.RLock() + defer i.RUnlock() return viper.GetString(PreviewExcludeEnd) } // GetPreviewPreset returns the preset when generating previews. Defaults to // Slow. func (i *Instance) GetPreviewPreset() models.PreviewPreset { + i.RLock() + defer i.RUnlock() ret := viper.GetString(PreviewPreset) // default to slow @@ -458,6 +566,8 @@ func (i *Instance) GetPreviewPreset() models.PreviewPreset { } func (i *Instance) GetMaxTranscodeSize() models.StreamingResolutionEnum { + i.RLock() + defer i.RUnlock() ret := viper.GetString(MaxTranscodeSize) // default to original @@ -469,6 +579,8 @@ func (i *Instance) GetMaxTranscodeSize() models.StreamingResolutionEnum { } func (i *Instance) GetMaxStreamingTranscodeSize() models.StreamingResolutionEnum { + i.RLock() + defer i.RUnlock() ret := viper.GetString(MaxStreamingTranscodeSize) // default to original @@ -480,19 +592,27 @@ func (i *Instance) GetMaxStreamingTranscodeSize() models.StreamingResolutionEnum } func (i *Instance) GetAPIKey() string { + i.RLock() + defer i.RUnlock() return viper.GetString(ApiKey) } func (i *Instance) GetUsername() string { + i.RLock() + defer i.RUnlock() return viper.GetString(Username) } func (i *Instance) GetPasswordHash() string { + i.RLock() + defer i.RUnlock() return viper.GetString(Password) } func (i *Instance) GetCredentials() (string, string) { if i.HasCredentials() { + i.RLock() + defer i.RUnlock() return viper.GetString(Username), viper.GetString(Password) } @@ -500,12 +620,14 @@ func (i *Instance) GetCredentials() (string, string) { } func (i *Instance) HasCredentials() bool { + i.RLock() + defer i.RUnlock() if !viper.IsSet(Username) || !viper.IsSet(Password) { return false } - username := i.GetUsername() - pwHash := i.GetPasswordHash() + username := viper.GetString(Username) + pwHash := viper.GetString(Password) return username != "" && pwHash != "" } @@ -554,6 +676,8 @@ func (i *Instance) ValidateStashBoxes(boxes []*models.StashBoxInput) error { // GetMaxSessionAge gets the maximum age for session cookies, in seconds. // Session cookie expiry times are refreshed every request. func (i *Instance) GetMaxSessionAge() int { + i.Lock() + defer i.Unlock() viper.SetDefault(MaxSessionAge, DefaultMaxSessionAge) return viper.GetInt(MaxSessionAge) } @@ -561,15 +685,21 @@ func (i *Instance) GetMaxSessionAge() int { // GetCustomServedFolders gets the map of custom paths to their applicable // filesystem locations func (i *Instance) GetCustomServedFolders() URLMap { + i.RLock() + defer i.RUnlock() return viper.GetStringMapString(CustomServedFolders) } func (i *Instance) GetCustomUILocation() string { + i.RLock() + defer i.RUnlock() return viper.GetString(CustomUILocation) } // Interface options func (i *Instance) GetMenuItems() []string { + i.RLock() + defer i.RUnlock() if viper.IsSet(MenuItems) { return viper.GetStringSlice(MenuItems) } @@ -577,40 +707,63 @@ func (i *Instance) GetMenuItems() []string { } func (i *Instance) GetSoundOnPreview() bool { + i.RLock() + defer i.RUnlock() return viper.GetBool(SoundOnPreview) } func (i *Instance) GetWallShowTitle() bool { + i.Lock() + defer i.Unlock() viper.SetDefault(WallShowTitle, true) return viper.GetBool(WallShowTitle) } +func (i *Instance) GetCustomPerformerImageLocation() string { + i.Lock() + defer i.Unlock() + viper.SetDefault(CustomPerformerImageLocation, "") + return viper.GetString(CustomPerformerImageLocation) +} + func (i *Instance) GetWallPlayback() string { + i.Lock() + defer i.Unlock() viper.SetDefault(WallPlayback, "video") return viper.GetString(WallPlayback) } func (i *Instance) GetMaximumLoopDuration() int { + i.Lock() + defer i.Unlock() viper.SetDefault(MaximumLoopDuration, 0) return viper.GetInt(MaximumLoopDuration) } func (i *Instance) GetAutostartVideo() bool { + i.Lock() + defer i.Unlock() viper.SetDefault(AutostartVideo, false) return viper.GetBool(AutostartVideo) } func (i *Instance) GetShowStudioAsText() bool { + i.Lock() + defer i.Unlock() viper.SetDefault(ShowStudioAsText, false) return viper.GetBool(ShowStudioAsText) } func (i *Instance) GetSlideshowDelay() int { + i.Lock() + defer i.Unlock() viper.SetDefault(SlideshowDelay, 5000) return viper.GetInt(SlideshowDelay) } func (i *Instance) GetCSSPath() string { + i.RLock() + defer i.RUnlock() // use custom.css in the same directory as the config file configFileUsed := viper.ConfigFileUsed() configDir := filepath.Dir(configFileUsed) @@ -638,6 +791,8 @@ func (i *Instance) GetCSS() string { } func (i *Instance) SetCSS(css string) { + i.RLock() + defer i.RUnlock() fn := i.GetCSSPath() buf := []byte(css) @@ -646,39 +801,58 @@ func (i *Instance) SetCSS(css string) { } func (i *Instance) GetCSSEnabled() bool { + i.RLock() + defer i.RUnlock() return viper.GetBool(CSSEnabled) } func (i *Instance) GetHandyKey() string { + i.RLock() + defer i.RUnlock() return viper.GetString(HandyKey) } +func (i *Instance) GetFunscriptOffset() int { + viper.SetDefault(FunscriptOffset, 0) + return viper.GetInt(FunscriptOffset) +} + // GetDLNAServerName returns the visible name of the DLNA server. If empty, // "stash" will be used. func (i *Instance) GetDLNAServerName() string { + i.RLock() + defer i.RUnlock() return viper.GetString(DLNAServerName) } // GetDLNADefaultEnabled returns true if the DLNA is enabled by default. func (i *Instance) GetDLNADefaultEnabled() bool { + i.RLock() + defer i.RUnlock() return viper.GetBool(DLNADefaultEnabled) } // GetDLNADefaultIPWhitelist returns a list of IP addresses/wildcards that // are allowed to use the DLNA service. func (i *Instance) GetDLNADefaultIPWhitelist() []string { + i.RLock() + defer i.RUnlock() return viper.GetStringSlice(DLNADefaultIPWhitelist) } // GetDLNAInterfaces returns a list of interface names to expose DLNA on. If // empty, runs on all interfaces. func (i *Instance) GetDLNAInterfaces() []string { + i.RLock() + defer i.RUnlock() return viper.GetStringSlice(DLNAInterfaces) } // GetLogFile returns the filename of the file to output logs to. // An empty string means that file logging will be disabled. func (i *Instance) GetLogFile() string { + i.RLock() + defer i.RUnlock() return viper.GetString(LogFile) } @@ -686,6 +860,8 @@ func (i *Instance) GetLogFile() string { // in addition to writing to a log file. Logging will be output to the // terminal if file logging is disabled. Defaults to true. func (i *Instance) GetLogOut() bool { + i.RLock() + defer i.RUnlock() ret := true if viper.IsSet(LogOut) { ret = viper.GetBool(LogOut) @@ -697,6 +873,8 @@ func (i *Instance) GetLogOut() bool { // GetLogLevel returns the lowest log level to write to the log. // Should be one of "Debug", "Info", "Warning", "Error" func (i *Instance) GetLogLevel() string { + i.RLock() + defer i.RUnlock() const defaultValue = "Info" value := viper.GetString(LogLevel) @@ -710,6 +888,8 @@ func (i *Instance) GetLogLevel() string { // GetLogAccess returns true if http requests should be logged to the terminal. // HTTP requests are not logged to the log file. Defaults to true. func (i *Instance) GetLogAccess() bool { + i.RLock() + defer i.RUnlock() ret := true if viper.IsSet(LogAccess) { ret = viper.GetBool(LogAccess) @@ -720,6 +900,8 @@ func (i *Instance) GetLogAccess() bool { // Max allowed graphql upload size in megabytes func (i *Instance) GetMaxUploadSize() int64 { + i.RLock() + defer i.RUnlock() ret := int64(1024) if viper.IsSet(MaxUploadSize) { ret = viper.GetInt64(MaxUploadSize) @@ -728,6 +910,8 @@ func (i *Instance) GetMaxUploadSize() int64 { } func (i *Instance) Validate() error { + i.RLock() + defer i.RUnlock() mandatoryPaths := []string{ Database, Generated, @@ -750,7 +934,22 @@ func (i *Instance) Validate() error { return nil } +func (i *Instance) SetChecksumDefaultValues(defaultAlgorithm models.HashAlgorithm, usingMD5 bool) { + i.Lock() + defer i.Unlock() + viper.SetDefault(VideoFileNamingAlgorithm, defaultAlgorithm) + viper.SetDefault(CalculateMD5, usingMD5) +} + func (i *Instance) setDefaultValues() error { + + // read data before write lock scope + defaultDatabaseFilePath := i.GetDefaultDatabaseFilePath() + defaultScrapersPath := i.GetDefaultScrapersPath() + defaultPluginsPath := i.GetDefaultPluginsPath() + + i.Lock() + defer i.Unlock() viper.SetDefault(ParallelTasks, parallelTasksDefault) viper.SetDefault(PreviewSegmentDuration, previewSegmentDurationDefault) viper.SetDefault(PreviewSegments, previewSegmentsDefault) @@ -759,14 +958,14 @@ func (i *Instance) setDefaultValues() error { viper.SetDefault(PreviewAudio, previewAudioDefault) viper.SetDefault(SoundOnPreview, false) - viper.SetDefault(Database, i.GetDefaultDatabaseFilePath()) + viper.SetDefault(Database, defaultDatabaseFilePath) // Set generated to the metadata path for backwards compat viper.SetDefault(Generated, viper.GetString(Metadata)) // Set default scrapers and plugins paths - viper.SetDefault(ScrapersPath, i.GetDefaultScrapersPath()) - viper.SetDefault(PluginsPath, i.GetDefaultPluginsPath()) + viper.SetDefault(ScrapersPath, defaultScrapersPath) + viper.SetDefault(PluginsPath, defaultPluginsPath) return viper.WriteConfig() } diff --git a/pkg/manager/config/config_concurrency_test.go b/pkg/manager/config/config_concurrency_test.go new file mode 100644 index 000000000..2f86f332e --- /dev/null +++ b/pkg/manager/config/config_concurrency_test.go @@ -0,0 +1,100 @@ +package config + +import ( + "sync" + "testing" +) + +// should be run with -race +func TestConcurrentConfigAccess(t *testing.T) { + i := GetInstance() + + const workers = 8 + //const loops = 1000 + const loops = 200 + var wg sync.WaitGroup + for t := 0; t < workers; t++ { + wg.Add(1) + go func() { + for l := 0; l < loops; l++ { + i.SetInitialConfig() + + i.HasCredentials() + i.GetCPUProfilePath() + i.GetConfigFile() + i.GetConfigPath() + i.GetDefaultDatabaseFilePath() + i.GetStashPaths() + i.GetConfigFilePath() + i.Set(Cache, i.GetCachePath()) + i.Set(Generated, i.GetGeneratedPath()) + i.Set(Metadata, i.GetMetadataPath()) + i.Set(Database, i.GetDatabasePath()) + i.Set(JWTSignKey, i.GetJWTSignKey()) + i.Set(SessionStoreKey, i.GetSessionStoreKey()) + i.GetDefaultScrapersPath() + i.Set(Exclude, i.GetExcludes()) + i.Set(ImageExclude, i.GetImageExcludes()) + i.Set(VideoExtensions, i.GetVideoExtensions()) + i.Set(ImageExtensions, i.GetImageExtensions()) + i.Set(GalleryExtensions, i.GetGalleryExtensions()) + i.Set(CreateGalleriesFromFolders, i.GetCreateGalleriesFromFolders()) + i.Set(Language, i.GetLanguage()) + i.Set(VideoFileNamingAlgorithm, i.GetVideoFileNamingAlgorithm()) + i.Set(ScrapersPath, i.GetScrapersPath()) + i.Set(ScraperUserAgent, i.GetScraperUserAgent()) + i.Set(ScraperCDPPath, i.GetScraperCDPPath()) + i.Set(ScraperCertCheck, i.GetScraperCertCheck()) + i.Set(ScraperExcludeTagPatterns, i.GetScraperExcludeTagPatterns()) + i.Set(StashBoxes, i.GetStashBoxes()) + i.GetDefaultPluginsPath() + i.Set(PluginsPath, i.GetPluginsPath()) + i.Set(Host, i.GetHost()) + i.Set(Port, i.GetPort()) + i.Set(ExternalHost, i.GetExternalHost()) + i.Set(PreviewSegmentDuration, i.GetPreviewSegmentDuration()) + i.Set(ParallelTasks, i.GetParallelTasks()) + i.Set(ParallelTasks, i.GetParallelTasksWithAutoDetection()) + i.Set(PreviewAudio, i.GetPreviewAudio()) + i.Set(PreviewSegments, i.GetPreviewSegments()) + i.Set(PreviewExcludeStart, i.GetPreviewExcludeStart()) + i.Set(PreviewExcludeEnd, i.GetPreviewExcludeEnd()) + i.Set(PreviewPreset, i.GetPreviewPreset()) + i.Set(MaxTranscodeSize, i.GetMaxTranscodeSize()) + i.Set(MaxStreamingTranscodeSize, i.GetMaxStreamingTranscodeSize()) + i.Set(ApiKey, i.GetAPIKey()) + i.Set(Username, i.GetUsername()) + i.Set(Password, i.GetPasswordHash()) + i.GetCredentials() + i.Set(MaxSessionAge, i.GetMaxSessionAge()) + i.Set(CustomServedFolders, i.GetCustomServedFolders()) + i.Set(CustomUILocation, i.GetCustomUILocation()) + i.Set(MenuItems, i.GetMenuItems()) + i.Set(SoundOnPreview, i.GetSoundOnPreview()) + i.Set(WallShowTitle, i.GetWallShowTitle()) + i.Set(CustomPerformerImageLocation, i.GetCustomPerformerImageLocation()) + i.Set(WallPlayback, i.GetWallPlayback()) + i.Set(MaximumLoopDuration, i.GetMaximumLoopDuration()) + i.Set(AutostartVideo, i.GetAutostartVideo()) + i.Set(ShowStudioAsText, i.GetShowStudioAsText()) + i.Set(SlideshowDelay, i.GetSlideshowDelay()) + i.GetCSSPath() + i.GetCSS() + i.Set(CSSEnabled, i.GetCSSEnabled()) + i.Set(HandyKey, i.GetHandyKey()) + i.Set(DLNAServerName, i.GetDLNAServerName()) + i.Set(DLNADefaultEnabled, i.GetDLNADefaultEnabled()) + i.Set(DLNADefaultIPWhitelist, i.GetDLNADefaultIPWhitelist()) + i.Set(DLNAInterfaces, i.GetDLNAInterfaces()) + i.Set(LogFile, i.GetLogFile()) + i.Set(LogOut, i.GetLogOut()) + i.Set(LogLevel, i.GetLogLevel()) + i.Set(LogAccess, i.GetLogAccess()) + i.Set(MaxUploadSize, i.GetMaxUploadSize()) + } + wg.Done() + }() + } + + wg.Wait() +} diff --git a/pkg/manager/filename_parser.go b/pkg/manager/filename_parser.go index 5be8ed178..991261941 100644 --- a/pkg/manager/filename_parser.go +++ b/pkg/manager/filename_parser.go @@ -484,6 +484,11 @@ func (p *SceneFilenameParser) Parse(repo models.ReaderRepository) ([]*models.Sce }, } + if p.ParserInput.IgnoreOrganized != nil && *p.ParserInput.IgnoreOrganized { + organized := false + sceneFilter.Organized = &organized + } + p.Filter.Q = nil scenes, total, err := repo.Scene().Query(sceneFilter, p.Filter) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 349851cc2..638332619 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -58,7 +58,6 @@ func GetInstance() *singleton { func Initialize() *singleton { once.Do(func() { - _ = utils.EnsureDir(paths.GetStashHomeDirectory()) cfg, err := config.Initialize() if err != nil { @@ -269,6 +268,14 @@ func setSetupDefaults(input *models.SetupInput) { func (s *singleton) Setup(input models.SetupInput) error { setSetupDefaults(&input) + // create the config directory if it does not exist + configDir := filepath.Dir(input.ConfigLocation) + if exists, _ := utils.DirExists(configDir); !exists { + if err := os.Mkdir(configDir, 0755); err != nil { + return fmt.Errorf("abc: %s", err.Error()) + } + } + // create the generated directory if it does not exist if exists, _ := utils.DirExists(input.GeneratedLocation); !exists { if err := os.Mkdir(input.GeneratedLocation, 0755); err != nil { diff --git a/pkg/manager/manager_tasks.go b/pkg/manager/manager_tasks.go index abe8f7560..6173c30ed 100644 --- a/pkg/manager/manager_tasks.go +++ b/pkg/manager/manager_tasks.go @@ -322,6 +322,7 @@ func (s *singleton) Generate(ctx context.Context, input models.GenerateMetadataI Scene: *scene, fileNamingAlgorithm: fileNamingAlgo, txnManager: s.TxnManager, + Overwrite: overwrite, } wg.Add() go progress.ExecuteTask(fmt.Sprintf("Generating phash for %s", scene.Path), func() { diff --git a/pkg/manager/paths/paths.go b/pkg/manager/paths/paths.go index 0d06af2c0..d3216b6bc 100644 --- a/pkg/manager/paths/paths.go +++ b/pkg/manager/paths/paths.go @@ -29,11 +29,3 @@ func GetStashHomeDirectory() string { func GetDefaultDatabaseFilePath() string { return filepath.Join(GetStashHomeDirectory(), "stash-go.sqlite") } - -func GetSSLKey() string { - return filepath.Join(GetStashHomeDirectory(), "stash.key") -} - -func GetSSLCert() string { - return filepath.Join(GetStashHomeDirectory(), "stash.crt") -} diff --git a/pkg/manager/task_generate_phash.go b/pkg/manager/task_generate_phash.go index f8ef6d6be..0c1578ee5 100644 --- a/pkg/manager/task_generate_phash.go +++ b/pkg/manager/task_generate_phash.go @@ -13,6 +13,7 @@ import ( type GeneratePhashTask struct { Scene models.Scene + Overwrite bool fileNamingAlgorithm models.HashAlgorithm txnManager models.TransactionManager } @@ -58,5 +59,5 @@ func (t *GeneratePhashTask) Start(wg *sizedwaitgroup.SizedWaitGroup) { } func (t *GeneratePhashTask) shouldGenerate() bool { - return !t.Scene.Phash.Valid + return t.Overwrite || !t.Scene.Phash.Valid } diff --git a/pkg/models/extension_resolution.go b/pkg/models/extension_resolution.go index 864fd4421..6890ddac3 100644 --- a/pkg/models/extension_resolution.go +++ b/pkg/models/extension_resolution.go @@ -1,65 +1,33 @@ package models -var resolutionMax = []int{ - 240, - 360, - 480, - 540, - 720, - 1080, - 1440, - 1920, - 2160, - 2880, - 3384, - 4320, - 0, +type ResolutionRange struct { + min, max int +} + +var resolutionRanges = map[ResolutionEnum]ResolutionRange{ + ResolutionEnum("VERY_LOW"): {144, 239}, + ResolutionEnum("LOW"): {240, 359}, + ResolutionEnum("R360P"): {360, 479}, + ResolutionEnum("STANDARD"): {480, 539}, + ResolutionEnum("WEB_HD"): {540, 719}, + ResolutionEnum("STANDARD_HD"): {720, 1079}, + ResolutionEnum("FULL_HD"): {1080, 1439}, + ResolutionEnum("QUAD_HD"): {1440, 1919}, + ResolutionEnum("VR_HD"): {1920, 2159}, + ResolutionEnum("FOUR_K"): {2160, 2879}, + ResolutionEnum("FIVE_K"): {2880, 3383}, + ResolutionEnum("SIX_K"): {3384, 4319}, + ResolutionEnum("EIGHT_K"): {4320, 8639}, } // GetMaxResolution returns the maximum width or height that media must be -// to qualify as this resolution. A return value of 0 means that there is no -// maximum. +// to qualify as this resolution. func (r *ResolutionEnum) GetMaxResolution() int { - if !r.IsValid() { - return 0 - } - - // sanity check - length of arrays must be the same - if len(resolutionMax) != len(AllResolutionEnum) { - panic("resolutionMax array length != AllResolutionEnum array length") - } - - for i, rr := range AllResolutionEnum { - if rr == *r { - return resolutionMax[i] - } - } - - return 0 + return resolutionRanges[*r].max } // GetMinResolution returns the minimum width or height that media must be // to qualify as this resolution. func (r *ResolutionEnum) GetMinResolution() int { - if !r.IsValid() { - return 0 - } - - // sanity check - length of arrays must be the same - if len(resolutionMax) != len(AllResolutionEnum) { - panic("resolutionMax array length != AllResolutionEnum array length") - } - - // use the previous resolution max as this resolution min - for i, rr := range AllResolutionEnum { - if rr == *r { - if i > 0 { - return resolutionMax[i-1] - } - - return 0 - } - } - - return 0 + return resolutionRanges[*r].min } diff --git a/pkg/models/mocks/SceneReaderWriter.go b/pkg/models/mocks/SceneReaderWriter.go index 796c23878..326999518 100644 --- a/pkg/models/mocks/SceneReaderWriter.go +++ b/pkg/models/mocks/SceneReaderWriter.go @@ -254,6 +254,27 @@ func (_m *SceneReaderWriter) DestroyCover(sceneID int) error { return r0 } +// Duration provides a mock function with given fields: +func (_m *SceneReaderWriter) Duration() (float64, error) { + ret := _m.Called() + + var r0 float64 + if rf, ok := ret.Get(0).(func() float64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(float64) + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Find provides a mock function with given fields: id func (_m *SceneReaderWriter) Find(id int) (*models.Scene, error) { ret := _m.Called(id) diff --git a/pkg/models/model_scraped_item.go b/pkg/models/model_scraped_item.go index 0c102bcbe..230fd0ba0 100644 --- a/pkg/models/model_scraped_item.go +++ b/pkg/models/model_scraped_item.go @@ -46,6 +46,7 @@ type ScrapedPerformer struct { DeathDate *string `graphql:"death_date" json:"death_date"` HairColor *string `graphql:"hair_color" json:"hair_color"` Weight *string `graphql:"weight" json:"weight"` + RemoteSiteID *string `graphql:"remote_site_id" json:"remote_site_id"` } // this type has no Image field diff --git a/pkg/models/scene.go b/pkg/models/scene.go index 8e77b2497..60345fce9 100644 --- a/pkg/models/scene.go +++ b/pkg/models/scene.go @@ -15,6 +15,7 @@ type SceneReader interface { CountByMovieID(movieID int) (int, error) Count() (int, error) Size() (float64, error) + Duration() (float64, error) // SizeCount() (string, error) CountByStudioID(studioID int) (int, error) CountByTagID(tagID int) (int, error) diff --git a/pkg/plugin/plugins.go b/pkg/plugin/plugins.go index eff6d88ba..844834339 100644 --- a/pkg/plugin/plugins.go +++ b/pkg/plugin/plugins.go @@ -133,7 +133,7 @@ func (c Cache) makeServerConnection(ctx context.Context) common.StashServerConne Dir: c.config.GetConfigPath(), } - if config.HasTLSConfig() { + if c.config.HasTLSConfig() { serverConnection.Scheme = "https" } diff --git a/pkg/scraper/scrapers.go b/pkg/scraper/scrapers.go index a6ad82bf9..6c8d6e09d 100644 --- a/pkg/scraper/scrapers.go +++ b/pkg/scraper/scrapers.go @@ -5,10 +5,12 @@ import ( "errors" "os" "path/filepath" + "regexp" "strconv" "strings" "github.com/stashapp/stash/pkg/logger" + stash_config "github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/utils" ) @@ -239,12 +241,11 @@ func (c Cache) postScrapePerformer(ret *models.ScrapedPerformer) error { if err := c.txnManager.WithReadTxn(context.TODO(), func(r models.ReaderRepository) error { tqb := r.Tag() - for _, t := range ret.Tags { - err := MatchScrapedSceneTag(tqb, t) - if err != nil { - return err - } + tags, err := postProcessTags(tqb, ret.Tags) + if err != nil { + return err } + ret.Tags = tags return nil }); err != nil { @@ -263,12 +264,11 @@ func (c Cache) postScrapeScenePerformer(ret *models.ScrapedScenePerformer) error if err := c.txnManager.WithReadTxn(context.TODO(), func(r models.ReaderRepository) error { tqb := r.Tag() - for _, t := range ret.Tags { - err := MatchScrapedSceneTag(tqb, t) - if err != nil { - return err - } + tags, err := postProcessTags(tqb, ret.Tags) + if err != nil { + return err } + ret.Tags = tags return nil }); err != nil { @@ -302,12 +302,11 @@ func (c Cache) postScrapeScene(ret *models.ScrapedScene) error { } } - for _, t := range ret.Tags { - err := MatchScrapedSceneTag(tqb, t) - if err != nil { - return err - } + tags, err := postProcessTags(tqb, ret.Tags) + if err != nil { + return err } + ret.Tags = tags if ret.Studio != nil { err := MatchScrapedSceneStudio(sqb, ret.Studio) @@ -342,12 +341,11 @@ func (c Cache) postScrapeGallery(ret *models.ScrapedGallery) error { } } - for _, t := range ret.Tags { - err := MatchScrapedSceneTag(tqb, t) - if err != nil { - return err - } + tags, err := postProcessTags(tqb, ret.Tags) + if err != nil { + return err } + ret.Tags = tags if ret.Studio != nil { err := MatchScrapedSceneStudio(sqb, ret.Studio) @@ -509,3 +507,42 @@ func (c Cache) ScrapeMovieURL(url string) (*models.ScrapedMovie, error) { return nil, nil } + +func postProcessTags(tqb models.TagReader, scrapedTags []*models.ScrapedSceneTag) ([]*models.ScrapedSceneTag, error) { + var ret []*models.ScrapedSceneTag + + excludePatterns := stash_config.GetInstance().GetScraperExcludeTagPatterns() + var excludeRegexps []*regexp.Regexp + + for _, excludePattern := range excludePatterns { + reg, err := regexp.Compile(strings.ToLower(excludePattern)) + if err != nil { + logger.Errorf("Invalid tag exclusion pattern :%v", err) + } else { + excludeRegexps = append(excludeRegexps, reg) + } + } + + var ignoredTags []string +ScrapeTag: + for _, t := range scrapedTags { + for _, reg := range excludeRegexps { + if reg.MatchString(strings.ToLower(t.Name)) { + ignoredTags = append(ignoredTags, t.Name) + continue ScrapeTag + } + } + + err := MatchScrapedSceneTag(tqb, t) + if err != nil { + return nil, err + } + ret = append(ret, t) + } + + if len(ignoredTags) > 0 { + logger.Infof("Scraping ignored tags: %s", strings.Join(ignoredTags, ", ")) + } + + return ret, nil +} diff --git a/pkg/sqlite/filter.go b/pkg/sqlite/filter.go index dce1b11d3..1517bf99a 100644 --- a/pkg/sqlite/filter.go +++ b/pkg/sqlite/filter.go @@ -310,7 +310,7 @@ func (f *filterBuilder) andClauses(input []sqlClause) (string, []interface{}) { } if len(clauses) > 0 { - c := strings.Join(clauses, " AND ") + c := "(" + strings.Join(clauses, ") AND (") + ")" if len(clauses) > 1 { c = "(" + c + ")" } @@ -368,13 +368,8 @@ func stringCriterionHandler(c *models.StringCriterionInput, column string) crite func intCriterionHandler(c *models.IntCriterionInput, column string) criterionHandlerFunc { return func(f *filterBuilder) { if c != nil { - clause, count := getIntCriterionWhereClause(column, *c) - - if count == 1 { - f.addWhere(clause, c.Value) - } else { - f.addWhere(clause) - } + clause, args := getIntCriterionWhereClause(column, *c) + f.addWhere(clause, args...) } } } @@ -495,13 +490,9 @@ type countCriterionHandlerBuilder struct { func (m *countCriterionHandlerBuilder) handler(criterion *models.IntCriterionInput) criterionHandlerFunc { return func(f *filterBuilder) { if criterion != nil { - clause, count := getCountCriterionClause(m.primaryTable, m.joinTable, m.primaryFK, *criterion) + clause, args := getCountCriterionClause(m.primaryTable, m.joinTable, m.primaryFK, *criterion) - if count == 1 { - f.addWhere(clause, criterion.Value) - } else { - f.addWhere(clause) - } + f.addWhere(clause, args...) } } } @@ -548,18 +539,27 @@ func addHierarchicalWithClause(f *filterBuilder, value []string, derivedTable, t depthCondition = fmt.Sprintf("WHERE depth < %d", depth) } - withClause := utils.StrFormat(`RECURSIVE {derivedTable} AS ( -SELECT id as id, id as child_id, 0 as depth FROM {table} -WHERE id in {inBinding} -UNION SELECT p.id, c.id, depth + 1 FROM {table} as c -INNER JOIN {derivedTable} as p ON c.{parentFK} = p.child_id {depthCondition}) -`, utils.StrFormatMap{ + withClauseMap := utils.StrFormatMap{ "derivedTable": derivedTable, "table": table, "inBinding": getInBinding(inCount), "parentFK": parentFK, "depthCondition": depthCondition, - }) + "unionClause": "", + } + + if depth != 0 { + withClauseMap["unionClause"] = utils.StrFormat(` +UNION SELECT p.id, c.id, depth + 1 FROM {table} as c +INNER JOIN {derivedTable} as p ON c.{parentFK} = p.child_id {depthCondition} +`, withClauseMap) + } + + withClause := utils.StrFormat(`RECURSIVE {derivedTable} AS ( +SELECT id as id, id as child_id, 0 as depth FROM {table} +WHERE id in {inBinding} +{unionClause}) +`, withClauseMap) f.addWith(withClause, args...) } diff --git a/pkg/sqlite/filter_internal_test.go b/pkg/sqlite/filter_internal_test.go index e7a39521d..9a5042ba1 100644 --- a/pkg/sqlite/filter_internal_test.go +++ b/pkg/sqlite/filter_internal_test.go @@ -252,14 +252,14 @@ func TestGenerateWhereClauses(t *testing.T) { // ensure single where clause is generated correctly f.addWhere(clause1) r, rArgs := f.generateWhereClauses() - assert.Equal(clause1, r) + assert.Equal(fmt.Sprintf("(%s)", clause1), r) assert.Len(rArgs, 0) // ensure multiple where clauses are surrounded with parenthesis and // ANDed together f.addWhere(clause2, arg1, arg2) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("(%s AND %s)", clause1, clause2), r) + assert.Equal(fmt.Sprintf("((%s) AND (%s))", clause1, clause2), r) assert.Len(rArgs, 2) // ensure empty subfilter is not added to generated where clause @@ -267,13 +267,13 @@ func TestGenerateWhereClauses(t *testing.T) { f.and(sf) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("(%s AND %s)", clause1, clause2), r) + assert.Equal(fmt.Sprintf("((%s) AND (%s))", clause1, clause2), r) assert.Len(rArgs, 2) // ensure sub-filter is generated correctly sf.addWhere(clause3, arg3) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("(%s AND %s) AND (%s)", clause1, clause2, clause3), r) + assert.Equal(fmt.Sprintf("((%s) AND (%s)) AND ((%s))", clause1, clause2, clause3), r) assert.Len(rArgs, 3) // ensure OR sub-filter is generated correctly @@ -283,7 +283,7 @@ func TestGenerateWhereClauses(t *testing.T) { f.or(sf) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("(%s AND %s) OR (%s)", clause1, clause2, clause3), r) + assert.Equal(fmt.Sprintf("((%s) AND (%s)) OR ((%s))", clause1, clause2, clause3), r) assert.Len(rArgs, 3) // ensure NOT sub-filter is generated correctly @@ -293,7 +293,7 @@ func TestGenerateWhereClauses(t *testing.T) { f.not(sf) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("(%s AND %s) AND NOT (%s)", clause1, clause2, clause3), r) + assert.Equal(fmt.Sprintf("((%s) AND (%s)) AND NOT ((%s))", clause1, clause2, clause3), r) assert.Len(rArgs, 3) // ensure empty filter with ANDed sub-filter does not include AND @@ -301,7 +301,7 @@ func TestGenerateWhereClauses(t *testing.T) { f.and(sf) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("(%s)", clause3), r) + assert.Equal(fmt.Sprintf("((%s))", clause3), r) assert.Len(rArgs, 1) // ensure empty filter with ORed sub-filter does not include OR @@ -309,7 +309,7 @@ func TestGenerateWhereClauses(t *testing.T) { f.or(sf) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("(%s)", clause3), r) + assert.Equal(fmt.Sprintf("((%s))", clause3), r) assert.Len(rArgs, 1) // ensure empty filter with NOTed sub-filter does not include AND @@ -317,7 +317,7 @@ func TestGenerateWhereClauses(t *testing.T) { f.not(sf) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("NOT (%s)", clause3), r) + assert.Equal(fmt.Sprintf("NOT ((%s))", clause3), r) assert.Len(rArgs, 1) // (clause1) AND ((clause2) OR (clause3)) @@ -328,7 +328,7 @@ func TestGenerateWhereClauses(t *testing.T) { f.and(sf2) sf2.or(sf) r, rArgs = f.generateWhereClauses() - assert.Equal(fmt.Sprintf("%s AND (%s OR (%s))", clause1, clause2, clause3), r) + assert.Equal(fmt.Sprintf("(%s) AND ((%s) OR ((%s)))", clause1, clause2, clause3), r) assert.Len(rArgs, 3) } @@ -348,14 +348,14 @@ func TestGenerateHavingClauses(t *testing.T) { // ensure single Having clause is generated correctly f.addHaving(clause1) r, rArgs := f.generateHavingClauses() - assert.Equal(clause1, r) + assert.Equal(fmt.Sprintf("(%s)", clause1), r) assert.Len(rArgs, 0) // ensure multiple Having clauses are surrounded with parenthesis and // ANDed together f.addHaving(clause2, arg1, arg2) r, rArgs = f.generateHavingClauses() - assert.Equal("("+clause1+" AND "+clause2+")", r) + assert.Equal("(("+clause1+") AND ("+clause2+"))", r) assert.Len(rArgs, 2) // ensure empty subfilter is not added to generated Having clause @@ -363,13 +363,13 @@ func TestGenerateHavingClauses(t *testing.T) { f.and(sf) r, rArgs = f.generateHavingClauses() - assert.Equal("("+clause1+" AND "+clause2+")", r) + assert.Equal("(("+clause1+") AND ("+clause2+"))", r) assert.Len(rArgs, 2) // ensure sub-filter is generated correctly sf.addHaving(clause3, arg3) r, rArgs = f.generateHavingClauses() - assert.Equal("("+clause1+" AND "+clause2+") AND ("+clause3+")", r) + assert.Equal("(("+clause1+") AND ("+clause2+")) AND (("+clause3+"))", r) assert.Len(rArgs, 3) // ensure OR sub-filter is generated correctly @@ -379,7 +379,7 @@ func TestGenerateHavingClauses(t *testing.T) { f.or(sf) r, rArgs = f.generateHavingClauses() - assert.Equal("("+clause1+" AND "+clause2+") OR ("+clause3+")", r) + assert.Equal("(("+clause1+") AND ("+clause2+")) OR (("+clause3+"))", r) assert.Len(rArgs, 3) // ensure NOT sub-filter is generated correctly @@ -389,7 +389,7 @@ func TestGenerateHavingClauses(t *testing.T) { f.not(sf) r, rArgs = f.generateHavingClauses() - assert.Equal("("+clause1+" AND "+clause2+") AND NOT ("+clause3+")", r) + assert.Equal("(("+clause1+") AND ("+clause2+")) AND NOT (("+clause3+"))", r) assert.Len(rArgs, 3) } diff --git a/pkg/sqlite/gallery.go b/pkg/sqlite/gallery.go index de46f1d96..66bf2032a 100644 --- a/pkg/sqlite/gallery.go +++ b/pkg/sqlite/gallery.go @@ -3,7 +3,6 @@ package sqlite import ( "database/sql" "fmt" - "strconv" "github.com/stashapp/stash/pkg/models" ) @@ -426,23 +425,25 @@ func galleryPerformerTagsCriterionHandler(qb *galleryQueryBuilder, performerTags } } -func galleryAverageResolutionCriterionHandler(qb *galleryQueryBuilder, resolution *models.ResolutionEnum) criterionHandlerFunc { +func galleryAverageResolutionCriterionHandler(qb *galleryQueryBuilder, resolution *models.ResolutionCriterionInput) criterionHandlerFunc { return func(f *filterBuilder) { - if resolution != nil && resolution.IsValid() { + if resolution != nil && resolution.Value.IsValid() { qb.imagesRepository().join(f, "images_join", "galleries.id") f.addJoin("images", "", "images_join.image_id = images.id") - min := resolution.GetMinResolution() - max := resolution.GetMaxResolution() + min := resolution.Value.GetMinResolution() + max := resolution.Value.GetMaxResolution() const widthHeight = "avg(MIN(images.width, images.height))" - if min > 0 { - f.addHaving(widthHeight + " >= " + strconv.Itoa(min)) - } - - if max > 0 { - f.addHaving(widthHeight + " < " + strconv.Itoa(max)) + if resolution.Modifier == models.CriterionModifierEquals { + f.addHaving(fmt.Sprintf("%s BETWEEN %d AND %d", widthHeight, min, max)) + } else if resolution.Modifier == models.CriterionModifierNotEquals { + f.addHaving(fmt.Sprintf("%s NOT BETWEEN %d AND %d", widthHeight, min, max)) + } else if resolution.Modifier == models.CriterionModifierLessThan { + f.addHaving(fmt.Sprintf("%s < %d", widthHeight, min)) + } else if resolution.Modifier == models.CriterionModifierGreaterThan { + f.addHaving(fmt.Sprintf("%s > %d", widthHeight, max)) } } } diff --git a/pkg/sqlite/gallery_test.go b/pkg/sqlite/gallery_test.go index 9e409029d..5ba8db446 100644 --- a/pkg/sqlite/gallery_test.go +++ b/pkg/sqlite/gallery_test.go @@ -914,7 +914,10 @@ func TestGalleryQueryAverageResolution(t *testing.T) { qb := r.Gallery() resolution := models.ResolutionEnumLow galleryFilter := models.GalleryFilterType{ - AverageResolution: &resolution, + AverageResolution: &models.ResolutionCriterionInput{ + Value: resolution, + Modifier: models.CriterionModifierEquals, + }, } // not verifying average - just ensure we get at least one diff --git a/pkg/sqlite/image_test.go b/pkg/sqlite/image_test.go index cd225fc82..50006685b 100644 --- a/pkg/sqlite/image_test.go +++ b/pkg/sqlite/image_test.go @@ -389,7 +389,10 @@ func verifyImagesResolution(t *testing.T, resolution models.ResolutionEnum) { withTxn(func(r models.Repository) error { sqb := r.Image() imageFilter := models.ImageFilterType{ - Resolution: &resolution, + Resolution: &models.ResolutionCriterionInput{ + Value: resolution, + Modifier: models.CriterionModifierEquals, + }, } images, _, err := sqb.Query(&imageFilter, nil) diff --git a/pkg/sqlite/performer.go b/pkg/sqlite/performer.go index fbe33eb62..526a6e360 100644 --- a/pkg/sqlite/performer.go +++ b/pkg/sqlite/performer.go @@ -3,7 +3,6 @@ package sqlite import ( "database/sql" "fmt" - "strconv" "strings" "github.com/stashapp/stash/pkg/models" @@ -346,6 +345,9 @@ func performerIsMissingCriterionHandler(qb *performerQueryBuilder, isMissing *st case "image": f.addJoin(performersImageTable, "image_join", "image_join.performer_id = performers.id") f.addWhere("image_join.performer_id IS NULL") + case "stash_id": + qb.stashIDRepository().join(f, "performer_stash_ids", "performers.id") + f.addWhere("performer_stash_ids.performer_id IS NULL") default: f.addWhere("(performers." + *isMissing + " IS NULL OR TRIM(performers." + *isMissing + ") = '')") } @@ -356,25 +358,8 @@ func performerIsMissingCriterionHandler(qb *performerQueryBuilder, isMissing *st func yearFilterCriterionHandler(year *models.IntCriterionInput, col string) criterionHandlerFunc { return func(f *filterBuilder) { if year != nil && year.Modifier.IsValid() { - yearStr := strconv.Itoa(year.Value) - startOfYear := yearStr + "-01-01" - endOfYear := yearStr + "-12-31" - - switch year.Modifier { - case models.CriterionModifierEquals: - // between yyyy-01-01 and yyyy-12-31 - f.addWhere(col+" >= ?", startOfYear) - f.addWhere(col+" <= ?", endOfYear) - case models.CriterionModifierNotEquals: - // outside of yyyy-01-01 to yyyy-12-31 - f.addWhere(col+" < ? OR "+col+" > ?", startOfYear, endOfYear) - case models.CriterionModifierGreaterThan: - // > yyyy-12-31 - f.addWhere(col+" > ?", endOfYear) - case models.CriterionModifierLessThan: - // < yyyy-01-01 - f.addWhere(col+" < ?", startOfYear) - } + clause, args := getIntCriterionWhereClause("cast(strftime('%Y', "+col+") as int)", *year) + f.addWhere(clause, args...) } } } @@ -382,22 +367,11 @@ func yearFilterCriterionHandler(year *models.IntCriterionInput, col string) crit func performerAgeFilterCriterionHandler(age *models.IntCriterionInput) criterionHandlerFunc { return func(f *filterBuilder) { if age != nil && age.Modifier.IsValid() { - var op string - - switch age.Modifier { - case models.CriterionModifierEquals: - op = "==" - case models.CriterionModifierNotEquals: - op = "!=" - case models.CriterionModifierGreaterThan: - op = ">" - case models.CriterionModifierLessThan: - op = "<" - } - - if op != "" { - f.addWhere("cast(IFNULL(strftime('%Y.%m%d', performers.death_date), strftime('%Y.%m%d', 'now')) - strftime('%Y.%m%d', performers.birthdate) as int) "+op+" ?", age.Value) - } + clause, args := getIntCriterionWhereClause( + "cast(IFNULL(strftime('%Y.%m%d', performers.death_date), strftime('%Y.%m%d', 'now')) - strftime('%Y.%m%d', performers.birthdate) as int)", + *age, + ) + f.addWhere(clause, args...) } } } @@ -529,6 +503,12 @@ func (qb *performerQueryBuilder) getPerformerSort(findFilter *models.FindFilterT if sort == "scenes_count" { return getCountSort(performerTable, performersScenesTable, performerIDColumn, direction) } + if sort == "images_count" { + return getCountSort(performerTable, performersImagesTable, performerIDColumn, direction) + } + if sort == "galleries_count" { + return getCountSort(performerTable, performersGalleriesTable, performerIDColumn, direction) + } return getSort(sort, direction, "performers") } diff --git a/pkg/sqlite/query.go b/pkg/sqlite/query.go index 60b594f14..2d31ee583 100644 --- a/pkg/sqlite/query.go +++ b/pkg/sqlite/query.go @@ -135,11 +135,9 @@ func (qb *queryBuilder) addFilter(f *filterBuilder) { func (qb *queryBuilder) handleIntCriterionInput(c *models.IntCriterionInput, column string) { if c != nil { - clause, count := getIntCriterionWhereClause(column, *c) + clause, args := getIntCriterionWhereClause(column, *c) qb.addWhere(clause) - if count == 1 { - qb.addArg(c.Value) - } + qb.addArg(args...) } } @@ -192,12 +190,9 @@ func (qb *queryBuilder) handleStringCriterionInput(c *models.StringCriterionInpu func (qb *queryBuilder) handleCountCriterion(countFilter *models.IntCriterionInput, primaryTable, joinTable, primaryFK string) { if countFilter != nil { - clause, count := getCountCriterionClause(primaryTable, joinTable, primaryFK, *countFilter) - - if count == 1 { - qb.addArg(countFilter.Value) - } + clause, args := getCountCriterionClause(primaryTable, joinTable, primaryFK, *countFilter) qb.addWhere(clause) + qb.addArg(args...) } } diff --git a/pkg/sqlite/scene.go b/pkg/sqlite/scene.go index 4aec58ab9..92cdd5c2c 100644 --- a/pkg/sqlite/scene.go +++ b/pkg/sqlite/scene.go @@ -68,13 +68,15 @@ SELECT GROUP_CONCAT(id) as ids FROM scenes WHERE phash IS NOT NULL GROUP BY phash -HAVING COUNT(*) > 1; +HAVING COUNT(phash) > 1 +ORDER BY SUM(size) DESC; ` var findAllPhashesQuery = ` SELECT id, phash FROM scenes WHERE phash IS NOT NULL +ORDER BY size DESC ` type sceneQueryBuilder struct { @@ -272,6 +274,10 @@ func (qb *sceneQueryBuilder) Size() (float64, error) { return qb.runSumQuery("SELECT SUM(cast(size as double)) as sum FROM scenes", nil) } +func (qb *sceneQueryBuilder) Duration() (float64, error) { + return qb.runSumQuery("SELECT SUM(cast(duration as double)) as sum FROM scenes", nil) +} + func (qb *sceneQueryBuilder) CountByStudioID(studioID int) (int, error) { args := []interface{}{studioID} return qb.runCountQuery(qb.buildCountQuery(scenesForStudioQuery), args) @@ -461,54 +467,28 @@ func phashCriterionHandler(phashFilter *models.StringCriterionInput) criterionHa func durationCriterionHandler(durationFilter *models.IntCriterionInput, column string) criterionHandlerFunc { return func(f *filterBuilder) { if durationFilter != nil { - clause, thisArgs := getDurationWhereClause(*durationFilter, column) - f.addWhere(clause, thisArgs...) + clause, args := getIntCriterionWhereClause("cast("+column+" as int)", *durationFilter) + f.addWhere(clause, args...) } } } -func getDurationWhereClause(durationFilter models.IntCriterionInput, column string) (string, []interface{}) { - // special case for duration. We accept duration as seconds as int but the - // field is floating point. Change the equals filter to return a range - // between x and x + 1 - // likewise, not equals needs to be duration < x OR duration >= x - var clause string - args := []interface{}{} - - value := durationFilter.Value - if durationFilter.Modifier == models.CriterionModifierEquals { - clause = fmt.Sprintf("%[1]s >= ? AND %[1]s < ?", column) - args = append(args, value) - args = append(args, value+1) - } else if durationFilter.Modifier == models.CriterionModifierNotEquals { - clause = fmt.Sprintf("(%[1]s < ? OR %[1]s >= ?)", column) - args = append(args, value) - args = append(args, value+1) - } else { - var count int - clause, count = getIntCriterionWhereClause(column, durationFilter) - if count == 1 { - args = append(args, value) - } - } - - return clause, args -} - -func resolutionCriterionHandler(resolution *models.ResolutionEnum, heightColumn string, widthColumn string) criterionHandlerFunc { +func resolutionCriterionHandler(resolution *models.ResolutionCriterionInput, heightColumn string, widthColumn string) criterionHandlerFunc { return func(f *filterBuilder) { - if resolution != nil && resolution.IsValid() { - min := resolution.GetMinResolution() - max := resolution.GetMaxResolution() + if resolution != nil && resolution.Value.IsValid() { + min := resolution.Value.GetMinResolution() + max := resolution.Value.GetMaxResolution() widthHeight := fmt.Sprintf("MIN(%s, %s)", widthColumn, heightColumn) - if min > 0 { - f.addWhere(widthHeight + " >= " + strconv.Itoa(min)) - } - - if max > 0 { - f.addWhere(widthHeight + " < " + strconv.Itoa(max)) + if resolution.Modifier == models.CriterionModifierEquals { + f.addWhere(fmt.Sprintf("%s BETWEEN %d AND %d", widthHeight, min, max)) + } else if resolution.Modifier == models.CriterionModifierNotEquals { + f.addWhere(fmt.Sprintf("%s NOT BETWEEN %d AND %d", widthHeight, min, max)) + } else if resolution.Modifier == models.CriterionModifierLessThan { + f.addWhere(fmt.Sprintf("%s < %d", widthHeight, min)) + } else if resolution.Modifier == models.CriterionModifierGreaterThan { + f.addWhere(fmt.Sprintf("%s > %d", widthHeight, max)) } } } diff --git a/pkg/sqlite/scene_test.go b/pkg/sqlite/scene_test.go index fa43e53f9..ec95447da 100644 --- a/pkg/sqlite/scene_test.go +++ b/pkg/sqlite/scene_test.go @@ -648,7 +648,10 @@ func verifyScenesResolution(t *testing.T, resolution models.ResolutionEnum) { withTxn(func(r models.Repository) error { sqb := r.Scene() sceneFilter := models.SceneFilterType{ - Resolution: &resolution, + Resolution: &models.ResolutionCriterionInput{ + Value: resolution, + Modifier: models.CriterionModifierEquals, + }, } scenes := queryScene(t, sqb, &sceneFilter, nil) @@ -679,6 +682,76 @@ func verifySceneResolution(t *testing.T, height sql.NullInt64, resolution models } } +func TestAllResolutionsHaveResolutionRange(t *testing.T) { + for _, resolution := range models.AllResolutionEnum { + assert.NotZero(t, resolution.GetMinResolution(), "Define resolution range for %s in extension_resolution.go", resolution) + assert.NotZero(t, resolution.GetMaxResolution(), "Define resolution range for %s in extension_resolution.go", resolution) + } +} + +func TestSceneQueryResolutionModifiers(t *testing.T) { + if err := withRollbackTxn(func(r models.Repository) error { + qb := r.Scene() + sceneNoResolution, _ := createScene(qb, 0, 0) + firstScene540P, _ := createScene(qb, 960, 540) + secondScene540P, _ := createScene(qb, 1280, 719) + firstScene720P, _ := createScene(qb, 1280, 720) + secondScene720P, _ := createScene(qb, 1280, 721) + thirdScene720P, _ := createScene(qb, 1920, 1079) + scene1080P, _ := createScene(qb, 1920, 1080) + + scenesEqualTo720P := queryScenes(t, qb, models.ResolutionEnumStandardHd, models.CriterionModifierEquals) + scenesNotEqualTo720P := queryScenes(t, qb, models.ResolutionEnumStandardHd, models.CriterionModifierNotEquals) + scenesGreaterThan720P := queryScenes(t, qb, models.ResolutionEnumStandardHd, models.CriterionModifierGreaterThan) + scenesLessThan720P := queryScenes(t, qb, models.ResolutionEnumStandardHd, models.CriterionModifierLessThan) + + assert.Subset(t, scenesEqualTo720P, []*models.Scene{firstScene720P, secondScene720P, thirdScene720P}) + assert.NotSubset(t, scenesEqualTo720P, []*models.Scene{sceneNoResolution, firstScene540P, secondScene540P, scene1080P}) + + assert.Subset(t, scenesNotEqualTo720P, []*models.Scene{sceneNoResolution, firstScene540P, secondScene540P, scene1080P}) + assert.NotSubset(t, scenesNotEqualTo720P, []*models.Scene{firstScene720P, secondScene720P, thirdScene720P}) + + assert.Subset(t, scenesGreaterThan720P, []*models.Scene{scene1080P}) + assert.NotSubset(t, scenesGreaterThan720P, []*models.Scene{sceneNoResolution, firstScene540P, secondScene540P, firstScene720P, secondScene720P, thirdScene720P}) + + assert.Subset(t, scenesLessThan720P, []*models.Scene{sceneNoResolution, firstScene540P, secondScene540P}) + assert.NotSubset(t, scenesLessThan720P, []*models.Scene{scene1080P, firstScene720P, secondScene720P, thirdScene720P}) + + return nil + }); err != nil { + t.Error(err.Error()) + } +} + +func queryScenes(t *testing.T, queryBuilder models.SceneReaderWriter, resolution models.ResolutionEnum, modifier models.CriterionModifier) []*models.Scene { + sceneFilter := models.SceneFilterType{ + Resolution: &models.ResolutionCriterionInput{ + Value: resolution, + Modifier: modifier, + }, + } + + return queryScene(t, queryBuilder, &sceneFilter, nil) +} + +func createScene(queryBuilder models.SceneReaderWriter, width int64, height int64) (*models.Scene, error) { + name := fmt.Sprintf("TestSceneQueryResolutionModifiers %d %d", width, height) + scene := models.Scene{ + Path: name, + Width: sql.NullInt64{ + Int64: width, + Valid: true, + }, + Height: sql.NullInt64{ + Int64: height, + Valid: true, + }, + Checksum: sql.NullString{String: utils.MD5FromString(name), Valid: true}, + } + + return queryBuilder.Create(scene) +} + func TestSceneQueryHasMarkers(t *testing.T) { withTxn(func(r models.Repository) error { sqb := r.Scene() diff --git a/pkg/sqlite/setup_test.go b/pkg/sqlite/setup_test.go index 1cd30fd5f..d25e3c4e4 100644 --- a/pkg/sqlite/setup_test.go +++ b/pkg/sqlite/setup_test.go @@ -605,6 +605,7 @@ func createScenes(sqb models.SceneReaderWriter, n int) error { OCounter: getOCounter(i), Duration: getSceneDuration(i), Height: getHeight(i), + Width: getWidth(i), Date: getSceneDate(i), } diff --git a/pkg/sqlite/sql.go b/pkg/sqlite/sql.go index b683e1a07..b3bcdd514 100644 --- a/pkg/sqlite/sql.go +++ b/pkg/sqlite/sql.go @@ -160,7 +160,7 @@ func getCriterionModifierBinding(criterionModifier models.CriterionModifier, val } if modifier := criterionModifier.String(); criterionModifier.IsValid() { switch modifier { - case "EQUALS", "NOT_EQUALS", "GREATER_THAN", "LESS_THAN", "IS_NULL", "NOT_NULL": + case "EQUALS", "NOT_EQUALS", "GREATER_THAN", "LESS_THAN", "IS_NULL", "NOT_NULL", "BETWEEN", "NOT_BETWEEN": return getSimpleCriterionClause(criterionModifier, "?") case "INCLUDES": return "IN " + getInBinding(length), length // TODO? @@ -189,6 +189,10 @@ func getSimpleCriterionClause(criterionModifier models.CriterionModifier, rhs st return "IS NULL", 0 case "NOT_NULL": return "IS NOT NULL", 0 + case "BETWEEN": + return "BETWEEN (" + rhs + ") AND (" + rhs + ")", 2 + case "NOT_BETWEEN": + return "NOT BETWEEN (" + rhs + ") AND (" + rhs + ")", 2 default: logger.Errorf("todo") return "= ?", 1 // TODO @@ -198,9 +202,30 @@ func getSimpleCriterionClause(criterionModifier models.CriterionModifier, rhs st return "= ?", 1 // TODO } -func getIntCriterionWhereClause(column string, input models.IntCriterionInput) (string, int) { - binding, count := getCriterionModifierBinding(input.Modifier, input.Value) - return column + " " + binding, count +func getIntCriterionWhereClause(column string, input models.IntCriterionInput) (string, []interface{}) { + binding, _ := getSimpleCriterionClause(input.Modifier, "?") + var args []interface{} + + switch input.Modifier { + case "EQUALS", "NOT_EQUALS": + args = []interface{}{input.Value} + break + case "LESS_THAN": + args = []interface{}{input.Value} + break + case "GREATER_THAN": + args = []interface{}{input.Value} + break + case "BETWEEN", "NOT_BETWEEN": + upper := 0 + if input.Value2 != nil { + upper = *input.Value2 + } + args = []interface{}{input.Value, upper} + break + } + + return column + " " + binding, args } // returns where clause and having clause @@ -226,7 +251,7 @@ func getMultiCriterionClause(primaryTable, foreignTable, joinTable, primaryFK, f return whereClause, havingClause } -func getCountCriterionClause(primaryTable, joinTable, primaryFK string, criterion models.IntCriterionInput) (string, int) { +func getCountCriterionClause(primaryTable, joinTable, primaryFK string, criterion models.IntCriterionInput) (string, []interface{}) { lhs := fmt.Sprintf("(SELECT COUNT(*) FROM %s s WHERE s.%s = %s.id)", joinTable, primaryFK, primaryTable) return getIntCriterionWhereClause(lhs, criterion) } diff --git a/pkg/sqlite/tag.go b/pkg/sqlite/tag.go index 444577a0a..ca97e5460 100644 --- a/pkg/sqlite/tag.go +++ b/pkg/sqlite/tag.go @@ -271,14 +271,6 @@ func (qb *tagQueryBuilder) makeFilter(tagFilter *models.TagFilterType) *filterBu query.not(qb.makeFilter(tagFilter.Not)) } - // if markerCount := tagFilter.MarkerCount; markerCount != nil { - // clause, count := getIntCriterionWhereClause("count(distinct scene_markers.id)", *markerCount) - // query.addHaving(clause) - // if count == 1 { - // query.addArg(markerCount.Value) - // } - // } - query.handleCriterion(stringCriterionHandler(tagFilter.Name, tagTable+".name")) query.handleCriterion(tagAliasCriterionHandler(qb, tagFilter.Aliases)) @@ -287,6 +279,7 @@ func (qb *tagQueryBuilder) makeFilter(tagFilter *models.TagFilterType) *filterBu query.handleCriterion(tagImageCountCriterionHandler(qb, tagFilter.ImageCount)) query.handleCriterion(tagGalleryCountCriterionHandler(qb, tagFilter.GalleryCount)) query.handleCriterion(tagPerformerCountCriterionHandler(qb, tagFilter.PerformerCount)) + query.handleCriterion(tagMarkerCountCriterionHandler(qb, tagFilter.MarkerCount)) return query } @@ -303,19 +296,6 @@ func (qb *tagQueryBuilder) Query(tagFilter *models.TagFilterType, findFilter *mo query.body = selectDistinctIDs(tagTable) - /* - query.body += ` - left join tags_image on tags_image.tag_id = tags.id - left join scenes_tags on scenes_tags.tag_id = tags.id - left join scene_markers_tags on scene_markers_tags.tag_id = tags.id - left join scene_markers on scene_markers.primary_tag_id = tags.id OR scene_markers.id = scene_markers_tags.scene_marker_id - left join scenes on scenes_tags.scene_id = scenes.id` - */ - - // the presence of joining on scene_markers.primary_tag_id and scene_markers_tags.tag_id - // appears to confuse sqlite and causes serious performance issues. - // Disabling querying/sorting on marker count for now. - if q := findFilter.Q; q != nil && *q != "" { query.join(tagAliasesTable, "", "tag_aliases.tag_id = tags.id") searchColumns := []string{"tags.name", "tag_aliases.alias"} @@ -379,12 +359,7 @@ func tagSceneCountCriterionHandler(qb *tagQueryBuilder, sceneCount *models.IntCr return func(f *filterBuilder) { if sceneCount != nil { f.addJoin("scenes_tags", "", "scenes_tags.tag_id = tags.id") - clause, count := getIntCriterionWhereClause("count(distinct scenes_tags.scene_id)", *sceneCount) - - args := []interface{}{} - if count == 1 { - args = append(args, sceneCount.Value) - } + clause, args := getIntCriterionWhereClause("count(distinct scenes_tags.scene_id)", *sceneCount) f.addHaving(clause, args...) } @@ -395,12 +370,7 @@ func tagImageCountCriterionHandler(qb *tagQueryBuilder, imageCount *models.IntCr return func(f *filterBuilder) { if imageCount != nil { f.addJoin("images_tags", "", "images_tags.tag_id = tags.id") - clause, count := getIntCriterionWhereClause("count(distinct images_tags.image_id)", *imageCount) - - args := []interface{}{} - if count == 1 { - args = append(args, imageCount.Value) - } + clause, args := getIntCriterionWhereClause("count(distinct images_tags.image_id)", *imageCount) f.addHaving(clause, args...) } @@ -411,12 +381,7 @@ func tagGalleryCountCriterionHandler(qb *tagQueryBuilder, galleryCount *models.I return func(f *filterBuilder) { if galleryCount != nil { f.addJoin("galleries_tags", "", "galleries_tags.tag_id = tags.id") - clause, count := getIntCriterionWhereClause("count(distinct galleries_tags.gallery_id)", *galleryCount) - - args := []interface{}{} - if count == 1 { - args = append(args, galleryCount.Value) - } + clause, args := getIntCriterionWhereClause("count(distinct galleries_tags.gallery_id)", *galleryCount) f.addHaving(clause, args...) } @@ -427,12 +392,19 @@ func tagPerformerCountCriterionHandler(qb *tagQueryBuilder, performerCount *mode return func(f *filterBuilder) { if performerCount != nil { f.addJoin("performers_tags", "", "performers_tags.tag_id = tags.id") - clause, count := getIntCriterionWhereClause("count(distinct performers_tags.performer_id)", *performerCount) + clause, args := getIntCriterionWhereClause("count(distinct performers_tags.performer_id)", *performerCount) - args := []interface{}{} - if count == 1 { - args = append(args, performerCount.Value) - } + f.addHaving(clause, args...) + } + } +} + +func tagMarkerCountCriterionHandler(qb *tagQueryBuilder, markerCount *models.IntCriterionInput) criterionHandlerFunc { + return func(f *filterBuilder) { + if markerCount != nil { + f.addJoin("scene_markers_tags", "", "scene_markers_tags.tag_id = tags.id") + f.addJoin("scene_markers", "", "scene_markers_tags.scene_marker_id = scene_markers.id OR scene_markers.primary_tag_id = tags.id") + clause, args := getIntCriterionWhereClause("count(distinct scene_markers.id)", *markerCount) f.addHaving(clause, args...) } @@ -459,6 +431,9 @@ func (qb *tagQueryBuilder) getTagSort(query *queryBuilder, findFilter *models.Fi case "scenes_count": query.join("scenes_tags", "", "scenes_tags.tag_id = tags.id") return " ORDER BY COUNT(distinct scenes_tags.scene_id) " + direction + case "scene_markers_count": + query.join("scene_markers_tags", "", "scene_markers_tags.tag_id = tags.id") + return " ORDER BY COUNT(distinct scene_markers_tags.scene_marker_id) " + direction case "images_count": query.join("images_tags", "", "images_tags.tag_id = tags.id") return " ORDER BY COUNT(distinct images_tags.image_id) " + direction diff --git a/pkg/sqlite/tag_test.go b/pkg/sqlite/tag_test.go index c346d5032..add3753a7 100644 --- a/pkg/sqlite/tag_test.go +++ b/pkg/sqlite/tag_test.go @@ -320,26 +320,24 @@ func verifyTagSceneCount(t *testing.T, sceneCountCriterion models.IntCriterionIn }) } -// disabled due to performance issues +func TestTagQueryMarkerCount(t *testing.T) { + countCriterion := models.IntCriterionInput{ + Value: 1, + Modifier: models.CriterionModifierEquals, + } -// func TestTagQueryMarkerCount(t *testing.T) { -// countCriterion := models.IntCriterionInput{ -// Value: 1, -// Modifier: models.CriterionModifierEquals, -// } + verifyTagMarkerCount(t, countCriterion) -// verifyTagMarkerCount(t, countCriterion) + countCriterion.Modifier = models.CriterionModifierNotEquals + verifyTagMarkerCount(t, countCriterion) -// countCriterion.Modifier = models.CriterionModifierNotEquals -// verifyTagMarkerCount(t, countCriterion) + countCriterion.Modifier = models.CriterionModifierLessThan + verifyTagMarkerCount(t, countCriterion) -// countCriterion.Modifier = models.CriterionModifierLessThan -// verifyTagMarkerCount(t, countCriterion) - -// countCriterion.Value = 0 -// countCriterion.Modifier = models.CriterionModifierGreaterThan -// verifyTagMarkerCount(t, countCriterion) -// } + countCriterion.Value = 0 + countCriterion.Modifier = models.CriterionModifierGreaterThan + verifyTagMarkerCount(t, countCriterion) +} func verifyTagMarkerCount(t *testing.T, markerCountCriterion models.IntCriterionInput) { withTxn(func(r models.Repository) error { diff --git a/pkg/utils/file.go b/pkg/utils/file.go index 81cd75598..87f7538b3 100644 --- a/pkg/utils/file.go +++ b/pkg/utils/file.go @@ -346,3 +346,14 @@ func IsFsPathCaseSensitive(path string) (bool, error) { } return false, fmt.Errorf("can not determine case sensitivity of path %s", path) } + +func FindInPaths(paths []string, baseName string) string { + for _, p := range paths { + filePath := filepath.Join(p, baseName) + if exists, _ := FileExists(filePath); exists { + return filePath + } + } + + return "" +} diff --git a/static/performer/NoName01.png b/static/performer/NoName01.png index 954267c9a..cdcba1db9 100644 Binary files a/static/performer/NoName01.png and b/static/performer/NoName01.png differ diff --git a/static/performer/NoName02.png b/static/performer/NoName02.png index 5e053bfed..4687adc08 100644 Binary files a/static/performer/NoName02.png and b/static/performer/NoName02.png differ diff --git a/static/performer/NoName03.png b/static/performer/NoName03.png index a3919229b..8ac0d13b7 100644 Binary files a/static/performer/NoName03.png and b/static/performer/NoName03.png differ diff --git a/static/performer/NoName04.png b/static/performer/NoName04.png index 342ab750a..41b55b816 100644 Binary files a/static/performer/NoName04.png and b/static/performer/NoName04.png differ diff --git a/static/performer/NoName05.png b/static/performer/NoName05.png index a917922b5..8a49ba6d3 100644 Binary files a/static/performer/NoName05.png and b/static/performer/NoName05.png differ diff --git a/static/performer/NoName06.png b/static/performer/NoName06.png index efc92ff1d..4359911ae 100644 Binary files a/static/performer/NoName06.png and b/static/performer/NoName06.png differ diff --git a/static/performer/NoName07.png b/static/performer/NoName07.png index 7c80d4240..1bb5f6f82 100644 Binary files a/static/performer/NoName07.png and b/static/performer/NoName07.png differ diff --git a/static/performer/NoName08.png b/static/performer/NoName08.png index 034c0a02a..8ff7ff734 100644 Binary files a/static/performer/NoName08.png and b/static/performer/NoName08.png differ diff --git a/static/performer/NoName09.png b/static/performer/NoName09.png index ef68106f9..49b54b725 100644 Binary files a/static/performer/NoName09.png and b/static/performer/NoName09.png differ diff --git a/static/performer/NoName10.png b/static/performer/NoName10.png index 8ca954825..a2b72043a 100644 Binary files a/static/performer/NoName10.png and b/static/performer/NoName10.png differ diff --git a/static/performer/NoName11.png b/static/performer/NoName11.png index 54b3cf370..01034c2b0 100644 Binary files a/static/performer/NoName11.png and b/static/performer/NoName11.png differ diff --git a/static/performer/NoName12.png b/static/performer/NoName12.png index 0e6854491..7f48ba39a 100644 Binary files a/static/performer/NoName12.png and b/static/performer/NoName12.png differ diff --git a/static/performer/NoName13.png b/static/performer/NoName13.png index 2a93676f7..fdefafb59 100644 Binary files a/static/performer/NoName13.png and b/static/performer/NoName13.png differ diff --git a/static/performer/NoName14.png b/static/performer/NoName14.png index 44add655f..20a20a209 100644 Binary files a/static/performer/NoName14.png and b/static/performer/NoName14.png differ diff --git a/static/performer/NoName15.png b/static/performer/NoName15.png index 003cea40e..cfc9d3a8c 100644 Binary files a/static/performer/NoName15.png and b/static/performer/NoName15.png differ diff --git a/static/performer/NoName16.png b/static/performer/NoName16.png index c76b4b71c..f54744280 100644 Binary files a/static/performer/NoName16.png and b/static/performer/NoName16.png differ diff --git a/static/performer/NoName17.png b/static/performer/NoName17.png index 96fbd481f..068d1cf73 100644 Binary files a/static/performer/NoName17.png and b/static/performer/NoName17.png differ diff --git a/static/performer/NoName18.png b/static/performer/NoName18.png index 13efa3da8..179d1d323 100644 Binary files a/static/performer/NoName18.png and b/static/performer/NoName18.png differ diff --git a/static/performer/NoName19.png b/static/performer/NoName19.png index c821fa39a..7349c26b2 100644 Binary files a/static/performer/NoName19.png and b/static/performer/NoName19.png differ diff --git a/static/performer/NoName20.png b/static/performer/NoName20.png index e1dbfa975..86dd404bc 100644 Binary files a/static/performer/NoName20.png and b/static/performer/NoName20.png differ diff --git a/static/performer/NoName21.png b/static/performer/NoName21.png index 5b961a4e5..7bee5cdb6 100644 Binary files a/static/performer/NoName21.png and b/static/performer/NoName21.png differ diff --git a/static/performer/NoName22.png b/static/performer/NoName22.png index e6b16f908..d92384f93 100644 Binary files a/static/performer/NoName22.png and b/static/performer/NoName22.png differ diff --git a/static/performer/NoName23.png b/static/performer/NoName23.png index 0ff5e9019..f28ca89c8 100644 Binary files a/static/performer/NoName23.png and b/static/performer/NoName23.png differ diff --git a/static/performer/NoName24.png b/static/performer/NoName24.png index a971dae43..7b9bb42a2 100644 Binary files a/static/performer/NoName24.png and b/static/performer/NoName24.png differ diff --git a/static/performer/NoName25.png b/static/performer/NoName25.png index 2439e14fc..1f4864eed 100644 Binary files a/static/performer/NoName25.png and b/static/performer/NoName25.png differ diff --git a/static/performer/NoName26.png b/static/performer/NoName26.png index b12f19c87..b63c47ab5 100644 Binary files a/static/performer/NoName26.png and b/static/performer/NoName26.png differ diff --git a/static/performer/NoName27.png b/static/performer/NoName27.png index 91ff3c027..eb57d9cf4 100644 Binary files a/static/performer/NoName27.png and b/static/performer/NoName27.png differ diff --git a/static/performer/NoName28.png b/static/performer/NoName28.png index 24c104e42..c00fb15b5 100644 Binary files a/static/performer/NoName28.png and b/static/performer/NoName28.png differ diff --git a/static/performer/NoName29.png b/static/performer/NoName29.png index f3cc718ca..21e9e27fa 100644 Binary files a/static/performer/NoName29.png and b/static/performer/NoName29.png differ diff --git a/static/performer/NoName30.png b/static/performer/NoName30.png index 343e8cf0f..ba968026d 100644 Binary files a/static/performer/NoName30.png and b/static/performer/NoName30.png differ diff --git a/static/performer/NoName31.png b/static/performer/NoName31.png index 284903fe8..a4003fa75 100644 Binary files a/static/performer/NoName31.png and b/static/performer/NoName31.png differ diff --git a/static/performer/NoName32.png b/static/performer/NoName32.png index ab0c8deb3..0ca4aca17 100644 Binary files a/static/performer/NoName32.png and b/static/performer/NoName32.png differ diff --git a/static/performer/NoName33.png b/static/performer/NoName33.png index ad9fcb8a8..38ae2116c 100644 Binary files a/static/performer/NoName33.png and b/static/performer/NoName33.png differ diff --git a/static/performer/NoName34.png b/static/performer/NoName34.png index 3e25c5622..c40683098 100644 Binary files a/static/performer/NoName34.png and b/static/performer/NoName34.png differ diff --git a/static/performer/NoName35.png b/static/performer/NoName35.png index d9f8cf040..92d9ad784 100644 Binary files a/static/performer/NoName35.png and b/static/performer/NoName35.png differ diff --git a/static/performer/NoName36.png b/static/performer/NoName36.png index ac2d8b89d..7796c8b63 100644 Binary files a/static/performer/NoName36.png and b/static/performer/NoName36.png differ diff --git a/static/performer/NoName37.png b/static/performer/NoName37.png index d10fd47e9..c47f0abac 100644 Binary files a/static/performer/NoName37.png and b/static/performer/NoName37.png differ diff --git a/static/performer/NoName38.png b/static/performer/NoName38.png index 7609ef61f..da9fa37c9 100644 Binary files a/static/performer/NoName38.png and b/static/performer/NoName38.png differ diff --git a/static/performer/NoName39.png b/static/performer/NoName39.png index d87790e0f..a7921d01d 100644 Binary files a/static/performer/NoName39.png and b/static/performer/NoName39.png differ diff --git a/static/performer/NoName40.png b/static/performer/NoName40.png index 0b13071cb..0214efad4 100644 Binary files a/static/performer/NoName40.png and b/static/performer/NoName40.png differ diff --git a/ui/v2.5/.vscode/settings.json b/ui/v2.5/.vscode/settings.json index 5265cba16..ba5be62ee 100644 --- a/ui/v2.5/.vscode/settings.json +++ b/ui/v2.5/.vscode/settings.json @@ -13,5 +13,14 @@ "src/locales" ], "i18n-ally.keystyle": "nested", - "i18n-ally.sourceLanguage": "en-GB" + "i18n-ally.sourceLanguage": "en-GB", + "spellright.language": [ + "en" + ], + "spellright.documentTypes": [ + "markdown", + "latex", + "plaintext", + "typescriptreact" + ] } \ No newline at end of file diff --git a/ui/v2.5/src/App.tsx b/ui/v2.5/src/App.tsx index fa506466b..c1560d1f5 100755 --- a/ui/v2.5/src/App.tsx +++ b/ui/v2.5/src/App.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from "react"; import { Route, Switch, useRouteMatch } from "react-router-dom"; import { IntlProvider } from "react-intl"; -import { merge } from "lodash"; +import { mergeWith } from "lodash"; import { ToastProvider } from "src/hooks/Toast"; import LightboxProvider from "src/hooks/Lightbox/context"; import { library } from "@fortawesome/fontawesome-svg-core"; @@ -59,11 +59,16 @@ export const App: React.FC = () => { const messageLanguage = languageMessageString(language); // use en-GB as default messages if any messages aren't found in the chosen language - const mergedMessages = merge( + const mergedMessages = mergeWith( // eslint-disable-next-line @typescript-eslint/no-explicit-any (locales as any)[defaultMessageLanguage], // eslint-disable-next-line @typescript-eslint/no-explicit-any - (locales as any)[messageLanguage] + (locales as any)[messageLanguage], + (objVal, srcVal) => { + if (srcVal === "") { + return objVal; + } + } ); const messages = flattenMessages(mergedMessages); diff --git a/ui/v2.5/src/components/Changelog/Changelog.tsx b/ui/v2.5/src/components/Changelog/Changelog.tsx index 5b7608034..87b8ff1db 100644 --- a/ui/v2.5/src/components/Changelog/Changelog.tsx +++ b/ui/v2.5/src/components/Changelog/Changelog.tsx @@ -11,6 +11,7 @@ import V050 from "./versions/v050.md"; import V060 from "./versions/v060.md"; import V070 from "./versions/v070.md"; import V080 from "./versions/v080.md"; +import V090 from "./versions/v090.md"; import { MarkdownPage } from "../Shared/MarkdownPage"; // to avoid use of explicit any @@ -49,9 +50,9 @@ const Changelog: React.FC = () => { // after new release: // add entry to releases, using the current* fields // then update the current fields. - const currentVersion = stashVersion || "v0.8.0"; + const currentVersion = stashVersion || "v0.9.0"; const currentDate = buildDate; - const currentPage = V080; + const currentPage = V090; const releases: IStashRelease[] = [ { @@ -60,6 +61,11 @@ const Changelog: React.FC = () => { page: currentPage, defaultOpen: true, }, + { + version: "v0.8.0", + date: "2021-07-02", + page: V080, + }, { version: "v0.7.0", date: "2021-05-15", diff --git a/ui/v2.5/src/components/Changelog/versions/v090.md b/ui/v2.5/src/components/Changelog/versions/v090.md new file mode 100644 index 000000000..49be1d202 --- /dev/null +++ b/ui/v2.5/src/components/Changelog/versions/v090.md @@ -0,0 +1,45 @@ +### ✨ New Features +* Support setting a fixed funscript offset/delay. ([#1573](https://github.com/stashapp/stash/pull/1573)) +* Added sort by options for image and gallery count for performers. ([#1671](https://github.com/stashapp/stash/pull/1671)) +* Added sort by options for date, duration and rating for movies. ([#1663](https://github.com/stashapp/stash/pull/1663)) +* Allow saving query page zoom level in saved and default filters. ([#1636](https://github.com/stashapp/stash/pull/1636)) +* Support custom page sizes in the query page size dropdown. ([#1636](https://github.com/stashapp/stash/pull/1636)) +* Added between/not between modifiers for number criteria. ([#1559](https://github.com/stashapp/stash/pull/1559)) +* Support excluding tag patterns when scraping. ([#1617](https://github.com/stashapp/stash/pull/1617)) +* Support setting a custom directory for default performer images. ([#1489](https://github.com/stashapp/stash/pull/1489)) +* Added filtering and sorting on scene marker count for tags. ([#1603](https://github.com/stashapp/stash/pull/1603)) +* Support excluding fields and editing tags when saving from scene tagger view. ([#1605](https://github.com/stashapp/stash/pull/1605)) +* Added not equals/greater than/less than modifiers for resolution criteria. ([#1568](https://github.com/stashapp/stash/pull/1568)) + +### 🎨 Improvements +* Added support for loading TLS/SSL configuration files from the configuration directory. ([#1678](https://github.com/stashapp/stash/pull/1678)) +* Added total scenes duration to Stats page. ([#1626](https://github.com/stashapp/stash/pull/1626)) +* Move Play Selected Scenes, and Add/Remove Gallery Image buttons to button toolbar. ([#1673](https://github.com/stashapp/stash/pull/1673)) +* Added image and gallery counts to tag list view. ([#1672](https://github.com/stashapp/stash/pull/1672)) +* Prompt when leaving gallery and image edit pages with unsaved changes. ([#1654](https://github.com/stashapp/stash/pull/1654), [#1669](https://github.com/stashapp/stash/pull/1669)) +* Show largest duplicates first in scene duplicate checker. ([#1639](https://github.com/stashapp/stash/pull/1639)) +* Added checkboxes to scene list view. ([#1642](https://github.com/stashapp/stash/pull/1642)) +* Added keyboard shortcuts for scene queue navigation. ([#1635](https://github.com/stashapp/stash/pull/1635)) +* Made performer scrape menu scrollable. ([#1634](https://github.com/stashapp/stash/pull/1634)) +* Improve Studio UI. ([#1629](https://github.com/stashapp/stash/pull/1629)) +* Improve link styling and ensure links open in a new tab. ([#1622](https://github.com/stashapp/stash/pull/1622)) +* Added zh-CN language option. ([#1620](https://github.com/stashapp/stash/pull/1620)) +* Moved scraping settings into the Scraping settings page. ([#1548](https://github.com/stashapp/stash/pull/1548)) +* Show current scene details in tagger view. ([#1605](https://github.com/stashapp/stash/pull/1605)) +* Removed stripes and added background colour to default performer images (old images can be downloaded from the PR link). ([#1609](https://github.com/stashapp/stash/pull/1609)) +* Added pt-BR language option. ([#1587](https://github.com/stashapp/stash/pull/1587)) +* Added de-DE language option. ([#1578](https://github.com/stashapp/stash/pull/1578)) + +### 🐛 Bug fixes +* Fix SQL error when filtering for Performers missing stash IDs. ([#1681](https://github.com/stashapp/stash/pull/1681)) +* Fix Play Selected scene UI error when one scene is selected. ([#1674](https://github.com/stashapp/stash/pull/1674)) +* Fix race condition panic when reading and writing config concurrently. ([#1645](https://github.com/stashapp/stash/issues/1343)) +* Fix performance issue on Studios page getting studio image count. ([#1643](https://github.com/stashapp/stash/pull/1643)) +* Regenerate scene phash if overwrite flag is set. ([#1633](https://github.com/stashapp/stash/pull/1633)) +* Create .stash directory in $HOME only if required. ([#1623](https://github.com/stashapp/stash/pull/1623)) +* Include stash id when scraping performer from stash-box. ([#1608](https://github.com/stashapp/stash/pull/1608)) +* Fix infinity framerate values causing resolver error. ([#1607](https://github.com/stashapp/stash/pull/1607)) +* Fix unsetting performer gender not working correctly. ([#1606](https://github.com/stashapp/stash/pull/1606)) +* Fix is missing date scene criterion causing invalid SQL. ([#1577](https://github.com/stashapp/stash/pull/1577)) +* Fix rendering of carousel images on Apple devices. ([#1562](https://github.com/stashapp/stash/pull/1562)) +* Show New and Delete buttons in mobile view. ([#1539](https://github.com/stashapp/stash/pull/1539)) \ No newline at end of file diff --git a/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx b/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx index 1cb433028..b438d54a7 100644 --- a/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx +++ b/ui/v2.5/src/components/Galleries/GalleryDetails/Gallery.tsx @@ -277,7 +277,7 @@ export const Gallery: React.FC = () => { if (isNew) return (
{intl.formatMessage({ id: "config.general.scraping" })}-- {intl.formatMessage({ id: "config.general.scraper_user_agent" })} --- {intl.formatMessage({ id: "config.general.chrome_cdp_path" })} --{intl.formatMessage({ id: "performers" })}{intl.formatMessage({ id: "config.ui.scene_wall.heading" })}{intl.formatMessage({ id: "config.ui.handy_connection_key" })}++ {intl.formatMessage({ id: "config.ui.handy_connection_key.heading" })} ++ {intl.formatMessage({ id: "config.ui.funscript_offset.heading" })} ++
-
+
);
}
}
@@ -299,7 +349,81 @@ export const SettingsScrapersPanel: React.FC = () => {
return (
<>
- {title}+
{intl.formatMessage({ id: "config.categories.scrapers" })}+{intl.formatMessage({ id: "config.general.scraping" })}++ {intl.formatMessage({ id: "config.general.scraper_user_agent" })} +++ {intl.formatMessage({ id: "config.general.chrome_cdp_path" })} +++ {intl.formatMessage({ + id: "config.scraping.excluded_tag_patterns_head", + })} +++ + {intl.formatMessage({ id: "config.scraping.scrapers" })}++ + > ); }; diff --git a/ui/v2.5/src/components/Settings/SettingsTasksPanel/DirectorySelectionDialog.tsx b/ui/v2.5/src/components/Settings/SettingsTasksPanel/DirectorySelectionDialog.tsx index d534e1001..0c5a4f179 100644 --- a/ui/v2.5/src/components/Settings/SettingsTasksPanel/DirectorySelectionDialog.tsx +++ b/ui/v2.5/src/components/Settings/SettingsTasksPanel/DirectorySelectionDialog.tsx @@ -35,12 +35,12 @@ export const DirectorySelectionDialog: React.FC |
|---|