13 Commits

Author SHA1 Message Date
366dccde12 fix: use go-migrate pkg to init or update db schema
Instead to implement own logic how the database scheme should be updated
or migrated to a newer or older version flucky use now instead the
go-migrate package.
2021-01-30 15:44:21 +01:00
23695b4513 fix: update rows when already exist during an import
When rows in the table devices, sensors, humidities, pressures and
temperatures already exist, they will only be updated.
2020-12-14 20:54:20 +01:00
522fe2746a fix: add or update devices, sensors and measured values
Add additional functions to the repository to add or update devices,
sensors or measured values. Furthermore the test has been adapt to the
new functions.
2020-12-14 20:54:20 +01:00
d0cfdd7102 fix: exclude dockerutils and testutils package 2020-11-07 23:03:11 +01:00
675af77965 feat: import from sqlite or postgresql 2020-11-07 22:59:48 +01:00
592e9b7f5c fix: upgrade dependencies 2020-11-06 23:08:54 +01:00
a2e66ce08b fix: sqlite and postgres, close rows and pass nothing instead nil 2020-11-06 23:07:10 +01:00
1701db7b8e fix: define cache values
The number of measured values in the cache before they are stored in the
database can not be defined over the flag --cached-values.
2020-10-07 23:59:27 +02:00
0fc4aa7c28 fix: postgres columns with timezone
Add timezone for the columns creation_date and update_date, otherwise
it's difficult to compare the times correctly in the unit test.

Furthermore the default value of the creation_date will now be defined
by the postgres implementation of the database interface.
2020-10-07 23:38:27 +02:00
3a090d190e fix: cli temperature read
changes:
- fix: read temperature values without daemon
  Add subcommand to read temperature values without starting the daemon

- fix: implement measured value types
  Replace measured value types with constants

- fix: add sensor pipelines
  Add functions which returns a channel with measured values

- fix: filter measured values from a channel
  Add functions to filter measured values by sensor id or measured
  value types.
2020-09-21 20:05:37 +02:00
7cbd80c726 fix: remove obsolete attributes from config.json
changes:
- removed unused attributes from config.json
2020-09-07 19:12:30 +02:00
c279d288b4 fix: increase jobs to number of cpus 2020-08-25 19:31:30 +02:00
ef9266b010 fix: systemd service unit 2020-08-19 19:15:06 +02:00
111 changed files with 2392 additions and 2412 deletions

View File

@ -6,7 +6,7 @@ steps:
- name: build-linux-amd64 - name: build-linux-amd64
image: docker.io/volkerraschek/build-image:latest image: docker.io/volkerraschek/build-image:latest
commands: commands:
- make bin/linux/amd64/flucky - make --jobs=$(nproc) bin/linux/amd64/flucky
when: when:
event: event:
- push - push

View File

