diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..8197510 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,55 @@ +name: Tests + +on: + push: + branches: + - master + pull_request: + +jobs: + run-tests: + runs-on: ubuntu-latest + strategy: + matrix: + go: [ '1.*' ] + name: Run tests + steps: + - uses: actions/checkout@v2 + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go }} + - name: Get dependencies + run: go get -v -t -d ./... + - name: Test + run: go test -race ./... + static-checks: + runs-on: ubuntu-latest + strategy: + matrix: + go: [ '1.*' ] + name: Static checks + steps: + - uses: actions/checkout@v2 + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go }} + - name: Get dependencies + run: go get -v -t -d ./... + - name: Go Vet + run: go vet ./... + - name: Go Fmt + run: | + fmt=$(gofmt -l .) + test -z $fmt || (echo "please run gofmt" ; echo $fmt ; exit 1) + - name: Go Lint + run: go run golang.org/x/lint/golint -set_exit_status $(go list ./...) + - name: Go Cyclo + run: go run github.com/fzipp/gocyclo/cmd/gocyclo -top 30 -ignore graphql . + - name: Spelling + run: | + find . -type f -name '*.go' | xargs go run github.com/client9/misspell/cmd/misspell -error + find . -type f -name '*.md' | xargs go run github.com/client9/misspell/cmd/misspell -error + - name: In effective assignments + run: go run github.com/gordonklaus/ineffassign . \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dc6f281..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: go - -go: - - 1.x - -install: true - -script: - - set -e - - fmt=$(gofmt -l .) - - test -z $fmt || (echo "please run gofmt" ; echo $fmt ; exit 1) - - go test -race -vet=all ./... - -jobs: - include: - - stage: testrecent - go: 1.x - script: - # test is done only for recent version. - # Older versions might include other files during compilation and may therefore generate different go.mod files - - go generate ./... - # Bug in swag results in Flaky swagger docs - see https://github.com/swaggo/swag/issues/721 - #- git diff --quiet || (echo 'generated go files are not up to date, check go generate, go.sum and go.mod' ; git diff ; exit 1) - - git diff --quiet -- . ":(exclude)docs" || (echo 'generated go files are not up to date, check go generate, go.sum and go.mod' ; git diff -- . ":(exclude)docs"; exit 1) diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8b7d618 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog + +## v0.0.3-beta [upcoming] + +* Update Readme's to reflect current configs / fix typos +* Update CueConfig to match used configurations +* Remove unused / commented out code +* Add module_tests +* Fix non-working SearchBy implementation +* Fix non-working Bleve pagination +* Add config for additional Facets/Sorting +* Allow different CSV delimiter via config +* Add support for stock level / saleable / retailer name attribute +* Add active Facets to search response +* Avoid indexing foreign language attributes +* Remove default title sort option + +## v0.0.2-beta + +**commercesearch** +* In memory repository was refactored +* Belve implementation was added + +**csvindexing** +* Module was added + +**emailplaceorder** +* Module was added + +## v0.0.1-beta +* First version containing in memory product / category repository \ No newline at end of file diff --git a/Readme.md b/Readme.md index 607607e..7aee2d2 100644 --- a/Readme.md +++ b/Readme.md @@ -1,45 +1,43 @@ [![Build Status](https://travis-ci.org/i-love-flamingo/flamingo-commerce-adapter-standalone.svg?branch=master)](https://travis-ci.org/i-love-flamingo/flamingo-commerce-adapter-standalone?branch=master) +# Flamingo Commerce Adapters Standalone -# Flamingo Commerce Adapters Standalone +This repository contains modules that allow to run Flamingo Commerce in a standalone mode. +(Not connected to any third party headless ecommerce API). -This repository contains modules that allow to run Flamingo Commerce n a standalone mode. -(Not connected to any thirds party headless ecommerc API). - -According to the Flamingo Commerce concept of "ports and adapters" the modules provide mplementations for Flamingo Commerce Ports. +According to the Flamingo Commerce concept of "ports and adapters" the modules provide implementations for Flamingo Commerce Ports. The following flamingo modules are part of that: -* commercesearch - * Provide Product; ProductSearch; Category and Search. That means you can have working product views, category vews and search features. - * The module therefore interally uses Repository where products are stored and received from. You can choose between - * A simple "InMemory" version - * A implementation based on bleve - a go based indexed search implementation ( https://github.com/blevesearch/bleve) - * The module requires someone who takes care if indexing new products and categories. Therefore it expects an implemantation of an "IndexUpdater" - * See [Module commercesearch Readme](commercesearch/Readme.md) - -* csvindexing - * usful addon module for the *commercesearch* module - * Provide a "IndexUpdater" that loads products and categories from a CSV file - * See [Module csvcommerce Readme](csvindexing/Readme.md) +* **commercesearch** + * Provide Product; ProductSearch; Category and Search. That means you can have working product views, category views and search features. + * The module therefore internally uses Repository where products are stored and received from. You can choose between + * A simple "InMemory" version + * An implementation based on bleve - a go based indexed search implementation ( https://github.com/blevesearch/bleve) + * The module requires someone who takes care of indexing new products and categories. Therefore, it expects an implementation of an "IndexUpdater" + * See [Module commercesearch Readme](commercesearch/Readme.md) -* emailplaceorder - * Like the name says a module that just sends mails (to customer and storeowner) after placing an order +* **csvindexing** + * useful addon module for the *commercesearch* module + * Provide a "IndexUpdater" that loads products and categories from a CSV file + * See [Module csvcommerce Readme](csvindexing/Readme.md) +* **emailplaceorder** + * Like the name says a module that just sends mails (to customer and store owner) after placing an order + * See [Module emailplaceorder Readme](emailplaceorder/Readme.md) ## Usage Just add the modules to your Flamingo bootstrap like this: -``` - //flamingo-commerce-adpater-standalone modules: +```go new(commercesearch.Module), new(commercesearch.CategoryModule), new(commercesearch.SearchModule), new(csvindexing.ProductModule), new(emailplaceorder.Module), - .. + ``` -There are a couple of configuration options. See the Flamingo `config` command and the module readme for details. \ No newline at end of file +There are a couple of configuration options. See the Flamingo `config` command, and the module readme for details. diff --git a/commercesearch/Readme.md b/commercesearch/Readme.md index c160e34..3a26748 100644 --- a/commercesearch/Readme.md +++ b/commercesearch/Readme.md @@ -3,59 +3,69 @@ Provides Adapters for Flamingo Commerce to persist and retrieve products. The provided adapters are: - * productService (to retrieve single products) - * productSearchService (to search for products - e.g. used on category listing page) - * categoryService (for Flamingo Commerce "category" module - to receive categorys and category trees). To use the Adapter you need to add the main `CategoryModule` to your bootstrap. - * searchService (for Flamingo Commerce "search" module allowing searching for products documents). To use the Adapters you need to add the main `SearchModule` to your bootstrap. + +* productService (to retrieve single products) +* productSearchService (to search for products - e.g. used on category listing page) +* categoryService (for Flamingo Commerce "category" module - to receive categories and category trees). To use the + Adapter you need to add the main `CategoryModule` to your bootstrap. +* searchService (for Flamingo Commerce "search" module allowing searching for products documents). To use the Adapters + you need to add the main `SearchModule` to your bootstrap. The available products need to be indexed first and will be stored in a `ProductRepository`. -The module also provides an adapter to receive categories and Category Trees and provides an Adpater for the Flamingo Commerce CategoryService (flamingo.me/flamingo-commerce/v3/category/domain) +The module also provides an adapter to receive categories and Category Trees and provides an Adapter for the Flamingo +Commerce CategoryService (flamingo.me/flamingo-commerce/v3/category/domain) + +## Indexing -## Indexing ## The indexing itself is not part of that module - because the indexing source might be something project specific. However - the module "csvindexing" implements an indexer that can be used to read products from a CSV file. The indexing (loading) of products is done by implementing and registering the `IndexUpdater` interface: + ```go - //IndexUpdater - interface to Load products in a Index - secondary port - IndexUpdater interface { - //Indexer method that is called with an initialized Indexer. The passed Indexer provides helpers to update the Repository - Index(ctx context.Context, rep *Indexer) error - } +// IndexUpdater interface to load products in an Index - secondary port +IndexUpdater interface { +// Indexer method that is called with an initialized Indexer. The passed Indexer provides helpers to update the Repository +Index(ctx context.Context, rep *Indexer) error +} ``` So you can implement that interface (port) by an own implementation (adapter) and then register your implementation: -``` +```go injector.Bind((*productSearchDomain.IndexUpdater)(nil)).To(YourLoaderImplementation) ``` - ## Configuration With the setting -`flamingo-commerce-adapter-standalone.commercesearch.repositoryAdapter` you can switch the repository implementation. +`flamingoCommerceAdapterStandalone.commercesearch.repositoryAdapter` you can switch the repository implementation. -The default is an simple in-memory product index, that works for single instances. +The default is a simple in-memory product index, that works for single instances. -## Bleve Repository +### Bleve Repository Adapter You can also use the bleve based repository - bleve (http://blevesearch.com/) is a full text search and index for go. +Supports sorting, facets and more. -``` -flamingo-commerce-adapter-standalone: - commercesearch +```yaml +flamingoCommerceAdapterStandalone: + commercesearch: enableIndexing: true - repositoryAdapter: bleve + repositoryAdapter: "bleve" bleveAdapter: - //if products should also be attached to theire parent categories (default is true) productsToParentCategories: true - //enable hierarichal category facet (based on the indexed products) enableCategoryFacet: true - // add facets for any additional attribute: facetConfig: - - attributeCode: brandCode - amount: 10 -``` \ No newline at end of file + # Add facet for the color attribute + - attributeCode: "color" + amount: 20 + sortConfig: + # Add sorting for color attribute + - attributeCode: "color" + attributeType: "text" # field content: text, numeric, bool + asc: true # Allow asc sorting + desc: true # Allow desc sorting +``` diff --git a/commercesearch/domain/indexing.go b/commercesearch/domain/indexing.go index 17bd94d..85f7f1c 100644 --- a/commercesearch/domain/indexing.go +++ b/commercesearch/domain/indexing.go @@ -2,15 +2,16 @@ package domain import ( "context" + "fmt" + "sync" + categoryDomain "flamingo.me/flamingo-commerce/v3/category/domain" product "flamingo.me/flamingo-commerce/v3/product/domain" "flamingo.me/flamingo/v3/framework/flamingo" - "fmt" - "sync" ) type ( - // IndexProcess - responsible to call the injected loader to index products into the passed repository + // IndexProcess responsible to call the injected loader to index products into the passed repository IndexProcess struct { indexUpdater IndexUpdater indexer *Indexer @@ -18,7 +19,7 @@ type ( enableIndexing bool } - //Indexer provides useful features to work with the Repositories for indexing purposes + // Indexer provides useful features to work with the Repositories for indexing purposes Indexer struct { productRepository ProductRepository categoryRepository CategoryRepository @@ -27,15 +28,15 @@ type ( batchCatQueue []product.CategoryTeaser } - //CategoryTreeBuilder helper to build category tree + // CategoryTreeBuilder helper to build category tree CategoryTreeBuilder struct { - //rootCategory - this is the link into the tree that is going to be build + // rootCategory - this is the link into the tree that is going to be built rootCategory *categoryDomain.TreeData - //categorTreeIndex - the link into the treenode - is build - categorTreeIndex map[string]*categoryDomain.TreeData + // categoryTreeIndex - the link into the treenode - is built + categoryTreeIndex map[string]*categoryDomain.TreeData - //child -> parent + // child -> parent nodeLinkRawData map[string]string } @@ -45,7 +46,7 @@ type ( parent string } - //IndexUpdater - interface to update the index with the help of the Indexer + // IndexUpdater - interface to update the index with the help of the Indexer IndexUpdater interface { Index(ctx context.Context, rep *Indexer) error } @@ -53,7 +54,7 @@ type ( var mutex sync.Mutex -//Inject for Indexer +// Inject for Indexer func (i *Indexer) Inject(logger flamingo.Logger, productRepository ProductRepository, config *struct { CategoryRepository CategoryRepository `inject:",optional"` @@ -65,7 +66,7 @@ func (i *Indexer) Inject(logger flamingo.Logger, productRepository ProductReposi } } -//PrepareIndex of the avaiable repository implementations +// PrepareIndex of the available repository implementations func (i *Indexer) PrepareIndex(ctx context.Context) error { err := i.productRepository.PrepareIndex(ctx) if err != nil { @@ -77,7 +78,7 @@ func (i *Indexer) PrepareIndex(ctx context.Context) error { return nil } -//ProductRepository to get +// ProductRepository to get func (i *Indexer) ProductRepository() ProductRepository { return i.productRepository } @@ -98,7 +99,7 @@ func (i *Indexer) commit(ctx context.Context) error { return nil } -//UpdateProductAndCategory helper to update product and the assigned categoryteasers +// UpdateProductAndCategory helper to update product and the assigned categoryteasers func (i *Indexer) UpdateProductAndCategory(ctx context.Context, product product.BasicProduct) error { i.batchProductQueue = append(i.batchProductQueue, product) @@ -112,7 +113,7 @@ func (i *Indexer) UpdateProductAndCategory(ctx context.Context, product product. return i.commit(ctx) } -//Inject dependencies +// Inject dependencies func (p *IndexProcess) Inject(indexUpdater IndexUpdater, logger flamingo.Logger, indexer *Indexer, config *struct { EnableIndexing bool `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.enableIndexing,optional"` }) { @@ -122,7 +123,7 @@ func (p *IndexProcess) Inject(indexUpdater IndexUpdater, logger flamingo.Logger, p.logger = logger.WithField(flamingo.LogKeyModule, "flamingo-commerce-adapter-standalone").WithField(flamingo.LogKeyCategory, "indexer") } -//Run the index process with registered loader (using indexer as helper for the repository access) +// Run the index process with registered loader (using indexer as helper for the repository access) func (p *IndexProcess) Run(ctx context.Context) error { if !p.enableIndexing { p.logger.Info("Skipping Indexing..") @@ -148,40 +149,40 @@ func (p *IndexProcess) Run(ctx context.Context) error { return nil } -//AddCategoryData to the builder.. Call this as often as you want to add before calling BuildTree +// AddCategoryData to the builder.. Call this as often as you want to add before calling BuildTree func (h *CategoryTreeBuilder) AddCategoryData(code string, name string, parentCode string) { - if h.categorTreeIndex == nil { - h.categorTreeIndex = make(map[string]*categoryDomain.TreeData) + if h.categoryTreeIndex == nil { + h.categoryTreeIndex = make(map[string]*categoryDomain.TreeData) } if h.rootCategory == nil { h.rootCategory = &categoryDomain.TreeData{} } - //root category is either a default empty node or detected by code == parentCode + // root category is either a default empty node or detected by code == parentCode if code == parentCode { h.rootCategory = &categoryDomain.TreeData{ CategoryCode: code, CategoryName: name, } - h.categorTreeIndex[code] = h.rootCategory + h.categoryTreeIndex[code] = h.rootCategory return } if h.nodeLinkRawData == nil { h.nodeLinkRawData = make(map[string]string) } - buildedBasicNode := categoryDomain.TreeData{ + builtBasicNode := categoryDomain.TreeData{ CategoryCode: code, CategoryName: name, } - h.categorTreeIndex[code] = &buildedBasicNode + h.categoryTreeIndex[code] = &builtBasicNode h.nodeLinkRawData[code] = parentCode } -//BuildTree build Tree based on added categoriedata +// BuildTree build Tree based on added categoriedata func (h *CategoryTreeBuilder) BuildTree() (*categoryDomain.TreeData, error) { - //Build the tree links + // Build the tree links for childCode, parentCode := range h.nodeLinkRawData { - childNode, ok := h.categorTreeIndex[childCode] + childNode, ok := h.categoryTreeIndex[childCode] if !ok { return nil, fmt.Errorf("ChildNode %v not found", childNode) } @@ -189,7 +190,7 @@ func (h *CategoryTreeBuilder) BuildTree() (*categoryDomain.TreeData, error) { if parentCode == "" { parentNode = h.rootCategory } else { - parentNode, ok = h.categorTreeIndex[parentCode] + parentNode, ok = h.categoryTreeIndex[parentCode] if !ok { return nil, fmt.Errorf("ParentCode %v not found", parentCode) } @@ -201,14 +202,14 @@ func (h *CategoryTreeBuilder) BuildTree() (*categoryDomain.TreeData, error) { } func buildPathString(parent *categoryDomain.TreeData) { - //Build the Path + // Build the Path for _, subNode := range parent.SubTreesData { subNode.CategoryPath = parent.CategoryPath + "/" + subNode.CategoryCode buildPathString(subNode) } } -//CategoryTreeToCategoryTeaser conversion +// CategoryTreeToCategoryTeaser conversion func CategoryTreeToCategoryTeaser(searchedCategoryCode string, tree categoryDomain.Tree) *product.CategoryTeaser { return categoryTreeToCategoryTeaser(searchedCategoryCode, tree, nil) } @@ -220,7 +221,7 @@ func categoryTreeToCategoryTeaser(searchedCategoryCode string, searchPosition ca Name: searchPosition.Name(), Parent: parentCategory, } - //recursion stops of category found + // recursion stops of category found if searchPosition.Code() == searchedCategoryCode { return teaserForCurrentNode } diff --git a/commercesearch/domain/repository.go b/commercesearch/domain/repository.go index 21871d2..fb3e1e4 100644 --- a/commercesearch/domain/repository.go +++ b/commercesearch/domain/repository.go @@ -2,13 +2,14 @@ package domain import ( "context" + categoryDomain "flamingo.me/flamingo-commerce/v3/category/domain" "flamingo.me/flamingo-commerce/v3/product/domain" searchDomain "flamingo.me/flamingo-commerce/v3/search/domain" ) type ( - // ProductRepository - interface + // ProductRepository port ProductRepository interface { FindByMarketplaceCode(ctx context.Context, marketplaceCode string) (domain.BasicProduct, error) Find(ctx context.Context, filters ...searchDomain.Filter) (*domain.SearchResult, error) @@ -17,7 +18,7 @@ type ( ClearProducts(ctx context.Context, productIds []string) error } - //CategoryRepository interface + // CategoryRepository port CategoryRepository interface { PrepareIndex(ctx context.Context) error CategoryTree(ctx context.Context, code string) (categoryDomain.Tree, error) diff --git a/commercesearch/infrastructure/category/adapter.go b/commercesearch/infrastructure/category/adapter.go index 720ed5d..aae14d3 100644 --- a/commercesearch/infrastructure/category/adapter.go +++ b/commercesearch/infrastructure/category/adapter.go @@ -2,14 +2,16 @@ package category import ( "context" - "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + "flamingo.me/flamingo/v3/framework/flamingo" + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + categoryDomain "flamingo.me/flamingo-commerce/v3/category/domain" ) type ( - //Adapter - Adapter that uses a category csv (WIP) + // Adapter that uses the category repository Adapter struct { categoryRepository domain.CategoryRepository logger flamingo.Logger @@ -20,7 +22,7 @@ var ( _ categoryDomain.CategoryService = &Adapter{} ) -//Inject - dingo injector +// Inject dependencies func (a *Adapter) Inject(categoryRepository domain.CategoryRepository, logger flamingo.Logger) { a.categoryRepository = categoryRepository a.logger = logger.WithField(flamingo.LogKeyModule, "flamingo-commerce-adapter-standalone.commercesearch").WithField(flamingo.LogKeyCategory, "categoryadapter") diff --git a/commercesearch/infrastructure/product/searchServiceAdapter.go b/commercesearch/infrastructure/product/searchServiceAdapter.go index b012974..6ecf8c3 100644 --- a/commercesearch/infrastructure/product/searchServiceAdapter.go +++ b/commercesearch/infrastructure/product/searchServiceAdapter.go @@ -2,6 +2,9 @@ package product import ( "context" + + "github.com/google/go-cmp/cmp" + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" productDomain "flamingo.me/flamingo-commerce/v3/product/domain" @@ -19,7 +22,7 @@ var ( _ productDomain.SearchService = &SearchServiceAdapter{} ) -//Inject - dingo injector +// Inject dependencies func (ps *SearchServiceAdapter) Inject(productRepository domain.ProductRepository) { ps.productRepository = productRepository } @@ -29,7 +32,20 @@ func (ps *SearchServiceAdapter) Search(ctx context.Context, filter ...searchDoma return ps.productRepository.Find(ctx, filter...) } -// SearchBy returns Products prefiltered by the given attribute (also based on additional given Filters) e.g. SearchBy(ctx,"brandCode","apple") -func (ps *SearchServiceAdapter) SearchBy(ctx context.Context, attribute string, values []string, filter ...searchDomain.Filter) (*productDomain.SearchResult, error) { - return ps.Search(ctx, nil) +// SearchBy returns Products prefiltered by the given attribute (also based on additional given Filters) e.g. SearchBy(ctx, "brandCode", []string{"apple"}) +func (ps *SearchServiceAdapter) SearchBy(ctx context.Context, attribute string, values []string, filters ...searchDomain.Filter) (*productDomain.SearchResult, error) { + attributeFilterPresent := false + for _, filter := range filters { + if keyValueFilter, ok := filter.(*searchDomain.KeyValueFilter); ok { + if keyValueFilter.Key() == attribute && cmp.Equal(keyValueFilter.KeyValues(), values) { + attributeFilterPresent = true + } + } + } + + if !attributeFilterPresent { + filters = append(filters, searchDomain.NewKeyValueFilter(attribute, values)) + } + + return ps.Search(ctx, filters...) } diff --git a/commercesearch/infrastructure/product/serviceAdapter.go b/commercesearch/infrastructure/product/serviceAdapter.go index e40db3f..a38b1e7 100644 --- a/commercesearch/infrastructure/product/serviceAdapter.go +++ b/commercesearch/infrastructure/product/serviceAdapter.go @@ -2,6 +2,7 @@ package product import ( "context" + domain "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" productDomain "flamingo.me/flamingo-commerce/v3/product/domain" @@ -14,7 +15,7 @@ type ( } ) -//Inject - dingo injector +// Inject dependencies func (ps *ServiceAdapter) Inject(productRepository domain.ProductRepository) { ps.productRepository = productRepository } diff --git a/commercesearch/infrastructure/productsearch/bleverepository.go b/commercesearch/infrastructure/productsearch/bleverepository.go index 7960c9a..b09c6fd 100644 --- a/commercesearch/infrastructure/productsearch/bleverepository.go +++ b/commercesearch/infrastructure/productsearch/bleverepository.go @@ -5,13 +5,17 @@ import ( "context" "encoding/gob" "errors" - "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + "fmt" + "math" + "strconv" + "strings" + "sync" + categoryDomain "flamingo.me/flamingo-commerce/v3/category/domain" productDomain "flamingo.me/flamingo-commerce/v3/product/domain" searchDomain "flamingo.me/flamingo-commerce/v3/search/domain" "flamingo.me/flamingo/v3/framework/config" "flamingo.me/flamingo/v3/framework/flamingo" - "fmt" "github.com/blevesearch/bleve" "github.com/blevesearch/bleve/analysis" "github.com/blevesearch/bleve/analysis/tokenizer/whitespace" @@ -19,9 +23,8 @@ import ( "github.com/blevesearch/bleve/mapping" "github.com/blevesearch/bleve/search" "github.com/blevesearch/bleve/search/query" - "math" - "strings" - "sync" + + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" ) type ( @@ -36,6 +39,7 @@ type ( cachedCategories map[string]categoryDomain.Category enableCategoryFacet bool facetConfig []facetConfig + sortConfig []sortConfig } facetConfig struct { @@ -43,22 +47,31 @@ type ( Amount int } - //bleveDocument - envelop for indexed entities + sortConfig struct { + AttributeCode string + AttributeType string + Asc bool + Desc bool + } + + // bleveDocument envelop for indexed entities bleveDocument struct { Product productDomain.BasicProduct Category *productDomain.CategoryTeaser } ) -const productType = "product" -const categoryType = "category" -const categoryIDPrefix = "cat_" - -const sourceFieldName = "_source" - -const typeFieldName = "_type" - -const fieldPrefixInIndexedDocument = "Product." +const ( + attributeTypeNumeric = "numeric" + attributeTypeText = "text" + attributeTypeBool = "bool" + productType = "product" + categoryType = "category" + categoryIDPrefix = "cat_" + sourceFieldName = "_source" + typeFieldName = "_type" + fieldPrefixInIndexedDocument = "Product." +) var ( _ domain.ProductRepository = &BleveRepository{} @@ -79,32 +92,43 @@ func (b *bleveDocument) Type() string { } func (b *bleveDocument) getTypeField() *document.TextField { - //Add type for phrase query + // Add type for phrase query return document.NewTextFieldCustom( typeFieldName, nil, []byte(b.Type()), document.IndexField|document.StoreField|document.IncludeTermVectors, nil) } -//Inject dep +// Inject dep func (r *BleveRepository) Inject(logger flamingo.Logger, config *struct { AssignProductsToParentCategories bool `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.bleveAdapter.productsToParentCategories,optional"` EnableCategoryFacet bool `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.bleveAdapter.enableCategoryFacet,optional"` FacetConfig config.Slice `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.bleveAdapter.facetConfig"` + SortConfig config.Slice `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.bleveAdapter.sortConfig"` }) *BleveRepository { r.logger = logger.WithField(flamingo.LogKeyModule, "flamingoCommerceAdapterStandalone.commercesearch").WithField(flamingo.LogKeyCategory, "bleve") if config != nil { r.assignProductsToParentCategories = config.AssignProductsToParentCategories r.enableCategoryFacet = config.EnableCategoryFacet var facetConfig []facetConfig - config.FacetConfig.MapInto(&facetConfig) + err := config.FacetConfig.MapInto(&facetConfig) + if err != nil { + panic(err) + } r.facetConfig = facetConfig + + var sortConfig []sortConfig + err = config.SortConfig.MapInto(&sortConfig) + if err != nil { + panic(err) + } + r.sortConfig = sortConfig } return r } -//PrepareIndex - prepares bleve index with given configuration +// PrepareIndex prepares bleve index with given configuration func (r *BleveRepository) PrepareIndex(_ context.Context) error { - //Init index + // Init index mapping := bleve.NewIndexMapping() categoryCodeField := bleve.NewTextFieldMapping() @@ -113,13 +137,6 @@ func (r *BleveRepository) PrepareIndex(_ context.Context) error { categoryCodeField.DocValues = false categoryCodeField.Store = false categoryCodeField.Index = false - /* - productMapping := bleve.NewDocumentMapping() - productMapping.AddFieldMappingsAt(fieldPrefixInIndexedDocument+"MMMainCategory.Code",categoryCodeField) - mapping.AddDocumentMapping(productType, productMapping) - mapping.DefaultMapping.AddFieldMappingsAt(fieldPrefixInIndexedDocument+"MMMainCategory.Code",categoryCodeField) - mapping.AddDocumentMapping(productType, productMapping) - */ /* todo - enable persistent index ? indexName := "productRepIndex" @@ -127,7 +144,7 @@ func (r *BleveRepository) PrepareIndex(_ context.Context) error { r.Logger.Warn(indexName+" already exist!") bleve.Open(indexName) }*/ - //index, err := bleve.NewUsing("lily.bleve", mapping, scorch.Name, scorch.Name, nil) + // index, err := bleve.NewUsing("lily.bleve", mapping, scorch.Name, scorch.Name, nil) index, err := bleve.NewMemOnly(mapping) if err != nil { return err @@ -138,13 +155,13 @@ func (r *BleveRepository) PrepareIndex(_ context.Context) error { func (r *BleveRepository) getIndex() (bleve.Index, error) { if r.index == nil { - return nil, errors.New("Index not prepared") + return nil, errors.New("index not prepared") } return r.index, nil } -// UpdateByCategoryTeasers - updates or appends a category to the Product Repository +// UpdateByCategoryTeasers updates or appends a category to the Product Repository func (r *BleveRepository) UpdateByCategoryTeasers(_ context.Context, categoryTeasers []productDomain.CategoryTeaser) error { index, err := r.getIndex() if err != nil { @@ -179,7 +196,7 @@ func (r *BleveRepository) ClearProducts(_ context.Context, products []string) er return nil } -// UpdateProducts products to the Product Repository +// UpdateProducts products to the Product Repository func (r *BleveRepository) UpdateProducts(_ context.Context, products []productDomain.BasicProduct) error { index, err := r.getIndex() if err != nil { @@ -187,7 +204,7 @@ func (r *BleveRepository) UpdateProducts(_ context.Context, products []productDo } for _, product := range products { - //to receive original + // to receive original if product.BaseData().MarketPlaceCode == "" { return fmt.Errorf("No marketplace code %v, %v", product.GetIdentifier(), product.BaseData().Title) } @@ -214,7 +231,7 @@ func (r *BleveRepository) UpdateProducts(_ context.Context, products []productDo return nil } -//productToBleveDocs - returns the Product and Category documents to be indexed +// productToBleveDocs returns the Product and Category documents to be indexed func (r *BleveRepository) productToBleveDocs(product productDomain.BasicProduct) ([]*document.Document, error) { var bleveDocuments []*document.Document index, err := r.getIndex() @@ -233,23 +250,35 @@ func (r *BleveRepository) productToBleveDocs(product productDomain.BasicProduct) return nil, err } - //Add _source field with Gib ncoded content (to restore original) + // Add _source field with Gob encoded content (to restore original) field := document.NewTextFieldWithIndexingOptions( sourceFieldName, nil, productEncoded, document.StoreField) bleveProductDocument = bleveProductDocument.AddField(field) - //Add price Field to support sorting by price + for _, sort := range r.sortConfig { + var field document.Field + switch sort.AttributeType { + case attributeTypeNumeric: + val, _ := strconv.ParseFloat(product.BaseData().Attribute(sort.AttributeCode).Value(), 64) + field = document.NewNumericField( + fieldPrefixInIndexedDocument+"sort."+sort.AttributeCode, nil, val) + case attributeTypeText: + field = document.NewTextFieldCustom( + fieldPrefixInIndexedDocument+"sort."+sort.AttributeCode, nil, []byte(product.BaseData().Attribute(sort.AttributeCode).Value()), document.IndexField, nil) + case attributeTypeBool: + val, _ := strconv.ParseBool(product.BaseData().Attribute(sort.AttributeCode).Value()) + field = document.NewBooleanField( + fieldPrefixInIndexedDocument+"sort."+sort.AttributeCode, nil, val) + } + bleveProductDocument = bleveProductDocument.AddField(field) + } + + // Add price Field to support sorting by price priceField := document.NewNumericField( - fieldPrefixInIndexedDocument+"Sort.Price", nil, product.TeaserData().TeaserPrice.GetFinalPrice().FloatAmount()) + fieldPrefixInIndexedDocument+"sort.price", nil, product.TeaserData().TeaserPrice.GetFinalPrice().FloatAmount()) bleveProductDocument = bleveProductDocument.AddField(priceField) - //Add title Field to support sorting by raw title (without analysers) - titleSortField := document.NewTextFieldCustom( - fieldPrefixInIndexedDocument+"Sort.Title", nil, []byte(product.BaseData().Title), - document.IndexField, nil) - bleveProductDocument = bleveProductDocument.AddField(titleSortField) - - //Add category field for category facet and filter + // Add category field for category facet and filter tok, err := whitespace.TokenizerConstructor(nil, nil) if err != nil { return nil, err @@ -283,12 +312,12 @@ func (r *BleveRepository) productToBleveDocs(product productDomain.BasicProduct) bleveProductDocument = bleveProductDocument.AddField(attributeField) } - //Add Type Field + // Add Type Field bleveProductDocument = bleveProductDocument.AddField(indexDocument.getTypeField()) for _, va := range bleveProductDocument.Fields { _ = va - //fmt.Printf("\n bleveDocument Fields: %#v : %v / tv: %v",va.Name(),string(va.Value()),va.Options().String()) + // fmt.Printf("\n bleveDocument Fields: %#v : %v / tv: %v",va.Name(),string(va.Value()),va.Options().String()) } bleveDocuments = append(bleveDocuments, bleveProductDocument) return bleveDocuments, nil @@ -308,7 +337,7 @@ func (r *BleveRepository) categoryParentCodes(teaser productDomain.CategoryTease return codes, paths } -//categoryTeaserToBleve returns bleve documents for type category for the given Teaserdata (called recursive with Parent) +// categoryTeaserToBleve returns bleve documents for type category for the given TeaserData (called recursive with Parent) func (r *BleveRepository) categoryTeaserToBleve(categoryTeaser productDomain.CategoryTeaser, alreadyAddedBleveDocs []*document.Document) ([]*document.Document, error) { index, err := r.getIndex() if err != nil { @@ -379,7 +408,7 @@ func (r *BleveRepository) FindByMarketplaceCode(_ context.Context, marketplaceCo return r.bleveHitToProduct(searchResult.Hits[0]) } -//CategoryTree returns tree +// CategoryTree returns tree func (r *BleveRepository) CategoryTree(_ context.Context, code string) (categoryDomain.Tree, error) { if code == "" && r.cachedCategoryTree != nil { @@ -403,7 +432,6 @@ func (r *BleveRepository) CategoryTree(_ context.Context, code string) (category return rootTreeNode, nil } -//mapCatToTree func mapCatToTree(category categoryDomain.Category) *categoryDomain.TreeData { return &categoryDomain.TreeData{ CategoryCode: category.Code(), @@ -416,7 +444,7 @@ func mapCatToTree(category categoryDomain.Category) *categoryDomain.TreeData { } func (r *BleveRepository) subTrees(parentNode *categoryDomain.TreeData) ([]*categoryDomain.TreeData, error) { - //fmt.Printf("\n subtrees for %v",parentNode.CategoryCode) + // fmt.Printf("\n subtrees for %v",parentNode.CategoryCode) index, err := r.getIndex() if err != nil { return nil, err @@ -445,7 +473,7 @@ func (r *BleveRepository) subTrees(parentNode *categoryDomain.TreeData) ([]*cate return subTreeNodes, nil } -//Category - receives indexed categories +// Category receives indexed categories func (r *BleveRepository) Category(_ context.Context, code string) (categoryDomain.Category, error) { r.cacheMutex.RLock() @@ -492,7 +520,6 @@ func (r *BleveRepository) Category(_ context.Context, code string) (categoryDoma } -//mapHitToCategory func mapHitToCategory(hit *search.DocumentMatch) categoryDomain.Category { return &categoryDomain.CategoryData{ CategoryCode: fmt.Sprintf("%v", hit.Fields["Category.Code"]), @@ -517,8 +544,8 @@ func (r *BleveRepository) Find(_ context.Context, filters ...searchDomain.Filter var mainQuery query.Query - currentPage := int(1) - pageSize := int(100) + currentPage := 1 + pageSize := 100 sortingField := "" sortingDesc := true @@ -536,11 +563,11 @@ func (r *BleveRepository) Find(_ context.Context, filters ...searchDomain.Filter return bleve.NewPhraseQuery([]string{code}, fieldPrefixInIndexedDocument+"Facet.Categorycode") } for _, filter := range filters { - r.logger.Warn("Find", fmt.Sprintf("%T %#v", filter, filter)) + r.logger.Info("Find ", fmt.Sprintf("%T %#v", filter, filter)) switch f := filter.(type) { case *searchDomain.KeyValueFilter: if f.Key() == "category" { - //The code "category" is handeled as CategoryFacet + // The code "category" is handeled as CategoryFacet for _, catV := range f.KeyValues() { filterQueryParts = append(filterQueryParts, categoryTermQuery(catV)) } @@ -556,7 +583,7 @@ func (r *BleveRepository) Find(_ context.Context, filters ...searchDomain.Filter case *searchDomain.PaginationPageSize: pageSize = f.GetPageSize() case *searchDomain.SortFilter: - sortingField = fieldPrefixInIndexedDocument + "Sort." + f.Field() + sortingField = fieldPrefixInIndexedDocument + "sort." + f.Field() sortingDesc = f.Descending() } } @@ -577,8 +604,9 @@ func (r *BleveRepository) Find(_ context.Context, filters ...searchDomain.Filter facetRequest := bleve.NewFacetRequest(fieldPrefixInIndexedDocument+"Facet.Attribute."+facetConfig.AttributeCode, facetConfig.Amount) facetsRequests[facetConfig.AttributeCode] = facetRequest } - query := bleve.NewConjunctionQuery(filterQueryParts...) - searchRequest := bleve.NewSearchRequestOptions(query, pageSize, currentPage-1, false) + conjunctionQuery := bleve.NewConjunctionQuery(filterQueryParts...) + from := (currentPage - 1) * pageSize + searchRequest := bleve.NewSearchRequestOptions(conjunctionQuery, pageSize, from, false) searchRequest.Facets = facetsRequests searchRequest.Fields = append(searchRequest.Fields, sourceFieldName) if sortingField != "" { @@ -597,15 +625,38 @@ func (r *BleveRepository) Find(_ context.Context, filters ...searchDomain.Filter return nil, err } - return r.mapBleveResultToResult(searchResults), nil + result := r.mapBleveResultToResult(searchResults) + markActiveFacets(filters, result) + + return result, nil +} + +func markActiveFacets(filters []searchDomain.Filter, result *productDomain.SearchResult) { + for _, filter := range filters { + if f, ok := filter.(*searchDomain.KeyValueFilter); ok { + for i, facetItem := range result.Facets[f.Key()].Items { + for _, selectedValue := range f.KeyValues() { + if facetItem.Value == selectedValue { + facetItem.Selected = true + facetItem.Active = true + } + } + result.Facets[f.Key()].Items[i] = facetItem + } + } + } } func (r *BleveRepository) mapBleveResultToResult(searchResults *bleve.SearchResult) *productDomain.SearchResult { pageAmount := 0 pageSize := searchResults.Request.Size - currentPage := searchResults.Request.From + 1 + currentPage := 1 + if pageSize > 0 { pageAmount = int(math.Ceil(float64(searchResults.Total) / float64(pageSize))) + if searchResults.Request.From > 0 { + currentPage = 1 + searchResults.Request.From/pageSize + } } var productResults []productDomain.BasicProduct resultFacetCollection := make(searchDomain.FacetCollection) @@ -642,6 +693,7 @@ func (r *BleveRepository) mapBleveResultToResult(searchResults *bleve.SearchResu } resultFacetCollection["category"] = facet } + for _, facetConfig := range r.facetConfig { facetResult := facetResultForConfiguredName(facetConfig.AttributeCode) if facetResult == nil { @@ -673,14 +725,45 @@ func (r *BleveRepository) mapBleveResultToResult(searchResults *bleve.SearchResu productResults = append(productResults, product) } + sortOptions := []searchDomain.SortOption{ + { + Label: "Price", + Field: "price", + SelectedAsc: false, + SelectedDesc: false, + Asc: "price", + Desc: "price", + }, + } + + for _, s := range r.sortConfig { + sortOptions = append(sortOptions, searchDomain.SortOption{ + Label: s.AttributeCode, + Field: s.AttributeCode, + Asc: func() string { + if s.Asc { + return s.AttributeCode + } + return "" + }(), + Desc: func() string { + if s.Desc { + return s.AttributeCode + } + return "" + }(), + }) + } + return &productDomain.SearchResult{ Hits: productResults, Result: searchDomain.Result{ Facets: resultFacetCollection, SearchMeta: searchDomain.SearchMeta{ - NumResults: int(searchResults.Total), - NumPages: pageAmount, - Page: currentPage, + NumResults: int(searchResults.Total), + NumPages: pageAmount, + Page: currentPage, + SortOptions: sortOptions, }}, } } @@ -727,7 +810,7 @@ func (r *BleveRepository) constructCategoryTreeFacet(parentSlice []*searchDomain parentSlice = append(parentSlice, foundItem) } if isLast { - //use count if path matches + // use count if path matches foundItem.Count = count return parentSlice } @@ -736,8 +819,8 @@ func (r *BleveRepository) constructCategoryTreeFacet(parentSlice []*searchDomain } func (r *BleveRepository) decodeProduct(b []byte) (productDomain.BasicProduct, error) { - messout := bytes.NewBuffer(b) - dec := gob.NewDecoder(messout) + buffer := bytes.NewBuffer(b) + dec := gob.NewDecoder(buffer) var sp productDomain.BasicProduct err := dec.Decode(&sp) diff --git a/commercesearch/infrastructure/productsearch/bleverepository_test.go b/commercesearch/infrastructure/productsearch/bleverepository_test.go index 797e1f4..260f010 100644 --- a/commercesearch/infrastructure/productsearch/bleverepository_test.go +++ b/commercesearch/infrastructure/productsearch/bleverepository_test.go @@ -2,14 +2,15 @@ package productsearch import ( "context" + "math/big" + "testing" + "time" + commercePriceDomain "flamingo.me/flamingo-commerce/v3/price/domain" searchDomain "flamingo.me/flamingo-commerce/v3/search/domain" "flamingo.me/flamingo/v3/framework/config" "flamingo.me/flamingo/v3/framework/flamingo" "github.com/stretchr/testify/require" - "math/big" - "testing" - "time" categoryDomain "flamingo.me/flamingo-commerce/v3/category/domain" "flamingo.me/flamingo-commerce/v3/product/domain" @@ -125,7 +126,7 @@ func TestBleveProductRepository_AddProduct(t *testing.T) { err = s.UpdateProducts(context.Background(), []domain.BasicProduct{product, product2, product3}) assert.NoError(t, err) - //test pagination + // test pagination t.Run("Find product by Id", func(t *testing.T) { found, err := s.FindByMarketplaceCode(context.Background(), "id") require.NoError(t, err) @@ -133,7 +134,7 @@ func TestBleveProductRepository_AddProduct(t *testing.T) { }) - //test if category was indexed as well + // test if category was indexed as well t.Run("Find by different Queries", func(t *testing.T) { result, _ := s.Find(context.Background(), searchDomain.NewQueryFilter("atitle"), searchDomain.NewSortFilter("Title", "A")) require.Len(t, result.Hits, 1, "expect 1 results for 'atitle' search") @@ -152,23 +153,14 @@ func TestBleveProductRepository_AddProduct(t *testing.T) { }) t.Run("Find with Sorting", func(t *testing.T) { - result, _ := s.Find(context.Background(), searchDomain.NewQueryFilter("*"), searchDomain.NewSortFilter("Title", "A")) - require.Equal(t, 3, result.SearchMeta.NumResults, "expect 2 results for * search") - assert.Equal(t, "atitle", result.Hits[0].BaseData().Title, "ascending should have a first") - result, _ = s.Find(context.Background(), searchDomain.NewQueryFilter("*"), searchDomain.NewSortFilter("Title", "D")) - require.Equal(t, 3, result.SearchMeta.NumResults, "expect 2 results for * search") - assert.Equal(t, "green bag of something", result.Hits[0].BaseData().Title, "descending should have b first") - - //sort by price - result, _ = s.Find(context.Background(), searchDomain.NewQueryFilter("*"), searchDomain.NewSortFilter("Price", "A")) + result, _ := s.Find(context.Background(), searchDomain.NewQueryFilter("*"), searchDomain.NewSortFilter("price", "A")) require.Equal(t, 3, result.SearchMeta.NumResults, "expect 2 results for * search") assert.Equal(t, 7.99, result.Hits[0].TeaserData().TeaserPrice.GetFinalPrice().FloatAmount(), "ascending price should have cheapest price first") - result, _ = s.Find(context.Background(), searchDomain.NewQueryFilter("*"), searchDomain.NewSortFilter("Price", "D")) + result, _ = s.Find(context.Background(), searchDomain.NewQueryFilter("*"), searchDomain.NewSortFilter("price", "D")) assert.Equal(t, 8.99, result.Hits[0].TeaserData().TeaserPrice.GetFinalPrice().FloatAmount(), "descending price should have expensivst first") - }) - //test if category was indexed as well + // test if category was indexed as well t.Run("Filter by category", func(t *testing.T) { result, _ := s.Find(context.Background(), searchDomain.NewQueryFilter("*"), categoryDomain.NewCategoryFacet("Sub1")) require.Equal(t, 1, result.SearchMeta.NumResults, "expect 1 results for 'Sub1' category search") @@ -182,7 +174,7 @@ func TestBleveProductRepository_AddProduct(t *testing.T) { }) - //test pagination + // test pagination t.Run("Test pagination", func(t *testing.T) { result, _ := s.Find(context.Background(), searchDomain.NewQueryFilter("*"), searchDomain.NewPaginationPageFilter(1), searchDomain.NewPaginationPageSizeFilter(2), searchDomain.NewSortFilter("Title", "A")) @@ -209,6 +201,7 @@ func TestBleveRepository_FacetsSearch(t *testing.T) { AssignProductsToParentCategories bool `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.bleveAdapter.productsToParentCategories,optional"` EnableCategoryFacet bool `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.bleveAdapter.enableCategoryFacet,optional"` FacetConfig config.Slice `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.bleveAdapter.facetConfig"` + SortConfig config.Slice `inject:"config:flamingoCommerceAdapterStandalone.commercesearch.bleveAdapter.sortConfig"` }{ AssignProductsToParentCategories: true, EnableCategoryFacet: true, @@ -313,7 +306,7 @@ func TestBleveRepository_FacetsSearch(t *testing.T) { err = s.UpdateProducts(context.Background(), []domain.BasicProduct{product, product2, product3}) assert.NoError(t, err) - //test pagination + // test pagination t.Run("Test facets", func(t *testing.T) { result, _ := s.Find(context.Background(), @@ -394,7 +387,7 @@ func TestBleveRepository_CategorySearch(t *testing.T) { }, }, }) - //test if category was indexed as well + // test if category was indexed as well t.Run("Find category code", func(t *testing.T) { cat, _ := s.Category(context.Background(), "Sub") if assert.NotNil(t, cat) { @@ -414,7 +407,7 @@ func TestBleveRepository_CategorySearch(t *testing.T) { }) - //test if category was indexed as well + // test if category was indexed as well t.Run("Get category tree", func(t *testing.T) { cat, _ := s.CategoryTree(context.Background(), "") if assert.NotNil(t, cat) { @@ -441,7 +434,7 @@ func TestBleveRepository_ProductDecodeEncode(t *testing.T) { r := &BleveRepository{} - //test pagination + // test pagination t.Run("Test simpl", func(t *testing.T) { simpleProduct := domain.SimpleProduct{ Identifier: "testid", @@ -487,7 +480,7 @@ func TestBleveRepository_ProductDecodeEncode(t *testing.T) { assert.Equal(t, simpleProduct, productGot) }) - //test pagination + // test pagination t.Run("Test configurable", func(t *testing.T) { product := domain.ConfigurableProduct{ Identifier: "testid", diff --git a/commercesearch/infrastructure/productsearch/inmemoryrepository.go b/commercesearch/infrastructure/productsearch/inmemoryrepository.go index 3c8231b..668dd06 100644 --- a/commercesearch/infrastructure/productsearch/inmemoryrepository.go +++ b/commercesearch/infrastructure/productsearch/inmemoryrepository.go @@ -3,13 +3,15 @@ package productsearch import ( "context" "errors" - "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" - "flamingo.me/flamingo/v3/framework/flamingo" "fmt" "math" "sort" "sync" + "flamingo.me/flamingo/v3/framework/flamingo" + + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + categoryDomain "flamingo.me/flamingo-commerce/v3/category/domain" productDomain "flamingo.me/flamingo-commerce/v3/product/domain" @@ -20,19 +22,19 @@ type ( // InMemoryProductRepository serves as a Repository of Products held in memory InMemoryProductRepository struct { - //marketplaceCodeIndex - index to get products from marketplaceCode + // marketplaceCodeIndex index to get products from marketplaceCode, e.g. get product for market place code 'foobar' marketplaceCodeIndex map[string]productDomain.BasicProduct - //attributeReverseIndex - index to get products from attribute + // attributeReverseIndex index to get all market place codes for a certain attribute, e.g. all market place codes with attribute 'size' and value 'large' attributeReverseIndex map[string]map[string][]string - //productsByCategoriesReverseIndex - index to get products by categoryCode + // productsByCategoriesReverseIndex index to get all market place codes for a categoryCode, e.g. all market place codes with category 'clothing' productsByCategoriesReverseIndex map[string][]string addReadMutex sync.RWMutex - //for category adapters: - rootCategory *categoryDomain.TreeData - categorTreeIndex map[string]*categoryDomain.TreeData + // for category adapters: + rootCategory *categoryDomain.TreeData + categoryTreeIndex map[string]*categoryDomain.TreeData logger flamingo.Logger } @@ -48,17 +50,17 @@ var ( _ domain.CategoryRepository = &InMemoryProductRepository{} ) -//PrepareIndex implementation +// PrepareIndex implementation func (r *InMemoryProductRepository) PrepareIndex(_ context.Context) error { return nil } -//Inject dep +// Inject dependencies func (r *InMemoryProductRepository) Inject(logger flamingo.Logger) { r.logger = logger.WithField(flamingo.LogKeyModule, "flamingo-commerce-adapter-standalone").WithField(flamingo.LogKeyCategory, "InMemoryProductRepository") } -// UpdateByCategoryTeasers - updates or appends a category to the Product Repository +// UpdateByCategoryTeasers updates or appends a category to the Product Repository func (r *InMemoryProductRepository) UpdateByCategoryTeasers(_ context.Context, categoryTeasers []productDomain.CategoryTeaser) error { for _, categoryTeaser := range categoryTeasers { @@ -96,43 +98,57 @@ func (r *InMemoryProductRepository) UpdateProducts(_ context.Context, products [ return errors.New("No marketplace code ") } marketPlaceCode := product.BaseData().MarketPlaceCode - //Set reverseindex for marketplaceCode (the primary indendifier) - if r.marketplaceCodeIndex == nil { - r.marketplaceCodeIndex = make(map[string]productDomain.BasicProduct) - } - if r.marketplaceCodeIndex[marketPlaceCode] != nil { - err := errors.New("Duplicate for marketplace code " + marketPlaceCode) - r.logger.Error(err) + + err := r.addProductToMarketplaceCodeReverseIndex(marketPlaceCode, product) + if err != nil { return err } - r.marketplaceCodeIndex[product.BaseData().MarketPlaceCode] = product - //Now add product to category indexes: - if r.productsByCategoriesReverseIndex == nil { - r.productsByCategoriesReverseIndex = make(map[string][]string) - } + r.addMarketplaceCodeToCategoryReverseIndex(product, marketPlaceCode) + r.addMarketplaceCodeToAttributeReverseIndex(product, marketPlaceCode) + } - for _, categoryTeaser := range product.BaseData().Categories { - r.productsByCategoriesReverseIndex[categoryTeaser.Code] = append(r.productsByCategoriesReverseIndex[categoryTeaser.Code], marketPlaceCode) - } - if product.BaseData().MainCategory.Code != "" { - if !inSlice(r.productsByCategoriesReverseIndex[product.BaseData().MainCategory.Code], marketPlaceCode) { - r.productsByCategoriesReverseIndex[product.BaseData().MainCategory.Code] = append(r.productsByCategoriesReverseIndex[product.BaseData().MainCategory.Code], marketPlaceCode) - } - } + return nil +} - //Now fill the reverse index for all products attributes: - if r.attributeReverseIndex == nil { - r.attributeReverseIndex = make(map[string]map[string][]string) +func (r *InMemoryProductRepository) addMarketplaceCodeToAttributeReverseIndex(product productDomain.BasicProduct, marketPlaceCode string) { + if r.attributeReverseIndex == nil { + r.attributeReverseIndex = make(map[string]map[string][]string) + } + for _, attribute := range product.BaseData().Attributes { + if _, ok := r.attributeReverseIndex[attribute.Code]; !ok { + r.attributeReverseIndex[attribute.Code] = make(map[string][]string) } - for _, attribute := range product.BaseData().Attributes { - if _, ok := r.attributeReverseIndex[attribute.Code]; !ok { - r.attributeReverseIndex[attribute.Code] = make(map[string][]string) - } - r.attributeReverseIndex[attribute.Code][attribute.Value()] = append(r.attributeReverseIndex[attribute.Code][attribute.Value()], marketPlaceCode) + r.attributeReverseIndex[attribute.Code][attribute.Value()] = append(r.attributeReverseIndex[attribute.Code][attribute.Value()], marketPlaceCode) + } +} + +func (r *InMemoryProductRepository) addMarketplaceCodeToCategoryReverseIndex(product productDomain.BasicProduct, marketPlaceCode string) { + if r.productsByCategoriesReverseIndex == nil { + r.productsByCategoriesReverseIndex = make(map[string][]string) + } + + for _, categoryTeaser := range product.BaseData().Categories { + r.productsByCategoriesReverseIndex[categoryTeaser.Code] = append(r.productsByCategoriesReverseIndex[categoryTeaser.Code], marketPlaceCode) + } + if product.BaseData().MainCategory.Code != "" { + if !inSlice(r.productsByCategoriesReverseIndex[product.BaseData().MainCategory.Code], marketPlaceCode) { + r.productsByCategoriesReverseIndex[product.BaseData().MainCategory.Code] = append(r.productsByCategoriesReverseIndex[product.BaseData().MainCategory.Code], marketPlaceCode) } } +} +func (r *InMemoryProductRepository) addProductToMarketplaceCodeReverseIndex(marketPlaceCode string, product productDomain.BasicProduct) error { + // Set reverse index for marketplaceCode (the primary identifier) + if r.marketplaceCodeIndex == nil { + r.marketplaceCodeIndex = make(map[string]productDomain.BasicProduct) + } + if r.marketplaceCodeIndex[marketPlaceCode] != nil { + err := errors.New("Duplicate for marketplace code " + marketPlaceCode) + r.logger.Error(err) + return err + } + r.marketplaceCodeIndex[marketPlaceCode] = product return nil } @@ -148,7 +164,7 @@ func (r *InMemoryProductRepository) FindByMarketplaceCode(_ context.Context, mar } } -//CategoryTree returns tree - empty code returns Rootnode +// CategoryTree returns tree - empty code returns RootNode func (r *InMemoryProductRepository) CategoryTree(_ context.Context, code string) (categoryDomain.Tree, error) { if r.rootCategory == nil { err := errors.New("category " + code + "not found. No tree indexed") @@ -157,13 +173,13 @@ func (r *InMemoryProductRepository) CategoryTree(_ context.Context, code string) if code == "" { return r.rootCategory, nil } - if tree, ok := r.categorTreeIndex[code]; ok { + if tree, ok := r.categoryTreeIndex[code]; ok { return tree, nil } return nil, categoryDomain.ErrNotFound } -//Category returns category - empty code returns root cat +// Category returns category - empty code returns root cat func (r *InMemoryProductRepository) Category(_ context.Context, code string) (categoryDomain.Category, error) { if r.rootCategory == nil { return nil, errors.New("root not found") @@ -174,7 +190,7 @@ func (r *InMemoryProductRepository) Category(_ context.Context, code string) (ca CategoryName: r.rootCategory.CategoryName, }, nil } - if tree, ok := r.categorTreeIndex[code]; ok { + if tree, ok := r.categoryTreeIndex[code]; ok { return &categoryDomain.CategoryData{ CategoryCode: tree.CategoryCode, CategoryName: tree.CategoryName, @@ -221,12 +237,12 @@ func (r *InMemoryProductRepository) Find(_ context.Context, filters ...searchDom } if !matchingMarketplaceCodes.initialFilled { - //get all products if not filtered yet + // get all products if not filtered yet for _, p := range r.marketplaceCodeIndex { productResults = append(productResults, p) } } else { - //otherwise get only the remaining marketplacecodes + // otherwise get only the remaining marketplace codes productResults = r.getMatchingProducts(matchingMarketplaceCodes.currentSet) } @@ -310,21 +326,21 @@ func (s *marketPlaceCodeSet) intersection(set2 []string) { s.currentSet = result } -//addCategoryPath - merges in the given categoryToAdd to the passed currentExisting +// addCategoryPath merges in the given categoryToAdd to the passed currentExisting // also adds new categories to the reverse index func (r *InMemoryProductRepository) addCategoryPath(currentTreeNode *categoryDomain.TreeData, treeNodeToAdd *categoryDomain.TreeData) *categoryDomain.TreeData { - if r.categorTreeIndex == nil { - r.categorTreeIndex = make(map[string]*categoryDomain.TreeData) + if r.categoryTreeIndex == nil { + r.categoryTreeIndex = make(map[string]*categoryDomain.TreeData) } - //if its the first node then make as current node + // if its the first node then make as current node if currentTreeNode == nil { clone := *treeNodeToAdd currentTreeNode = &clone currentTreeNode.SubTreesData = nil - r.categorTreeIndex[currentTreeNode.CategoryCode] = currentTreeNode + r.categoryTreeIndex[currentTreeNode.CategoryCode] = currentTreeNode } if currentTreeNode.CategoryCode != treeNodeToAdd.CategoryCode { - //No common root node - exit + // No common root node - exit return currentTreeNode } for _, subTreeNodeToAdd := range treeNodeToAdd.SubTreesData { @@ -332,11 +348,11 @@ func (r *InMemoryProductRepository) addCategoryPath(currentTreeNode *categoryDom for _, existingSubTree := range currentTreeNode.SubTreesData { if existingSubTree.CategoryCode == subTreeNodeToAdd.CategoryCode { exists = true - //match - proceed in recursion + // match - proceed in recursion existingSubTree = r.addCategoryPath(existingSubTree, subTreeNodeToAdd) } } - //subTreeNodeToAdd does not exist yet - so we merge it in: + // subTreeNodeToAdd does not exist yet - so we merge it in: if !exists { currentTreeNode.SubTreesData = append(currentTreeNode.SubTreesData, subTreeNodeToAdd) r.updateCategoryIndex(subTreeNodeToAdd) @@ -346,7 +362,7 @@ func (r *InMemoryProductRepository) addCategoryPath(currentTreeNode *categoryDom } func (r *InMemoryProductRepository) updateCategoryIndex(tree *categoryDomain.TreeData) { - r.categorTreeIndex[tree.Code()] = tree + r.categoryTreeIndex[tree.Code()] = tree for _, stree := range tree.SubTreesData { r.updateCategoryIndex(stree) } diff --git a/commercesearch/infrastructure/productsearch/inmemoryrepository_test.go b/commercesearch/infrastructure/productsearch/inmemoryrepository_test.go index 1f3fc8a..236c50b 100644 --- a/commercesearch/infrastructure/productsearch/inmemoryrepository_test.go +++ b/commercesearch/infrastructure/productsearch/inmemoryrepository_test.go @@ -2,10 +2,11 @@ package productsearch import ( "context" + "testing" + searchDomain "flamingo.me/flamingo-commerce/v3/search/domain" "flamingo.me/flamingo/v3/framework/flamingo" "github.com/stretchr/testify/require" - "testing" categoryDomain "flamingo.me/flamingo-commerce/v3/category/domain" "flamingo.me/flamingo-commerce/v3/product/domain" @@ -56,7 +57,7 @@ func TestInMemoryProductRepository_AddProduct(t *testing.T) { assert.Equal(t, "a title", result.Hits[0].BaseData().Title) assert.Equal(t, "b title", result.Hits[1].BaseData().Title) - //test pagination + // test pagination t.Run("Test pagination", func(t *testing.T) { result, _ = s.Find(context.Background(), categoryDomain.CategoryFacet{ CategoryCode: "Sub", diff --git a/commercesearch/infrastructure/productsearch/lily.bleve/index_meta.json b/commercesearch/infrastructure/productsearch/lily.bleve/index_meta.json deleted file mode 100644 index c75caf8..0000000 --- a/commercesearch/infrastructure/productsearch/lily.bleve/index_meta.json +++ /dev/null @@ -1 +0,0 @@ -{"storage":"scorch","index_type":"scorch"} \ No newline at end of file diff --git a/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000002.zap b/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000002.zap deleted file mode 100644 index 20b20cd..0000000 Binary files a/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000002.zap and /dev/null differ diff --git a/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000003.zap b/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000003.zap deleted file mode 100644 index 20b20cd..0000000 Binary files a/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000003.zap and /dev/null differ diff --git a/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000004.zap b/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000004.zap deleted file mode 100644 index 6335842..0000000 Binary files a/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000004.zap and /dev/null differ diff --git a/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000005.zap b/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000005.zap deleted file mode 100644 index e04e4d7..0000000 Binary files a/commercesearch/infrastructure/productsearch/lily.bleve/store/000000000005.zap and /dev/null differ diff --git a/commercesearch/infrastructure/productsearch/lily.bleve/store/root.bolt b/commercesearch/infrastructure/productsearch/lily.bleve/store/root.bolt deleted file mode 100644 index 2664214..0000000 Binary files a/commercesearch/infrastructure/productsearch/lily.bleve/store/root.bolt and /dev/null differ diff --git a/commercesearch/infrastructure/search/serviceadapter.go b/commercesearch/infrastructure/search/serviceadapter.go index 76a304d..70f1cb8 100644 --- a/commercesearch/infrastructure/search/serviceadapter.go +++ b/commercesearch/infrastructure/search/serviceadapter.go @@ -2,12 +2,14 @@ package search import ( "context" - "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + searchDomain "flamingo.me/flamingo-commerce/v3/search/domain" + + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" ) type ( - //ServiceAdapter for search service + // ServiceAdapter for search service ServiceAdapter struct { productRepository domain.ProductRepository } @@ -15,12 +17,12 @@ type ( var _ searchDomain.SearchService = &ServiceAdapter{} -//Inject - dingo injector +// Inject inject dependencies func (p *ServiceAdapter) Inject(productRepository domain.ProductRepository) { p.productRepository = productRepository } -//Search implementation +// Search implementation func (p *ServiceAdapter) Search(ctx context.Context, filter ...searchDomain.Filter) (map[string]searchDomain.Result, error) { res, err := p.productRepository.Find(ctx, filter...) if err != nil { @@ -41,7 +43,7 @@ func (p *ServiceAdapter) Search(ctx context.Context, filter ...searchDomain.Filt return mapRes, nil } -//SearchFor implementation +// SearchFor implementation func (p *ServiceAdapter) SearchFor(ctx context.Context, typ string, filter ...searchDomain.Filter) (*searchDomain.Result, error) { res, err := p.Search(ctx, filter...) if err != nil { diff --git a/commercesearch/module.go b/commercesearch/module.go index f94953a..82dcbb7 100644 --- a/commercesearch/module.go +++ b/commercesearch/module.go @@ -2,18 +2,21 @@ package commercesearch import ( "context" + "flamingo.me/dingo" - productSearchDomain "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" - "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/infrastructure/category" - "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/infrastructure/search" "flamingo.me/flamingo-commerce/v3/category/domain" domain2 "flamingo.me/flamingo-commerce/v3/search/domain" "flamingo.me/flamingo/v3/framework/flamingo" "flamingo.me/flamingo/v3/framework/web" + productSearchDomain "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/infrastructure/category" + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/infrastructure/search" + + productdomain "flamingo.me/flamingo-commerce/v3/product/domain" + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/infrastructure/product" "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/infrastructure/productsearch" - productdomain "flamingo.me/flamingo-commerce/v3/product/domain" ) type ( @@ -81,37 +84,9 @@ func (m *Module) Configure(injector *dingo.Injector) { case "bleve": injector.Bind((*productSearchDomain.ProductRepository)(nil)).To(productsearch.BleveRepository{}).In(dingo.ChildSingleton) injector.Bind((*productSearchDomain.CategoryRepository)(nil)).To(productsearch.BleveRepository{}).In(dingo.ChildSingleton) - - /* - injector.Bind((*productSearchDomain.ProductRepository)(nil)).ToProvider( - func(logger flamingo.Logger, repo *productSearch.BleveRepository, indexProcess *productSearchDomain.IndexProcess, config *struct { - EnableIndexing bool `inject:"config:flamingoCommerceAdapterStandalone.productSearch.enableIndexing,optional"` - }) productSearchDomain.ProductRepository { - enableIndexing := false - if config != nil { - enableIndexing = config.EnableIndexing - } - return indexIntoRepo(logger, repo, indexProcess, enableIndexing) - }).In(dingo.ChildSingleton) - */ - default: injector.Bind((*productSearchDomain.ProductRepository)(nil)).To(productsearch.InMemoryProductRepository{}).In(dingo.ChildSingleton) injector.Bind((*productSearchDomain.CategoryRepository)(nil)).To(productsearch.InMemoryProductRepository{}).In(dingo.ChildSingleton) - - /* - injector.Bind((*productSearchDomain.ProductRepository)(nil)).ToProvider( - func(logger flamingo.Logger, repo *productSearch.InMemoryProductRepository, indexProcess *productSearchDomain.IndexProcess, config *struct { - EnableIndexing bool `inject:"config:flamingoCommerceAdapterStandalone.productSearch.enableIndexing,optional"` - }) productSearchDomain.ProductRepository { - enableIndexing := false - if config != nil { - enableIndexing = config.EnableIndexing - } - return indexIntoRepo(logger, repo, indexProcess, enableIndexing) - }).In(dingo.ChildSingleton) - */ - } } @@ -134,6 +109,9 @@ flamingoCommerceAdapterStandalone: { repositoryAdapter: "bleve" | *"inmemory" bleveAdapter: { productsToParentCategories: bool | *true + enableCategoryFacet: bool | *false + facetConfig: [...{attributeCode: string, amount: number}] + sortConfig:[...{attributeCode: string, attributeType: "numeric"|"bool"|*"text", asc: bool, desc: bool}] } } }` diff --git a/commercesearch/module_test.go b/commercesearch/module_test.go new file mode 100644 index 0000000..82f0641 --- /dev/null +++ b/commercesearch/module_test.go @@ -0,0 +1,15 @@ +package commercesearch_test + +import ( + "testing" + + "flamingo.me/flamingo/v3/framework/config" + + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch" +) + +func TestModule_Configure(t *testing.T) { + if err := config.TryModules(nil, new(commercesearch.Module)); err != nil { + t.Error(err) + } +} diff --git a/csvindexing/Readme.md b/csvindexing/Readme.md index b0f67d6..2334b53 100644 --- a/csvindexing/Readme.md +++ b/csvindexing/Readme.md @@ -1,17 +1,18 @@ # csvcommerce This module provides: + * a IndexUpdater for "commercesearch" module * an image controller that shows product images - ## Usage for products: Place a `products.csv` and the product images in a folder - e.g. "ressources". -The images are served with the imagecontroller under the default route `/image/:size/:filename` -The ":size" parameter is in the form "widthxheight" - for example "200x" would scale the image to a width of 200px and the height is adjusted automatically. -The allowed imagesizes need to be configured (`flamingo-commerce-adapter-standalone.csvCommerce.allowedImageResizeParamaters`) +The images are served with the image controller under the default route `/image/:size/:filename` +The ":size" parameter is in the form "widthxheight" - for example "200x" would scale the image to a width of 200px and +the height is adjusted automatically. The allowed imagesizes need to be +configured (see `allowedImageResizeParamaters` config below) See the commerce-demo-carotene Demoshop for an example usage. @@ -19,51 +20,63 @@ Categories are only indexed if a category.csv is given. ## Configuration -``` -flamingoCommerceAdapterStandalone: - csvindexing: - productCsvPath: "ressources/products/products.csv" - categoryCsvPath: "ressources/products/category.csv" - locale: "en_GB" - currency: "€" - allowedImageResizeParamaters: "200x,300x,400x,x200,x300" - } +```yaml +flamingoCommerceAdapterStandalone: + csvindexing: + products: + file: + path: "resources/products/products.csv" + delimiter: "," + # attribute value that should be split by comma (e.g. attributeXY: "valueA, valueB" => attributeXY: ["valueA", "valueB"]) + attributesToSplit: "attributeXY" + categories: + file: + path: "resources/categories/categories.csv" + delimiter: ";" + locale: "en_GB" + currency: "GPB" + allowedImageResizeParameters: "200x,300x,400x,x200,x300" ``` - ## CSV Format -Use UTF8 encoded CSV with optional quotes and comma (,) as seperator. - +Use UTF8 encoded CSV with optional quotes and comma (,) as separator. Different delimters can be provided via config. ### Product CSV -The text fields that are normaly localized need to be postfixed with the configured local. -So if you have the configuration `flamingoCommerceAdapterStandalone.csvindexing.locale: en_GB` -a product title fieldname in the CSV need to be `title-en_GB`. +The text fields that are normally localized need to be postfixed with the configured local. So if you have the +configuration `flamingoCommerceAdapterStandalone.csvindexing.locale: en_GB` +a product title field name in the CSV need to be `title-en_GB`. + +Price fields need to be postfixed with currency name. Asset and Images paths need to be relative to the CSV folder. -Price fields need to be postfixed with currency name. -Asset and Images paths need to be relative to the CSV folder. +Mandatory fields: -Must have fields: -* marketplaceCode (the unique idendifier of the product) -* title-LOCALEPREFIX (the title) +* marketplaceCode (the unique identifier of the product) +* retailerCode (reference to the retailer) +* title-LOCALE (the title) +* metaKeywords-LOCALE (comma separated keywords) * productType ("simple" or "configurable") -* price-CURRENCY +* price-CURRENCY +* shortDescription-LOCALE Optional: -* specialPrice-CURRENCY -* categories (comma separated references to categories. Using the category code as idendifier) +* saleable (1/0 if product is saleable true/false, if not provided assumed as true) +* saleableFromDate (from when should the product be saleable, date string in RFC3339 format) +* saleableToDate (till when should the product be saleable, RFC3339) +* specialPrice-CURRENCY (promotional price) +* retailerName +* categories (comma separated references to categories. Using the category code as identifier) * retailerCode (reference to the retailer / vendor of the product) -* shortDescription-LOCALEPREFIX -* description-LOCALEPREFIX -* metaKeywords-LOCALEPREFIX (comma separated keywords) +* stockLevel (define stock level of product: in, out, low) +* description-LOCALE * listImage * thumbnailImage * detailImage01,detailImage02 ... detailImage10 * ??? - any other field will be added as a product attribute For configurable product types: + * variantVariationAttributes (The attribute) * CONFIGURABLE-products (comma separated references to other products (use marketplacecode as id)) @@ -72,9 +85,17 @@ For configurable product types: "hellokitty-s-red",98,"Hello Kitty S Red","Hello Kitty S Red","Hello Kitty S Red description","Hello Kitty is great",,"30.00",,,,,"productfiles/images/sanni-sahil-1173038-unsplash.jpg","productfiles/images/sanni-sahil-1173038-unsplash.jpg","productfiles/images/sanni-sahil-1173038-unsplash.jpg",,"clothing","aoepeople","cross_segment","hellokitty-s-red","kitty","simple","S","Red",, ``` - ### Category CSV + +Mandatory fields: + +* code +* parent (code of the parent category, if root category same as code) +* label-LOCALE (category label) + +``` "code","parent","label-en_GB" "master","master","master" "clothing","master","Clothing" -"accessories","master","accessories" \ No newline at end of file +"accessories","master","accessories" +``` \ No newline at end of file diff --git a/csvindexing/infrastructure/commercesearch/indexing.go b/csvindexing/infrastructure/commercesearch/indexing.go index c69d962..50e31ef 100644 --- a/csvindexing/infrastructure/commercesearch/indexing.go +++ b/csvindexing/infrastructure/commercesearch/indexing.go @@ -3,31 +3,33 @@ package commercesearch import ( "context" "errors" - commerceSearchDomain "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" - categorydomain "flamingo.me/flamingo-commerce/v3/category/domain" - "fmt" + "strconv" "strings" + "time" + categorydomain "flamingo.me/flamingo-commerce/v3/category/domain" priceDomain "flamingo.me/flamingo-commerce/v3/price/domain" - - "strconv" - - "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing/infrastructure/csv" - "flamingo.me/flamingo-commerce/v3/product/domain" + "flamingo.me/flamingo/v3/framework/config" "flamingo.me/flamingo/v3/framework/flamingo" + + commerceSearchDomain "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing/infrastructure/csv" ) type ( // IndexUpdater implements indexing based on CSV file IndexUpdater struct { - logger flamingo.Logger - productCsvFile string - categoryCsvFile string - categoryTreeBuilder *commerceSearchDomain.CategoryTreeBuilder - locale string - currency string + logger flamingo.Logger + productCsvFile string + productCsvDelimiter rune + productAttributesToSplit map[string]struct{} + categoryCsvFile string + categoryCsvDelimiter rune + categoryTreeBuilder *commerceSearchDomain.CategoryTreeBuilder + locale string + currency string } ) @@ -38,23 +40,43 @@ var ( // Inject method to inject dependencies func (f *IndexUpdater) Inject(logger flamingo.Logger, categoryTreeBuilder *commerceSearchDomain.CategoryTreeBuilder, config *struct { - ProductCsvFile string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.productCsvPath"` - CategoryCsvFile string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.categoryCsvPath, optional"` - Locale string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.locale"` - Currency string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.currency"` + ProductCsvFile string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.products.file.path"` + ProductCsvDelimiter string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.products.file.delimiter"` + ProductAttributesToSplit config.Slice `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.products.attributesToSplit"` + CategoryCsvFile string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.categories.file.path,optional"` + CategoryCsvDelimiter string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.categories.file.delimiter,optional"` + Locale string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.locale"` + Currency string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.currency"` }) { f.logger = logger.WithField(flamingo.LogKeyModule, "flamingo-commerce-adapter-standalone.csvindexing").WithField(flamingo.LogKeyCategory, "IndexUpdater") - if config == nil { - return - } - f.productCsvFile = config.ProductCsvFile - f.categoryCsvFile = config.CategoryCsvFile - f.locale = config.Locale - f.currency = config.Currency f.categoryTreeBuilder = categoryTreeBuilder + if config != nil { + f.productCsvFile = config.ProductCsvFile + if config.ProductCsvDelimiter != "" { + f.productCsvDelimiter = []rune(config.ProductCsvDelimiter)[0] + } + f.categoryCsvFile = config.CategoryCsvFile + if config.CategoryCsvDelimiter != "" { + f.categoryCsvDelimiter = []rune(config.CategoryCsvDelimiter)[0] + } + + var toSplit []string + err := config.ProductAttributesToSplit.MapInto(&toSplit) + if err != nil { + panic(err) + } + + f.productAttributesToSplit = make(map[string]struct{}) + for _, attribute := range toSplit { + f.productAttributesToSplit[attribute] = struct{}{} + } + + f.locale = config.Locale + f.currency = config.Currency + } } -//Index starts index process +// Index starts index process func (f *IndexUpdater) Index(ctx context.Context, indexer *commerceSearchDomain.Indexer) error { f.logger.Info(fmt.Sprintf("Start loading CSV file: %v with locale: %v and currency %v", f.productCsvFile, f.locale, f.currency)) @@ -62,7 +84,7 @@ func (f *IndexUpdater) Index(ctx context.Context, indexer *commerceSearchDomain. var tree categorydomain.Tree // read category tree if f.categoryCsvFile != "" { - catrows, err := csv.ReadCSV(f.categoryCsvFile) + catrows, err := csv.ReadCSV(f.categoryCsvFile, csv.DelimiterOption(f.productCsvDelimiter)) if err != nil { return errors.New(err.Error() + " / File: " + f.categoryCsvFile) } @@ -70,15 +92,14 @@ func (f *IndexUpdater) Index(ctx context.Context, indexer *commerceSearchDomain. f.categoryTreeBuilder.AddCategoryData(row["code"], row["label-"+f.locale], row["parent"]) } tree, err = f.categoryTreeBuilder.BuildTree() - //fmt.Printf("\n %#v",tree) - //printTree(tree,"") + // printTree(tree,"") if err != nil { return err } } - //Index products - rows, err := csv.ReadCSV(f.productCsvFile) + // Index products + rows, err := csv.ReadCSV(f.productCsvFile, csv.DelimiterOption(f.categoryCsvDelimiter)) if err != nil { return errors.New(err.Error() + " / File: " + f.productCsvFile) } @@ -159,7 +180,16 @@ func splitTrimmed(value string) []string { // validateRow ensures CSV Rows have the correct columns func (f *IndexUpdater) validateRow(row map[string]string, locale string, currency string, additionalRequiredCols []string) error { - additionalRequiredCols = append(additionalRequiredCols, []string{"marketplaceCode", "retailerCode", "title-" + locale, "metaKeywords-" + locale, "shortDescription-" + locale, "description-" + locale, "price-" + currency}...) + additionalRequiredCols = append(additionalRequiredCols, + []string{ + "marketplaceCode", + "retailerCode", + "title-" + locale, + "metaKeywords-" + locale, + "shortDescription-" + locale, + "description-" + locale, + "price-" + currency, + }...) for _, requiredAttribute := range additionalRequiredCols { if _, ok := row[requiredAttribute]; !ok { return fmt.Errorf("required attribute %q is missing", requiredAttribute) @@ -174,11 +204,33 @@ func (f *IndexUpdater) getBasicProductData(row map[string]string, locale string, attributes := make(map[string]domain.Attribute) for key, data := range row { + + // skip other locales + parts := strings.Split(key, "-") + if len(parts) > 1 { + l := parts[len(parts)-1] + if l != "" && l != locale { + continue + } + } + + key = strings.TrimSuffix(key, "-"+locale) + attributes[key] = domain.Attribute{ Code: key, CodeLabel: key, Label: data, - RawValue: data, + RawValue: func() interface{} { + if _, found := f.productAttributesToSplit[key]; !found { + return data + } + + var split []interface{} + for _, s := range strings.Split(data, ",") { + split = append(split, s) + } + return split + }(), } } @@ -194,6 +246,14 @@ func (f *IndexUpdater) getBasicProductData(row map[string]string, locale string, } } + stockLevel := domain.StockLevelInStock + switch row["stockLevel"] { + case domain.StockLevelInStock, + domain.StockLevelLowStock, + domain.StockLevelOutOfStock: + stockLevel = row["stockLevel"] + } + basicProductData := domain.BasicProductData{ MarketPlaceCode: row["marketplaceCode"], RetailerCode: row["retailerCode"], @@ -201,10 +261,11 @@ func (f *IndexUpdater) getBasicProductData(row map[string]string, locale string, Title: row["title-"+locale], ShortDescription: row["shortDescription-"+locale], Description: row["description-"+locale], - RetailerName: row["retailerCode"], + RetailerName: row["retailerName"], Media: f.getMedia(row, locale), Keywords: strings.Split("metaKeywords-"+locale, ","), Attributes: attributes, + StockLevel: stockLevel, } if len(categories) > 0 { basicProductData.MainCategory = categories[0] @@ -230,10 +291,29 @@ func (f *IndexUpdater) buildSimpleProduct(row map[string]string, locale string, if specialPriceErr == nil && specialPrice != price { hasSpecialPrice = true } + + isSaleable := true + if _, ok := row["saleable"]; ok { + isSaleable, _ = strconv.ParseBool(row["saleable"]) + } + + saleableFrom := time.Time{} + if from, ok := row["saleableFromDate"]; ok { + saleableFrom, _ = time.Parse(time.RFC3339, from) + } + + saleableTo := time.Time{} + if from, ok := row["saleableToDate"]; ok { + saleableTo, _ = time.Parse(time.RFC3339, from) + } + simple := domain.SimpleProduct{ Identifier: f.getIdentifier(row), BasicProductData: f.getBasicProductData(row, locale, tree), Saleable: domain.Saleable{ + IsSaleable: isSaleable, + SaleableFrom: saleableFrom, + SaleableTo: saleableTo, ActivePrice: domain.PriceInfo{ Default: priceDomain.NewFromFloat(price, currency).GetPayable(), IsDiscounted: hasSpecialPrice, @@ -243,9 +323,10 @@ func (f *IndexUpdater) buildSimpleProduct(row map[string]string, locale string, } simple.Teaser = domain.TeaserData{ - TeaserPrice: simple.Saleable.ActivePrice, - ShortDescription: simple.BasicProductData.ShortDescription, ShortTitle: simple.BasicProductData.Title, + ShortDescription: simple.BasicProductData.ShortDescription, + TeaserPrice: simple.Saleable.ActivePrice, + Media: simple.BaseData().Media, MarketPlaceCode: simple.BasicProductData.MarketPlaceCode, } diff --git a/csvindexing/infrastructure/csv/csvReader.go b/csvindexing/infrastructure/csv/csvReader.go index b801c1c..7b4bbdd 100644 --- a/csvindexing/infrastructure/csv/csvReader.go +++ b/csvindexing/infrastructure/csv/csvReader.go @@ -4,18 +4,29 @@ import ( "bufio" "encoding/csv" "io" - "os" - "log" + "os" ) type ( // RowDto is a simple Data Transfer Object to receive CSV Rows RowDto map[string]string + + // ReadOption option to modify the csv.Reader + ReadOption func(reader *csv.Reader) ) +// DelimiterOption to set the csv delimiter +func DelimiterOption(delimiter rune) ReadOption { + return func(reader *csv.Reader) { + if delimiter > 0 { + reader.Comma = delimiter + } + } +} + // ReadCSV reads a CSV File and returns its Contents -func ReadCSV(csvFile string) ([]RowDto, error) { +func ReadCSV(csvFile string, options ...ReadOption) ([]RowDto, error) { f, err := os.Open(csvFile) if err != nil { log.Printf("Error - RowDto %v", err) @@ -28,7 +39,12 @@ func ReadCSV(csvFile string) ([]RowDto, error) { // Create a new reader. r := csv.NewReader(bufio.NewReader(f)) r.LazyQuotes = true - r.Comma = ',' + r.TrimLeadingSpace = true + if options != nil { + for _, option := range options { + option(r) + } + } rowCount := 0 isFirstRow := true diff --git a/csvindexing/interfaces/controller/imagecontroller.go b/csvindexing/interfaces/controller/imagecontroller.go index 997c315..dfe9942 100644 --- a/csvindexing/interfaces/controller/imagecontroller.go +++ b/csvindexing/interfaces/controller/imagecontroller.go @@ -6,11 +6,10 @@ import ( "image" "image/jpeg" "os" + "path/filepath" "strconv" "strings" - "path/filepath" - "flamingo.me/flamingo/v3/framework/flamingo" "flamingo.me/flamingo/v3/framework/web" "github.com/disintegration/imaging" @@ -21,26 +20,26 @@ type ( ImageController struct { Responder *web.Responder `inject:""` Logger flamingo.Logger `inject:""` - ProductCsvPath string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.productCsvPath"` - AllowedResizeParamaters string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.allowedImageResizeParamaters"` + ProductCsvPath string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.products.file.path"` + AllowedResizeParameters string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.allowedImageResizeParameters"` } ) -//renderChan - channel that is limited to 5 - used to block amount of parallel requests +// renderChan channel that is limited to 5 - used to block amount of parallel requests var renderChan = make(chan struct{}, 5) // Get Response for Images func (vc *ImageController) Get(c context.Context, r *web.Request) web.Result { - //block if buffered channel size is reached + // block if buffered channel size is reached renderChan <- struct{}{} defer func() { - //release one entry from channel (will release one block) + // release one entry from channel (will release one block) <-renderChan }() filename := r.Params["filename"] size := r.Params["size"] - if !inSlice(size, strings.Split(vc.AllowedResizeParamaters, ",")) { + if !inSlice(size, strings.Split(vc.AllowedResizeParameters, ",")) { vc.Logger.Warn("Imagesize " + size + " not allowed!") size = "200x" } diff --git a/csvindexing/module.go b/csvindexing/module.go index c0aeaf7..7a9c29f 100644 --- a/csvindexing/module.go +++ b/csvindexing/module.go @@ -2,14 +2,15 @@ package csvindexing import ( "flamingo.me/dingo" - commercesearchModule "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch" - commercesearchDomain "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" - "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing/infrastructure/commercesearch" - "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing/interfaces/controller" categorydomain "flamingo.me/flamingo-commerce/v3/category/domain" productdomain "flamingo.me/flamingo-commerce/v3/product/domain" searchdomain "flamingo.me/flamingo-commerce/v3/search/domain" "flamingo.me/flamingo/v3/framework/web" + + commercesearchModule "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch" + commercesearchDomain "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing/infrastructure/commercesearch" + "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing/interfaces/controller" ) // Ensure types for the Ports and Adapters @@ -27,7 +28,7 @@ type ( // Configure DI func (m *ProductModule) Configure(injector *dingo.Injector) { - //Register IndexUpdater for productSearch + // Register IndexUpdater for productSearch injector.Bind((*commercesearchDomain.IndexUpdater)(nil)).To(commercesearch.IndexUpdater{}) web.BindRoutes(injector, new(routes)) @@ -43,7 +44,7 @@ func (r *routes) Inject(controller *controller.ImageController) { func (r *routes) Routes(registry *web.RouterRegistry) { registry.HandleGet("csvcommerce.image.get", r.controller.Get) - registry.Route("/image/:size/:filename", `csvcommerce.image.get(size,filename)`) + registry.MustRoute("/image/:size/:filename", `csvcommerce.image.get(size,filename)`) } // Depends on other modules @@ -58,11 +59,27 @@ func (m *ProductModule) CueConfig() string { return ` flamingoCommerceAdapterStandalone: { csvindexing: { - productCsvPath: string | *"ressources/products/products.csv" - categoryCsvPath: string | *"" + file :: { + path: string + delimiter: string | *"," + } + + products: { + file: file & { + path: string | *"resources/products/products.csv" + } + attributesToSplit: [...string] + } + + categories: { + file: file & { + path: string | *"resources/categories/categories.csv" + } + } + locale: string | *"en" currency: string | *"€" - allowedImageResizeParamaters: string | *"200x,300x,400x,x200,x300" + allowedImageResizeParameters: string | *"200x,300x,400x,x200,x300" } }` } diff --git a/csvindexing/module_test.go b/csvindexing/module_test.go new file mode 100644 index 0000000..072a26e --- /dev/null +++ b/csvindexing/module_test.go @@ -0,0 +1,15 @@ +package csvindexing_test + +import ( + "testing" + + "flamingo.me/flamingo/v3/framework/config" + + "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing" +) + +func TestModule_Configure(t *testing.T) { + if err := config.TryModules(nil, new(csvindexing.ProductModule)); err != nil { + t.Error(err) + } +} diff --git a/csvindexing/test/functional_test.go b/csvindexing/test/functional_test.go index a78486e..0a00e57 100644 --- a/csvindexing/test/functional_test.go +++ b/csvindexing/test/functional_test.go @@ -2,21 +2,24 @@ package test_test import ( "context" - domain2 "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" - csvcommerceLoader "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing/infrastructure/commercesearch" - "flamingo.me/flamingo/v3/framework/flamingo" "fmt" - "github.com/stretchr/testify/require" + "path" + "runtime" "sort" "testing" - "path" - "runtime" + "flamingo.me/flamingo/v3/framework/config" + "flamingo.me/flamingo/v3/framework/flamingo" + "github.com/stretchr/testify/require" + + domain2 "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/domain" + csvcommerceLoader "flamingo.me/flamingo-commerce-adapter-standalone/csvindexing/infrastructure/commercesearch" - "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/infrastructure/productsearch" "flamingo.me/flamingo-commerce/v3/product/domain" searchDomain "flamingo.me/flamingo-commerce/v3/search/domain" "github.com/stretchr/testify/assert" + + "flamingo.me/flamingo-commerce-adapter-standalone/commercesearch/infrastructure/productsearch" ) func TestFactoryCanBuildSimpleTest(t *testing.T) { @@ -187,15 +190,20 @@ func getRepositoryWithFixturesLoaded(t *testing.T, productCsv string) *productse loader.Inject(flamingo.NullLogger{}, &domain2.CategoryTreeBuilder{}, &struct { - ProductCsvFile string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.productCsvPath"` - CategoryCsvFile string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.categoryCsvPath, optional"` - Locale string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.locale"` - Currency string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.currency"` + ProductCsvFile string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.products.file.path"` + ProductCsvDelimiter string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.products.file.delimiter"` + ProductAttributesToSplit config.Slice `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.products.attributesToSplit"` + CategoryCsvFile string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.categories.file.path,optional"` + CategoryCsvDelimiter string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.categories.file.delimiter,optional"` + Locale string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.locale"` + Currency string `inject:"config:flamingoCommerceAdapterStandalone.csvindexing.currency"` }{ - Currency: "GBP", - Locale: "en_GB", - ProductCsvFile: "fixture/" + productCsv, - CategoryCsvFile: "fixture/categories.csv", + Currency: "GBP", + Locale: "en_GB", + ProductCsvFile: "fixture/" + productCsv, + CategoryCsvFile: "fixture/categories.csv", + ProductCsvDelimiter: ",", + CategoryCsvDelimiter: ",", }, ) err := loader.Index(context.Background(), indexer) diff --git a/emailplaceorder/Readme.md b/emailplaceorder/Readme.md index 5659c9c..a988399 100644 --- a/emailplaceorder/Readme.md +++ b/emailplaceorder/Readme.md @@ -1,14 +1,34 @@ -# csvcommerce +# E-Mail place order adapter -This module provides: -* a Loader for "productSearch" module that loads from CSV -* an image controller that shows product images +Adapter that sends basic emails as soon as a customer places an order. Both the admin/owner of the shop as well as the +customer get an email confirmation. +## `MailSender` Port -## Usage: +To deliver an email a custom `MailSender` implementation can be used. The module comes with a default implementation +that relies on basic SMTP functionality. -Place a `products.csv` and the product images in a folder - e.g. "ressources". +## `MailTemplate` Port + +Besides, the actual mail delivery there is also a port for defining the used email templates. There is a default +implementation as well, see `infrastructure/template` for details. + +## Configuration + +There are various configurations that can be set. In addition, the default SMTP delivery needs some credentials to work. + +```yaml +flamingoCommerceAdapterStandalone: + emailplaceorder: + emailAddress: fulfilment@flamingo-shop.example + fromMail: no-reply@flamingo-shop.example + fromName: Flamingo Shop + credentials: + server: smtp.example.com + port: 587 + user: user + password: %%ENV:SMTP_PASSWORD%% +``` -See the commerce-demo-carotene for an example. diff --git a/emailplaceorder/infrastructure/emailplaceorder.go b/emailplaceorder/infrastructure/emailplaceorder.go index 042a0ba..f4bf147 100644 --- a/emailplaceorder/infrastructure/emailplaceorder.go +++ b/emailplaceorder/infrastructure/emailplaceorder.go @@ -3,12 +3,13 @@ package infrastructure import ( "context" "errors" - "flamingo.me/flamingo/v3/framework/config" "fmt" "net/smtp" "net/textproto" "strings" + "flamingo.me/flamingo/v3/framework/config" + cartDomain "flamingo.me/flamingo-commerce/v3/cart/domain/cart" "flamingo.me/flamingo-commerce/v3/cart/domain/placeorder" "flamingo.me/flamingo/v3/core/auth" @@ -37,25 +38,25 @@ type ( User string } - //MailSender interface + // MailSender interface MailSender interface { Send(credentials Credentials, to string, fromMail string, fromName string, mail *Mail) error } - //MailTemplate interface + // MailTemplate interface MailTemplate interface { AdminMail(cart *cartDomain.Cart, payment *placeorder.Payment) (*Mail, error) CustomerMail(cart *cartDomain.Cart, payment *placeorder.Payment) (*Mail, error) } - //Mail representation + // Mail representation Mail struct { HTML string Plain string Subject string } - //DefaultMailSender implementation of MailSender + // DefaultMailSender implementation of MailSender DefaultMailSender struct { logger flamingo.Logger } @@ -189,12 +190,12 @@ func (e *PlaceOrderServiceAdapter) sendMail(to string, mail *Mail) error { return nil } -//Inject dep +// Inject dep func (m *DefaultMailSender) Inject(logger flamingo.Logger) { m.logger = logger.WithField(flamingo.LogKeyModule, "flamingo-commerce-adapter-standalone.emailplaceorder").WithField("category", "emailplaceorder") } -//Send mail +// Send mail func (m *DefaultMailSender) Send(credentials Credentials, to string, fromMail string, fromName string, mail *Mail) error { err := credentials.Validate() if err != nil { @@ -212,7 +213,7 @@ func (m *DefaultMailSender) Send(credentials Credentials, to string, fromMail st return email.Send(fmt.Sprintf("%v:%v", credentials.Server, credentials.Port), smtp.PlainAuth("", credentials.User, credentials.Password, credentials.Server)) } -//Validate helper +// Validate helper func (s *Credentials) Validate() error { if s.Server == "" { return errors.New("Credentials missing server") diff --git a/emailplaceorder/infrastructure/emailplaceorder_test.go b/emailplaceorder/infrastructure/emailplaceorder_test.go index 605c8f2..32a2037 100644 --- a/emailplaceorder/infrastructure/emailplaceorder_test.go +++ b/emailplaceorder/infrastructure/emailplaceorder_test.go @@ -2,30 +2,31 @@ package infrastructure_test import ( "context" - "flamingo.me/flamingo-commerce-adapter-standalone/emailplaceorder/infrastructure" - "flamingo.me/flamingo-commerce-adapter-standalone/emailplaceorder/infrastructure/template" + "fmt" + "testing" + "flamingo.me/flamingo-commerce/v3/cart/domain/cart" "flamingo.me/flamingo-commerce/v3/cart/domain/placeorder" "flamingo.me/flamingo-commerce/v3/price/domain" "flamingo.me/flamingo/v3/framework/config" "flamingo.me/flamingo/v3/framework/flamingo" - "fmt" "github.com/stretchr/testify/assert" - "testing" + "flamingo.me/flamingo-commerce-adapter-standalone/emailplaceorder/infrastructure" + "flamingo.me/flamingo-commerce-adapter-standalone/emailplaceorder/infrastructure/template" ) type mailSenderStub struct { called int lastText string - lastHtml string + lastHTML string } var _ infrastructure.MailSender = &mailSenderStub{} func (m *mailSenderStub) Send(credentials infrastructure.Credentials, to string, fromMail string, fromName string, mail *infrastructure.Mail) error { m.called++ - m.lastHtml = mail.HTML + m.lastHTML = mail.HTML m.lastText = mail.Plain return nil } @@ -59,9 +60,9 @@ func TestPlaceOrderServiceAdapter_PlaceGuestCart(t *testing.T) { po, err := adapter.PlaceGuestCart(context.Background(), &exampleCart, &payment) assert.NoError(t, err) assert.Len(t, po, 2) - assert.Contains(t, mailsender.lastHtml, "adrianna@mail.de") - assert.Contains(t, mailsender.lastHtml, "ProductName 2") - assert.Contains(t, mailsender.lastHtml, "Opa", "Deliveryaddress not part of mail template") + assert.Contains(t, mailsender.lastHTML, "adrianna@mail.de") + assert.Contains(t, mailsender.lastHTML, "ProductName 2") + assert.Contains(t, mailsender.lastHTML, "Opa", "Deliveryaddress not part of mail template") }) t.Run("cart with delivery same as billing ", func(t *testing.T) { @@ -86,9 +87,9 @@ func TestPlaceOrderServiceAdapter_PlaceGuestCart(t *testing.T) { po, err := adapter.PlaceGuestCart(context.Background(), &exampleCart, &payment) assert.NoError(t, err) assert.Len(t, po, 2) - assert.Contains(t, mailsender.lastHtml, "adrianna@mail.de") - assert.Contains(t, mailsender.lastHtml, "ProductName 2") - assert.Contains(t, mailsender.lastHtml, "Use billing address", "Same as billing missing") + assert.Contains(t, mailsender.lastHTML, "adrianna@mail.de") + assert.Contains(t, mailsender.lastHTML, "ProductName 2") + assert.Contains(t, mailsender.lastHTML, "Use billing address", "Same as billing missing") }) } diff --git a/emailplaceorder/module.go b/emailplaceorder/module.go index 3e30607..ba7c4ce 100644 --- a/emailplaceorder/module.go +++ b/emailplaceorder/module.go @@ -10,7 +10,7 @@ import ( ) type ( - // Module registers our profiler + // Module registers our email place order adapter Module struct { } ) diff --git a/emailplaceorder/module_test.go b/emailplaceorder/module_test.go new file mode 100644 index 0000000..c5eca9a --- /dev/null +++ b/emailplaceorder/module_test.go @@ -0,0 +1,18 @@ +package emailplaceorder_test + +import ( + "testing" + + "flamingo.me/flamingo/v3/framework/config" + + "flamingo.me/flamingo-commerce-adapter-standalone/emailplaceorder" +) + +func TestModule_Configure(t *testing.T) { + if err := config.TryModules(config.Map{ + "core.auth.web.debugController": false, + "commerce.cart.placeOrderLogger.enabled": false, + }, new(emailplaceorder.Module)); err != nil { + t.Error(err) + } +} diff --git a/go.mod b/go.mod index 1cf6ad4..6d5ca5b 100644 --- a/go.mod +++ b/go.mod @@ -1,36 +1,30 @@ module flamingo.me/flamingo-commerce-adapter-standalone +go 1.13 + require ( flamingo.me/dingo v0.2.9 - flamingo.me/flamingo-commerce/v3 v3.3.1-0.20200904150134-2ee09e6ec33b - flamingo.me/flamingo/v3 v3.2.1-0.20200829173237-c992c361e4d1 - git.apache.org/thrift.git v0.12.0 // indirect - github.com/Masterminds/sprig v2.16.0+incompatible - github.com/RoaringBitmap/roaring v0.4.19 // indirect - github.com/blevesearch/bleve v0.8.0 - github.com/blevesearch/go-porterstemmer v1.0.2 // indirect - github.com/blevesearch/segment v0.0.0-20160915185041-762005e7a34f // indirect - github.com/couchbase/vellum v0.0.0-20190823171024-95128b2d4edb // indirect - github.com/disintegration/imaging v1.5.0 - github.com/edsrzf/mmap-go v1.0.0 // indirect - github.com/etcd-io/bbolt v1.3.3 // indirect - github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835 // indirect - github.com/garyburd/redigo v1.6.0 // indirect - github.com/go-bindata/go-bindata v0.0.0-20190711162640-ee3c2418e368 // indirect - github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 // indirect - github.com/gordonklaus/ineffassign v0.0.0-20200809085317-e36bfde3bb78 // indirect - github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect - github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e - github.com/matcornic/hermes/v2 v2.1.0 - github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d // indirect - github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect + flamingo.me/flamingo-commerce/v3 v3.3.1-0.20201102130503-2e26bb234ade + flamingo.me/flamingo/v3 v3.2.1 + github.com/Masterminds/goutils v1.1.0 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Masterminds/sprig v2.22.0+incompatible + github.com/blevesearch/bleve v1.0.12 + github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect + github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect + github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect + github.com/disintegration/imaging v1.6.2 + github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c // indirect + github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect + github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 // indirect + github.com/google/go-cmp v0.4.0 + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.11 // indirect + github.com/jmhodges/levigo v1.0.0 // indirect + github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/stretchr/testify v1.6.1 - github.com/urfave/cli v1.22.4 // indirect - github.com/urfave/cli/v2 v2.2.0 // indirect - github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe - golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 // indirect - google.golang.org/api v0.19.0 - gotest.tools v2.2.0+incompatible // indirect + github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + github.com/vanng822/go-premailer v1.9.0 ) - -go 1.13 diff --git a/go.sum b/go.sum index 2be377a..4782acc 100644 --- a/go.sum +++ b/go.sum @@ -2,7 +2,6 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxo 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= -contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA= contrib.go.opencensus.io/exporter/jaeger v0.2.0 h1:nhTv/Ry3lGmqbJ/JGvCjWxBl5ozRfqo86Ngz59UAlfk= contrib.go.opencensus.io/exporter/jaeger v0.2.0/go.mod h1:ukdzwIYYHgZ7QYtwVFQUjiT28BJHiMhTERo32s6qVgM= contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= @@ -11,80 +10,47 @@ contrib.go.opencensus.io/exporter/zipkin v0.1.1 h1:PR+1zWqY8ceXs1qDQQIlgXe+sdiwC contrib.go.opencensus.io/exporter/zipkin v0.1.1/go.mod h1:GMvdSl3eJ2gapOaLKzTKE3qDgUkJ86k9k3yY2eqwkzc= cuelang.org/go v0.0.15 h1:rpZtf1ZGYfZwbMHLwIif5Gczil+HF7rHAU7MFNOGV/A= cuelang.org/go v0.0.15/go.mod h1:gehQASsTv+lFZknWIG0hANGVSBiHD7HyKWmAdEZL3No= -flamingo.me/dingo v0.1.3/go.mod h1:9jDIxhkRLEW9I8axzJb0S/kJ0xv3U8gPxY92uEIHEcE= -flamingo.me/dingo v0.1.4 h1:NiwticQpW6LZGseaa8TCZRV3S3zGCV+GSa+L5P6wYD4= -flamingo.me/dingo v0.1.4/go.mod h1:jLnqSPkxqE113eKreQ4uBx1fnwluGuaK3rjRi9041wU= -flamingo.me/dingo v0.1.5 h1:nvhmtoSE8ihA+q5qHgh6WXrmLS5QX8jdCDwydyIrwh8= -flamingo.me/dingo v0.1.5/go.mod h1:jLnqSPkxqE113eKreQ4uBx1fnwluGuaK3rjRi9041wU= flamingo.me/dingo v0.1.6/go.mod h1:jLnqSPkxqE113eKreQ4uBx1fnwluGuaK3rjRi9041wU= -flamingo.me/dingo v0.1.7/go.mod h1:jLnqSPkxqE113eKreQ4uBx1fnwluGuaK3rjRi9041wU= -flamingo.me/dingo v0.2.3/go.mod h1:NXspAYkbktnP0EKs/27QW6Evija8WZfWGtrMcauOejQ= -flamingo.me/dingo v0.2.6/go.mod h1:NXspAYkbktnP0EKs/27QW6Evija8WZfWGtrMcauOejQ= -flamingo.me/dingo v0.2.7/go.mod h1:NXspAYkbktnP0EKs/27QW6Evija8WZfWGtrMcauOejQ= flamingo.me/dingo v0.2.9 h1:HL7YV4iv3F6xLcUPvIBEzdkbhBSb6PukkZdoOZ8H+Eo= flamingo.me/dingo v0.2.9/go.mod h1:NXspAYkbktnP0EKs/27QW6Evija8WZfWGtrMcauOejQ= -flamingo.me/flamingo-commerce/v3 v3.0.0-beta.1 h1:GJ7OKKgWJx455dZJYCh/cHtdmIa+NEtnHnBvmAKXU/0= -flamingo.me/flamingo-commerce/v3 v3.0.0-beta.1/go.mod h1:Dv0jLLTiSeFbhX7JNW2YXZ8kvelvGVzmGQ+zmr4qhHc= -flamingo.me/flamingo-commerce/v3 v3.2.1-0.20200629110035-7265f9cb9c9f h1:+Z7OqKqivjvccitYaJg//d9SYsoj6GL2AF17nlwCVKg= -flamingo.me/flamingo-commerce/v3 v3.2.1-0.20200629110035-7265f9cb9c9f/go.mod h1:B/UEppOc0/3zV1wgdsnvLh1PlEVNYMyA5yKAW+Gc2YQ= -flamingo.me/flamingo-commerce/v3 v3.3.1-0.20200829191916-b2d851444347 h1:dvt8W6ZMg27CB7i4a7C3nN+WiDv9b55+zLmo0PcxsOs= -flamingo.me/flamingo-commerce/v3 v3.3.1-0.20200829191916-b2d851444347/go.mod h1:BMlFWNTMucrs3z9bTEYY6azDbFnIb0ZDH9bVNi8bjkA= -flamingo.me/flamingo-commerce/v3 v3.3.1-0.20200831171617-1db70b384288 h1:7AMu8EsF5aamKnimLjw/OqBdP6An8cL3enjE4XtqMhw= -flamingo.me/flamingo-commerce/v3 v3.3.1-0.20200831171617-1db70b384288/go.mod h1:BMlFWNTMucrs3z9bTEYY6azDbFnIb0ZDH9bVNi8bjkA= -flamingo.me/flamingo-commerce/v3 v3.3.1-0.20200904150134-2ee09e6ec33b h1:8sdPhoZZXZJEqCQSNJ+PVKa1y42YaSqmSjGJZrBwvGk= flamingo.me/flamingo-commerce/v3 v3.3.1-0.20200904150134-2ee09e6ec33b/go.mod h1:BMlFWNTMucrs3z9bTEYY6azDbFnIb0ZDH9bVNi8bjkA= -flamingo.me/flamingo/v3 v3.0.0-beta.1 h1:re3uxGtUWSwKpsFANXGOBX0qJoP2AA5V1yZ3Jb2ZbQ4= -flamingo.me/flamingo/v3 v3.0.0-beta.1/go.mod h1:DUYtZWF8zGyACglnKKcqWsKtgUSUJFZoZh7NpBzQ9wQ= +flamingo.me/flamingo-commerce/v3 v3.3.1-0.20201102130503-2e26bb234ade h1:TjXPlr3Gjwnz8kiBNpdggNS3o64rDua0qp+Tg4/KXuE= +flamingo.me/flamingo-commerce/v3 v3.3.1-0.20201102130503-2e26bb234ade/go.mod h1:FoXf/whN/y89UAk1TbokGykJSYbTQ7iqKo5EWvGWJGo= flamingo.me/flamingo/v3 v3.0.1/go.mod h1:qxq7rnO6bKIMgyx7WOoi3QcTy9UkX9jrAEGvFDnWFlc= flamingo.me/flamingo/v3 v3.2.0/go.mod h1:7HSp+QNMoJicGcGbwSYTQpg4rVGcDTqmVhVUfeGrs7A= -flamingo.me/flamingo/v3 v3.2.1-0.20200331091700-03bb354d2ab5/go.mod h1:demLn9ui2B45vrOfz+/aKohcJy/B56deyygcLBHjBzk= flamingo.me/flamingo/v3 v3.2.1-0.20200812074650-142034e9fe96/go.mod h1:demLn9ui2B45vrOfz+/aKohcJy/B56deyygcLBHjBzk= -flamingo.me/flamingo/v3 v3.2.1-0.20200829173237-c992c361e4d1 h1:KOyOBwRjw3c+zcdoj6rkP6nyb2Bj+s64IPmbwD9stA8= -flamingo.me/flamingo/v3 v3.2.1-0.20200829173237-c992c361e4d1/go.mod h1:demLn9ui2B45vrOfz+/aKohcJy/B56deyygcLBHjBzk= -flamingo.me/form v1.0.0-alpha.1/go.mod h1:TliCSseukmM53A0RaEqDoIUY9AVRTbwUGsf5DH4WntY= +flamingo.me/flamingo/v3 v3.2.1 h1:O74S+8CedKmBVo8wkqNWTfOfFlTjORn+gRYu6DjuPMI= +flamingo.me/flamingo/v3 v3.2.1/go.mod h1:demLn9ui2B45vrOfz+/aKohcJy/B56deyygcLBHjBzk= flamingo.me/form v1.0.1 h1:mII37OSedlU4ruWdH234UF5ebG7j+WAz1SlX8o6QiPY= flamingo.me/form v1.0.1/go.mod h1:wvH0kq3mTrMmRVGuPT2HwvTScz4xTH11YUeWXCxlRMQ= -flamingo.me/graphql v1.0.1/go.mod h1:JfIijC5pf1WqeSJjtTGljqNkG19n18EBZuC7uy0VoFc= -flamingo.me/graphql v1.0.2-0.20200109090653-271ced2b302c/go.mod h1:JfIijC5pf1WqeSJjtTGljqNkG19n18EBZuC7uy0VoFc= -flamingo.me/graphql v1.0.2 h1:qLaGI/aEC3kdeeZqSXDCq+RV5ifjJNHYcH8Jp1hB8FM= -flamingo.me/graphql v1.0.2/go.mod h1:z8n2VabzBzcwgHIiZj9rmWCsjyRjef4EPt5yQE+iFy0= flamingo.me/graphql v1.1.0 h1:Q2toZo2bp4HlIHqXDKkEHUd2WHeEr1eOjEYgzLDb+Jk= flamingo.me/graphql v1.1.0/go.mod h1:YHly7YG0Ml8jPLyNMGfEsHHOCU9G+yToFWCNQE/oVfs= -flamingo.me/pugtemplate v1.0.0-alpha.1/go.mod h1:7FK11kDpxdUYRCn94lCzExtcBpPlU6uQQ/RZL8JaIog= -flamingo.me/pugtemplate v1.0.0/go.mod h1:2Aj4xrnyOb4FZTzgwHho/ui05St3ya5IXPd17mqlL1Y= flamingo.me/pugtemplate v1.1.3 h1:zjBJid1ZBaoNecAG814syuvB40EXIQ59ZUkAOs5kpdw= flamingo.me/pugtemplate v1.1.3/go.mod h1:jhoYixt7j9ZkLjwMS/ZeYUqRVaNFF+dCa1CuzHNDdRM= -git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -git.apache.org/thrift.git v0.12.0 h1:CMxsZlAmxKs+VAZMlDDL0wXciMblJcutQbEe3A9CYUM= -git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/99designs/gqlgen v0.9.0 h1:g1arBPML74Vqv0L3Q+TqIhGXLspV+2MYtRLkBxuZrlE= -github.com/99designs/gqlgen v0.9.0/go.mod h1:HrrG7ic9EgLPsULxsZh/Ti+p0HNWgR3XRuvnD0pb5KY= github.com/99designs/gqlgen v0.11.4-0.20200726064323-39a12e0f1b6d h1:sCM41FFWut2s4tF4+TS/EXtJIM7L1H3mnJHU4Fro4Wo= github.com/99designs/gqlgen v0.11.4-0.20200726064323-39a12e0f1b6d/go.mod h1:7zdGo6ry9u1YBp/qlb2uxSU5Mt2jQKLcBETQiKk+Bxo= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.16.0+incompatible h1:QZbMUPxRQ50EKAq3LFMnxddMu88/EUUG3qmxwtDmPsY= -github.com/Masterminds/sprig v2.16.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= -github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= +github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/RoaringBitmap/roaring v0.4.19 h1:xy932fRqfJ3qXVm8XKymSfwSnv3bXvC0n4TNs2LdeQs= -github.com/RoaringBitmap/roaring v0.4.19/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= +github.com/RoaringBitmap/roaring v0.4.23 h1:gpyfd12QohbqhFO4NVDUdoPOCXsyahYRQhINmlHxKeo= +github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0= github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs= @@ -93,29 +59,40 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/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-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= -github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= +github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= -github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg= -github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= -github.com/aokoli/goutils v1.1.0/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/blevesearch/bleve v0.8.0 h1:DCoCrxscCXrlzVWK92k7Vq4d28lTAFuigVmcgIX0VCo= -github.com/blevesearch/bleve v0.8.0/go.mod h1:Y2lmIkzV6mcNfAnAdOd+ZxHkHchhBfU/xroGIp61wfw= -github.com/blevesearch/go-porterstemmer v1.0.2 h1:qe7n69gBd1OLY5sHKnxQHIbzn0LNJA4hpAf+5XDxV2I= -github.com/blevesearch/go-porterstemmer v1.0.2/go.mod h1:haWQqFT3RdOGz7PJuM3or/pWNJS1pKkoZJWCkWu0DVA= -github.com/blevesearch/segment v0.0.0-20160915185041-762005e7a34f h1:kqbi9lqXLLs+zfWlgo1PIiRQ86n33K1JKotjj4rSYOg= -github.com/blevesearch/segment v0.0.0-20160915185041-762005e7a34f/go.mod h1:IInt5XRvpiGE09KOk9mmCMLjHhydIhNPKPPFLFBB7L8= -github.com/boj/redistore v0.0.0-20160128113310-fc113767cd6b/go.mod h1:5r9chGCb4uUhBCGMDDCYfyHU/awSRoBeG53Zaj1crhU= +github.com/blevesearch/bleve v1.0.12 h1:2qJUSBpU/h1z8x3ERRB5WwpmEpJwoivPqmDpHzv4tuk= +github.com/blevesearch/bleve v1.0.12/go.mod h1:G0ErXWdIrUSYZLPoMpS9Z3saTnTsk4ebhPsVv/+0nxk= +github.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040 h1:SjYVcfJVZoCfBlg+fkaq2eoZHTf5HaJfaTeTkOtyfHQ= +github.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040/go.mod h1:WH+MU2F4T0VmSdaPX+Wu5GYoZBrYWdOZWSjzvYcDmqQ= +github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= +github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= +github.com/blevesearch/mmap-go v1.0.2 h1:JtMHb+FgQCTTYIhtMvimw15dJwu1Y5lrZDMOFXVWPk0= +github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA= +github.com/blevesearch/segment v0.9.0 h1:5lG7yBCx98or7gK2cHMKPukPZ/31Kag7nONpoBt22Ac= +github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ= +github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= +github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= +github.com/blevesearch/zap/v11 v11.0.12 h1:ZA+80yajko2tXr1kmbSoVRMCo0mFZAVJmoijjYsZuwc= +github.com/blevesearch/zap/v11 v11.0.12/go.mod h1:JLfFhc8DWP01zMG/6VwEY2eAnlJsTN1vDE4S0rC5Y78= +github.com/blevesearch/zap/v12 v12.0.12 h1:9eWaL9/2hcjy1VR3lrl/b+kWh5G7w/BkNYI07mWActw= +github.com/blevesearch/zap/v12 v12.0.12/go.mod h1:1HrB4hhPfI8u8x4SPYbluhb8xhflpPvvj8EcWImNnJY= +github.com/blevesearch/zap/v13 v13.0.4 h1:eoRvJmLeIQUs1mAF+fAFALg1dPHOI1e1KFuXL0I7us4= +github.com/blevesearch/zap/v13 v13.0.4/go.mod h1:YdB7UuG7TBWu/1dz9e2SaLp1RKfFfdJx+ulIK5HR1bA= +github.com/blevesearch/zap/v14 v14.0.3 h1:ccEv296u6DEUHFF9U4W2E/6/WkbuDrS9/1VJM34SCzA= +github.com/blevesearch/zap/v14 v14.0.3/go.mod h1:oObAhcDHw7p1ahiTCqhRkdxdl7UA8qpvX10pSgrTMHc= +github.com/blevesearch/zap/v15 v15.0.1 h1:jEism63eY+qdcvwXH0K8MiKhv5tb10T1k7SNx6fauCM= +github.com/blevesearch/zap/v15 v15.0.1/go.mod h1:ho0frqAex2ktT9cYFAxQpoQXsxb/KEfdjpx4s49rf/M= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -124,58 +101,71 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd/v2 v2.0.1 h1:y1Rh3tEU89D+7Tgbw+lp52T6p/GJLpDmNvr10UWqLTE= github.com/cockroachdb/apd/v2 v2.0.1/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= -github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/containerd/continuity v0.0.0-20200107194136-26c1120b8d41/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= 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/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.0.0+incompatible h1:+RStIopZ8wooMx+Vs5Bt8zMXxV1ABl5LbakNExNmZIg= github.com/coreos/go-oidc v2.0.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.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/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/corpix/uarand v0.0.0 h1:mNbzro1GwUcZ1hmO2rWXytkR3JBxNxxctzjyuhO+Aig= github.com/corpix/uarand v0.0.0/go.mod h1:JSm890tOkDN+M1jqN8pUGDKnzJrsVbJwSMHBY4zwz7M= -github.com/couchbase/vellum v0.0.0-20190823171024-95128b2d4edb h1:KGkbXeg7OEi/415VIYCnpXW9KdZBXzZCsw9jbC6xAAo= -github.com/couchbase/vellum v0.0.0-20190823171024-95128b2d4edb/go.mod h1:prYTC8EgTu3gwbqJihkud9zRXISvyulAplQ6exdCo1g= +github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k= +github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs= +github.com/couchbase/vellum v1.0.2 h1:BrbP0NKiyDdndMPec8Jjhy0U47CZ0Lgx3xUC2r9rZqw= +github.com/couchbase/vellum v1.0.2/go.mod h1:FcwrEivFpNi24R3jLOs3n+fs5RnuQnQqCLBJ1uAg1W4= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/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/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8= +github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= +github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso= +github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= +github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 h1:MZRmHqDBd0vxNwenEbKSQqRVT24d3C05ft8kduSwlqM= +github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/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/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMNtWtNvI9mIV6isjEb9lBMNv+77IGM= github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= -github.com/disintegration/imaging v1.5.0 h1:uYqUhwNmLU4K1FN44vhqS4TZJRAA4RhBINgbQlKyGi0= -github.com/disintegration/imaging v1.5.0/go.mod h1:9B/deIUIrliYkyMTuXJd6OUFLcrZ2tf+3Qlwnaf/CjU= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/emicklei/proto v1.6.15/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etgryphon/stringUp v0.0.0-20121020160746-31534ccd8cac h1:YFKhR0PR8mPI+6EdPhW9BXobntXx3v3F4/1Z9xmw8t8= github.com/etgryphon/stringUp v0.0.0-20121020160746-31534ccd8cac/go.mod h1:Vd+6pUuXoxJuiYG9i6uqoew9XOpXVE9w4OovDqwM8NY= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835 h1:roDmqJ4Qes7hrDOsWsMCce0vQHz3xiMPjJ9m4c2eeNs= -github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835/go.mod h1:BjL/N0+C+j9uNX+1xcNuM9vdSIcXCZrQZUYbXOFbgN8= -github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= -github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc= +github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= github.com/gavv/httpexpect/v2 v2.0.2/go.mod h1:LAoDcy8I/EXEtKJV6wMEJvOMAZVo0MfEk5u4NfiNQa4= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -187,13 +177,11 @@ github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6 github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= -github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-bindata/go-bindata v0.0.0-20190711162640-ee3c2418e368 h1:FRtLU+Y0bfJRflZITQXhiUI2uS+XelSbHqo+em6gpps= -github.com/go-bindata/go-bindata v0.0.0-20190711162640-ee3c2418e368/go.mod h1:7xCgX1lzlrXPHkfvn3EhumqHkmSlzt8at9q7v0ax19c= +github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8= +github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-bindata/go-bindata/v3 v3.1.4-0.20200620005137-771f8d80059e h1:lsrtUlq+yZ7fI7ss3w2wh57EEYFUi/tTFYImVHHJ4h8= github.com/go-bindata/go-bindata/v3 v3.1.4-0.20200620005137-771f8d80059e/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -220,6 +208,7 @@ github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rm github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-redsync/redsync v1.3.1/go.mod h1:qxZwM5JOimfq8y98Wk2+c8dKtxJgG5/yIl2ODz2E5Dk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.1 h1:UQhStjbkDClarlmv0am7OXXO4/GaPdCGiUiMTvi28sg= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -232,18 +221,13 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk= -github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= 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 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -251,102 +235,89 @@ github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNu github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= 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 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/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/gordonklaus/ineffassign v0.0.0-20190601041439-ed7b1b5ee0f8/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw= +github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20200809085317-e36bfde3bb78 h1:U/zHjaVG/sECz5xhnh7kPH+Fv/maPbhZPcaTquo5sPg= github.com/gordonklaus/ineffassign v0.0.0-20200809085317-e36bfde3bb78/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= -github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU= github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.0.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v0.0.0-20150609070431-0dc08b1671f3/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/headzoo/surf v1.0.0/go.mod h1:/bct0m/iMNEqpn520y01yoaWxsAEigGFPnvyR1ewR5M= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.2.0 h1:yPeWdRnmynF7p+lLYz0H2tthW9lqhMJrQV/U7yy4wX0= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428 h1:Mo9W14pwbO9VfRe+ygqZ8dFbPpoIK1HFrG/zjTuQ+nc= github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGznybq1itEKXj6RYw9I71qK4kH+OGMjRC4KEo= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imkira/go-interpol v1.0.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ= -github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= -github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= -github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= +github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= +github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jordan-wright/email v0.0.0-20200322182553-8eef2508c362/go.mod h1:Fy2gCFfZhay8jplf/Csj6cyH/oshQTkLQYZbKkcV+SY= -github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e h1:OGunVjqY7y4U4laftpEHv+mvZBlr7UGimJXKEGQtg48= -github.com/jordan-wright/email v0.0.0-20200602115436-fd8a7622303e/go.mod h1:Fy2gCFfZhay8jplf/Csj6cyH/oshQTkLQYZbKkcV+SY= +github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible h1:CL0ooBNfbNyJTJATno+m0h+zM5bW6v7fKlboKUGP/dI= +github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 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/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= 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.4.0 h1:ueN6QYA+c7eDQo7ebpNdYR8mUJZThiGz9PEoJEMGPzA= github.com/kisielk/errcheck v1.4.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -360,12 +331,12 @@ github.com/labstack/gommon v0.0.0-20180613044413-d6898124de91/go.mod h1:/tj9csK2 github.com/leebenson/conform v0.0.0-20180615210222-bc2e0311fd85 h1:tf+wtKA+17Wj34t4NfTBaIFVqjubC9EAxc/nJgRwUMw= github.com/leebenson/conform v0.0.0-20180615210222-bc2e0311fd85/go.mod h1:a8mcsW8FbNiGeH6aQUuWm1Ix64JZTLYWNHOooj7Pl4I= github.com/leekchan/accounting v0.0.0-20161211142212-a35854c07593/go.mod h1:LErrn9E6BDZ0rwAIrPk99+1+KCSU2X+fy+6xeCB1C5U= -github.com/leekchan/accounting v0.0.0-20180703100437-18a1925d6514/go.mod h1:LErrn9E6BDZ0rwAIrPk99+1+KCSU2X+fy+6xeCB1C5U= github.com/leekchan/accounting v0.0.0-20191104051123-0b9b0bd19c36 h1:3C1jmoEH/NOepFcaU7bT9Ga8M5XOsTQo42FO3mGzdog= github.com/leekchan/accounting v0.0.0-20191104051123-0b9b0bd19c36/go.mod h1:VfQkU+lPM8fjkGqiTn6R+4MX4A/pVwE1XGdDBqp0JFk= github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= @@ -374,8 +345,6 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/matcornic/hermes/v2 v2.1.0 h1:9TDYFBPFv6mcXanaDmRDEp/RTWj0dTTi+LpFnnnfNWc= -github.com/matcornic/hermes/v2 v2.1.0/go.mod h1:2+ziJeoyRfaLiATIL8VZ7f9hpzH4oDHqTmn0bhrsgVI= github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -384,49 +353,42 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de h1:D5x39vF5KCwKQaw+OC9ZPiLVHXz3UFw2+psEX+gYcto= github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de/go.mod h1:kJun4WP5gFuHZgRjZUWWuH1DTxCtxbHDOIJsudS8jzY= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= +github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nicksnyder/go-i18n v0.0.0-20180814031359-04f547cc50da h1:tpULxp4ppsu2YYiUTbMk/kzB2692EKmgaNvM2Z2kBNU= github.com/nicksnyder/go-i18n v0.0.0-20180814031359-04f547cc50da/go.mod h1:e4Di5xjP9oTVrC6y3C7C0HoSYXjSbhh/dU0eUV32nB4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openzipkin/zipkin-go v0.1.6 h1:yXiysv1CSK7Q5yjGy1710zZGnsbMUIjluWBxtLXHPBo= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.0/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2 h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= @@ -439,7 +401,6 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -448,107 +409,87 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU= github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.4.1 h1:FFSuS004yOQEtDdTq+TAOLP5xUq63KqAFYyOi8zA+Y8= github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= 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/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190209105433-f8d8b3f739bd/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190225181712-6ed1f7e10411 h1:36uaMBlK2GZuKRj/x7fKs5QffyHXTYxq+oeBi7KiSrg= -github.com/prometheus/procfs v0.0.0-20190225181712-6ed1f7e10411/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190306233201-d0f344d83b0c h1:xAaFC6WmfeVufj49LZocAyA0S4FSB8eB/himN+phUR4= -github.com/prometheus/procfs v0.0.0-20190306233201-d0f344d83b0c/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.10 h1:QJQN3jYQhkamO4mhfUWqdDH2asK7ONOI9MTWjyAxNKM= github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= +github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 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/rogpeppe/testscript v1.1.0/go.mod h1:lzMlnW8LS56mcdJoQYkrlzqOoTFCOemzt5LusJ93bDM= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= 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.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/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/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/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.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= -github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= -github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 h1:JNEGSiWg6D3lcBCMCBqN3ELniXujt+0QNHLhNnO0w3s= -github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2/go.mod h1:mjqs7N0Q6m5HpR7QfXVBZXZWSqTjQLeTujjA/xUp2uw= +github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM= +github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= 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/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.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -556,10 +497,11 @@ github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKN github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI= github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y= -github.com/swaggo/swag v1.6.0/go.mod h1:YyZstMc22WYm6GEDx/CYWxq+faBbjQ5EqwQcrjREDBo= -github.com/swaggo/swag v1.6.5/go.mod h1:Y7ZLSS0d0DdxhWGVhQdu+Bu1QhaF5k0RD7FKdiAykeY= github.com/swaggo/swag v1.6.6-0.20200603163350-20638f327979/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= -github.com/swaggo/swag v1.6.6/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= +github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -569,23 +511,21 @@ github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMW github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI= +github.com/unrolled/render v1.0.3/go.mod h1:gN9T0NhL4Bfbwu8ann7Ry/TGHYfosul+J0obPf6NBdM= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.0.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= -github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 h1:L0rPdfzq43+NV8rfIx2kA4iSSLRj2jN5ijYHoeXRwvQ= -github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04/go.mod h1:tcnB1voG49QhCrwq1W0w5hhGasvOg+VQp9i9H1rCM1w= -github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe h1:9YnI5plmy+ad6BM+JCLJb2ZV7/TNiE5l7SNKfumYKgc= -github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe/go.mod h1:JTFJA/t820uFDoyPpErFQ3rb3amdZoPtxcKervG0OE4= +github.com/vanng822/css v0.1.0 h1:lFOaxbqoxqgBv9gTOJavvKRS+5oy4YJ/ZBmW1EeYr3M= +github.com/vanng822/css v0.1.0/go.mod h1:tcnB1voG49QhCrwq1W0w5hhGasvOg+VQp9i9H1rCM1w= +github.com/vanng822/go-premailer v1.9.0 h1:ZZPb98JeuUCzlWQAh7r/V8Y5aH8cw2f4HGNVy1HBNsw= +github.com/vanng822/go-premailer v1.9.0/go.mod h1:g1rRrfcv1K+lk7QkA+adzB8aoVTbUG2/f0GNUji7rrU= +github.com/vanng822/r2router v0.0.0-20150523112421-1023140a4f30/go.mod h1:1BVq8p2jVr55Ost2PkZWDrG86PiJ/0lxqcXoAcGxvWU= github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U= -github.com/vektah/gqlparser v1.1.2 h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU= github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o= @@ -608,67 +548,50 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/zemirco/memorystore v0.0.0-20160308183530-ecd57e5134f6 h1:j+ZgVPhfLkC3WDIqNCSpU2/Y67d2FNohAjrxR3HV+KQ= github.com/zemirco/memorystore v0.0.0-20160308183530-ecd57e5134f6/go.mod h1:PLhuixMlky6sB4/LEnpp1//u2BcRF2pKUYXLMVyOrIc= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.19.1 h1:gPYKQ/GAQYR2ksU+qXNmq3CrOZWT1kkryvW6O0v1acY= -go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= +go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.2-0.20191001044506-fa651b05963c/go.mod h1:UWyr2ASM/8PqbWLQNwpB46Cmj/Dx8KV8jSAqRZcqxVI= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= 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.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU= -go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0= go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= 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.14.0 h1:/pduUoebOeeJzTDFuoMgC6nRkiasr1sBCIEorly7m4o= go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029175232-7e6ffbd03851/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-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-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 h1:00VmoueYNlNz/aHIilyyQz/MHSqGoWJzpFv/HW8xpzI= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/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-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-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 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -678,15 +601,12 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190226193003-66a96c8a540e h1:TGoDF9zniB3VYDU2lugdOjop2aTuNSIj7tPHG/bvYZc= -golang.org/x/net v0.0.0-20190226193003-66a96c8a540e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -698,30 +618,21 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/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-20200226051749-491c5fce7268 h1:fnuNgko6vrkrxuKfTMd+0eOz50ziv+Wi+t38KUT3j+E= golang.org/x/net v0.0.0-20200226051749-491c5fce7268/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-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190212230446-3e8b2be13635/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190226191147-529b322ea346/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= 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 h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -731,12 +642,11 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= 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-20190225065934-cc5685c2db12/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -744,16 +654,14 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -764,14 +672,12 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm 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-20181112210238-4b1f3b6b1646/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/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-20190125232054-d66bd3c5d5a6/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-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-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -786,10 +692,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/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-20200225230052-807dcd883420/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200519205726-57a9e4404bf7/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200603170713-0310561d584d h1:uHd7B+jdDraEUYC/fseWgiZgUT1x2uD43ii19+bZYb4= -golang.org/x/tools v0.0.0-20200603170713-0310561d584d/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-20200729041821-df70183b1872 h1:/U95VAvB4ZsR91rpZX2MwiKpejhWr+UxJ+N2VlJuESk= golang.org/x/tools v0.0.0-20200729041821-df70183b1872/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -797,70 +699,56 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.1.0 h1:K6z2u68e86TPdSdefXdzvXgR1zEMa+459vBSfWYAZkI= -google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.19.0 h1:GwFK8+l5/gdsOYKz5p6M4UK+QT8OvmHWZPJCnf+5DjA= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 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 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= -google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= 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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA= -google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= 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.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.27.0 h1:wCg/0hk9RzcB0CYw8pYV6FiBYug1on0cpco9YZF8jqA= gopkg.in/go-playground/validator.v9 v9.27.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= -gopkg.in/headzoo/surf.v1 v1.0.0/go.mod h1:T0BH8276y+OPL0E4tisxCFjBVIAKGbwdYU7AS7/EpQQ= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.0 h1:nLzhkFyl5bkblqYBoiWJUt5JkWOzmiaBtCxdJAqJd3U= gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -868,10 +756,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/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= moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e/go.mod h1:nejbQVfXh96n9dSF6cH3Jsk/QI1Z2oEL7sSI2ifXFNA=