├── go.mod ├── pipeline.go ├── pure_pipeline.go ├── static_pipeline.go ├── tests └── pipeline_test.go ├── readme.md └── go.sum /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/goal-web/pipeline 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/goal-web/container v0.1.4 7 | github.com/goal-web/contracts v0.1.62 8 | github.com/pkg/errors v0.8.1 9 | ) 10 | 11 | require github.com/goal-web/supports v0.1.12 // indirect 12 | -------------------------------------------------------------------------------- /pipeline.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import ( 4 | "errors" 5 | "github.com/goal-web/container" 6 | "github.com/goal-web/contracts" 7 | ) 8 | 9 | type Pipeline struct { 10 | container contracts.Container 11 | 12 | passable interface{} 13 | 14 | pipes []contracts.MagicalFunc 15 | } 16 | 17 | var PipeArgumentError = errors.New("pipe parameters must have a return value") 18 | 19 | type Callback func(stack contracts.Pipe, next contracts.MagicalFunc) contracts.Pipe 20 | 21 | func New(container contracts.Container) contracts.Pipeline { 22 | return &Pipeline{ 23 | container: container, 24 | } 25 | } 26 | 27 | func (this *Pipeline) Send(passable interface{}) contracts.Pipeline { 28 | this.passable = passable 29 | return this 30 | } 31 | 32 | func (this *Pipeline) Through(pipes ...interface{}) contracts.Pipeline { 33 | for _, item := range pipes { 34 | pipe, isStaticFunc := item.(contracts.MagicalFunc) 35 | if !isStaticFunc { 36 | pipe = container.NewMagicalFunc(item) 37 | } 38 | if pipe.NumOut() != 1 { 39 | panic(PipeArgumentError) 40 | } 41 | this.pipes = append(this.pipes, pipe) 42 | } 43 | return this 44 | } 45 | 46 | func (this *Pipeline) Then(destination interface{}) interface{} { 47 | return this.ArrayReduce( 48 | this.reversePipes(), this.carry(), this.prepareDestination(destination), 49 | )(this.passable) 50 | } 51 | 52 | func (this *Pipeline) carry() Callback { 53 | return func(stack contracts.Pipe, next contracts.MagicalFunc) contracts.Pipe { 54 | return func(passable interface{}) interface{} { 55 | return this.container.StaticCall(next, passable, stack)[0] 56 | } 57 | } 58 | } 59 | 60 | func (this *Pipeline) ArrayReduce(pipes []contracts.MagicalFunc, callback Callback, current contracts.Pipe) contracts.Pipe { 61 | for _, magicalFunc := range pipes { 62 | current = callback(current, magicalFunc) 63 | } 64 | return current 65 | } 66 | 67 | func (this *Pipeline) reversePipes() []contracts.MagicalFunc { 68 | for from, to := 0, len(this.pipes)-1; from < to; from, to = from+1, to-1 { 69 | this.pipes[from], this.pipes[to] = this.pipes[to], this.pipes[from] 70 | } 71 | return this.pipes 72 | } 73 | 74 | func (this *Pipeline) prepareDestination(destination interface{}) contracts.Pipe { 75 | pipe, isStaticFunc := destination.(contracts.MagicalFunc) 76 | if !isStaticFunc { 77 | pipe = container.NewMagicalFunc(destination) 78 | } 79 | if pipe.NumOut() != 1 { 80 | panic(PipeArgumentError) 81 | } 82 | return func(passable interface{}) interface{} { 83 | return this.container.StaticCall(pipe, passable)[0] 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /pure_pipeline.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import ( 4 | "github.com/goal-web/contracts" 5 | ) 6 | 7 | type PurePipeline struct { 8 | passable interface{} 9 | 10 | pipes []NextFunc 11 | } 12 | 13 | type PureCallback func(stack contracts.Pipe, next NextFunc) contracts.Pipe 14 | type NextFunc func(passable interface{}, pipe contracts.Pipe) interface{} 15 | type PureDestination func(passable interface{}) interface{} 16 | 17 | func Pure() *PurePipeline { 18 | return &PurePipeline{} 19 | } 20 | 21 | func (this *PurePipeline) Send(passable interface{}) contracts.Pipeline { 22 | this.passable = passable 23 | return this 24 | } 25 | 26 | func (this *PurePipeline) SendPure(passable interface{}) *PurePipeline { 27 | this.passable = passable 28 | return this 29 | } 30 | 31 | func (this *PurePipeline) Through(pipes ...interface{}) contracts.Pipeline { 32 | for _, item := range pipes { 33 | pipe, isNextFunc := item.(NextFunc) 34 | if !isNextFunc { 35 | panic(PipeArgumentError) 36 | } 37 | this.pipes = append(this.pipes, pipe) 38 | } 39 | return this 40 | } 41 | 42 | func (this *PurePipeline) ThroughPure(pipes ...NextFunc) *PurePipeline { 43 | this.pipes = append(this.pipes, pipes...) 44 | return this 45 | } 46 | 47 | func (this *PurePipeline) Then(destination interface{}) interface{} { 48 | return this.ArrayReduce( 49 | this.reversePipes(), this.carry(), this.prepareDestination(destination), 50 | )(this.passable) 51 | } 52 | 53 | func (this *PurePipeline) ThenPure(destination contracts.Pipe) interface{} { 54 | return this.ArrayReduce( 55 | this.reversePipes(), this.carry(), destination, 56 | )(this.passable) 57 | } 58 | 59 | func (this *PurePipeline) carry() PureCallback { 60 | return func(stack contracts.Pipe, next NextFunc) contracts.Pipe { 61 | return func(passable interface{}) interface{} { 62 | return next(passable, stack) 63 | } 64 | } 65 | } 66 | 67 | func (this *PurePipeline) ArrayReduce(pipes []NextFunc, callback PureCallback, current contracts.Pipe) contracts.Pipe { 68 | for _, magicalFunc := range pipes { 69 | current = callback(current, magicalFunc) 70 | } 71 | return current 72 | } 73 | 74 | func (this *PurePipeline) reversePipes() []NextFunc { 75 | for from, to := 0, len(this.pipes)-1; from < to; from, to = from+1, to-1 { 76 | this.pipes[from], this.pipes[to] = this.pipes[to], this.pipes[from] 77 | } 78 | return this.pipes 79 | } 80 | 81 | func (this *PurePipeline) prepareDestination(destination interface{}) contracts.Pipe { 82 | pipe, isPipeFunc := destination.(contracts.Pipe) 83 | if !isPipeFunc { 84 | panic(PipeArgumentError) 85 | } 86 | return pipe 87 | } 88 | -------------------------------------------------------------------------------- /static_pipeline.go: -------------------------------------------------------------------------------- 1 | package pipeline 2 | 3 | import ( 4 | "github.com/goal-web/container" 5 | "github.com/goal-web/contracts" 6 | ) 7 | 8 | type StaticPipeline struct { 9 | container contracts.Container 10 | 11 | passable interface{} 12 | 13 | pipes []contracts.MagicalFunc 14 | } 15 | 16 | func Static(container contracts.Container) *StaticPipeline { 17 | return &StaticPipeline{ 18 | container: container, 19 | } 20 | } 21 | 22 | func (this *StaticPipeline) Send(passable interface{}) contracts.Pipeline { 23 | this.passable = passable 24 | return this 25 | } 26 | 27 | func (this *StaticPipeline) SendStatic(passable interface{}) *StaticPipeline { 28 | this.passable = passable 29 | return this 30 | } 31 | 32 | func (this *StaticPipeline) Through(pipes ...interface{}) contracts.Pipeline { 33 | for _, item := range pipes { 34 | pipe, isStaticFunc := item.(contracts.MagicalFunc) 35 | if !isStaticFunc { 36 | pipe = container.NewMagicalFunc(item) 37 | } 38 | if pipe.NumOut() != 1 { 39 | panic(PipeArgumentError) 40 | } 41 | this.pipes = append(this.pipes, pipe) 42 | } 43 | return this 44 | } 45 | 46 | func (this *StaticPipeline) ThroughStatic(pipes ...contracts.MagicalFunc) *StaticPipeline { 47 | this.pipes = append(this.pipes, pipes...) 48 | return this 49 | } 50 | 51 | func (this *StaticPipeline) Then(destination interface{}) interface{} { 52 | return this.ArrayReduce( 53 | this.reversePipes(), this.carry(), this.prepareDestination(destination), 54 | )(this.passable) 55 | } 56 | 57 | func (this *StaticPipeline) ThenStatic(destination contracts.MagicalFunc) interface{} { 58 | return this.ArrayReduce( 59 | this.reversePipes(), this.carry(), this.prepareStaticDestination(destination), 60 | )(this.passable) 61 | } 62 | 63 | func (this *StaticPipeline) carry() Callback { 64 | return func(stack contracts.Pipe, next contracts.MagicalFunc) contracts.Pipe { 65 | return func(passable interface{}) interface{} { 66 | return this.container.StaticCall(next, passable, stack)[0] 67 | } 68 | } 69 | } 70 | 71 | func (this *StaticPipeline) ArrayReduce(pipes []contracts.MagicalFunc, callback Callback, current contracts.Pipe) contracts.Pipe { 72 | for _, magicalFunc := range pipes { 73 | current = callback(current, magicalFunc) 74 | } 75 | return current 76 | } 77 | 78 | func (this *StaticPipeline) reversePipes() []contracts.MagicalFunc { 79 | for from, to := 0, len(this.pipes)-1; from < to; from, to = from+1, to-1 { 80 | this.pipes[from], this.pipes[to] = this.pipes[to], this.pipes[from] 81 | } 82 | return this.pipes 83 | } 84 | 85 | func (this *StaticPipeline) prepareDestination(destination interface{}) contracts.Pipe { 86 | pipe, isStaticFunc := destination.(contracts.MagicalFunc) 87 | if !isStaticFunc { 88 | pipe = container.NewMagicalFunc(destination) 89 | } 90 | if pipe.NumOut() != 1 { 91 | panic(PipeArgumentError) 92 | } 93 | return func(passable interface{}) interface{} { 94 | return this.container.StaticCall(pipe, passable)[0] 95 | } 96 | } 97 | 98 | func (this *StaticPipeline) prepareStaticDestination(destination contracts.MagicalFunc) contracts.Pipe { 99 | if destination.NumOut() != 1 { 100 | panic(PipeArgumentError) 101 | } 102 | return func(passable interface{}) interface{} { 103 | return this.container.StaticCall(destination, passable)[0] 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tests/pipeline_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "fmt" 5 | "github.com/goal-web/container" 6 | "github.com/goal-web/contracts" 7 | "github.com/goal-web/pipeline" 8 | "github.com/pkg/errors" 9 | "testing" 10 | ) 11 | 12 | type User struct { 13 | Id int 14 | Name string 15 | } 16 | 17 | func TestPipeline(t *testing.T) { 18 | pipe := pipeline.New(container.New()) 19 | result := pipe.Send(User{Id: 1, Name: "goal"}). 20 | Through( 21 | func(user User, next contracts.Pipe) interface{} { 22 | fmt.Println("中间件1-start") 23 | result := next(user) 24 | fmt.Println("中间件1-end") 25 | return result 26 | }, 27 | func(user User, next contracts.Pipe) interface{} { 28 | fmt.Println("中间件2-start") 29 | result := next(user) 30 | fmt.Println("中间件2-end") 31 | return result 32 | }, 33 | ). 34 | Then(func(user User) interface{} { 35 | fmt.Println("then", user) 36 | return user.Id 37 | }) 38 | 39 | fmt.Println("穿梭结果:", result) 40 | /** 41 | 中间件1-start 42 | 中间件2-start 43 | then {1 goal} 44 | 中间件2-end 45 | 中间件1-end 46 | 穿梭结果: 1 47 | */ 48 | } 49 | 50 | // TestPipelineException 测试异常情况 51 | func TestPipelineException(t *testing.T) { 52 | defer func() { 53 | recover() 54 | }() 55 | pipe := pipeline.New(container.New()) 56 | pipe.Send(User{Id: 1, Name: "goal"}). 57 | Through( 58 | func(user User, next contracts.Pipe) interface{} { 59 | fmt.Println("中间件1-start") 60 | result := next(user) 61 | fmt.Println("中间件1-end", result) 62 | return result 63 | }, 64 | func(user User, next contracts.Pipe) interface{} { 65 | fmt.Println("中间件2-start") 66 | result := next(user) 67 | fmt.Println("中间件2-end", result) 68 | return result 69 | }, 70 | ). 71 | Then(func(user User) { 72 | panic(errors.New("报个错")) 73 | }) 74 | /** 75 | 中间件1-start 76 | 中间件2-start 77 | */ 78 | } 79 | 80 | // TestStaticPipeline 测试调用magical函数 81 | func TestStaticPipeline(t *testing.T) { 82 | // 应用启动时就准备好的中间件和控制器函数,在大量并发时用 StaticPipeline 可以提高性能 83 | middlewares := []contracts.MagicalFunc{ 84 | container.NewMagicalFunc(func(user User, next contracts.Pipe) interface{} { 85 | fmt.Println("中间件1-start") 86 | result := next(user) 87 | fmt.Println("中间件1-end", result) 88 | return result 89 | }), 90 | container.NewMagicalFunc(func(user User, next contracts.Pipe) interface{} { 91 | fmt.Println("中间件2-start") 92 | result := next(user) 93 | fmt.Println("中间件2-end", result) 94 | return result 95 | }), 96 | } 97 | controller := container.NewMagicalFunc(func(user User) int { 98 | fmt.Println("then", user) 99 | return user.Id 100 | }) 101 | 102 | pipe := pipeline.Static(container.New()) 103 | result := pipe.SendStatic(User{Id: 1, Name: "goal"}). 104 | ThroughStatic(middlewares...). 105 | ThenStatic(controller) 106 | 107 | fmt.Println("穿梭结果", result) 108 | 109 | pipe = pipeline.Static(container.New()) 110 | result = pipe.SendStatic(User{Id: 1, Name: "goal"}). 111 | ThroughStatic(middlewares...). 112 | ThenStatic(controller) 113 | fmt.Println("穿梭结果", result) 114 | /** 115 | 中间件1-start 116 | 中间件2-start 117 | then {1 goal} 118 | 中间件2-end 1 119 | 中间件1-end 1 120 | 穿梭结果 1 121 | */ 122 | } 123 | 124 | // TestPurePipeline 测试纯净的 pipeline 125 | func TestPurePipeline(t *testing.T) { 126 | // 如果你的应用场景对性能要求极高,不希望反射影响你,那么你可以试试下面这个纯净的管道 127 | pipe := pipeline.Pure() 128 | result := pipe.SendPure(User{Id: 1, Name: "goal"}). 129 | ThroughPure( 130 | func(user interface{}, next contracts.Pipe) interface{} { 131 | fmt.Println("中间件1-start") 132 | result := next(user) 133 | fmt.Println("中间件1-end", result) 134 | return result 135 | }, 136 | func(user interface{}, next contracts.Pipe) interface{} { 137 | fmt.Println("中间件2-start") 138 | result := next(user) 139 | fmt.Println("中间件2-end", result) 140 | return result 141 | }, 142 | ). 143 | ThenPure(func(user interface{}) interface{} { 144 | fmt.Println("then", user) 145 | return user.(User).Id 146 | }) 147 | fmt.Println("穿梭结果", result) 148 | /** 149 | 中间件1-start 150 | 中间件2-start 151 | then {1 goal} 152 | 中间件2-end 1 153 | 中间件1-end 1 154 | 穿梭结果 1 155 | */ 156 | } 157 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Goal-web/pipeline 2 | [goal-web/pipeline](https://github.com/goal-web/pipeline) 3 | 这是一个管道库,实现了 和 `laravel` 一样的管道功能,如果你很熟悉 `laravel` 的管道或者中间件,那你一定对这个库很有亲切感。 4 | 5 | ## 安装 - install 6 | ```bash 7 | go get github.com/goal-web/pipeline 8 | ``` 9 | 10 | ## 使用 - usage 11 | 得益于 goal 强大的容器,你可以在管道(pipe)和目的地(destination)任意注入容器中存在的实例 12 | > 对管道不熟悉的同学,可以把 pipe 理解为中间件,destination 就是控制器方法 13 | > 14 | ```go 15 | package tests 16 | 17 | import ( 18 | "fmt" 19 | "github.com/goal-web/container" 20 | "github.com/goal-web/contracts" 21 | "github.com/goal-web/pipeline" 22 | "github.com/pkg/errors" 23 | "testing" 24 | ) 25 | 26 | type User struct { 27 | Id int 28 | Name string 29 | } 30 | 31 | func TestPipeline(t *testing.T) { 32 | pipe := pipeline.New(container.New()) 33 | pipe.Send(User{Id: 1, Name: "goal"}). 34 | Through( 35 | func(user User, next contracts.Pipe) interface{} { 36 | fmt.Println("中间件1-start") 37 | result := next(user) 38 | fmt.Println("中间件1-end") 39 | return result 40 | }, 41 | func(user User, next contracts.Pipe) interface{} { 42 | fmt.Println("中间件2-start") 43 | result := next(user) 44 | fmt.Println("中间件2-end") 45 | return result 46 | }, 47 | ). 48 | Then(func(user User) { 49 | fmt.Println("then", user) 50 | }) 51 | } 52 | 53 | // TestPipelineException 测试异常情况 54 | func TestPipelineException(t *testing.T) { 55 | defer func() { 56 | recover() 57 | }() 58 | pipe := pipeline.New(container.New()) 59 | pipe.Send(User{Id: 1, Name: "goal"}). 60 | Through( 61 | func(user User, next contracts.Pipe) interface{} { 62 | fmt.Println("中间件1-start") 63 | result := next(user) 64 | fmt.Println("中间件1-end", result) 65 | return result 66 | }, 67 | func(user User, next contracts.Pipe) interface{} { 68 | fmt.Println("中间件2-start") 69 | result := next(user) 70 | fmt.Println("中间件2-end", result) 71 | return result 72 | }, 73 | ). 74 | Then(func(user User) { 75 | panic(errors.New("报个错")) 76 | }) 77 | } 78 | 79 | // TestStaticPipeline 测试调用magical函数 80 | func TestStaticPipeline(t *testing.T) { 81 | // 应用启动时就准备好的中间件和控制器函数,在大量并发时用 StaticPipeline 可以提高性能 82 | middlewares := []contracts.MagicalFunc{ 83 | container.NewMagicalFunc(func(user User, next contracts.Pipe) interface{} { 84 | fmt.Println("中间件1-start") 85 | result := next(user) 86 | fmt.Println("中间件1-end", result) 87 | return result 88 | }), 89 | container.NewMagicalFunc(func(user User, next contracts.Pipe) interface{} { 90 | fmt.Println("中间件2-start") 91 | result := next(user) 92 | fmt.Println("中间件2-end", result) 93 | return result 94 | }), 95 | } 96 | controller := container.NewMagicalFunc(func(user User) int { 97 | fmt.Println("then", user) 98 | return user.Id 99 | }) 100 | 101 | pipe := pipeline.Static(container.New()) 102 | result := pipe.SendStatic(User{Id: 1, Name: "goal"}). 103 | ThroughStatic(middlewares...). 104 | ThenStatic(controller) 105 | 106 | fmt.Println("穿梭结果", result) 107 | /** 108 | 中间件1-start 109 | 中间件2-start 110 | then {1 goal} 111 | 中间件2-end 1 112 | 中间件1-end 1 113 | 穿梭结果 1 114 | */ 115 | } 116 | 117 | // TestPurePipeline 测试纯净的 pipeline 118 | func TestPurePipeline(t *testing.T) { 119 | // 如果你的应用场景对性能要求极高,不希望反射影响你,那么你可以试试下面这个纯净的管道 120 | pipe := pipeline.Pure() 121 | result := pipe.SendPure(User{Id: 1, Name: "goal"}). 122 | ThroughPure( 123 | func(user interface{}, next contracts.Pipe) interface{} { 124 | fmt.Println("中间件1-start") 125 | result := next(user) 126 | fmt.Println("中间件1-end", result) 127 | return result 128 | }, 129 | func(user interface{}, next contracts.Pipe) interface{} { 130 | fmt.Println("中间件2-start") 131 | result := next(user) 132 | fmt.Println("中间件2-end", result) 133 | return result 134 | }, 135 | ). 136 | ThenPure(func(user interface{}) interface{} { 137 | fmt.Println("then", user) 138 | return user.(User).Id 139 | }) 140 | fmt.Println("穿梭结果", result) 141 | /** 142 | 中间件1-start 143 | 中间件2-start 144 | then {1 goal} 145 | 中间件2-end 1 146 | 中间件1-end 1 147 | 穿梭结果 1 148 | */ 149 | } 150 | 151 | ``` 152 | 153 | ### 在 goal 之外的框架使用 - use in frameworks other than goal 154 | 这个库并不会限制你在哪个框架使用它,所以你可以在任意 go 环境使用这个管道库 155 | 156 | [goal-web](https://github.com/goal-web/goal) 157 | [goal-web/pipeline](https://github.com/goal-web/pipeline) 158 | qbhy0715@qq.com 159 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= 2 | github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= 3 | github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= 4 | github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= 5 | github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 6 | github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 10 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 11 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 12 | github.com/goal-web/container v0.1.4 h1:nCdlzRYJGfkNNAsXZQ5TElrwr7P01oIM5tS75KAqe2c= 13 | github.com/goal-web/container v0.1.4/go.mod h1:xbOKGHxV8Pg4IPTVDEEVQ21YZ2Fr2u7sjMUSTVmh05A= 14 | github.com/goal-web/contracts v0.1.62.19/go.mod h1:lKHynU2Kgk6xyxL4afOJM4TO1kSa3RrCJ2bm5RtFMBw= 15 | github.com/goal-web/contracts v0.1.62.21/go.mod h1:lKHynU2Kgk6xyxL4afOJM4TO1kSa3RrCJ2bm5RtFMBw= 16 | github.com/goal-web/contracts v0.1.62.36 h1:D5/AK9H2wHHA6fwLWTkLjoxflBdrLBO4N8kwv2Ikesg= 17 | github.com/goal-web/contracts v0.1.62.36/go.mod h1:lKHynU2Kgk6xyxL4afOJM4TO1kSa3RrCJ2bm5RtFMBw= 18 | github.com/goal-web/supports v0.1.12 h1:upnHi9tn+kartpXPlBdAV8xXR8T+tn0Grt+oCJGD0Mc= 19 | github.com/goal-web/supports v0.1.12/go.mod h1:QAvaUh/dtKUA027AvZaPPk5y/E1wlfJieEJoDDcQdOE= 20 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 21 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 22 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 23 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 24 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 25 | github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= 26 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 27 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 28 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 29 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 30 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 31 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 32 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 33 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 34 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 35 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 36 | github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 37 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 38 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 39 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 40 | github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 41 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 42 | github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= 43 | github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= 44 | github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= 45 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 46 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 47 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 48 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 49 | github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= 50 | github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= 51 | github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= 52 | github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= 53 | github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= 54 | github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= 55 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 56 | golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 57 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 58 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 59 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 60 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 61 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 62 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 63 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 64 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 65 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 66 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 67 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 68 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 69 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 70 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 71 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 72 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 73 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 74 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 75 | gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 76 | --------------------------------------------------------------------------------