seba-365 - implemented dep
Change-Id: Ia6226d50e7615935a0c8876809a687427ff88c22
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/description.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/description.go
new file mode 100644
index 0000000..758b112
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/description.go
@@ -0,0 +1,10 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+// Unknown is an unknown server or topology kind.
+const Unknown = 0
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/feature.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/feature.go
new file mode 100644
index 0000000..f0236c0
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/feature.go
@@ -0,0 +1,36 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+import (
+ "fmt"
+)
+
+// MaxStalenessSupported returns an error if the given server version
+// does not support max staleness.
+func MaxStalenessSupported(wireVersion *VersionRange) error {
+ if wireVersion != nil && wireVersion.Max < 5 {
+ return fmt.Errorf("max staleness is only supported for servers 3.4 or newer")
+ }
+
+ return nil
+}
+
+// ScramSHA1Supported returns an error if the given server version
+// does not support scram-sha-1.
+func ScramSHA1Supported(wireVersion *VersionRange) error {
+ if wireVersion != nil && wireVersion.Max < 3 {
+ return fmt.Errorf("SCRAM-SHA-1 is only supported for servers 3.0 or newer")
+ }
+
+ return nil
+}
+
+// SessionsSupported returns true of the given server version indicates that it supports sessions.
+func SessionsSupported(wireVersion *VersionRange) bool {
+ return wireVersion != nil && wireVersion.Max >= 6
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server.go
new file mode 100644
index 0000000..d6857ce
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server.go
@@ -0,0 +1,144 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/bson/primitive"
+ "github.com/mongodb/mongo-go-driver/tag"
+ "github.com/mongodb/mongo-go-driver/x/network/address"
+ "github.com/mongodb/mongo-go-driver/x/network/result"
+)
+
+// UnsetRTT is the unset value for a round trip time.
+const UnsetRTT = -1 * time.Millisecond
+
+// SelectedServer represents a selected server that is a member of a topology.
+type SelectedServer struct {
+ Server
+ Kind TopologyKind
+}
+
+// Server represents a description of a server. This is created from an isMaster
+// command.
+type Server struct {
+ Addr address.Address
+
+ AverageRTT time.Duration
+ AverageRTTSet bool
+ Compression []string // compression methods returned by server
+ CanonicalAddr address.Address
+ ElectionID primitive.ObjectID
+ HeartbeatInterval time.Duration
+ LastError error
+ LastUpdateTime time.Time
+ LastWriteTime time.Time
+ MaxBatchCount uint32
+ MaxDocumentSize uint32
+ MaxMessageSize uint32
+ Members []address.Address
+ ReadOnly bool
+ SessionTimeoutMinutes uint32
+ SetName string
+ SetVersion uint32
+ Tags tag.Set
+ Kind ServerKind
+ WireVersion *VersionRange
+
+ SaslSupportedMechs []string // user-specific from server handshake
+}
+
+// NewServer creates a new server description from the given parameters.
+func NewServer(addr address.Address, isMaster result.IsMaster) Server {
+ i := Server{
+ Addr: addr,
+
+ CanonicalAddr: address.Address(isMaster.Me).Canonicalize(),
+ Compression: isMaster.Compression,
+ ElectionID: isMaster.ElectionID,
+ LastUpdateTime: time.Now().UTC(),
+ LastWriteTime: isMaster.LastWriteTimestamp,
+ MaxBatchCount: isMaster.MaxWriteBatchSize,
+ MaxDocumentSize: isMaster.MaxBSONObjectSize,
+ MaxMessageSize: isMaster.MaxMessageSizeBytes,
+ SaslSupportedMechs: isMaster.SaslSupportedMechs,
+ SessionTimeoutMinutes: isMaster.LogicalSessionTimeoutMinutes,
+ SetName: isMaster.SetName,
+ SetVersion: isMaster.SetVersion,
+ Tags: tag.NewTagSetFromMap(isMaster.Tags),
+ }
+
+ if i.CanonicalAddr == "" {
+ i.CanonicalAddr = addr
+ }
+
+ if isMaster.OK != 1 {
+ i.LastError = fmt.Errorf("not ok")
+ return i
+ }
+
+ for _, host := range isMaster.Hosts {
+ i.Members = append(i.Members, address.Address(host).Canonicalize())
+ }
+
+ for _, passive := range isMaster.Passives {
+ i.Members = append(i.Members, address.Address(passive).Canonicalize())
+ }
+
+ for _, arbiter := range isMaster.Arbiters {
+ i.Members = append(i.Members, address.Address(arbiter).Canonicalize())
+ }
+
+ i.Kind = Standalone
+
+ if isMaster.IsReplicaSet {
+ i.Kind = RSGhost
+ } else if isMaster.SetName != "" {
+ if isMaster.IsMaster {
+ i.Kind = RSPrimary
+ } else if isMaster.Hidden {
+ i.Kind = RSMember
+ } else if isMaster.Secondary {
+ i.Kind = RSSecondary
+ } else if isMaster.ArbiterOnly {
+ i.Kind = RSArbiter
+ } else {
+ i.Kind = RSMember
+ }
+ } else if isMaster.Msg == "isdbgrid" {
+ i.Kind = Mongos
+ }
+
+ i.WireVersion = &VersionRange{
+ Min: isMaster.MinWireVersion,
+ Max: isMaster.MaxWireVersion,
+ }
+
+ return i
+}
+
+// SetAverageRTT sets the average round trip time for this server description.
+func (s Server) SetAverageRTT(rtt time.Duration) Server {
+ s.AverageRTT = rtt
+ if rtt == UnsetRTT {
+ s.AverageRTTSet = false
+ } else {
+ s.AverageRTTSet = true
+ }
+
+ return s
+}
+
+// DataBearing returns true if the server is a data bearing server.
+func (s Server) DataBearing() bool {
+ return s.Kind == RSPrimary ||
+ s.Kind == RSSecondary ||
+ s.Kind == Mongos ||
+ s.Kind == Standalone
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server_kind.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server_kind.go
new file mode 100644
index 0000000..657791b
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server_kind.go
@@ -0,0 +1,43 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+// ServerKind represents the type of a server.
+type ServerKind uint32
+
+// These constants are the possible types of servers.
+const (
+ Standalone ServerKind = 1
+ RSMember ServerKind = 2
+ RSPrimary ServerKind = 4 + RSMember
+ RSSecondary ServerKind = 8 + RSMember
+ RSArbiter ServerKind = 16 + RSMember
+ RSGhost ServerKind = 32 + RSMember
+ Mongos ServerKind = 256
+)
+
+// String implements the fmt.Stringer interface.
+func (kind ServerKind) String() string {
+ switch kind {
+ case Standalone:
+ return "Standalone"
+ case RSMember:
+ return "RSOther"
+ case RSPrimary:
+ return "RSPrimary"
+ case RSSecondary:
+ return "RSSecondary"
+ case RSArbiter:
+ return "RSArbiter"
+ case RSGhost:
+ return "RSGhost"
+ case Mongos:
+ return "Mongos"
+ }
+
+ return "Unknown"
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server_selector.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server_selector.go
new file mode 100644
index 0000000..9c31b6e
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/server_selector.go
@@ -0,0 +1,279 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+import (
+ "fmt"
+ "math"
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/tag"
+)
+
+// ServerSelector is an interface implemented by types that can select a server given a
+// topology description.
+type ServerSelector interface {
+ SelectServer(Topology, []Server) ([]Server, error)
+}
+
+// ServerSelectorFunc is a function that can be used as a ServerSelector.
+type ServerSelectorFunc func(Topology, []Server) ([]Server, error)
+
+// SelectServer implements the ServerSelector interface.
+func (ssf ServerSelectorFunc) SelectServer(t Topology, s []Server) ([]Server, error) {
+ return ssf(t, s)
+}
+
+type compositeSelector struct {
+ selectors []ServerSelector
+}
+
+// CompositeSelector combines multiple selectors into a single selector.
+func CompositeSelector(selectors []ServerSelector) ServerSelector {
+ return &compositeSelector{selectors: selectors}
+}
+
+func (cs *compositeSelector) SelectServer(t Topology, candidates []Server) ([]Server, error) {
+ var err error
+ for _, sel := range cs.selectors {
+ candidates, err = sel.SelectServer(t, candidates)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return candidates, nil
+}
+
+type latencySelector struct {
+ latency time.Duration
+}
+
+// LatencySelector creates a ServerSelector which selects servers based on their latency.
+func LatencySelector(latency time.Duration) ServerSelector {
+ return &latencySelector{latency: latency}
+}
+
+func (ls *latencySelector) SelectServer(t Topology, candidates []Server) ([]Server, error) {
+ if ls.latency < 0 {
+ return candidates, nil
+ }
+
+ switch len(candidates) {
+ case 0, 1:
+ return candidates, nil
+ default:
+ min := time.Duration(math.MaxInt64)
+ for _, candidate := range candidates {
+ if candidate.AverageRTTSet {
+ if candidate.AverageRTT < min {
+ min = candidate.AverageRTT
+ }
+ }
+ }
+
+ if min == math.MaxInt64 {
+ return candidates, nil
+ }
+
+ max := min + ls.latency
+
+ var result []Server
+ for _, candidate := range candidates {
+ if candidate.AverageRTTSet {
+ if candidate.AverageRTT <= max {
+ result = append(result, candidate)
+ }
+ }
+ }
+
+ return result, nil
+ }
+}
+
+// WriteSelector selects all the writable servers.
+func WriteSelector() ServerSelector {
+ return ServerSelectorFunc(func(t Topology, candidates []Server) ([]Server, error) {
+ switch t.Kind {
+ case Single:
+ return candidates, nil
+ default:
+ result := []Server{}
+ for _, candidate := range candidates {
+ switch candidate.Kind {
+ case Mongos, RSPrimary, Standalone:
+ result = append(result, candidate)
+ }
+ }
+ return result, nil
+ }
+ })
+}
+
+// ReadPrefSelector selects servers based on the provided read preference.
+func ReadPrefSelector(rp *readpref.ReadPref) ServerSelector {
+ return ServerSelectorFunc(func(t Topology, candidates []Server) ([]Server, error) {
+ if _, set := rp.MaxStaleness(); set {
+ for _, s := range candidates {
+ if s.Kind != Unknown {
+ if err := MaxStalenessSupported(s.WireVersion); err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+
+ switch t.Kind {
+ case Single:
+ return candidates, nil
+ case ReplicaSetNoPrimary, ReplicaSetWithPrimary:
+ return selectForReplicaSet(rp, t, candidates)
+ case Sharded:
+ return selectByKind(candidates, Mongos), nil
+ }
+
+ return nil, nil
+ })
+}
+
+func selectForReplicaSet(rp *readpref.ReadPref, t Topology, candidates []Server) ([]Server, error) {
+ if err := verifyMaxStaleness(rp, t); err != nil {
+ return nil, err
+ }
+
+ switch rp.Mode() {
+ case readpref.PrimaryMode:
+ return selectByKind(candidates, RSPrimary), nil
+ case readpref.PrimaryPreferredMode:
+ selected := selectByKind(candidates, RSPrimary)
+
+ if len(selected) == 0 {
+ selected = selectSecondaries(rp, candidates)
+ return selectByTagSet(selected, rp.TagSets()), nil
+ }
+
+ return selected, nil
+ case readpref.SecondaryPreferredMode:
+ selected := selectSecondaries(rp, candidates)
+ selected = selectByTagSet(selected, rp.TagSets())
+ if len(selected) > 0 {
+ return selected, nil
+ }
+ return selectByKind(candidates, RSPrimary), nil
+ case readpref.SecondaryMode:
+ selected := selectSecondaries(rp, candidates)
+ return selectByTagSet(selected, rp.TagSets()), nil
+ case readpref.NearestMode:
+ selected := selectByKind(candidates, RSPrimary)
+ selected = append(selected, selectSecondaries(rp, candidates)...)
+ return selectByTagSet(selected, rp.TagSets()), nil
+ }
+
+ return nil, fmt.Errorf("unsupported mode: %d", rp.Mode())
+}
+
+func selectSecondaries(rp *readpref.ReadPref, candidates []Server) []Server {
+ secondaries := selectByKind(candidates, RSSecondary)
+ if len(secondaries) == 0 {
+ return secondaries
+ }
+ if maxStaleness, set := rp.MaxStaleness(); set {
+ primaries := selectByKind(candidates, RSPrimary)
+ if len(primaries) == 0 {
+ baseTime := secondaries[0].LastWriteTime
+ for i := 1; i < len(secondaries); i++ {
+ if secondaries[i].LastWriteTime.After(baseTime) {
+ baseTime = secondaries[i].LastWriteTime
+ }
+ }
+
+ var selected []Server
+ for _, secondary := range secondaries {
+ estimatedStaleness := baseTime.Sub(secondary.LastWriteTime) + secondary.HeartbeatInterval
+ if estimatedStaleness <= maxStaleness {
+ selected = append(selected, secondary)
+ }
+ }
+
+ return selected
+ }
+
+ primary := primaries[0]
+
+ var selected []Server
+ for _, secondary := range secondaries {
+ estimatedStaleness := secondary.LastUpdateTime.Sub(secondary.LastWriteTime) - primary.LastUpdateTime.Sub(primary.LastWriteTime) + secondary.HeartbeatInterval
+ if estimatedStaleness <= maxStaleness {
+ selected = append(selected, secondary)
+ }
+ }
+ return selected
+ }
+
+ return secondaries
+}
+
+func selectByTagSet(candidates []Server, tagSets []tag.Set) []Server {
+ if len(tagSets) == 0 {
+ return candidates
+ }
+
+ for _, ts := range tagSets {
+ var results []Server
+ for _, s := range candidates {
+ if len(s.Tags) > 0 && s.Tags.ContainsAll(ts) {
+ results = append(results, s)
+ }
+ }
+
+ if len(results) > 0 {
+ return results
+ }
+ }
+
+ return []Server{}
+}
+
+func selectByKind(candidates []Server, kind ServerKind) []Server {
+ var result []Server
+ for _, s := range candidates {
+ if s.Kind == kind {
+ result = append(result, s)
+ }
+ }
+
+ return result
+}
+
+func verifyMaxStaleness(rp *readpref.ReadPref, t Topology) error {
+ maxStaleness, set := rp.MaxStaleness()
+ if !set {
+ return nil
+ }
+
+ if maxStaleness < 90*time.Second {
+ return fmt.Errorf("max staleness (%s) must be greater than or equal to 90s", maxStaleness)
+ }
+
+ if len(t.Servers) < 1 {
+ // Maybe we should return an error here instead?
+ return nil
+ }
+
+ // we'll assume all candidates have the same heartbeat interval.
+ s := t.Servers[0]
+ idleWritePeriod := 10 * time.Second
+
+ if maxStaleness < s.HeartbeatInterval+idleWritePeriod {
+ return fmt.Errorf(
+ "max staleness (%s) must be greater than or equal to the heartbeat interval (%s) plus idle write period (%s)",
+ maxStaleness, s.HeartbeatInterval, idleWritePeriod,
+ )
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/topology.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/topology.go
new file mode 100644
index 0000000..caf447d
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/topology.go
@@ -0,0 +1,89 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+import (
+ "sort"
+ "strings"
+
+ "github.com/mongodb/mongo-go-driver/x/network/address"
+)
+
+// Topology represents a description of a mongodb topology
+type Topology struct {
+ Servers []Server
+ Kind TopologyKind
+ SessionTimeoutMinutes uint32
+}
+
+// Server returns the server for the given address. Returns false if the server
+// could not be found.
+func (t Topology) Server(addr address.Address) (Server, bool) {
+ for _, server := range t.Servers {
+ if server.Addr.String() == addr.String() {
+ return server, true
+ }
+ }
+ return Server{}, false
+}
+
+// TopologyDiff is the difference between two different topology descriptions.
+type TopologyDiff struct {
+ Added []Server
+ Removed []Server
+}
+
+// DiffTopology compares the two topology descriptions and returns the difference.
+func DiffTopology(old, new Topology) TopologyDiff {
+ var diff TopologyDiff
+
+ // TODO: do this without sorting...
+ oldServers := serverSorter(old.Servers)
+ newServers := serverSorter(new.Servers)
+
+ sort.Sort(oldServers)
+ sort.Sort(newServers)
+
+ i := 0
+ j := 0
+ for {
+ if i < len(oldServers) && j < len(newServers) {
+ comp := strings.Compare(oldServers[i].Addr.String(), newServers[j].Addr.String())
+ switch comp {
+ case 1:
+ //left is bigger than
+ diff.Added = append(diff.Added, newServers[j])
+ j++
+ case -1:
+ // right is bigger
+ diff.Removed = append(diff.Removed, oldServers[i])
+ i++
+ case 0:
+ i++
+ j++
+ }
+ } else if i < len(oldServers) {
+ diff.Removed = append(diff.Removed, oldServers[i])
+ i++
+ } else if j < len(newServers) {
+ diff.Added = append(diff.Added, newServers[j])
+ j++
+ } else {
+ break
+ }
+ }
+
+ return diff
+}
+
+type serverSorter []Server
+
+func (ss serverSorter) Len() int { return len(ss) }
+func (ss serverSorter) Swap(i, j int) { ss[i], ss[j] = ss[j], ss[i] }
+func (ss serverSorter) Less(i, j int) bool {
+ return strings.Compare(ss[i].Addr.String(), ss[j].Addr.String()) < 0
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/topology_kind.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/topology_kind.go
new file mode 100644
index 0000000..69f8177
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/topology_kind.go
@@ -0,0 +1,37 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+// TopologyKind represents a specific topology configuration.
+type TopologyKind uint32
+
+// These constants are the available topology configurations.
+const (
+ Single TopologyKind = 1
+ ReplicaSet TopologyKind = 2
+ ReplicaSetNoPrimary TopologyKind = 4 + ReplicaSet
+ ReplicaSetWithPrimary TopologyKind = 8 + ReplicaSet
+ Sharded TopologyKind = 256
+)
+
+// String implements the fmt.Stringer interface.
+func (kind TopologyKind) String() string {
+ switch kind {
+ case Single:
+ return "Single"
+ case ReplicaSet:
+ return "ReplicaSet"
+ case ReplicaSetNoPrimary:
+ return "ReplicaSetNoPrimary"
+ case ReplicaSetWithPrimary:
+ return "ReplicaSetWithPrimary"
+ case Sharded:
+ return "Sharded"
+ }
+
+ return "Unknown"
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/version.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/version.go
new file mode 100644
index 0000000..60cda4e
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/version.go
@@ -0,0 +1,44 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+import "strconv"
+
+// Version represents a software version.
+type Version struct {
+ Desc string
+ Parts []uint8
+}
+
+// AtLeast ensures that the version is at least as large as the "other" version.
+func (v Version) AtLeast(other ...uint8) bool {
+ for i := range other {
+ if i == len(v.Parts) {
+ return false
+ }
+ if v.Parts[i] < other[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// String provides the string represtation of the Version.
+func (v Version) String() string {
+ if v.Desc == "" {
+ var s string
+ for i, p := range v.Parts {
+ if i != 0 {
+ s += "."
+ }
+ s += strconv.Itoa(int(p))
+ }
+ return s
+ }
+
+ return v.Desc
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/x/network/description/version_range.go b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/version_range.go
new file mode 100644
index 0000000..984dff8
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/x/network/description/version_range.go
@@ -0,0 +1,31 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package description
+
+import "fmt"
+
+// VersionRange represents a range of versions.
+type VersionRange struct {
+ Min int32
+ Max int32
+}
+
+// NewVersionRange creates a new VersionRange given a min and a max.
+func NewVersionRange(min, max int32) VersionRange {
+ return VersionRange{Min: min, Max: max}
+}
+
+// Includes returns a bool indicating whether the supplied integer is included
+// in the range.
+func (vr VersionRange) Includes(v int32) bool {
+ return v >= vr.Min && v <= vr.Max
+}
+
+// String implements the fmt.Stringer interface.
+func (vr VersionRange) String() string {
+ return fmt.Sprintf("[%d, %d]", vr.Min, vr.Max)
+}