@ -66,13 +66,25 @@ bin/tmp/${EXECUTABLE}: bindata
# GO-BINDATA # GO-BINDATA
# ============================================================================== # ==============================================================================
BINDATA_TARGETS := \ BINDATA_TARGETS := \
pkg/repository/db/bindataSQL.go \ pkg/repository/db/postgres/ddl/bindata.go \
pkg/repository/db/postgres/dml/bindata.go \
pkg/repository/db/sqlite3/ddl/bindata.go \
pkg/repository/db/sqlite3/dml/bindata.go
PHONY+=bindata PHONY+=bindata
bindata: clean ${BINDATA_TARGETS} bindata: clean ${BINDATA_TARGETS}
pkg/repository/db/bindataSQL.go: pkg/repository/db/postgres/ddl/bindata.go:
go-bindata -pkg db -o ./pkg/repository/db/bindataSQL.go pkg/repository/db/postgres/*** pkg/repository/db/sqlite3/*** go-bindata -pkg postgresddl -prefix ${@:%/bindata.go=%} -o ${@} ${@:%/bindata.go=%}/*
pkg/repository/db/postgres/dml/bindata.go:
go-bindata -pkg postgresdml -prefix ${@:%/bindata.go=%} -o ${@} ${@:%/bindata.go=%}/*
pkg/repository/db/sqlite3/ddl/bindata.go:
go-bindata -pkg sqlite3ddl -prefix ${@:%/bindata.go=%} -o ${@} ${@:%/bindata.go=%}/*
pkg/repository/db/sqlite3/dml/bindata.go:
go-bindata -pkg sqlite3dml -prefix ${@:%/bindata.go=%} -o ${@} ${@:%/bindata.go=%}/*
# CLEAN # CLEAN
# ============================================================================== # ==============================================================================

View File

@ -18,9 +18,7 @@ func InitCmd(cmd *cobra.Command) error {
RunE: run, RunE: run,
} }
daemonCmd.Flags().Bool("compression", true, "Compress measured values") daemonCmd.Flags().Uint("cached-values", 500, "Number of measured values in the cache before they are stored in the database")
daemonCmd.Flags().Uint("cached-values", 500, "Number of cached values before saveing into the backend")
daemonCmd.Flags().Float64("round", 0.5, "Round values. The value 0 deactivates the function")
cmd.AddCommand(daemonCmd) cmd.AddCommand(daemonCmd)
return nil return nil
@ -32,6 +30,11 @@ func run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("No config file defined: %v", err) return fmt.Errorf("No config file defined: %v", err)
} }
cachedEntries, err := cmd.Flags().GetUint("cached-values")
if err != nil {
return fmt.Errorf("No cached-entries defined")
}
// logLevel, err := cmd.Flags().GetString("loglevel") // logLevel, err := cmd.Flags().GetString("loglevel")
// if err != nil { // if err != nil {
// return fmt.Errorf("No loglevel defined: %v", err) // return fmt.Errorf("No loglevel defined: %v", err)
@ -44,5 +47,5 @@ func run(cmd *cobra.Command, args []string) error {
return err return err
} }
return daemon.Start(cnf, flogger) return daemon.Start(cnf, cachedEntries, flogger)
} }

81
cli/imp/imp.go Normal file
View File

@ -0,0 +1,81 @@
package imp
import (
"fmt"
"net/url"
"git.cryptic.systems/volker.raschek/flucky/pkg/config"
"git.cryptic.systems/volker.raschek/flucky/pkg/repository"
"git.cryptic.systems/volker.raschek/go-logger"
"github.com/spf13/cobra"
)
var (
importSensors bool
importHumidities bool
importPressures bool
importTemperatures bool
)
func InitCmd(cmd *cobra.Command) error {
importCmd := &cobra.Command{
Use: "import",
Short: "Import data from passed URL",
RunE: importSources,
}
importCmd.Flags().BoolVar(&importSensors, "sensors", true, "Import sensors")
importCmd.Flags().BoolVar(&importHumidities, "humidities", true, "Import humidities")
importCmd.Flags().BoolVar(&importPressures, "pressures", true, "Import pressures")
importCmd.Flags().BoolVar(&importTemperatures, "temperatures", true, "Import temperatures")
cmd.AddCommand(importCmd)
return nil
}
func importSources(cmd *cobra.Command, args []string) error {
configFile, err := cmd.Flags().GetString("config")
if err != nil {
return fmt.Errorf("No config file defined")
}
cnf, err := config.Read(configFile)
if err != nil {
return err
}
destURL, err := url.Parse(cnf.DSN)
if err != nil {
return err
}
logLevelString, err := cmd.Flags().GetString("loglevel")
if err != nil {
return err
}
logLevel, err := logger.ParseLogLevel(logLevelString)
if err != nil {
return err
}
flogger := logger.NewLogger(logLevel)
sourceURL, err := url.Parse(args[0])
if err != nil {
return fmt.Errorf("Failed to parse source url: %w", err)
}
err = repository.Import(sourceURL, destURL, flogger, repository.OptImport{
Sensors: importSensors,
Humidities: importHumidities,
Pressures: importPressures,
Temperatures: importTemperatures,
})
if err != nil {
return fmt.Errorf("Failed to import: %w", err)
}
return nil
}

View File

@ -9,9 +9,10 @@ import (
"time" "time"
"git.cryptic.systems/volker.raschek/flucky/cli/daemon" "git.cryptic.systems/volker.raschek/flucky/cli/daemon"
imp "git.cryptic.systems/volker.raschek/flucky/cli/imp"
"git.cryptic.systems/volker.raschek/flucky/cli/sensor" "git.cryptic.systems/volker.raschek/flucky/cli/sensor"
"git.cryptic.systems/volker.raschek/flucky/cli/temperature"
"git.cryptic.systems/volker.raschek/flucky/pkg/config" "git.cryptic.systems/volker.raschek/flucky/pkg/config"
"git.cryptic.systems/volker.raschek/flucky/pkg/types"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
@ -38,7 +39,9 @@ func Execute(version *semver.Version) error {
subCommands := []func(cmd *cobra.Command) error{ subCommands := []func(cmd *cobra.Command) error{
daemon.InitCmd, daemon.InitCmd,
imp.InitCmd,
sensor.InitCmd, sensor.InitCmd,
temperature.InitCmd,
} }
for _, subCommand := range subCommands { for _, subCommand := range subCommands {
@ -62,11 +65,6 @@ func preRunError(cmd *cobra.Command, args []string) error {
// check if config file exists // check if config file exists
if _, err := os.Stat(configFile); os.IsNotExist(err) { if _, err := os.Stat(configFile); os.IsNotExist(err) {
hostname, err := os.Hostname()
if err != nil {
return fmt.Errorf("Failed to determine the hostname: %v", err)
}
// Time must be truncted for postgres. Postgres currently does not support // Time must be truncted for postgres. Postgres currently does not support
// nanoseconds which is automatically include into the go time object // nanoseconds which is automatically include into the go time object
postgresTimeStamp := time.Now() postgresTimeStamp := time.Now()
@ -85,12 +83,8 @@ func preRunError(cmd *cobra.Command, args []string) error {
// Default configuration // Default configuration
dsn := fmt.Sprintf("sqlite3://%v/sqlite.db?cache=shared&mode=memory&foreign_keys=on", defaultCacheDir) dsn := fmt.Sprintf("sqlite3://%v/sqlite.db?cache=shared&mode=memory&foreign_keys=on", defaultCacheDir)
cnf := config.Config{ cnf := config.Config{
Device: &types.Device{ DeviceID: uuid.NewV4().String(),
ID: uuid.NewV4().String(), DSN: dsn,
Name: hostname,
CreationDate: postgresTimeStamp,
},
DSN: dsn,
} }
err = config.Write(&cnf, configFile) err = config.Write(&cnf, configFile)

View File

@ -164,7 +164,7 @@ func addSensor(cmd *cobra.Command, args []string) error {
return err return err
} }
sensor.DeviceID = cnf.Device.ID sensor.DeviceID = cnf.DeviceID
dsnURL, err := url.Parse(cnf.DSN) dsnURL, err := url.Parse(cnf.DSN)
if err != nil { if err != nil {
@ -292,7 +292,7 @@ func listSensors(cmd *cobra.Command, args []string) error {
} }
// add sensor entry to list // add sensor entry to list
sensors, err := repo.GetSensorsByDeviceID(cnf.Device.ID) sensors, err := repo.GetSensorsByDeviceID(cnf.DeviceID)
if err != nil { if err != nil {
return err return err
} }

View File

@ -0,0 +1,133 @@
package temperature
import (
"context"
"fmt"
"net/url"
"os"
"git.cryptic.systems/volker.raschek/flucky/pkg/cli"
"git.cryptic.systems/volker.raschek/flucky/pkg/config"
"git.cryptic.systems/volker.raschek/flucky/pkg/repository"
"git.cryptic.systems/volker.raschek/flucky/pkg/sensor"
"git.cryptic.systems/volker.raschek/flucky/pkg/types"
"git.cryptic.systems/volker.raschek/go-logger"
"github.com/spf13/cobra"
)
func InitCmd(cmd *cobra.Command) error {
temperatureCmd := &cobra.Command{
Use: "temperature",
Short: "Read and list temperature values",
}
readTemperatureCmd := &cobra.Command{
Use: "read",
Short: "Read temperature values from sensors",
RunE: readTemperature,
}
readTemperatureCmd.Flags().Bool("persist", true, "Persist measured values to the repository")
temperatureCmd.AddCommand(readTemperatureCmd)
cmd.AddCommand(temperatureCmd)
return nil
}
func readTemperature(cmd *cobra.Command, args []string) error {
configFile, err := cmd.Flags().GetString("config")
if err != nil {
return fmt.Errorf("No config file defined")
}
persist, err := cmd.Flags().GetBool("persist")
if err != nil {
return fmt.Errorf("Flag persist not defined: %v", err)
}
cnf, err := config.Read(configFile)
if err != nil {
return err
}
dsnURL, err := url.Parse(cnf.DSN)
if err != nil {
return err
}
logLevelString, err := cmd.Flags().GetString("loglevel")
if err != nil {
return err
}
logLevel, err := logger.ParseLogLevel(logLevelString)
if err != nil {
return err
}
flogger := logger.NewLogger(logLevel)
repo, err := repository.New(dsnURL, flogger)
if err != nil {
return err
}
sensorTypes, err := repo.GetSensors()
if err != nil {
return err
}
sensorTypes, err = types.FilterSensorByMeasuredValueTypes(sensorTypes, types.Temperature)
if err != nil {
return err
}
sensors := make([]sensor.Sensor, 0)
for i := range sensorTypes {
s, err := sensor.New(sensorTypes[i])
if err != nil {
return err
}
sensors = append(sensors, s)
}
measuredValueChannel, errorChannel := sensor.ReadPipeline(context.TODO(), sensors...)
go func() {
for {
select {
case err, open := <-errorChannel:
if !open {
return
}
flogger.Error("%v", err)
}
}
}()
measuredValues := make([]*types.MeasuredValue, 0)
LOOP:
for {
select {
case measuredValue, open := <-measuredValueChannel:
if !open {
break LOOP
}
measuredValues = append(measuredValues, measuredValue)
}
}
err = cli.PrintMeasuredValues(measuredValues, os.Stdout)
if err != nil {
return err
}
if persist {
err = repo.AddMeasuredValues(measuredValues...)
if err != nil {
return err
}
}
return nil
}

View File

@ -6,7 +6,7 @@ services:
- PGTZ=Europe/Berlin - PGTZ=Europe/Berlin
- POSTGRES_PASSWORD=postgres - POSTGRES_PASSWORD=postgres
- TZ=Europe/Berlin - TZ=Europe/Berlin
image: postgres:11.5-alpine image: postgres:13-alpine
ports: ports:
- 5432:5432 - 5432:5432
restart: always restart: always

18
go.mod
View File

@ -3,22 +3,20 @@ module git.cryptic.systems/volker.raschek/flucky
go 1.14 go 1.14
require ( require (
git.cryptic.systems/volker.raschek/dockerutils v0.2.0
git.cryptic.systems/volker.raschek/go-dht v0.1.2 git.cryptic.systems/volker.raschek/go-dht v0.1.2
git.cryptic.systems/volker.raschek/go-logger v0.1.0 git.cryptic.systems/volker.raschek/go-logger v0.1.0
github.com/Masterminds/semver v1.5.0 github.com/Masterminds/semver v1.5.0
github.com/Microsoft/go-winio v0.4.14 // indirect github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375 github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375
github.com/d2r2/go-i2c v0.0.0-20191123181816-73a8a799d6bc github.com/d2r2/go-i2c v0.0.0-20191123181816-73a8a799d6bc
github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e
github.com/docker/distribution v2.7.1+incompatible // indirect github.com/golang-migrate/migrate/v4 v4.14.1
github.com/docker/docker v1.13.1 github.com/lib/pq v1.9.0
github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.4.0 // indirect
github.com/lib/pq v1.7.0
github.com/mattn/go-sqlite3 v2.0.3+incompatible github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.1.1
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect github.com/ugorji/go v1.1.4 // indirect
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 // indirect
) )

641
go.sum
View File

@ -1,27 +1,105 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.63.0/go.mod h1:GmezbQc7T2snqkEXWfZ0sy0VfkB/ivI2DdtJL2DEmlg=
cloud.google.com/go v0.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv4=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/spanner v1.9.0/go.mod h1:xvlEn0NZ5v1iJPYsBnUVRDNvccDxsBTEi16pJRKQVws=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.cryptic.systems/volker.raschek/dockerutils v0.1.0 h1:NjE5BVS0k9XoRj8qZOHNvpjb1+C8Zr4sK/g4Yjw5Of4=
git.cryptic.systems/volker.raschek/dockerutils v0.1.0/go.mod h1:PikYsmSANKHEKJSD2pIY9gPqMpiQh1ufCrU/s/v2I5Q=
git.cryptic.systems/volker.raschek/dockerutils v0.2.0 h1:HJhAfHoyKHOt76T5PxeLvpoA0FCiGu50u4GRwGLGVJs=
git.cryptic.systems/volker.raschek/dockerutils v0.2.0/go.mod h1:c4ZZpD2unnzwr7qHDpVdCmxLGOSnJagli7xNGgTBhk0=
git.cryptic.systems/volker.raschek/go-dht v0.1.2 h1:kGmfpaVUETQhSELCIrKXMjKwuUhQkRUz/7VbLYiTRJA= git.cryptic.systems/volker.raschek/go-dht v0.1.2 h1:kGmfpaVUETQhSELCIrKXMjKwuUhQkRUz/7VbLYiTRJA=
git.cryptic.systems/volker.raschek/go-dht v0.1.2/go.mod h1:FUMwxa4cD+ATHPztXJntlO22I0DBTUPtXxfRF0JxXy8= git.cryptic.systems/volker.raschek/go-dht v0.1.2/go.mod h1:FUMwxa4cD+ATHPztXJntlO22I0DBTUPtXxfRF0JxXy8=
git.cryptic.systems/volker.raschek/go-logger v0.1.0 h1:JHBDesKBZaXjc2AlqYms1T3dGIX0oNIOBWl4cnVFWIo= git.cryptic.systems/volker.raschek/go-logger v0.1.0 h1:JHBDesKBZaXjc2AlqYms1T3dGIX0oNIOBWl4cnVFWIo=
git.cryptic.systems/volker.raschek/go-logger v0.1.0/go.mod h1:GqeuxFj64SAolfj5kpbWup6E1vv37SaH5S+4wa40Tqs= git.cryptic.systems/volker.raschek/go-logger v0.1.0/go.mod h1:GqeuxFj64SAolfj5kpbWup6E1vv37SaH5S+4wa40Tqs=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 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/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/arrow/go/arrow v0.0.0-20200601151325-b2287a20f230/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
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/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY=
github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/containerd/containerd v1.4.3 h1:ijQT13JedHSHrQGWFcGEwzcNKrAGIiZ+jSD5QQG07SY=
github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 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.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 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-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375 h1:vdUOwcZdV+bBfGUUh5oPPWSzw9p+lBnNSuGgQwGpCH4= github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375 h1:vdUOwcZdV+bBfGUUh5oPPWSzw9p+lBnNSuGgQwGpCH4=
github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375/go.mod h1:3iz1WHlYJU9b4NJei+Q8G7DN3K05arcCMlOQ+qNCDjo= github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375/go.mod h1:3iz1WHlYJU9b4NJei+Q8G7DN3K05arcCMlOQ+qNCDjo=
github.com/d2r2/go-i2c v0.0.0-20191123181816-73a8a799d6bc h1:HLRSIWzUGMLCq4ldt0W1GLs3nnAxa5EGoP+9qHgh6j0= github.com/d2r2/go-i2c v0.0.0-20191123181816-73a8a799d6bc h1:HLRSIWzUGMLCq4ldt0W1GLs3nnAxa5EGoP+9qHgh6j0=
@ -32,154 +110,707 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dhui/dktest v0.3.3/go.mod h1:EML9sP4sqJELHn4jV7B0TY8oF6077nk83/tz7M56jcQ=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo= github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8=
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.2+incompatible h1:vFgEHPqWBTp4pTjdLwjAA4bSo3gvIGOYwuJTlEjVBCw=
github.com/docker/docker v20.10.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
github.com/gogo/protobuf v1.1.1/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.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-migrate/migrate v1.3.2 h1:QAlFV1QF9zdkzy/jujlBVkVu+L/+k18cg8tuY1/4JDY=
github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA=
github.com/golang-migrate/migrate/v4 v4.14.1 h1:qmRd/rNGjM1r3Ve5gHd5ZplytrD02UcItYNxJ3iUHHE=
github.com/golang-migrate/migrate/v4 v4.14.1/go.mod h1:l7Ks0Au6fYHuUIxUhQ0rcVX1uLlJg54C/VvW7tvxSz0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.0.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.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.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 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/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
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/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.3.2/go.mod h1:LvCquS3HbBKwgl7KbX9KyqEIumJAbm1UMcTvGaIf3bM=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/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/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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY= github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
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=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
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-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 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/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 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.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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.9.1/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/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 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-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.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-20181005140218-185b4288413d/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-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
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=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 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/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.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.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/snowflakedb/glog v0.0.0-20180824191149-f5055e6f21ce/go.mod h1:EB/w24pR5VKI60ecFnKqXzxX3dOorz1rnVicQTQrGM0=
github.com/snowflakedb/gosnowflake v1.3.5/go.mod h1:13Ky+lxzIm3VqNDZJdyvu9MCGy+WgRdYFdXp96UcLZU=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 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.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= 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/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= 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/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 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 v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 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/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-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-20181023162649-9b4f9f5ad519/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-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-20181220203305-927f97764cc3/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/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= 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-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/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-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-20180905080454-ebe1bf3edb33/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-20181026203630-95b1ffbd15a5/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-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-20181116152217-5ac8a444bdc5/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-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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/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 h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= 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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418 h1:HlFl4V6pEMziuLXyRkm5BIYq1y1GAbb02pRlWvI54OM=
golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 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/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/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-20180221164845-07fd8470d635/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-20181030221726-6c7e314b6563/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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200806022845-90696ccdc692/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200818005847-188abfa75333/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200911024640-645f7a48b24f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3 h1:sg8vLDNIxFPHTchfhH1E3AI32BL3f23oie38xUWnJM8=
google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 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.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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 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-20180628173108-788fd7840127/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/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
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.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.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 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/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=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg=
modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8=
modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM=
modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY=
modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k=
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
periph.io/x/periph v3.6.4+incompatible h1:8FyXTbu9lcMVofz8mf+cj1pzTLN4V6EuPY2EF+DoJF4= periph.io/x/periph v3.6.4+incompatible h1:8FyXTbu9lcMVofz8mf+cj1pzTLN4V6EuPY2EF+DoJF4=
periph.io/x/periph v3.6.4+incompatible/go.mod h1:EWr+FCIU2dBWz5/wSWeiIUJTriYv9v2j2ENBmgYyy7Y= periph.io/x/periph v3.6.4+incompatible/go.mod h1:EWr+FCIU2dBWz5/wSWeiIUJTriYv9v2j2ENBmgYyy7Y=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@ -7,6 +7,8 @@ import (
"git.cryptic.systems/volker.raschek/flucky/cli" "git.cryptic.systems/volker.raschek/flucky/cli"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
_ "github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/database/sqlite3"
_ "github.com/lib/pq" _ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )

View File

@ -8,6 +8,25 @@ import (
"git.cryptic.systems/volker.raschek/flucky/pkg/types" "git.cryptic.systems/volker.raschek/flucky/pkg/types"
) )
func PrintMeasuredValues(measuredValues []*types.MeasuredValue, w io.Writer) error {
// declar tabwriter
tw := tabwriter.NewWriter(w, 0, 0, 3, ' ', 0)
fmt.Fprint(tw, "timestamp\ttype\tvalue\n")
for i := range measuredValues {
fmt.Fprintf(tw, "%v\t%v\t%v\n", measuredValues[i].Date.String(), measuredValues[i].ValueType, measuredValues[i].Value)
}
err := tw.Flush()
if err != nil {
return err
}
return nil
}
// PrintSensors displays a list with all configured sensors // PrintSensors displays a list with all configured sensors
func PrintSensors(sensors []*types.Sensor, w io.Writer) error { func PrintSensors(sensors []*types.Sensor, w io.Writer) error {
@ -42,7 +61,10 @@ func PrintSensors(sensors []*types.Sensor, w io.Writer) error {
fmt.Fprintf(tw, "%v\t%v\n", sensor.TickDuration, sensor.Enabled) fmt.Fprintf(tw, "%v\t%v\n", sensor.TickDuration, sensor.Enabled)
} }
tw.Flush() err := tw.Flush()
if err != nil {
return err
}
return nil return nil
} }

View File

@ -1,191 +1,7 @@
package config package config
import (
"fmt"
"os"
"path/filepath"
"regexp"
"time"
"git.cryptic.systems/volker.raschek/flucky/pkg/internal/format"
"git.cryptic.systems/volker.raschek/flucky/pkg/types"
uuid "github.com/satori/go.uuid"
)
var (
validUUID = regexp.MustCompile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
)
// Config represent the configuration // Config represent the configuration
type Config struct { type Config struct {
Device *types.Device `json:"device"` DeviceID string `json:"device_id"`
Sensors []*types.Sensor `json:"sensors"` DSN string `json:"dsn"`
DSN string `json:"dsn"`
DSNFallback string `json:"dsn_fallback"`
}
// AddSensor add a new sensor
func (cnf *Config) AddSensor(sensor *types.Sensor) error {
// Verify that a device is configured
if cnf.Device == nil {
return fmt.Errorf("No device configured")
}
// Define a new UUID if the current UUID is invalid
if !validUUID.MatchString(sensor.ID) {
sensor.ID = uuid.NewV4().String()
}
// Verify that the sensor has a valid name
if len(sensor.Name) <= 0 {
return fmt.Errorf("No sensor name defined")
}
// check if sensor name and sensor uuid already exists
for _, cnfSensor := range cnf.Sensors {
if cnfSensor.Name == sensor.Name ||
cnfSensor.ID == sensor.ID {
return fmt.Errorf("Sensor with same name or id already exist")
}
if cnfSensor.WireID != nil &&
sensor.WireID != nil &&
*cnfSensor.WireID == *sensor.WireID {
return fmt.Errorf("Sensor with same wire id already exist")
}
}
// check if sensor has a valid tick time
if _, err := time.ParseDuration(sensor.TickDuration); err != nil {
return fmt.Errorf("Failed to parse tick duration: %v", err)
}
// check if sensor has a valid device id
if sensor.DeviceID != cnf.Device.ID {
sensor.DeviceID = cnf.Device.ID
}
// overwrite creation date
sensor.CreationDate = format.FormatedTime()
// check if wire socket is available
if sensor.WireID != nil {
socketPath := filepath.Join("/sys/bus/w1/devices", *sensor.WireID, "/w1_slave")
if _, err := os.Stat(socketPath); os.IsNotExist(err) {
return fmt.Errorf("Wire socket not found: %v", socketPath)
}
}
cnf.Sensors = append(cnf.Sensors, sensor)
return nil
}
// DisableSensor disables a sensor by its name or its unique UUID
func (cnf *Config) DisableSensor(name string) error {
found := false
for _, sensor := range cnf.Sensors {
// disable sensor matched after name
if !validUUID.MatchString(name) &&
sensor.Name == name {
sensor.Enabled = false
found = true
break
}
// remove machted uuid
if validUUID.MatchString(name) &&
sensor.ID == name {
sensor.Enabled = false
found = true
break
}
}
if !found {
return fmt.Errorf("Can not found sensor %v", name)
}
return nil
}
// EnableSensor enables a sensor by its name or its unique UUID
func (cnf *Config) EnableSensor(name string) error {
found := false
for _, sensor := range cnf.Sensors {
// disable sensor matched after name
if !validUUID.MatchString(name) &&
sensor.Name == name {
sensor.Enabled = true
found = true
break
}
// remove machted uuid
if validUUID.MatchString(name) &&
sensor.ID == name {
sensor.Enabled = true
found = true
break
}
}
if !found {
return fmt.Errorf("Can not found sensor %v", name)
}
return nil
}
// GetSensorByID returns a sensor matched by his id. If no sensor has this id,
// the function returns nil
func (cnf *Config) GetSensorByID(id string) *types.Sensor {
for _, sensor := range cnf.Sensors {
if sensor.ID == id {
return sensor
}
}
return nil
}
// RemoveSensor deletes a sensor by its name or its unique UUID, If definitive
// is set to true, the sensor will not only be removed in the configuration file
// but also in the backend.
func (cnf *Config) RemoveSensor(name string) error {
for i, sensor := range cnf.Sensors {
// remove machted name
if !validUUID.MatchString(name) &&
sensor.Name == name {
cnf.Sensors = append(cnf.Sensors[:i], cnf.Sensors[i+1:]...)
return nil
}
// remove machted uuid
if validUUID.MatchString(name) &&
sensor.ID == name {
cnf.Sensors = append(cnf.Sensors[:i], cnf.Sensors[i+1:]...)
return nil
}
}
return fmt.Errorf("Can not find sensor %v", name)
}
// RenameSensor renamed a sensor
func (cnf *Config) RenameSensor(oldName string, newName string) error {
for _, cnfSensor := range cnf.Sensors {
if cnfSensor.Name == oldName {
cnfSensor.Name = newName
return nil
}
}
return fmt.Errorf("No sensor %v found", oldName)
} }

View File

@ -1,31 +0,0 @@
package config_test
// func TestAddRemoveSensor(t *testing.T) {
// require := require.New(t)
// // Test: No device configured
// cnf := new(config.Config)
// err := cnf.AddSensor(&types.Sensor{ID: "1aa32c9a-b505-456d-868b-0403344f4cdf"})
// require.Error(err)
// // wireID := "sdfsdff"
// // i2cBus := 1
// // i2cAddress := 78
// cnf.Device = &types.Device{ID: "d6176a06-2b0b-41af-a85c-913e8f61c35d"}
// testCases := map[*types.Sensor]error{
// {ID: "1aa32c9a-b505-456d-868b-0403344f4cdf", DeviceID: "d6176a06-2b0b-41af-a85c-913e8f61c35d"}: fmt.Errorf("No sensor name defined"),
// {ID: "1aa32c9a-b505-456d-868b-0403344f4cdf", DeviceID: "d6176a06-2b0b-41af-a85c-913e8f61c35d", Name: "Test01"}: fmt.Errorf("Failed to parse tick duration: time: invalid duration "),
// {ID: "1aa32c9a-b505-456d-868b-0403344f4cdf", DeviceID: "d6176a06-2b0b-41af-a85c-913e8f61c35d", Name: "Test01", TickDuration: "5s"}: nil,
// {ID: "1aa32c9a-b505-456d-868b-0403344f4cdf", DeviceID: "d6176a06-2b0b-41af-a85c-913e8f61c35d", Name: "Test01", TickDuration: "5s"}: fmt.Errorf("Sensor with same name or id already exist"),
// // {ID: "f90cfc18-f141-4cfd-a8d2-fb40082de5cc", DeviceID: "d6176a06-2b0b-41af-a85c-913e8f61c35d", Name: "Test01", TickDuration: "5s"}: fmt.Errorf("Sensor with same name or id already exist"),
// // {ID: "860a9922-62cb-4c9b-b5af-5fa783cebe9d", DeviceID: "d6176a06-2b0b-41af-a85c-913e8f61c35d", Name: "Test02", TickDuration: "5s", WireID: &wireID}: fmt.Errorf("Wire socket not found: /sys/bus/w1/devices/sdfsdff/w1_slave"),
// // {ID: "9be8989c-b2a1-4401-a82f-d6989ec226fe", DeviceID: "d6176a06-2b0b-41af-a85c-913e8f61c35d", Name: "Test02", TickDuration: "5s"}: nil,
// }
// for sensor, expectedErr := range testCases {
// err := cnf.AddSensor(sensor)
// require.Equal(expectedErr, err)
// }
// }

View File

@ -14,9 +14,7 @@ import (
"git.cryptic.systems/volker.raschek/go-logger" "git.cryptic.systems/volker.raschek/go-logger"
) )
func Start(cnf *config.Config, flogger logger.Logger) error { func Start(cnf *config.Config, cachedEntries uint, flogger logger.Logger) error {
measuredValueChannel := make(chan *types.MeasuredValue, 0)
// load data source name (dsn) // load data source name (dsn)
dsnURL, err := url.Parse(cnf.DSN) dsnURL, err := url.Parse(cnf.DSN)
@ -30,17 +28,26 @@ func Start(cnf *config.Config, flogger logger.Logger) error {
} }
// Add // Add
repoDevice, err := repo.GetDevice(cnf.Device.ID) repoDevice, err := repo.GetDevice(cnf.DeviceID)
switch { switch {
case err != nil: case err != nil:
return err return err
case repoDevice == nil: case repoDevice == nil:
err = repo.AddDevices(cnf.Device)
hostname, err := os.Hostname()
if err != nil { if err != nil {
return err return err
} }
repoDevice, err = repo.GetDevice(cnf.Device.ID) err = repo.AddDevices(&types.Device{
ID: cnf.DeviceID,
Name: hostname,
})
if err != nil {
return err
}
repoDevice, err = repo.GetDevice(cnf.DeviceID)
if err != nil { if err != nil {
return err return err
} }
@ -60,7 +67,7 @@ func Start(cnf *config.Config, flogger logger.Logger) error {
continue continue
} }
flogger.Debug("Found sensor %v", repoSensor.GetName()) flogger.Debug("Found sensor %v", repoSensor.Name)
sensor, err := sensor.New(repoSensor) sensor, err := sensor.New(repoSensor)
if err != nil { if err != nil {
@ -76,27 +83,25 @@ func Start(cnf *config.Config, flogger logger.Logger) error {
parentCtx := context.Background() parentCtx := context.Background()
ctx, cancel := context.WithCancel(parentCtx) ctx, cancel := context.WithCancel(parentCtx)
for _, s := range sensors { measuredValueChannel, errorChannel := sensor.ReadTickingPipeline(ctx, sensors...)
go func(sensor sensor.Sensor) {
for { go func() {
select { for {
case <-ctx.Done(): select {
case <-ctx.Done():
return
case err, open := <-errorChannel:
if !open {
return return
case <-sensor.GetTicker().C: }
measuredValues, err := sensor.Read() if err != nil {
if err != nil { flogger.Error("%v", err)
flogger.Error("%v", err)
continue
}
for _, measuredValue := range measuredValues {
measuredValueChannel <- measuredValue
}
} }
} }
}(s) }
} }()
measuredValues := make([]*types.MeasuredValue, 0, 10) measuredValues := make([]*types.MeasuredValue, 0, cachedEntries)
for { for {
select { select {
case measuredValue := <-measuredValueChannel: case measuredValue := <-measuredValueChannel:
@ -109,12 +114,11 @@ func Start(cnf *config.Config, flogger logger.Logger) error {
if err != nil { if err != nil {
flogger.Error("%v", err) flogger.Error("%v", err)
} }
measuredValues = make([]*types.MeasuredValue, 0, 10) measuredValues = make([]*types.MeasuredValue, 0, cachedEntries)
} }
case signal := <-interruptChannel: case signal := <-interruptChannel:
cancel() cancel()
close(measuredValueChannel)
flogger.Info("Stopping daemon: Received process signal %v", signal.String()) flogger.Info("Stopping daemon: Received process signal %v", signal.String())

View File

@ -7,8 +7,9 @@ import (
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"strings"
postgresdml "git.cryptic.systems/volker.raschek/flucky/pkg/repository/db/postgres/dml"
sqlite3dml "git.cryptic.systems/volker.raschek/flucky/pkg/repository/db/sqlite3/dml"
"git.cryptic.systems/volker.raschek/flucky/pkg/types" "git.cryptic.systems/volker.raschek/flucky/pkg/types"
"git.cryptic.systems/volker.raschek/go-logger" "git.cryptic.systems/volker.raschek/go-logger"
) )
@ -20,9 +21,12 @@ type Database interface {
DeleteDevices(ctx context.Context, deviceIDs ...string) error DeleteDevices(ctx context.Context, deviceIDs ...string) error
DeleteSensors(ctx context.Context, sensorIDs ...string) error DeleteSensors(ctx context.Context, sensorIDs ...string) error
InsertDevices(ctx context.Context, devices ...*types.Device) error InsertDevices(ctx context.Context, devices ...*types.Device) error
InsertOrUpdateDevices(ctx context.Context, devices ...*types.Device) error
InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error
InsertOrUpdateMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error
InsertSensors(ctx context.Context, sensors ...*types.Sensor) error InsertSensors(ctx context.Context, sensors ...*types.Sensor) error
Scheme(ctx context.Context) error InsertOrUpdateSensors(ctx context.Context, sensors ...*types.Sensor) error
Migrate(ctx context.Context) error
SelectDevice(ctx context.Context, deviceID string) (*types.Device, error) SelectDevice(ctx context.Context, deviceID string) (*types.Device, error)
SelectDevices(ctx context.Context) ([]*types.Device, error) SelectDevices(ctx context.Context) ([]*types.Device, error)
SelectHumidity(ctx context.Context, id string) (*types.MeasuredValue, error) SelectHumidity(ctx context.Context, id string) (*types.MeasuredValue, error)
@ -38,11 +42,11 @@ type Database interface {
} }
// New returns a new database backend interface // New returns a new database backend interface
func New(dsnURL *url.URL, flogger logger.Logger) (Database, error) { func New(databaseURL *url.URL, flogger logger.Logger) (Database, error) {
// Check of nil pointer // Check of nil pointer
for _, parameter := range []interface{}{ for _, parameter := range []interface{}{
dsnURL, databaseURL,
flogger, flogger,
} { } {
if parameter == nil { if parameter == nil {
@ -50,72 +54,78 @@ func New(dsnURL *url.URL, flogger logger.Logger) (Database, error) {
} }
} }
// Load Queryfiles
queries := make(map[string]string, 0)
for _, asset := range AssetNames() {
if !strings.Contains(asset, dsnURL.Scheme) {
continue
}
body, err := Asset(asset)
if err != nil {
return nil, err
}
queryFile := filepath.Base(asset)
queries[queryFile] = string(body)
}
var ( var (
database Database database Database
err error err error
) )
switch dsnURL.Scheme { switch databaseURL.Scheme {
case "postgres": case "postgres":
// postgres://[user]:[password]@[host]:[port]/[path]?[query] // postgres://[user]:[password]@[host]:[port]/[path]?[query]
newDBO, err := sql.Open(dsnURL.Scheme, dsnURL.String()) newDBO, err := sql.Open(databaseURL.Scheme, databaseURL.String())
if err != nil { if err != nil {
return nil, err return nil, err
} }
queries := make(map[string]string, 0)
for _, assetName := range postgresdml.AssetNames() {
body, err := postgresdml.Asset(assetName)
if err != nil {
return nil, fmt.Errorf("Failed to load asset %v, %w", assetName, err)
}
queries[assetName] = string(body)
}
database = &Postgres{ database = &Postgres{
dbo: newDBO, databaseURL: databaseURL,
flogger: flogger, dbo: newDBO,
queries: queries, flogger: flogger,
queries: queries,
} }
case "sqlite3": case "sqlite3":
// Create directory where the db file will be created if not exists. // Create directory if not exist
if _, err := os.Stat(filepath.Dir(dsnURL.Path)); os.IsNotExist(err) { if _, err := os.Stat(filepath.Dir(databaseURL.Path)); os.IsNotExist(err) {
err := os.MkdirAll(filepath.Dir(dsnURL.Path), 0755) err := os.MkdirAll(filepath.Dir(databaseURL.Path), 0755)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
// sqlite3:///[path]?[query] flucky dsn // enable foreign keys
// file:///[path]?[query] sql-lib dsn values := databaseURL.Query()
newDBO, err := sql.Open(dsnURL.Scheme, fmt.Sprintf("file://%v?%v", dsnURL.Path, dsnURL.RawQuery)) values.Set("_foreign_keys", "on")
customRawURL := fmt.Sprintf("file://%v?%v", databaseURL.Path, values.Encode())
sqlDB, err := sql.Open("sqlite3", customRawURL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
queries := make(map[string]string, 0)
for _, assetName := range sqlite3dml.AssetNames() {
body, err := sqlite3dml.Asset(assetName)
if err != nil {
return nil, fmt.Errorf("Failed to load asset %v, %w", assetName, err)
}
queries[assetName] = string(body)
}
database = &SQLite{ database = &SQLite{
dbo: newDBO, databaseURL: databaseURL,
flogger: flogger, dbo: sqlDB,
queries: queries, flogger: flogger,
queries: queries,
} }
default: default:
return nil, fmt.Errorf("Unsupported database scheme: %v", dsnURL.Scheme) return nil, fmt.Errorf("Unsupported database scheme: %v", databaseURL.Scheme)
} }
// Initialize database scheme if not exists // Initialize database scheme if not exists
err = database.Scheme(context.Background()) err = database.Migrate(context.Background())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,18 +3,24 @@ package db
import ( import (
"context" "context"
"database/sql" "database/sql"
"errors"
"fmt" "fmt"
"net/url"
"time" "time"
postgresddl "git.cryptic.systems/volker.raschek/flucky/pkg/repository/db/postgres/ddl"
"git.cryptic.systems/volker.raschek/flucky/pkg/types" "git.cryptic.systems/volker.raschek/flucky/pkg/types"
"git.cryptic.systems/volker.raschek/go-logger" "git.cryptic.systems/volker.raschek/go-logger"
"github.com/golang-migrate/migrate/v4"
bindata "github.com/golang-migrate/migrate/v4/source/go_bindata"
) )
// Postgres implementation // Postgres implementation
type Postgres struct { type Postgres struct {
dbo *sql.DB databaseURL *url.URL
flogger logger.Logger dbo *sql.DB
queries map[string]string flogger logger.Logger
queries map[string]string
} }
// Close closes the database and prevents new queries from starting. Close then // Close closes the database and prevents new queries from starting. Close then
@ -28,7 +34,7 @@ func (postgres *Postgres) DeleteDevices(ctx context.Context, deviceIDs ...string
queryFile := "deleteDevice.sql" queryFile := "deleteDevice.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
@ -58,7 +64,7 @@ func (postgres *Postgres) DeleteSensors(ctx context.Context, sensorIDs ...string
queryFile := "deleteSensor.sql" queryFile := "deleteSensor.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
@ -85,17 +91,26 @@ func (postgres *Postgres) DeleteSensors(ctx context.Context, sensorIDs ...string
// InsertDevices into the database // InsertDevices into the database
func (postgres *Postgres) InsertDevices(ctx context.Context, devices ...*types.Device) error { func (postgres *Postgres) InsertDevices(ctx context.Context, devices ...*types.Device) error {
queryFile := "insertDevice.sql"
query, present := postgres.queries[queryFile]
if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
}
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
if err != nil { if err != nil {
return fmt.Errorf("Failed to begin new transaction: %v", err) return fmt.Errorf("Failed to begin new transaction: %v", err)
} }
err = postgres.insertDevices(tx, devices...)
if err != nil {
return err
}
return tx.Commit()
}
func (postgres *Postgres) insertDevices(tx *sql.Tx, devices ...*types.Device) error {
queryFile := "insertDevice.sql"
query, present := postgres.queries[queryFile]
if !present {
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
}
stmt, err := tx.Prepare(query) stmt, err := tx.Prepare(query)
if err != nil { if err != nil {
return fmt.Errorf("Failed to prepare statement: %v", err) return fmt.Errorf("Failed to prepare statement: %v", err)
@ -103,19 +118,30 @@ func (postgres *Postgres) InsertDevices(ctx context.Context, devices ...*types.D
defer stmt.Close() defer stmt.Close()
for _, device := range devices { for _, device := range devices {
_, err = stmt.Exec(&device.ID, &device.Name, &device.Location, &device.CreationDate, &device.UpdateDate)
if device.CreationDate.Equal(time.Time{}) {
device.CreationDate = time.Now()
}
_, err = stmt.Exec(
&device.ID,
&device.Name,
&device.Location,
&device.CreationDate,
&device.UpdateDate,
)
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
return fmt.Errorf("Failed to execute statement: %v", err) return fmt.Errorf("Failed to execute statement: %v", err)
} }
} }
return tx.Commit() return nil
} }
// InsertMeasuredValues into the database // InsertMeasuredValues into the database
func (postgres *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error { func (postgres *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error {
splittedMeasuredValues := make(map[string][]*types.MeasuredValue, 0) splittedMeasuredValues := make(map[types.MeasuredValueType][]*types.MeasuredValue, 0)
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok { if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok {
@ -133,7 +159,7 @@ func (postgres *Postgres) InsertMeasuredValues(ctx context.Context, measuredValu
insert := func(tx *sql.Tx, queryFile string, measuredValues []*types.MeasuredValue) error { insert := func(tx *sql.Tx, queryFile string, measuredValues []*types.MeasuredValue) error {
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
stmt, err := tx.Prepare(query) stmt, err := tx.Prepare(query)
@ -143,6 +169,11 @@ func (postgres *Postgres) InsertMeasuredValues(ctx context.Context, measuredValu
defer stmt.Close() defer stmt.Close()
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
if measuredValue.CreationDate.Equal(time.Time{}) {
measuredValue.CreationDate = time.Now()
}
_, err := stmt.Exec( _, err := stmt.Exec(
&measuredValue.ID, &measuredValue.ID,
&measuredValue.Value, &measuredValue.Value,
@ -164,11 +195,11 @@ func (postgres *Postgres) InsertMeasuredValues(ctx context.Context, measuredValu
var queryFile string var queryFile string
switch measuredValueType { switch measuredValueType {
case "humidity": case types.Humidity:
queryFile = "insertHumidity.sql" queryFile = "insertHumidity.sql"
case "pressure": case types.Pressure:
queryFile = "insertPressure.sql" queryFile = "insertPressure.sql"
case "temperature": case types.Temperature:
queryFile = "insertTemperature.sql" queryFile = "insertTemperature.sql"
default: default:
tx.Rollback() tx.Rollback()
@ -185,12 +216,124 @@ func (postgres *Postgres) InsertMeasuredValues(ctx context.Context, measuredValu
return tx.Commit() return tx.Commit()
} }
// InsertSensors into the database func (postgres *Postgres) InsertOrUpdateDevices(ctx context.Context, devices ...*types.Device) error {
func (postgres *Postgres) InsertSensors(ctx context.Context, sensors ...*types.Sensor) error { queryFile := "insertOrUpdateDevice.sql"
queryFile := "insertSensor.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
}
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
if err != nil {
return fmt.Errorf("Failed to begin new transaction: %v", err)
}
for _, device := range devices {
if device.CreationDate.Equal(time.Time{}) {
device.CreationDate = time.Now()
}
_, err = tx.Exec(
query,
&device.ID,
&device.Name,
&device.Location,
&device.CreationDate,
&device.UpdateDate,
)
if err != nil {
tx.Rollback()
return fmt.Errorf("Failed to execute statement: %v", err)
}
}
return tx.Commit()
}
// InsertOrUpdateMeasuredValues into the database
func (postgres *Postgres) InsertOrUpdateMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error {
splittedMeasuredValues := make(map[types.MeasuredValueType][]*types.MeasuredValue, 0)
for _, measuredValue := range measuredValues {
if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok {
splittedMeasuredValues[measuredValue.ValueType] = make([]*types.MeasuredValue, 0)
}
splittedMeasuredValues[measuredValue.ValueType] = append(splittedMeasuredValues[measuredValue.ValueType], measuredValue)
}
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
if err != nil {
return fmt.Errorf("Failed to begin new transaction: %v", err)
}
// General insert function
insert := func(tx *sql.Tx, queryFile string, measuredValues []*types.MeasuredValue) error {
query, present := postgres.queries[queryFile]
if !present {
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
}
stmt, err := tx.Prepare(query)
if err != nil {
return fmt.Errorf("Failed to prepare statement: %v", err)
}
defer stmt.Close()
for _, measuredValue := range measuredValues {
if measuredValue.CreationDate.Equal(time.Time{}) {
measuredValue.CreationDate = time.Now()
}
_, err := stmt.Exec(
&measuredValue.ID,
&measuredValue.Value,
&measuredValue.Date,
&measuredValue.SensorID,
&measuredValue.CreationDate,
&measuredValue.UpdateDate,
)
if err != nil {
return fmt.Errorf("Failed to execute statement: %v", err)
}
}
return nil
}
for measuredValueType, measuredValues := range splittedMeasuredValues {
var queryFile string
switch measuredValueType {
case types.Humidity:
queryFile = "insertOrUpdateHumidity.sql"
case types.Pressure:
queryFile = "insertOrUpdatePressure.sql"
case types.Temperature:
queryFile = "insertOrUpdateTemperature.sql"
default:
tx.Rollback()
return fmt.Errorf("Measured value type %v not supported", measuredValueType)
}
err := insert(tx, queryFile, measuredValues)
if err != nil {
tx.Rollback()
return err
}
}
return tx.Commit()
}
// InsertOrUpdateSensors into the database
func (postgres *Postgres) InsertOrUpdateSensors(ctx context.Context, sensors ...*types.Sensor) error {
queryFile := "insertOrUpdateSensor.sql"
query, present := postgres.queries[queryFile]
if !present {
return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
@ -205,6 +348,11 @@ func (postgres *Postgres) InsertSensors(ctx context.Context, sensors ...*types.S
defer stmt.Close() defer stmt.Close()
for _, sensor := range sensors { for _, sensor := range sensors {
if sensor.CreationDate.Equal(time.Time{}) {
sensor.CreationDate = time.Now()
}
_, err = stmt.Exec( _, err = stmt.Exec(
&sensor.ID, &sensor.ID,
&sensor.Name, &sensor.Name,
@ -229,21 +377,78 @@ func (postgres *Postgres) InsertSensors(ctx context.Context, sensors ...*types.S
return tx.Commit() return tx.Commit()
} }
// Scheme creates all required tables if not exist // InsertSensors into the database
func (postgres *Postgres) Scheme(ctx context.Context) error { func (postgres *Postgres) InsertSensors(ctx context.Context, sensors ...*types.Sensor) error {
for _, query := range []string{ queryFile := "insertSensor.sql"
postgres.queries["createTableDevices.sql"], query, present := postgres.queries[queryFile]
postgres.queries["createTableSensors.sql"], if !present {
postgres.queries["createTableHumidities.sql"], return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
postgres.queries["createTablePressures.sql"], }
postgres.queries["createTableTemperatures.sql"],
} { tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
_, err := postgres.dbo.ExecContext(ctx, query) if err != nil {
return fmt.Errorf("Failed to begin new transaction: %v", err)
}
stmt, err := tx.Prepare(query)
if err != nil {
return fmt.Errorf("Failed to prepare statement: %v", err)
}
defer stmt.Close()
for _, sensor := range sensors {
if sensor.CreationDate.Equal(time.Time{}) {
sensor.CreationDate = time.Now()
}
_, err = stmt.Exec(
&sensor.ID,
&sensor.Name,
&sensor.Location,
&sensor.WireID,
&sensor.I2CBus,
&sensor.I2CAddress,
&sensor.GPIONumber,
&sensor.Model,
&sensor.Enabled,
&sensor.TickDuration,
&sensor.DeviceID,
&sensor.CreationDate,
&sensor.UpdateDate,
)
if err != nil { if err != nil {
return err tx.Rollback()
return fmt.Errorf("Failed to execute statement: %v", err)
} }
} }
return nil
return tx.Commit()
}
// Migrate creates all required tables if not exist
func (postgres *Postgres) Migrate(ctx context.Context) error {
assetSource := bindata.Resource(postgresddl.AssetNames(), func(query string) ([]byte, error) {
return postgresddl.Asset(query)
})
sourceDriver, err := bindata.WithInstance(assetSource)
if err != nil {
return err
}
m, err := migrate.NewWithSourceInstance("bindata", sourceDriver, postgres.databaseURL.String())
if err != nil {
return err
}
err = m.Up()
switch {
case errors.Is(err, migrate.ErrNoChange):
return nil
default:
return err
}
} }
// SelectDevice from database // SelectDevice from database
@ -251,7 +456,7 @@ func (postgres *Postgres) SelectDevice(ctx context.Context, id string) (*types.D
queryFile := "selectDevice.sql" queryFile := "selectDevice.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -281,7 +486,7 @@ func (postgres *Postgres) SelectDevices(ctx context.Context) ([]*types.Device, e
queryFile := "selectDevices.sql" queryFile := "selectDevices.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -338,7 +543,7 @@ func (postgres *Postgres) SelectHumidity(ctx context.Context, id string) (*types
queryFile := "selectHumidity.sql" queryFile := "selectHumidity.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -361,7 +566,7 @@ func (postgres *Postgres) SelectHumidity(ctx context.Context, id string) (*types
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "humidity" measuredValue.ValueType = types.Humidity
} }
return measuredValues[0], nil return measuredValues[0], nil
@ -372,7 +577,7 @@ func (postgres *Postgres) SelectHumidities(ctx context.Context) ([]*types.Measur
queryFile := "selectHumidities.sql" queryFile := "selectHumidities.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -380,7 +585,7 @@ func (postgres *Postgres) SelectHumidities(ctx context.Context) ([]*types.Measur
return nil, err return nil, err
} }
measuredValues, err := postgres.selectMeasuredValue(tx, query, nil) measuredValues, err := postgres.selectMeasuredValue(tx, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -391,7 +596,7 @@ func (postgres *Postgres) SelectHumidities(ctx context.Context) ([]*types.Measur
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "humidity" measuredValue.ValueType = types.Humidity
} }
return measuredValues, nil return measuredValues, nil
@ -417,8 +622,8 @@ func (postgres *Postgres) selectMeasuredValue(tx *sql.Tx, query string, args ...
err := rows.Scan( err := rows.Scan(
&measuredValue.ID, &measuredValue.ID,
&measuredValue.Value, &measuredValue.Value,
&measuredValue.SensorID,
&measuredValue.Date, &measuredValue.Date,
&measuredValue.SensorID,
&measuredValue.CreationDate, &measuredValue.CreationDate,
&measuredValue.UpdateDate, &measuredValue.UpdateDate,
) )
@ -439,7 +644,7 @@ func (postgres *Postgres) SelectPressure(ctx context.Context, id string) (*types
queryFile := "selectPressure.sql" queryFile := "selectPressure.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -462,7 +667,7 @@ func (postgres *Postgres) SelectPressure(ctx context.Context, id string) (*types
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "pressure" measuredValue.ValueType = types.Pressure
} }
return measuredValues[0], nil return measuredValues[0], nil
@ -473,7 +678,7 @@ func (postgres *Postgres) SelectPressures(ctx context.Context) ([]*types.Measure
queryFile := "selectPressures.sql" queryFile := "selectPressures.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -481,7 +686,7 @@ func (postgres *Postgres) SelectPressures(ctx context.Context) ([]*types.Measure
return nil, err return nil, err
} }
measuredValues, err := postgres.selectMeasuredValue(tx, query, nil) measuredValues, err := postgres.selectMeasuredValue(tx, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -492,7 +697,7 @@ func (postgres *Postgres) SelectPressures(ctx context.Context) ([]*types.Measure
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "pressure" measuredValue.ValueType = types.Pressure
} }
return measuredValues, nil return measuredValues, nil
@ -503,7 +708,7 @@ func (postgres *Postgres) SelectSensor(ctx context.Context, id string) (*types.S
queryFile := "selectSensor.sql" queryFile := "selectSensor.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -533,7 +738,7 @@ func (postgres *Postgres) SelectSensors(ctx context.Context) ([]*types.Sensor, e
queryFile := "selectSensors.sql" queryFile := "selectSensors.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -599,7 +804,7 @@ func (postgres *Postgres) SelectTemperature(ctx context.Context, id string) (*ty
queryFile := "selectTemperature.sql" queryFile := "selectTemperature.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -622,7 +827,7 @@ func (postgres *Postgres) SelectTemperature(ctx context.Context, id string) (*ty
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "temperatures" measuredValue.ValueType = types.Temperature
} }
return measuredValues[0], nil return measuredValues[0], nil
@ -633,7 +838,7 @@ func (postgres *Postgres) SelectTemperatures(ctx context.Context) ([]*types.Meas
queryFile := "selectTemperatures.sql" queryFile := "selectTemperatures.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return nil, fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return nil, fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
@ -641,7 +846,7 @@ func (postgres *Postgres) SelectTemperatures(ctx context.Context) ([]*types.Meas
return nil, err return nil, err
} }
measuredValues, err := postgres.selectMeasuredValue(tx, query, nil) measuredValues, err := postgres.selectMeasuredValue(tx, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -652,7 +857,7 @@ func (postgres *Postgres) SelectTemperatures(ctx context.Context) ([]*types.Meas
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "temperatures" measuredValue.ValueType = types.Temperature
} }
return measuredValues, nil return measuredValues, nil
@ -663,7 +868,7 @@ func (postgres *Postgres) UpdateDevices(ctx context.Context, devices ...*types.D
queryFile := "updateDevice.sql" queryFile := "updateDevice.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
@ -703,7 +908,7 @@ func (postgres *Postgres) UpdateSensors(ctx context.Context, sensors ...*types.S
queryFile := "updateSensor.sql" queryFile := "updateSensor.sql"
query, present := postgres.queries[queryFile] query, present := postgres.queries[queryFile]
if !present { if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile) return fmt.Errorf("Postgres-Backend: File %v not found", queryFile)
} }
tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false}) tx, err := postgres.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})

View File

@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS humidities (
id CHAR(36) CONSTRAINT pk_humidities PRIMARY KEY,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP
);
ALTER TABLE humidities
ADD FOREIGN KEY (sensor_id)
REFERENCES sensors(sensor_id)
ON DELETE CASCADE
ON UPDATE CASCADE;

View File

@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS pressures (
id CHAR(36) CONSTRAINT pk_pressures PRIMARY KEY,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP
);
ALTER TABLE pressures
ADD FOREIGN KEY (sensor_id)
REFERENCES sensors(sensor_id)
ON DELETE CASCADE
ON UPDATE CASCADE;

View File

@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS temperatures (
id CHAR(36) CONSTRAINT pk_temperatures PRIMARY KEY,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP
);
ALTER TABLE temperatures
ADD FOREIGN KEY (sensor_id)
REFERENCES sensors(sensor_id)
ON DELETE CASCADE
ON UPDATE CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE devices;

View File

@ -1,7 +1,8 @@
CREATE TABLE IF NOT EXISTS devices ( CREATE TABLE devices (
device_id CHAR(36) CONSTRAINT pk_devices PRIMARY KEY, device_id CHAR(36) NOT NULL,
device_name VARCHAR(64) NOT NULL, device_name VARCHAR(64) NOT NULL,
device_location VARCHAR(64), device_location VARCHAR(64),
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, creation_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP update_date TIMESTAMP WITH TIME ZONE,
CONSTRAINT pk_devices PRIMARY KEY(device_id)
); );

View File

@ -0,0 +1 @@
DROP TABLE sensors;

View File

@ -1,5 +1,5 @@
CREATE TABLE IF NOT EXISTS sensors ( CREATE TABLE sensors (
sensor_id CHAR(36) CONSTRAINT pk_sensors PRIMARY KEY, sensor_id CHAR(36) NOT NULL,
sensor_name VARCHAR(64) NOT NULL, sensor_name VARCHAR(64) NOT NULL,
sensor_location VARCHAR(64), sensor_location VARCHAR(64),
wire_id VARCHAR(64), wire_id VARCHAR(64),
@ -10,12 +10,8 @@ CREATE TABLE IF NOT EXISTS sensors (
sensor_enabled BOOLEAN DEFAULT TRUE NOT NULL, sensor_enabled BOOLEAN DEFAULT TRUE NOT NULL,
tick_duration VARCHAR(6) NOT NULL, tick_duration VARCHAR(6) NOT NULL,
device_id CHAR(36) NOT NULL, device_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, creation_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP update_date TIMESTAMP WITH TIME ZONE,
); CONSTRAINT pk_sensors PRIMARY KEY(sensor_id),
CONSTRAINT fk_sensors_device_id FOREIGN KEY (device_id) REFERENCES devices(device_id) ON DELETE CASCADE ON UPDATE CASCADE
ALTER TABLE sensors );
ADD FOREIGN KEY (device_id)
REFERENCES devices(device_id)
ON DELETE CASCADE
ON UPDATE CASCADE;

View File

@ -0,0 +1 @@
DROP TABLE humidities;

View File

@ -0,0 +1,10 @@
CREATE TABLE humidities (
id CHAR(36) NOT NULL,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP WITH TIME ZONE NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP WITH TIME ZONE,
CONSTRAINT pk_humidites PRIMARY KEY (id),
CONSTRAINT pk_humidites_sensor_id FOREIGN KEY(sensor_id) REFERENCES sensors(sensor_id) ON DELETE CASCADE ON UPDATE CASCADE
);

View File

@ -0,0 +1 @@
DROP TABLE pressures;

View File

@ -0,0 +1,10 @@
CREATE TABLE pressures (
id CHAR(36) NOT NULL,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP WITH TIME ZONE NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP WITH TIME ZONE,
CONSTRAINT pk_pressures PRIMARY KEY(id),
CONSTRAINT pk_pressures_sensor_id FOREIGN KEY(sensor_id) REFERENCES sensors(sensor_id) ON DELETE CASCADE ON UPDATE CASCADE
);

View File

@ -0,0 +1 @@
DROP TABLE temperatures;

View File

@ -0,0 +1,10 @@
CREATE TABLE temperatures (
id CHAR(36) NOT NULL,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP WITH TIME ZONE NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP WITH TIME ZONE,
CONSTRAINT pk_temperatures PRIMARY KEY (id),
CONSTRAINT fk_temperatures_sensor_id FOREIGN KEY (sensor_id) REFERENCES sensors(sensor_id) ON DELETE CASCADE ON UPDATE CASCADE
);

View File

@ -0,0 +1,14 @@
INSERT INTO devices (
device_id,
device_name,
device_location,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (device_id)
DO
UPDATE SET
device_name = EXCLUDED.device_name,
device_location = EXCLUDED.device_location,
update_date = NOW();

View File

@ -0,0 +1,16 @@
INSERT INTO humidities (
id,
value,
date,
sensor_id,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (id)
DO
UPDATE SET
value = EXCLUDED.value,
date = EXCLUDED.date,
sensor_id = EXCLUDED.sensor_id,
update_date = NOW();

View File

@ -0,0 +1,16 @@
INSERT INTO pressures (
id,
value,
date,
sensor_id,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (id)
DO
UPDATE SET
value = EXCLUDED.value,
date = EXCLUDED.date,
sensor_id = EXCLUDED.sensor_id,
update_date = NOW();

View File

@ -0,0 +1,31 @@
INSERT INTO sensors (
sensor_id,
sensor_name,
sensor_location,
wire_id,
i2c_bus,
i2c_address,
gpio_number,
sensor_model,
sensor_enabled,
tick_duration,
device_id,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
ON CONFLICT (sensor_id)
DO
UPDATE SET
sensor_name = EXCLUDED.sensor_name,
sensor_location = EXCLUDED.sensor_location,
wire_id = EXCLUDED.wire_id,
i2c_bus = EXCLUDED.i2c_bus,
i2c_address = EXCLUDED.i2c_address,
gpio_number = EXCLUDED.gpio_number,
sensor_model = EXCLUDED.sensor_model,
sensor_enabled = EXCLUDED.sensor_enabled,
tick_duration = EXCLUDED.tick_duration,
device_id = EXCLUDED.device_id,
creation_date = EXCLUDED.creation_date,
update_date = NOW();

View File

@ -0,0 +1,16 @@
INSERT INTO temperatures (
id,
value,
date,
sensor_id,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (id)
DO
UPDATE SET
value = EXCLUDED.value,
date = EXCLUDED.date,
sensor_id = EXCLUDED.sensor_id,
update_date = NOW();

View File

@ -8,4 +8,4 @@ SELECT
FROM FROM
humidities humidities
WHERE WHERE
humidity_id = $1 id = $1

View File

@ -8,4 +8,4 @@ SELECT
FROM FROM
pressures pressures
WHERE WHERE
pressure_id = $1 id = $1

View File

@ -15,4 +15,6 @@ SELECT
FROM FROM
sensors sensors
WHERE WHERE
sensor_id = $1; sensor_id = $1
ORDER BY
sensor_name ASC;

View File

@ -8,4 +8,4 @@ SELECT
FROM FROM
temperatures temperatures
WHERE WHERE
temperature_id = $1 id = $1

View File

@ -3,17 +3,23 @@ package db
import ( import (
"context" "context"
"database/sql" "database/sql"
"errors"
"fmt" "fmt"
"net/url"
sqlite3ddl "git.cryptic.systems/volker.raschek/flucky/pkg/repository/db/sqlite3/ddl"
"git.cryptic.systems/volker.raschek/flucky/pkg/types" "git.cryptic.systems/volker.raschek/flucky/pkg/types"
"git.cryptic.systems/volker.raschek/go-logger" "git.cryptic.systems/volker.raschek/go-logger"
"github.com/golang-migrate/migrate/v4"
bindata "github.com/golang-migrate/migrate/v4/source/go_bindata"
) )
// SQLite implementation // SQLite implementation
type SQLite struct { type SQLite struct {
dbo *sql.DB databaseURL *url.URL
flogger logger.Logger dbo *sql.DB
queries map[string]string flogger logger.Logger
queries map[string]string
} }
// Close closes the database and prevents new queries from starting. Close then // Close closes the database and prevents new queries from starting. Close then
@ -82,6 +88,42 @@ func (sqlite *SQLite) DeleteSensors(ctx context.Context, sensorIDs ...string) er
return tx.Commit() return tx.Commit()
} }
func (sqlite *SQLite) ExistDevice(ctx context.Context, deviceID string) (bool, error) {
queryFile := "existDevice.sql"
query, present := sqlite.queries[queryFile]
if !present {
return false, fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
}
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
if err != nil {
return false, fmt.Errorf("Failed to begin new transaction: %v", err)
}
stmt, err := tx.Prepare(query)
if err != nil {
return false, fmt.Errorf("Failed to prepare statement: %v", err)
}
defer stmt.Close()
rows, err := stmt.Query()
if err != nil {
return false, fmt.Errorf("Failed to query statement: %v", err)
}
defer rows.Close()
var t bool
for rows.Next() {
rows.Scan(&t)
}
return t, nil
}
func (sqlite *SQLite) ExistDevices(ctx context.Context, deviceIDs ...string) (map[string]bool, error) {
return nil, nil
}
// InsertDevices into the database // InsertDevices into the database
func (sqlite *SQLite) InsertDevices(ctx context.Context, devices ...*types.Device) error { func (sqlite *SQLite) InsertDevices(ctx context.Context, devices ...*types.Device) error {
queryFile := "insertDevice.sql" queryFile := "insertDevice.sql"
@ -114,7 +156,7 @@ func (sqlite *SQLite) InsertDevices(ctx context.Context, devices ...*types.Devic
// InsertMeasuredValues into the database // InsertMeasuredValues into the database
func (sqlite *SQLite) InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error { func (sqlite *SQLite) InsertMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error {
splittedMeasuredValues := make(map[string][]*types.MeasuredValue, 0) splittedMeasuredValues := make(map[types.MeasuredValueType][]*types.MeasuredValue, 0)
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok { if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok {
@ -163,11 +205,11 @@ func (sqlite *SQLite) InsertMeasuredValues(ctx context.Context, measuredValues .
var queryFile string var queryFile string
switch measuredValueType { switch measuredValueType {
case "humidity": case types.Humidity:
queryFile = "insertHumidity.sql" queryFile = "insertHumidity.sql"
case "pressure": case types.Pressure:
queryFile = "insertPressure.sql" queryFile = "insertPressure.sql"
case "temperature": case types.Temperature:
queryFile = "insertTemperature.sql" queryFile = "insertTemperature.sql"
default: default:
tx.Rollback() tx.Rollback()
@ -184,6 +226,152 @@ func (sqlite *SQLite) InsertMeasuredValues(ctx context.Context, measuredValues .
return tx.Commit() return tx.Commit()
} }
// InsertOrUpdateMeasuredValues into the database
func (sqlite *SQLite) InsertOrUpdateMeasuredValues(ctx context.Context, measuredValues ...*types.MeasuredValue) error {
splittedMeasuredValues := make(map[types.MeasuredValueType][]*types.MeasuredValue, 0)
for _, measuredValue := range measuredValues {
if _, ok := splittedMeasuredValues[measuredValue.ValueType]; !ok {
splittedMeasuredValues[measuredValue.ValueType] = make([]*types.MeasuredValue, 0)
}
splittedMeasuredValues[measuredValue.ValueType] = append(splittedMeasuredValues[measuredValue.ValueType], measuredValue)
}
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
if err != nil {
return fmt.Errorf("Failed to begin new transaction: %v", err)
}
// General insert function
insert := func(tx *sql.Tx, queryFile string, measuredValues []*types.MeasuredValue) error {
query, present := sqlite.queries[queryFile]
if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
}
stmt, err := tx.Prepare(query)
if err != nil {
return fmt.Errorf("Failed to prepare statement: %v", err)
}
defer stmt.Close()
for _, measuredValue := range measuredValues {
_, err := stmt.Exec(
&measuredValue.ID,
&measuredValue.Value,
&measuredValue.Date,
&measuredValue.SensorID,
&measuredValue.CreationDate,
&measuredValue.UpdateDate,
)
if err != nil {
return fmt.Errorf("Failed to execute statement: %v", err)
}
}
return nil
}
for measuredValueType, measuredValues := range splittedMeasuredValues {
var queryFile string
switch measuredValueType {
case types.Humidity:
queryFile = "insertOrUpdateHumidity.sql"
case types.Pressure:
queryFile = "insertOrUpdatePressure.sql"
case types.Temperature:
queryFile = "insertOrUpdateTemperature.sql"
default:
tx.Rollback()
return fmt.Errorf("Measured value type %v not supported", measuredValueType)
}
err := insert(tx, queryFile, measuredValues)
if err != nil {
tx.Rollback()
return err
}
}
return tx.Commit()
}
// InsertOrUpdateDevices into the database
func (sqlite *SQLite) InsertOrUpdateDevices(ctx context.Context, devices ...*types.Device) error {
queryFile := "insertOrUpdateDevice.sql"
query, present := sqlite.queries[queryFile]
if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
}
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
if err != nil {
return fmt.Errorf("Failed to begin new transaction: %v", err)
}
stmt, err := tx.Prepare(query)
if err != nil {
return fmt.Errorf("Failed to prepare statement: %v", err)
}
defer stmt.Close()
for _, device := range devices {
_, err = stmt.Exec(&device.ID, &device.Name, &device.Location, &device.CreationDate, &device.UpdateDate)
if err != nil {
tx.Rollback()
return fmt.Errorf("Failed to execute statement: %v", err)
}
}
return tx.Commit()
}
// InsertOrUpdateSensors into the database
func (sqlite *SQLite) InsertOrUpdateSensors(ctx context.Context, sensors ...*types.Sensor) error {
queryFile := "insertOrUpdateSensor.sql"
query, present := sqlite.queries[queryFile]
if !present {
return fmt.Errorf("SQLite-Backend: File %v not found", queryFile)
}
tx, err := sqlite.dbo.BeginTx(ctx, &sql.TxOptions{ReadOnly: false})
if err != nil {
return fmt.Errorf("Failed to begin new transaction: %v", err)
}
stmt, err := tx.Prepare(query)
if err != nil {
return fmt.Errorf("Failed to prepare statement: %v", err)
}
defer stmt.Close()
for _, sensor := range sensors {
_, err = stmt.Exec(
&sensor.ID,
&sensor.Name,
&sensor.Location,
&sensor.WireID,
&sensor.I2CBus,
&sensor.I2CAddress,
&sensor.GPIONumber,
&sensor.Model,
&sensor.Enabled,
&sensor.TickDuration,
&sensor.DeviceID,
&sensor.CreationDate,
&sensor.UpdateDate,
)
if err != nil {
tx.Rollback()
return fmt.Errorf("Failed to execute statement: %v", err)
}
}
return tx.Commit()
}
// InsertSensors into the database // InsertSensors into the database
func (sqlite *SQLite) InsertSensors(ctx context.Context, sensors ...*types.Sensor) error { func (sqlite *SQLite) InsertSensors(ctx context.Context, sensors ...*types.Sensor) error {
queryFile := "insertSensor.sql" queryFile := "insertSensor.sql"
@ -228,21 +416,29 @@ func (sqlite *SQLite) InsertSensors(ctx context.Context, sensors ...*types.Senso
return tx.Commit() return tx.Commit()
} }
// Scheme creates all required tables if not exist // Migrate creates all required tables if not exist
func (sqlite *SQLite) Scheme(ctx context.Context) error { func (sqlite *SQLite) Migrate(ctx context.Context) error {
for _, query := range []string{ assetSource := bindata.Resource(sqlite3ddl.AssetNames(), func(query string) ([]byte, error) {
sqlite.queries["createTableDevices.sql"], return sqlite3ddl.Asset(query)
sqlite.queries["createTableSensors.sql"], })
sqlite.queries["createTableHumidities.sql"],
sqlite.queries["createTablePressures.sql"], sourceDriver, err := bindata.WithInstance(assetSource)
sqlite.queries["createTableTemperatures.sql"], if err != nil {
} { return err
_, err := sqlite.dbo.ExecContext(ctx, query) }
if err != nil {
return err m, err := migrate.NewWithSourceInstance("bindata", sourceDriver, sqlite.databaseURL.String())
} if err != nil {
return err
}
err = m.Up()
switch {
case errors.Is(err, migrate.ErrNoChange):
return nil
default:
return err
} }
return nil
} }
// SelectDevice from database // SelectDevice from database
@ -312,6 +508,7 @@ func (sqlite *SQLite) selectDevices(tx *sql.Tx, query string, args ...interface{
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to query statement: %v", err) return nil, fmt.Errorf("Failed to query statement: %v", err)
} }
defer rows.Close()
devices := make([]*types.Device, 0) devices := make([]*types.Device, 0)
for rows.Next() { for rows.Next() {
@ -360,7 +557,7 @@ func (sqlite *SQLite) SelectHumidity(ctx context.Context, id string) (*types.Mea
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "humidity" measuredValue.ValueType = types.Humidity
} }
return measuredValues[0], nil return measuredValues[0], nil
@ -379,7 +576,7 @@ func (sqlite *SQLite) SelectHumidities(ctx context.Context) ([]*types.MeasuredVa
return nil, err return nil, err
} }
measuredValues, err := sqlite.selectMeasuredValue(tx, query, nil) measuredValues, err := sqlite.selectMeasuredValue(tx, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -390,7 +587,7 @@ func (sqlite *SQLite) SelectHumidities(ctx context.Context) ([]*types.MeasuredVa
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "humidity" measuredValue.ValueType = types.Humidity
} }
return measuredValues, nil return measuredValues, nil
@ -409,6 +606,7 @@ func (sqlite *SQLite) selectMeasuredValue(tx *sql.Tx, query string, args ...inte
tx.Rollback() tx.Rollback()
return nil, err return nil, err
} }
defer rows.Close()
measuredValues := make([]*types.MeasuredValue, 0) measuredValues := make([]*types.MeasuredValue, 0)
for rows.Next() { for rows.Next() {
@ -416,8 +614,8 @@ func (sqlite *SQLite) selectMeasuredValue(tx *sql.Tx, query string, args ...inte
err := rows.Scan( err := rows.Scan(
&measuredValue.ID, &measuredValue.ID,
&measuredValue.Value, &measuredValue.Value,
&measuredValue.SensorID,
&measuredValue.Date, &measuredValue.Date,
&measuredValue.SensorID,
&measuredValue.CreationDate, &measuredValue.CreationDate,
&measuredValue.UpdateDate, &measuredValue.UpdateDate,
) )
@ -461,7 +659,7 @@ func (sqlite *SQLite) SelectPressure(ctx context.Context, id string) (*types.Mea
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "pressure" measuredValue.ValueType = types.Pressure
} }
return measuredValues[0], nil return measuredValues[0], nil
@ -480,7 +678,7 @@ func (sqlite *SQLite) SelectPressures(ctx context.Context) ([]*types.MeasuredVal
return nil, err return nil, err
} }
measuredValues, err := sqlite.selectMeasuredValue(tx, query, nil) measuredValues, err := sqlite.selectMeasuredValue(tx, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -491,7 +689,7 @@ func (sqlite *SQLite) SelectPressures(ctx context.Context) ([]*types.MeasuredVal
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "pressure" measuredValue.ValueType = types.Pressure
} }
return measuredValues, nil return measuredValues, nil
@ -564,6 +762,7 @@ func (sqlite *SQLite) selectSensors(tx *sql.Tx, query string, args ...interface{
if err != nil { if err != nil {
return nil, fmt.Errorf("Failed to query statement: %v", err) return nil, fmt.Errorf("Failed to query statement: %v", err)
} }
defer rows.Close()
sensors := make([]*types.Sensor, 0) sensors := make([]*types.Sensor, 0)
for rows.Next() { for rows.Next() {
@ -621,7 +820,7 @@ func (sqlite *SQLite) SelectTemperature(ctx context.Context, id string) (*types.
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "temperatures" measuredValue.ValueType = types.Temperature
} }
return measuredValues[0], nil return measuredValues[0], nil
@ -640,7 +839,7 @@ func (sqlite *SQLite) SelectTemperatures(ctx context.Context) ([]*types.Measured
return nil, err return nil, err
} }
measuredValues, err := sqlite.selectMeasuredValue(tx, query, nil) measuredValues, err := sqlite.selectMeasuredValue(tx, query)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -651,7 +850,7 @@ func (sqlite *SQLite) SelectTemperatures(ctx context.Context) ([]*types.Measured
} }
for _, measuredValue := range measuredValues { for _, measuredValue := range measuredValues {
measuredValue.ValueType = "temperatures" measuredValue.ValueType = types.Temperature
} }
return measuredValues, nil return measuredValues, nil

View File

@ -1,7 +0,0 @@
CREATE TABLE IF NOT EXISTS devices (
device_id CHAR(36) PRIMARY KEY,
device_name VARCHAR(64) NOT NULL,
device_location VARCHAR(64),
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP
);

View File

@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS humidities (
id CHAR(36) PRIMARY KEY,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP,
FOREIGN KEY(sensor_id) REFERENCES sensors(sensor_id)
);

View File

@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS pressures (
id CHAR(36) PRIMARY KEY,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP,
FOREIGN KEY(sensor_id) REFERENCES sensors(sensor_id)
);

View File

@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS temperatures (
id CHAR(36) PRIMARY KEY,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_date TIMESTAMP,
FOREIGN KEY(sensor_id) REFERENCES sensors(sensor_id)
);

View File

@ -0,0 +1 @@
DROP TABLE devices;

View File

@ -0,0 +1,8 @@
CREATE TABLE devices (
device_id CHAR(36) NOT NULL,
device_name VARCHAR(64) NOT NULL,
device_location VARCHAR(64),
creation_date TIMESTAMP DEFAULT (datetime('now', 'localtime')) NOT NULL,
update_date TIMESTAMP,
CONSTRAINT pk_devices PRIMARY KEY (device_id)
);

View File

@ -0,0 +1 @@
DROP TABLE sensors;

View File

@ -1,16 +1,17 @@
CREATE TABLE IF NOT EXISTS sensors ( CREATE TABLE sensors (
sensor_id CHAR(36) PRIMARY KEY, sensor_id CHAR(36) NOT NULL,
sensor_name VARCHAR(64) NOT NULL, sensor_name VARCHAR(64) NOT NULL,
sensor_location VARCHAR(64), sensor_location VARCHAR(64),
wire_id VARCHAR(64), wire_id VARCHAR(64),
i2c_bus VARCHAR(255), i2c_bus VARCHAR(255),
i2c_address VARCHAR(12), i2c_address VARCHAR(12),
gpio_number VARCHAR(6), gpio_number VARCHAR(6),
sensor_model VARCHAR(16) NOT NULL, sensor_model VARCHAR(16) NOT NULL,
sensor_enabled INTEGER(1) DEFAULT 1 NOT NULL, sensor_enabled INTEGER(1) DEFAULT 1 NOT NULL,
tick_duration VARCHAR(6) NOT NULL, tick_duration VARCHAR(6) NOT NULL,
device_id CHAR(36) NOT NULL, device_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, creation_date TIMESTAMP DEFAULT (datetime('now', 'localtime')) NOT NULL,
update_date TIMESTAMP, update_date TIMESTAMP,
FOREIGN KEY(device_id) REFERENCES devices(device_id) CONSTRAINT pk_sensors PRIMARY KEY(sensor_id),
CONSTRAINT fk_sensors_device_id FOREIGN KEY(device_id) REFERENCES devices(device_id) ON DELETE CASCADE ON UPDATE CASCADE
); );

View File

@ -0,0 +1 @@
DROP TABLE humidities;

View File

@ -0,0 +1,10 @@
CREATE TABLE humidities (
id CHAR(36) NOT NULL,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT (datetime('now', 'localtime')) NOT NULL,
update_date TIMESTAMP,
CONSTRAINT pk_humidities PRIMARY KEY(id),
CONSTRAINT fk_humidities_sensor_id FOREIGN KEY(sensor_id) REFERENCES sensors(sensor_id) ON DELETE CASCADE ON UPDATE CASCADE
);

View File

@ -0,0 +1 @@
DROP TABLE humidities;

View File

@ -0,0 +1,10 @@
CREATE TABLE pressures (
id CHAR(36) NOT NULL,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT (datetime('now', 'localtime')) NOT NULL,
update_date TIMESTAMP,
CONSTRAINT pk_pressures PRIMARY KEY(id),
CONSTRAINT fk_pressures_sensor_id FOREIGN KEY(sensor_id) REFERENCES sensors(sensor_id) ON DELETE CASCADE ON UPDATE CASCADE
);

View File

@ -0,0 +1 @@
DROP TABLE temperatures;

View File

@ -0,0 +1,10 @@
CREATE TABLE temperatures (
id CHAR(36) NOT NULL,
value NUMERIC(10,3) NOT NULL,
date TIMESTAMP NOT NULL,
sensor_id CHAR(36) NOT NULL,
creation_date TIMESTAMP DEFAULT (datetime('now', 'localtime')) NOT NULL,
update_date TIMESTAMP,
CONSTRAINT pk_temperatures PRIMARY KEY(id),
CONSTRAINT fk_temperatures_id FOREIGN KEY(sensor_id) REFERENCES sensors(sensor_id) ON DELETE CASCADE ON UPDATE CASCADE
);

View File

@ -0,0 +1,14 @@
INSERT INTO devices (
device_id,
device_name,
device_location,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (device_id)
DO
UPDATE SET
device_name = EXCLUDED.device_name,
device_location = EXCLUDED.device_location,
update_date = date('now');

View File

@ -0,0 +1,16 @@
INSERT INTO humidities (
id,
value,
date,
sensor_id,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (id)
DO
UPDATE SET
value = EXCLUDED.value,
date = EXCLUDED.date,
sensor_id = EXCLUDED.sensor_id,
update_date = date('now');

View File

@ -0,0 +1,16 @@
INSERT INTO pressures (
id,
value,
date,
sensor_id,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (id)
DO
UPDATE SET
value = EXCLUDED.value,
date = EXCLUDED.date,
sensor_id = EXCLUDED.sensor_id,
update_date = date('now');

View File

@ -0,0 +1,31 @@
INSERT INTO sensors (
sensor_id,
sensor_name,
sensor_location,
wire_id,
i2c_bus,
i2c_address,
gpio_number,
sensor_model,
sensor_enabled,
tick_duration,
device_id,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
ON CONFLICT (sensor_id)
DO
UPDATE SET
sensor_name = EXCLUDED.sensor_name,
sensor_location = EXCLUDED.sensor_location,
wire_id = EXCLUDED.wire_id,
i2c_bus = EXCLUDED.i2c_bus,
i2c_address = EXCLUDED.i2c_address,
gpio_number = EXCLUDED.gpio_number,
sensor_model = EXCLUDED.sensor_model,
sensor_enabled = EXCLUDED.sensor_enabled,
tick_duration = EXCLUDED.tick_duration,
device_id = EXCLUDED.device_id,
creation_date = EXCLUDED.creation_date,
update_date = date('now');

View File

@ -0,0 +1,16 @@
INSERT INTO temperatures (
id,
value,
date,
sensor_id,
creation_date,
update_date
)
VALUES ($1, $2, $3, $4, $5, $6)
ON CONFLICT (id)
DO
UPDATE SET
value = EXCLUDED.value,
date = EXCLUDED.date,
sensor_id = EXCLUDED.sensor_id,
update_date = date('now');

View File

@ -8,4 +8,4 @@ SELECT
FROM FROM
humidities humidities
WHERE WHERE
humidity_id = $1 id = $1

View File

@ -8,4 +8,4 @@ SELECT
FROM FROM
pressures pressures
WHERE WHERE
pressure_id = $1 id = $1

View File

@ -8,4 +8,4 @@ SELECT
FROM FROM
temperatures temperatures
WHERE WHERE
temperature_id = $1 id = $1

View File

@ -2,6 +2,7 @@ package repository
import ( import (
"context" "context"
"fmt"
"net/url" "net/url"
"strings" "strings"
@ -26,6 +27,21 @@ func (repo *Repository) AddMeasuredValues(measuredValues ...*types.MeasuredValue
return repo.database.InsertMeasuredValues(context.Background(), measuredValues...) return repo.database.InsertMeasuredValues(context.Background(), measuredValues...)
} }
// AddOrUpdateDevices to the repository
func (repo *Repository) AddOrUpdateDevices(devices ...*types.Device) error {
return repo.database.InsertOrUpdateDevices(context.Background(), devices...)
}
// AddOrUpdateMeasuredValues to the repository
func (repo *Repository) AddOrUpdateMeasuredValues(measuredValues ...*types.MeasuredValue) error {
return repo.database.InsertOrUpdateMeasuredValues(context.Background(), measuredValues...)
}
// AddOrUpdateSensors to the repository
func (repo *Repository) AddOrUpdateSensors(sensors ...*types.Sensor) error {
return repo.database.InsertOrUpdateSensors(context.Background(), sensors...)
}
// AddSensors to the repository // AddSensors to the repository
func (repo *Repository) AddSensors(sensors ...*types.Sensor) error { func (repo *Repository) AddSensors(sensors ...*types.Sensor) error {
return repo.database.InsertSensors(context.Background(), sensors...) return repo.database.InsertSensors(context.Background(), sensors...)
@ -90,6 +106,16 @@ func (repo *Repository) GetDevices() ([]*types.Device, error) {
return repo.database.SelectDevices(context.Background()) return repo.database.SelectDevices(context.Background())
} }
// GetHumidity returns a humidity value by id
func (repo *Repository) GetHumidity(humidityID string) (*types.MeasuredValue, error) {
return repo.database.SelectHumidity(context.Background(), humidityID)
}
// GetPressure returns a pressure value by id
func (repo *Repository) GetPressure(pressureID string) (*types.MeasuredValue, error) {
return repo.database.SelectPressure(context.Background(), pressureID)
}
// GetSensor returns a sensor by his id. If no sensor has been found, the // GetSensor returns a sensor by his id. If no sensor has been found, the
// function returns nil. // function returns nil.
func (repo *Repository) GetSensor(sensorID string) (*types.Sensor, error) { func (repo *Repository) GetSensor(sensorID string) (*types.Sensor, error) {
@ -98,8 +124,28 @@ func (repo *Repository) GetSensor(sensorID string) (*types.Sensor, error) {
// GetSensors returns all sensors. If no sensors has been found, the function // GetSensors returns all sensors. If no sensors has been found, the function
// returns nil. // returns nil.
func (repo *Repository) GetSensors() ([]*types.Sensor, error) { func (repo *Repository) GetSensors(models ...string) ([]*types.Sensor, error) {
return repo.database.SelectSensors(context.Background()) sensors, err := repo.database.SelectSensors(context.Background())
switch {
case err != nil:
return nil, err
case len(models) > 0:
cachedSensors := make([]*types.Sensor, 0)
LOOP:
for i := range sensors {
for j := range models {
if strings.ToLower(sensors[i].Model) == strings.ToLower(models[j]) {
cachedSensors = append(cachedSensors, sensors[i])
continue LOOP
}
}
}
return cachedSensors, nil
case len(models) <= 0:
fallthrough
default:
return sensors, err
}
} }
// GetSensorsByDeviceID returns all sensors by a device id. If no sensor has // GetSensorsByDeviceID returns all sensors by a device id. If no sensor has
@ -120,6 +166,11 @@ func (repo *Repository) GetSensorsByDeviceID(deviceID string) ([]*types.Sensor,
return cachedSensors, nil return cachedSensors, nil
} }
// GetTemperature returns a temperature value by id
func (repo *Repository) GetTemperature(pressureID string) (*types.MeasuredValue, error) {
return repo.database.SelectTemperature(context.Background(), pressureID)
}
// RemoveDevices removes devices by their ids from the repository. Additional // RemoveDevices removes devices by their ids from the repository. Additional
// all sensors and measured values, which are in relation with the device // all sensors and measured values, which are in relation with the device
// respectively the sensors will also be deleted. // respectively the sensors will also be deleted.
@ -194,3 +245,98 @@ func New(dsnURL *url.URL, flogger logger.Logger) (*Repository, error) {
database: database, database: database,
}, nil }, nil
} }
type OptImport struct {
Sensors bool
Humidities bool
Pressures bool
Temperatures bool
}
func Import(sourceDSNURL *url.URL, destDNSURL *url.URL, flogger logger.Logger, optImport OptImport) error {
importMap := map[string]bool{
"humidities": optImport.Humidities,
"pressures": optImport.Pressures,
"temperatures": optImport.Temperatures,
}
// enable sensors if one measured value is enabled
if !optImport.Sensors {
for key, value := range importMap {
if value {
flogger.Info("Enable import option sensors. It's required as foreign key for %v", key)
optImport.Sensors = true
}
}
}
// Initialize source repository
sourceRepo, err := New(sourceDSNURL, flogger)
if err != nil {
return fmt.Errorf("Failed to open the source repo: %w", err)
}
defer sourceRepo.Close()
// Initialize destination repository
destRepo, err := New(destDNSURL, flogger)
if err != nil {
return fmt.Errorf("Failed to open the destination repo: %w", err)
}
defer destRepo.Close()
// AddOrUpdate: Devices
ctx := context.Background()
devices, err := sourceRepo.database.SelectDevices(ctx)
if err != nil {
return fmt.Errorf("Failed to fetch devices from source repo: %w", err)
}
flogger.Debug("Found %v devices", len(devices))
for i := range devices {
err := destRepo.AddOrUpdateDevices(devices[i])
if err != nil {
return fmt.Errorf("Failed to add or update device %v into dest repo: %w", devices[i].Name, err)
}
}
// AddOrUpdate: Sensors
if optImport.Sensors {
sensors, err := sourceRepo.database.SelectSensors(ctx)
if err != nil {
return fmt.Errorf("Failed to fetch sensors from source repo: %w", err)
}
flogger.Debug("Found %v sensors", len(sensors))
for i := range sensors {
err := destRepo.AddOrUpdateSensors(sensors[i])
if err != nil {
return fmt.Errorf("Failed to add or update sensor %v into dest repo: %w", sensors[i].Name, err)
}
}
}
for key, f := range map[string]func(context.Context) ([]*types.MeasuredValue, error){
"humidities": sourceRepo.database.SelectHumidities,
"pressures": sourceRepo.database.SelectPressures,
"temperatures": sourceRepo.database.SelectTemperatures,
} {
if importMap[key] {
measuredValues, err := f(ctx)
if err != nil {
return fmt.Errorf("Failed to select %v from source repo: %w", key, err)
}
flogger.Debug("Found %v %v values", len(measuredValues), key)
err = destRepo.AddOrUpdateMeasuredValues(measuredValues...)
if err != nil {
return fmt.Errorf("Failed to add or update %v into dest repo: %w", key, err)
}
}
}
return nil
}

View File

@ -12,13 +12,15 @@ import (
"testing" "testing"
"time" "time"
"git.cryptic.systems/volker.raschek/dockerutils"
"git.cryptic.systems/volker.raschek/flucky/pkg/repository" "git.cryptic.systems/volker.raschek/flucky/pkg/repository"
"git.cryptic.systems/volker.raschek/flucky/pkg/testutils/dockerutils"
"git.cryptic.systems/volker.raschek/flucky/pkg/types" "git.cryptic.systems/volker.raschek/flucky/pkg/types"
"git.cryptic.systems/volker.raschek/go-logger" "git.cryptic.systems/volker.raschek/go-logger"
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
_ "github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/database/sqlite3"
_ "github.com/lib/pq" _ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
@ -135,7 +137,47 @@ func testBackend(t *testing.T, repo *repository.Repository) {
device, err = repo.GetDevice(expectedDevice.ID) device, err = repo.GetDevice(expectedDevice.ID)
require.NoError(err) require.NoError(err)
// require.JSONEq(jsonEncoder(expectedDevice), jsonEncoder(device)) require.NotEmpty(device)
require.Equal(expectedDevice.ID, device.ID)
require.Equal(expectedDevice.Name, device.Name)
require.Equal(expectedDevice.Location, device.Location)
// Test: AddOrUpdateDevices
location = "MySweetLocation"
expectedDevice = &types.Device{
ID: "9d8c59a5-7927-4a7c-ad48-dbf5405ffd68",
Name: "MySweetDevice",
Location: &location,
CreationDate: *timeNow(require),
}
err = repo.AddOrUpdateDevices(expectedDevice)
require.NoError(err)
// time.Sleep(time.Minute * 10)
device, err = repo.GetDevice(expectedDevice.ID)
require.NoError(err)
require.NotEmpty(device)
require.Equal(expectedDevice.ID, device.ID)
require.Equal(expectedDevice.Name, device.Name)
require.Equal(expectedDevice.Location, device.Location)
location = "MyUglyLocation"
expectedDevice = &types.Device{
ID: "9d8c59a5-7927-4a7c-ad48-dbf5405ffd68",
Name: "MyUglyDevice",
Location: &location,
CreationDate: *timeNow(require),
}
err = repo.AddOrUpdateDevices(expectedDevice)
require.NoError(err)
device, err = repo.GetDevice(expectedDevice.ID)
require.NoError(err)
require.NotEmpty(device)
require.Equal(expectedDevice.ID, device.ID)
require.Equal(expectedDevice.Name, device.Name)
require.Equal(expectedDevice.Location, device.Location)
var ( var (
wireID = "50473fdc-f6ef-4227-b3c4-484d8e9c1323" wireID = "50473fdc-f6ef-4227-b3c4-484d8e9c1323"
@ -144,7 +186,7 @@ func testBackend(t *testing.T, repo *repository.Repository) {
expectedSensors = []*types.Sensor{ expectedSensors = []*types.Sensor{
{ {
ID: "0f8b88b0-c20d-42b2-ab51-b09ca99c0752", ID: "0f8b88b0-c20d-42b2-ab51-b09ca99c0752",
Name: "e1fbdbe9-cebf-42ed-8065-bf4882ccf76b", Name: "01fbdbe9-cebf-42ed-8065-bf4882ccf76b",
Location: "6d5b5450-1f87-47cb-b185-f64c35fae3c1", Location: "6d5b5450-1f87-47cb-b185-f64c35fae3c1",
GPIONumber: "GPIO14", GPIONumber: "GPIO14",
Model: "DHT11", Model: "DHT11",
@ -188,6 +230,26 @@ func testBackend(t *testing.T, repo *repository.Repository) {
require.NoError(err) require.NoError(err)
require.Len(sensors, len(expectedSensors)) require.Len(sensors, len(expectedSensors))
sensors, err = repo.GetSensors("BME280")
require.NoError(err)
require.Len(sensors, 1)
require.JSONEq(jsonEncoder(expectedSensors[2]), jsonEncoder(sensors[0]))
sensors, err = repo.GetSensors("DS18B20")
require.NoError(err)
require.Len(sensors, 1)
require.JSONEq(jsonEncoder(expectedSensors[1]), jsonEncoder(sensors[0]))
sensors, err = repo.GetSensors("DHT11")
require.NoError(err)
require.Len(sensors, 1)
require.JSONEq(jsonEncoder(expectedSensors[0]), jsonEncoder(sensors[0]))
sensors, err = repo.GetSensors("DHT11", "DS18B20")
require.NoError(err)
require.Len(sensors, 2)
require.JSONEq(jsonEncoder(expectedSensors[0:2]), jsonEncoder(sensors[0:2]))
// Test: GetSensor // Test: GetSensor
sensor, err := repo.GetSensor(expectedSensors[0].ID) sensor, err := repo.GetSensor(expectedSensors[0].ID)
require.NoError(err) require.NoError(err)
@ -273,12 +335,71 @@ func testBackend(t *testing.T, repo *repository.Repository) {
require.NotNil(sensor) require.NotNil(sensor)
// require.JSONEq(jsonEncoder(expectedSensor), jsonEncoder(sensor)) // require.JSONEq(jsonEncoder(expectedSensor), jsonEncoder(sensor))
// Test: AddOrUpdateSensors
expectedSensor = &types.Sensor{
ID: "9bba0e0a-e996-4242-966f-db21bab6752f",
Name: "b4ac3d0f-cef6-4e93-bd7b-e821ae5ab593",
Location: "HelloWorld",
I2CBus: nil,
I2CAddress: nil,
Model: "SDS011",
Enabled: true,
TickDuration: "6h",
DeviceID: "39b8f150-8abf-4539-9f16-7f68cedb1649",
CreationDate: *timeNow(require),
}
err = repo.AddOrUpdateSensors(expectedSensor)
require.NoError(err)
sensor, err = repo.GetSensor(expectedSensor.ID)
require.NoError(err)
require.NotEmpty(sensor)
require.Equal(expectedSensor.ID, sensor.ID)
require.Equal(expectedSensor.Name, sensor.Name)
require.Equal(expectedSensor.Location, sensor.Location)
require.Equal(expectedSensor.I2CBus, sensor.I2CBus)
require.Equal(expectedSensor.I2CAddress, sensor.I2CAddress)
require.Equal(expectedSensor.Model, sensor.Model)
require.Equal(expectedSensor.Enabled, sensor.Enabled)
require.Equal(expectedSensor.TickDuration, sensor.TickDuration)
require.Equal(expectedSensor.DeviceID, sensor.DeviceID)
expectedSensor = &types.Sensor{
ID: "9bba0e0a-e996-4242-966f-db21bab6752f",
Name: "MySweetSensor",
Location: "MySweetLocation",
I2CBus: nil,
I2CAddress: nil,
Model: "Jap",
Enabled: false,
TickDuration: "8h",
DeviceID: "39b8f150-8abf-4539-9f16-7f68cedb1649",
CreationDate: *timeNow(require),
}
err = repo.AddOrUpdateSensors(expectedSensor)
require.NoError(err)
sensor, err = repo.GetSensor(expectedSensor.ID)
require.NoError(err)
require.NotEmpty(sensor)
require.Equal(expectedSensor.ID, sensor.ID)
require.Equal(expectedSensor.Name, sensor.Name)
require.Equal(expectedSensor.Location, sensor.Location)
require.Equal(expectedSensor.I2CBus, sensor.I2CBus)
require.Equal(expectedSensor.I2CAddress, sensor.I2CAddress)
require.Equal(expectedSensor.Model, sensor.Model)
require.Equal(expectedSensor.Enabled, sensor.Enabled)
require.Equal(expectedSensor.TickDuration, sensor.TickDuration)
require.Equal(expectedSensor.DeviceID, sensor.DeviceID)
var ( var (
expectedMeasuredValues = []*types.MeasuredValue{ expectedMeasuredValues = []*types.MeasuredValue{
{ {
ID: "2e5a297a-3da0-46ae-89d2-0fcab0f1d5f7", ID: "2e5a297a-3da0-46ae-89d2-0fcab0f1d5f7",
Value: 32, Value: 32,
ValueType: "humidity", ValueType: types.Humidity,
Date: *timeNow(require), Date: *timeNow(require),
SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a",
CreationDate: *timeNow(require), CreationDate: *timeNow(require),
@ -287,7 +408,7 @@ func testBackend(t *testing.T, repo *repository.Repository) {
{ {
ID: "d69f1b62-0c6c-4058-b42c-4a2821bd220c", ID: "d69f1b62-0c6c-4058-b42c-4a2821bd220c",
Value: 38, Value: 38,
ValueType: "pressure", ValueType: types.Pressure,
Date: *timeNow(require), Date: *timeNow(require),
SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a",
CreationDate: *timeNow(require), CreationDate: *timeNow(require),
@ -296,7 +417,7 @@ func testBackend(t *testing.T, repo *repository.Repository) {
{ {
ID: "ea945ae0-412b-4561-a191-1f8f1f909fa4", ID: "ea945ae0-412b-4561-a191-1f8f1f909fa4",
Value: 35.4, Value: 35.4,
ValueType: "temperature", ValueType: types.Temperature,
Date: *timeNow(require), Date: *timeNow(require),
SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a", SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a",
CreationDate: *timeNow(require), CreationDate: *timeNow(require),
@ -308,6 +429,97 @@ func testBackend(t *testing.T, repo *repository.Repository) {
// Test: AddMeasuredValues // Test: AddMeasuredValues
err = repo.AddMeasuredValues(expectedMeasuredValues...) err = repo.AddMeasuredValues(expectedMeasuredValues...)
require.NoError(err) require.NoError(err)
for i := range expectedMeasuredValues {
var (
err error
measuredValue *types.MeasuredValue
)
switch expectedMeasuredValues[i].ValueType {
case types.Humidity:
measuredValue, err = repo.GetHumidity(expectedMeasuredValues[i].ID)
require.NoError(err)
require.NotNil(measuredValue)
case types.Pressure:
measuredValue, err = repo.GetPressure(expectedMeasuredValues[i].ID)
require.NoError(err)
require.NotNil(measuredValue)
case types.Temperature:
measuredValue, err = repo.GetTemperature(expectedMeasuredValues[i].ID)
require.NoError(err)
require.NotNil(measuredValue)
}
require.Equal(expectedMeasuredValues[i].ID, measuredValue.ID)
require.Equal(expectedMeasuredValues[i].Value, measuredValue.Value)
require.Equal(expectedMeasuredValues[i].ValueType, measuredValue.ValueType)
require.Equal(expectedMeasuredValues[i].SensorID, measuredValue.SensorID)
}
// Test: AddOrUpdateMeasuredValues
expectedMeasuredValues = []*types.MeasuredValue{
{
ID: "2e5a297a-3da0-46ae-89d2-0fcab0f1d5f7",
Value: 35,
ValueType: types.Humidity,
Date: *timeNow(require),
SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a",
CreationDate: *timeNow(require),
UpdateDate: timeNow(require),
},
{
ID: "d69f1b62-0c6c-4058-b42c-4a2821bd220c",
Value: 37,
ValueType: types.Pressure,
Date: *timeNow(require),
SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a",
CreationDate: *timeNow(require),
UpdateDate: timeNow(require),
},
{
ID: "ea945ae0-412b-4561-a191-1f8f1f909fa4",
Value: 35.4,
ValueType: types.Temperature,
Date: *timeNow(require),
SensorID: "8c74397f-8e60-4c9d-960d-3197747cef9a",
CreationDate: *timeNow(require),
UpdateDate: timeNow(require),
},
}
err = repo.AddOrUpdateMeasuredValues(expectedMeasuredValues...)
require.NoError(err)
for i := range expectedMeasuredValues {
var (
err error
measuredValue *types.MeasuredValue
)
switch expectedMeasuredValues[i].ValueType {
case types.Humidity:
measuredValue, err = repo.GetHumidity(expectedMeasuredValues[i].ID)
require.NoError(err)
require.NotNil(measuredValue)
case types.Pressure:
measuredValue, err = repo.GetPressure(expectedMeasuredValues[i].ID)
require.NoError(err)
require.NotNil(measuredValue)
case types.Temperature:
measuredValue, err = repo.GetTemperature(expectedMeasuredValues[i].ID)
require.NoError(err)
require.NotNil(measuredValue)
}
require.Equal(expectedMeasuredValues[i].ID, measuredValue.ID)
require.Equal(expectedMeasuredValues[i].Value, measuredValue.Value)
require.Equal(expectedMeasuredValues[i].ValueType, measuredValue.ValueType)
require.Equal(expectedMeasuredValues[i].SensorID, measuredValue.SensorID)
}
} }
func jsonEncoder(v interface{}) string { func jsonEncoder(v interface{}) string {
@ -320,7 +532,7 @@ func jsonEncoder(v interface{}) string {
} }
func timeNow(require *require.Assertions) *time.Time { func timeNow(require *require.Assertions) *time.Time {
now, err := time.Parse("2006-01-02 15:04:05.999999Z", time.Now().Format("2006-01-02 15:04:05.999999Z")) now, err := time.Parse("2006-01-02 15:04:05.999999-07", time.Now().Format("2006-01-02 15:04:05.999999-07"))
require.NoError(err) require.NoError(err)
return &now return &now
} }

View File

@ -66,21 +66,21 @@ func (bme280 *BME280) Read() ([]*types.MeasuredValue, error) {
{ {
ID: uuid.NewV4().String(), ID: uuid.NewV4().String(),
Value: float64(humidityValue), Value: float64(humidityValue),
ValueType: "humidity", ValueType: types.Humidity,
Date: format.FormatedTime(), Date: format.FormatedTime(),
SensorID: bme280.ID, SensorID: bme280.ID,
}, },
{ {
ID: uuid.NewV4().String(), ID: uuid.NewV4().String(),
Value: float64(pressureValue), Value: float64(pressureValue),
ValueType: "pressure", ValueType: types.Pressure,
Date: format.FormatedTime(), Date: format.FormatedTime(),
SensorID: bme280.ID, SensorID: bme280.ID,
}, },
{ {
ID: uuid.NewV4().String(), ID: uuid.NewV4().String(),
Value: float64(temperatureValue), Value: float64(temperatureValue),
ValueType: "temperature", ValueType: types.Temperature,
Date: format.FormatedTime(), Date: format.FormatedTime(),
SensorID: bme280.ID, SensorID: bme280.ID,
}, },

View File

@ -42,14 +42,14 @@ func (dht11 *DHT11) Read() ([]*types.MeasuredValue, error) {
{ {
ID: uuid.NewV4().String(), ID: uuid.NewV4().String(),
Value: float64(humidityValue), Value: float64(humidityValue),
ValueType: "humidity", ValueType: types.Humidity,
Date: format.FormatedTime(), Date: format.FormatedTime(),
SensorID: dht11.ID, SensorID: dht11.ID,
}, },
{ {
ID: uuid.NewV4().String(), ID: uuid.NewV4().String(),
Value: float64(temperatureValue), Value: float64(temperatureValue),
ValueType: "temperature", ValueType: types.Temperature,
Date: format.FormatedTime(), Date: format.FormatedTime(),
SensorID: dht11.ID, SensorID: dht11.ID,
}, },

View File

@ -42,14 +42,14 @@ func (dht22 *DHT22) Read() ([]*types.MeasuredValue, error) {
{ {
ID: uuid.NewV4().String(), ID: uuid.NewV4().String(),
Value: float64(humidityValue), Value: float64(humidityValue),
ValueType: "humidity", ValueType: types.Humidity,
Date: format.FormatedTime(), Date: format.FormatedTime(),
SensorID: dht22.ID, SensorID: dht22.ID,
}, },
{ {
ID: uuid.NewV4().String(), ID: uuid.NewV4().String(),
Value: float64(temperatureValue), Value: float64(temperatureValue),
ValueType: "temperature", ValueType: types.Temperature,
Date: format.FormatedTime(), Date: format.FormatedTime(),
SensorID: dht22.ID, SensorID: dht22.ID,
}, },

View File

@ -59,7 +59,7 @@ func (ds18b20 *DS18B20) Read() ([]*types.MeasuredValue, error) {
{ {
ID: uuid.NewV4().String(), ID: uuid.NewV4().String(),
Value: float64(temperatureValue), Value: float64(temperatureValue),
ValueType: "temperature", ValueType: types.Temperature,
Date: format.FormatedTime(), Date: format.FormatedTime(),
SensorID: ds18b20.ID, SensorID: ds18b20.ID,
}, },

View File

@ -7,7 +7,8 @@ import (
) )
type Sensor interface { type Sensor interface {
GetID() string
GetTicker() *time.Ticker GetTicker() *time.Ticker
// Read single measured values from sensor
Read() ([]*types.MeasuredValue, error) Read() ([]*types.MeasuredValue, error)
} }

Some files were not shown because too many files have changed in this diff Show More