Browse Source

Merge pull request #34061 from cyli/re-vendor-swarmkit

Re-vendor swarmkit.
Sebastiaan van Stijn 8 years ago
parent
commit
c0e6da7637
34 changed files with 1155 additions and 734 deletions
  1. 1 1
      daemon/cluster/executor/container/container.go
  2. 1 1
      vendor.conf
  3. 4 4
      vendor/github.com/docker/swarmkit/agent/storage.go
  4. 11 11
      vendor/github.com/docker/swarmkit/api/genericresource/helpers.go
  5. 18 18
      vendor/github.com/docker/swarmkit/api/genericresource/resource_management.go
  6. 9 9
      vendor/github.com/docker/swarmkit/api/genericresource/string.go
  7. 11 11
      vendor/github.com/docker/swarmkit/api/genericresource/validate.go
  8. 411 400
      vendor/github.com/docker/swarmkit/api/types.pb.go
  9. 14 4
      vendor/github.com/docker/swarmkit/api/types.proto
  10. 22 20
      vendor/github.com/docker/swarmkit/ca/config.go
  11. 15 3
      vendor/github.com/docker/swarmkit/ca/external.go
  12. 7 1
      vendor/github.com/docker/swarmkit/manager/controlapi/service.go
  13. 5 5
      vendor/github.com/docker/swarmkit/manager/dispatcher/dispatcher.go
  14. 25 16
      vendor/github.com/docker/swarmkit/manager/orchestrator/global/global.go
  15. 55 15
      vendor/github.com/docker/swarmkit/manager/scheduler/nodeinfo.go
  16. 3 3
      vendor/github.com/docker/swarmkit/manager/scheduler/scheduler.go
  17. 4 14
      vendor/github.com/docker/swarmkit/manager/state/store/clusters.go
  18. 4 14
      vendor/github.com/docker/swarmkit/manager/state/store/configs.go
  19. 12 14
      vendor/github.com/docker/swarmkit/manager/state/store/extensions.go
  20. 4 14
      vendor/github.com/docker/swarmkit/manager/state/store/networks.go
  21. 4 14
      vendor/github.com/docker/swarmkit/manager/state/store/nodes.go
  22. 43 0
      vendor/github.com/docker/swarmkit/manager/state/store/object.go
  23. 12 14
      vendor/github.com/docker/swarmkit/manager/state/store/resources.go
  24. 4 14
      vendor/github.com/docker/swarmkit/manager/state/store/secrets.go
  25. 4 14
      vendor/github.com/docker/swarmkit/manager/state/store/services.go
  26. 4 14
      vendor/github.com/docker/swarmkit/manager/state/store/tasks.go
  27. 21 21
      vendor/github.com/docker/swarmkit/node/node.go
  28. 25 7
      vendor/github.com/docker/swarmkit/template/context.go
  29. 8 7
      vendor/github.com/docker/swarmkit/template/expand.go
  30. 11 9
      vendor/github.com/docker/swarmkit/template/getter.go
  31. 5 7
      vendor/github.com/docker/swarmkit/vendor.conf
  32. 158 0
      vendor/github.com/docker/swarmkit/watch/queue/queue.go
  33. 95 0
      vendor/github.com/docker/swarmkit/watch/sinks.go
  34. 125 35
      vendor/github.com/docker/swarmkit/watch/watch.go

+ 1 - 1
daemon/cluster/executor/container/container.go

@@ -77,7 +77,7 @@ func (c *containerConfig) setTask(t *api.Task) error {
 	c.task = t
 	c.task = t
 
 
 	if t.Spec.GetContainer() != nil {
 	if t.Spec.GetContainer() != nil {
-		preparedSpec, err := template.ExpandContainerSpec(t)
+		preparedSpec, err := template.ExpandContainerSpec(nil, t)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}

+ 1 - 1
vendor.conf

@@ -106,7 +106,7 @@ github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d
 github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb
 github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb
 
 
 # cluster
 # cluster
-github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb
+github.com/docker/swarmkit a3d96fe13e30e46c3d4cfc3f316ebdd8446a079d
 github.com/gogo/protobuf v0.4
 github.com/gogo/protobuf v0.4
 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
 github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
 github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
 github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e

+ 4 - 4
vendor/github.com/docker/swarmkit/agent/storage.go

@@ -35,7 +35,7 @@ func GetTask(tx *bolt.Tx, id string) (*api.Task, error) {
 	var t api.Task
 	var t api.Task
 
 
 	if err := withTaskBucket(tx, id, func(bkt *bolt.Bucket) error {
 	if err := withTaskBucket(tx, id, func(bkt *bolt.Bucket) error {
-		p := bkt.Get([]byte("data"))
+		p := bkt.Get(bucketKeyData)
 		if p == nil {
 		if p == nil {
 			return errTaskUnknown
 			return errTaskUnknown
 		}
 		}
@@ -136,7 +136,7 @@ func PutTaskStatus(tx *bolt.Tx, id string, status *api.TaskStatus) error {
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-		return bkt.Put([]byte("status"), p)
+		return bkt.Put(bucketKeyStatus, p)
 	})
 	})
 }
 }
 
 
@@ -154,9 +154,9 @@ func DeleteTask(tx *bolt.Tx, id string) error {
 func SetTaskAssignment(tx *bolt.Tx, id string, assigned bool) error {
 func SetTaskAssignment(tx *bolt.Tx, id string, assigned bool) error {
 	return withTaskBucket(tx, id, func(bkt *bolt.Bucket) error {
 	return withTaskBucket(tx, id, func(bkt *bolt.Bucket) error {
 		if assigned {
 		if assigned {
-			return bkt.Put([]byte("assigned"), []byte{0xFF})
+			return bkt.Put(bucketKeyAssigned, []byte{0xFF})
 		}
 		}
-		return bkt.Delete([]byte("assigned"))
+		return bkt.Delete(bucketKeyAssigned)
 	})
 	})
 }
 }
 
 

+ 11 - 11
vendor/github.com/docker/swarmkit/api/genericresource/helpers.go

@@ -18,8 +18,8 @@ func NewSet(key string, vals ...string) []*api.GenericResource {
 // NewString creates a String resource
 // NewString creates a String resource
 func NewString(key, val string) *api.GenericResource {
 func NewString(key, val string) *api.GenericResource {
 	return &api.GenericResource{
 	return &api.GenericResource{
-		Resource: &api.GenericResource_Str{
-			Str: &api.GenericString{
+		Resource: &api.GenericResource_NamedResourceSpec{
+			NamedResourceSpec: &api.NamedGenericResource{
 				Kind:  key,
 				Kind:  key,
 				Value: val,
 				Value: val,
 			},
 			},
@@ -30,8 +30,8 @@ func NewString(key, val string) *api.GenericResource {
 // NewDiscrete creates a Discrete resource
 // NewDiscrete creates a Discrete resource
 func NewDiscrete(key string, val int64) *api.GenericResource {
 func NewDiscrete(key string, val int64) *api.GenericResource {
 	return &api.GenericResource{
 	return &api.GenericResource{
-		Resource: &api.GenericResource_Discrete{
-			Discrete: &api.GenericDiscrete{
+		Resource: &api.GenericResource_DiscreteResourceSpec{
+			DiscreteResourceSpec: &api.DiscreteGenericResource{
 				Kind:  key,
 				Kind:  key,
 				Value: val,
 				Value: val,
 			},
 			},
@@ -86,21 +86,21 @@ loop:
 // Returns true if the element is to be removed from the list
 // Returns true if the element is to be removed from the list
 func remove(na, r *api.GenericResource) bool {
 func remove(na, r *api.GenericResource) bool {
 	switch tr := r.Resource.(type) {
 	switch tr := r.Resource.(type) {
-	case *api.GenericResource_Discrete:
-		if na.GetDiscrete() == nil {
+	case *api.GenericResource_DiscreteResourceSpec:
+		if na.GetDiscreteResourceSpec() == nil {
 			return false // Type change, ignore
 			return false // Type change, ignore
 		}
 		}
 
 
-		na.GetDiscrete().Value -= tr.Discrete.Value
-		if na.GetDiscrete().Value <= 0 {
+		na.GetDiscreteResourceSpec().Value -= tr.DiscreteResourceSpec.Value
+		if na.GetDiscreteResourceSpec().Value <= 0 {
 			return true
 			return true
 		}
 		}
-	case *api.GenericResource_Str:
-		if na.GetStr() == nil {
+	case *api.GenericResource_NamedResourceSpec:
+		if na.GetNamedResourceSpec() == nil {
 			return false // Type change, ignore
 			return false // Type change, ignore
 		}
 		}
 
 
-		if tr.Str.Value != na.GetStr().Value {
+		if tr.NamedResourceSpec.Value != na.GetNamedResourceSpec().Value {
 			return false // not the right item, ignore
 			return false // not the right item, ignore
 		}
 		}
 
 

+ 18 - 18
vendor/github.com/docker/swarmkit/api/genericresource/resource_management.go

@@ -12,7 +12,7 @@ func Claim(nodeAvailableResources, taskAssigned *[]*api.GenericResource,
 	var resSelected []*api.GenericResource
 	var resSelected []*api.GenericResource
 
 
 	for _, res := range taskReservations {
 	for _, res := range taskReservations {
-		tr := res.GetDiscrete()
+		tr := res.GetDiscreteResourceSpec()
 		if tr == nil {
 		if tr == nil {
 			return fmt.Errorf("task should only hold Discrete type")
 			return fmt.Errorf("task should only hold Discrete type")
 		}
 		}
@@ -39,7 +39,7 @@ func ClaimResources(nodeAvailableResources, taskAssigned *[]*api.GenericResource
 }
 }
 
 
 func selectNodeResources(nodeRes []*api.GenericResource,
 func selectNodeResources(nodeRes []*api.GenericResource,
-	tr *api.GenericDiscrete) ([]*api.GenericResource, error) {
+	tr *api.DiscreteGenericResource) ([]*api.GenericResource, error) {
 	var nrs []*api.GenericResource
 	var nrs []*api.GenericResource
 
 
 	for _, res := range nodeRes {
 	for _, res := range nodeRes {
@@ -48,13 +48,13 @@ func selectNodeResources(nodeRes []*api.GenericResource,
 		}
 		}
 
 
 		switch nr := res.Resource.(type) {
 		switch nr := res.Resource.(type) {
-		case *api.GenericResource_Discrete:
-			if nr.Discrete.Value >= tr.Value && tr.Value != 0 {
+		case *api.GenericResource_DiscreteResourceSpec:
+			if nr.DiscreteResourceSpec.Value >= tr.Value && tr.Value != 0 {
 				nrs = append(nrs, NewDiscrete(tr.Kind, tr.Value))
 				nrs = append(nrs, NewDiscrete(tr.Kind, tr.Value))
 			}
 			}
 
 
 			return nrs, nil
 			return nrs, nil
-		case *api.GenericResource_Str:
+		case *api.GenericResource_NamedResourceSpec:
 			nrs = append(nrs, res.Copy())
 			nrs = append(nrs, res.Copy())
 
 
 			if int64(len(nrs)) == tr.Value {
 			if int64(len(nrs)) == tr.Value {
@@ -90,8 +90,8 @@ func reclaimResources(nodeAvailableResources *[]*api.GenericResource, taskAssign
 
 
 	for _, res := range taskAssigned {
 	for _, res := range taskAssigned {
 		switch tr := res.Resource.(type) {
 		switch tr := res.Resource.(type) {
-		case *api.GenericResource_Discrete:
-			nrs := GetResource(tr.Discrete.Kind, *nodeAvailableResources)
+		case *api.GenericResource_DiscreteResourceSpec:
+			nrs := GetResource(tr.DiscreteResourceSpec.Kind, *nodeAvailableResources)
 
 
 			// If the resource went down to 0 it's no longer in the
 			// If the resource went down to 0 it's no longer in the
 			// available list
 			// available list
@@ -103,13 +103,13 @@ func reclaimResources(nodeAvailableResources *[]*api.GenericResource, taskAssign
 				continue // Type change
 				continue // Type change
 			}
 			}
 
 
-			nr := nrs[0].GetDiscrete()
+			nr := nrs[0].GetDiscreteResourceSpec()
 			if nr == nil {
 			if nr == nil {
 				continue // Type change
 				continue // Type change
 			}
 			}
 
 
-			nr.Value += tr.Discrete.Value
-		case *api.GenericResource_Str:
+			nr.Value += tr.DiscreteResourceSpec.Value
+		case *api.GenericResource_NamedResourceSpec:
 			*nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
 			*nodeAvailableResources = append(*nodeAvailableResources, res.Copy())
 		}
 		}
 	}
 	}
@@ -157,8 +157,8 @@ func sanitize(nodeRes []*api.GenericResource, nodeAvailableResources *[]*api.Gen
 // Returns false if the element isn't in nodeRes and "sane" and the element(s) that should be replacing it
 // Returns false if the element isn't in nodeRes and "sane" and the element(s) that should be replacing it
 func sanitizeResource(nodeRes []*api.GenericResource, res *api.GenericResource) (ok bool, nrs []*api.GenericResource) {
 func sanitizeResource(nodeRes []*api.GenericResource, res *api.GenericResource) (ok bool, nrs []*api.GenericResource) {
 	switch na := res.Resource.(type) {
 	switch na := res.Resource.(type) {
-	case *api.GenericResource_Discrete:
-		nrs := GetResource(na.Discrete.Kind, nodeRes)
+	case *api.GenericResource_DiscreteResourceSpec:
+		nrs := GetResource(na.DiscreteResourceSpec.Kind, nodeRes)
 
 
 		// Type change or removed: reset
 		// Type change or removed: reset
 		if len(nrs) != 1 {
 		if len(nrs) != 1 {
@@ -166,17 +166,17 @@ func sanitizeResource(nodeRes []*api.GenericResource, res *api.GenericResource)
 		}
 		}
 
 
 		// Type change: reset
 		// Type change: reset
-		nr := nrs[0].GetDiscrete()
+		nr := nrs[0].GetDiscreteResourceSpec()
 		if nr == nil {
 		if nr == nil {
 			return false, nrs
 			return false, nrs
 		}
 		}
 
 
 		// Amount change: reset
 		// Amount change: reset
-		if na.Discrete.Value > nr.Value {
+		if na.DiscreteResourceSpec.Value > nr.Value {
 			return false, nrs
 			return false, nrs
 		}
 		}
-	case *api.GenericResource_Str:
-		nrs := GetResource(na.Str.Kind, nodeRes)
+	case *api.GenericResource_NamedResourceSpec:
+		nrs := GetResource(na.NamedResourceSpec.Kind, nodeRes)
 
 
 		// Type change
 		// Type change
 		if len(nrs) == 0 {
 		if len(nrs) == 0 {
@@ -185,11 +185,11 @@ func sanitizeResource(nodeRes []*api.GenericResource, res *api.GenericResource)
 
 
 		for _, nr := range nrs {
 		for _, nr := range nrs {
 			// Type change: reset
 			// Type change: reset
-			if nr.GetDiscrete() != nil {
+			if nr.GetDiscreteResourceSpec() != nil {
 				return false, nrs
 				return false, nrs
 			}
 			}
 
 
-			if na.Str.Value == nr.GetStr().Value {
+			if na.NamedResourceSpec.Value == nr.GetNamedResourceSpec().Value {
 				return true, nil
 				return true, nil
 			}
 			}
 		}
 		}

+ 9 - 9
vendor/github.com/docker/swarmkit/api/genericresource/string.go

@@ -7,17 +7,17 @@ import (
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 )
 )
 
 
-func discreteToString(d *api.GenericResource_Discrete) string {
-	return strconv.FormatInt(d.Discrete.Value, 10)
+func discreteToString(d *api.GenericResource_DiscreteResourceSpec) string {
+	return strconv.FormatInt(d.DiscreteResourceSpec.Value, 10)
 }
 }
 
 
 // Kind returns the kind key as a string
 // Kind returns the kind key as a string
 func Kind(res *api.GenericResource) string {
 func Kind(res *api.GenericResource) string {
 	switch r := res.Resource.(type) {
 	switch r := res.Resource.(type) {
-	case *api.GenericResource_Discrete:
-		return r.Discrete.Kind
-	case *api.GenericResource_Str:
-		return r.Str.Kind
+	case *api.GenericResource_DiscreteResourceSpec:
+		return r.DiscreteResourceSpec.Kind
+	case *api.GenericResource_NamedResourceSpec:
+		return r.NamedResourceSpec.Kind
 	}
 	}
 
 
 	return ""
 	return ""
@@ -26,10 +26,10 @@ func Kind(res *api.GenericResource) string {
 // Value returns the value key as a string
 // Value returns the value key as a string
 func Value(res *api.GenericResource) string {
 func Value(res *api.GenericResource) string {
 	switch res := res.Resource.(type) {
 	switch res := res.Resource.(type) {
-	case *api.GenericResource_Discrete:
+	case *api.GenericResource_DiscreteResourceSpec:
 		return discreteToString(res)
 		return discreteToString(res)
-	case *api.GenericResource_Str:
-		return res.Str.Value
+	case *api.GenericResource_NamedResourceSpec:
+		return res.NamedResourceSpec.Value
 	}
 	}
 
 
 	return ""
 	return ""

+ 11 - 11
vendor/github.com/docker/swarmkit/api/genericresource/validate.go

@@ -9,7 +9,7 @@ import (
 // for generic resources
 // for generic resources
 func ValidateTask(resources *api.Resources) error {
 func ValidateTask(resources *api.Resources) error {
 	for _, v := range resources.Generic {
 	for _, v := range resources.Generic {
-		if v.GetDiscrete() != nil {
+		if v.GetDiscreteResourceSpec() != nil {
 			continue
 			continue
 		}
 		}
 
 
@@ -21,7 +21,7 @@ func ValidateTask(resources *api.Resources) error {
 
 
 // HasEnough returns true if node can satisfy the task's GenericResource request
 // HasEnough returns true if node can satisfy the task's GenericResource request
 func HasEnough(nodeRes []*api.GenericResource, taskRes *api.GenericResource) (bool, error) {
 func HasEnough(nodeRes []*api.GenericResource, taskRes *api.GenericResource) (bool, error) {
-	t := taskRes.GetDiscrete()
+	t := taskRes.GetDiscreteResourceSpec()
 	if t == nil {
 	if t == nil {
 		return false, fmt.Errorf("task should only hold Discrete type")
 		return false, fmt.Errorf("task should only hold Discrete type")
 	}
 	}
@@ -36,11 +36,11 @@ func HasEnough(nodeRes []*api.GenericResource, taskRes *api.GenericResource) (bo
 	}
 	}
 
 
 	switch nr := nrs[0].Resource.(type) {
 	switch nr := nrs[0].Resource.(type) {
-	case *api.GenericResource_Discrete:
-		if t.Value > nr.Discrete.Value {
+	case *api.GenericResource_DiscreteResourceSpec:
+		if t.Value > nr.DiscreteResourceSpec.Value {
 			return false, nil
 			return false, nil
 		}
 		}
-	case *api.GenericResource_Str:
+	case *api.GenericResource_NamedResourceSpec:
 		if t.Value > int64(len(nrs)) {
 		if t.Value > int64(len(nrs)) {
 			return false, nil
 			return false, nil
 		}
 		}
@@ -57,22 +57,22 @@ func HasResource(res *api.GenericResource, resources []*api.GenericResource) boo
 		}
 		}
 
 
 		switch rtype := r.Resource.(type) {
 		switch rtype := r.Resource.(type) {
-		case *api.GenericResource_Discrete:
-			if res.GetDiscrete() == nil {
+		case *api.GenericResource_DiscreteResourceSpec:
+			if res.GetDiscreteResourceSpec() == nil {
 				return false
 				return false
 			}
 			}
 
 
-			if res.GetDiscrete().Value < rtype.Discrete.Value {
+			if res.GetDiscreteResourceSpec().Value < rtype.DiscreteResourceSpec.Value {
 				return false
 				return false
 			}
 			}
 
 
 			return true
 			return true
-		case *api.GenericResource_Str:
-			if res.GetStr() == nil {
+		case *api.GenericResource_NamedResourceSpec:
+			if res.GetNamedResourceSpec() == nil {
 				return false
 				return false
 			}
 			}
 
 
-			if res.GetStr().Value != rtype.Str.Value {
+			if res.GetNamedResourceSpec().Value != rtype.NamedResourceSpec.Value {
 				continue
 				continue
 			}
 			}
 
 

+ 411 - 400
vendor/github.com/docker/swarmkit/api/types.pb.go

@@ -23,8 +23,8 @@
 		Version
 		Version
 		IndexEntry
 		IndexEntry
 		Annotations
 		Annotations
-		GenericString
-		GenericDiscrete
+		NamedGenericResource
+		DiscreteGenericResource
 		GenericResource
 		GenericResource
 		Resources
 		Resources
 		ResourceRequirements
 		ResourceRequirements
@@ -781,28 +781,38 @@ func (m *Annotations) Reset()                    { *m = Annotations{} }
 func (*Annotations) ProtoMessage()               {}
 func (*Annotations) ProtoMessage()               {}
 func (*Annotations) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{2} }
 func (*Annotations) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{2} }
 
 
-type GenericString struct {
+// NamedGenericResource represents a "user defined" resource which is defined
+// as a string.
+// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
+// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...)
+type NamedGenericResource struct {
 	Kind  string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"`
 	Kind  string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"`
 	Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
 	Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
 }
 }
 
 
-func (m *GenericString) Reset()                    { *m = GenericString{} }
-func (*GenericString) ProtoMessage()               {}
-func (*GenericString) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{3} }
+func (m *NamedGenericResource) Reset()                    { *m = NamedGenericResource{} }
+func (*NamedGenericResource) ProtoMessage()               {}
+func (*NamedGenericResource) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{3} }
 
 
-type GenericDiscrete struct {
+// DiscreteGenericResource represents a "user defined" resource which is defined
+// as an integer
+// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
+// Value is used to count the resource (SSD=5, HDD=3, ...)
+type DiscreteGenericResource struct {
 	Kind  string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"`
 	Kind  string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"`
 	Value int64  `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
 	Value int64  `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
 }
 }
 
 
-func (m *GenericDiscrete) Reset()                    { *m = GenericDiscrete{} }
-func (*GenericDiscrete) ProtoMessage()               {}
-func (*GenericDiscrete) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{4} }
+func (m *DiscreteGenericResource) Reset()                    { *m = DiscreteGenericResource{} }
+func (*DiscreteGenericResource) ProtoMessage()               {}
+func (*DiscreteGenericResource) Descriptor() ([]byte, []int) { return fileDescriptorTypes, []int{4} }
 
 
+// GenericResource represents a "user defined" resource which can
+// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1)
 type GenericResource struct {
 type GenericResource struct {
 	// Types that are valid to be assigned to Resource:
 	// Types that are valid to be assigned to Resource:
-	//	*GenericResource_Str
-	//	*GenericResource_Discrete
+	//	*GenericResource_NamedResourceSpec
+	//	*GenericResource_DiscreteResourceSpec
 	Resource isGenericResource_Resource `protobuf_oneof:"resource"`
 	Resource isGenericResource_Resource `protobuf_oneof:"resource"`
 }
 }
 
 
@@ -816,15 +826,15 @@ type isGenericResource_Resource interface {
 	Size() int
 	Size() int
 }
 }
 
 
-type GenericResource_Str struct {
-	Str *GenericString `protobuf:"bytes,1,opt,name=str,oneof"`
+type GenericResource_NamedResourceSpec struct {
+	NamedResourceSpec *NamedGenericResource `protobuf:"bytes,1,opt,name=named_resource_spec,json=namedResourceSpec,oneof"`
 }
 }
-type GenericResource_Discrete struct {
-	Discrete *GenericDiscrete `protobuf:"bytes,2,opt,name=discrete,oneof"`
+type GenericResource_DiscreteResourceSpec struct {
+	DiscreteResourceSpec *DiscreteGenericResource `protobuf:"bytes,2,opt,name=discrete_resource_spec,json=discreteResourceSpec,oneof"`
 }
 }
 
 
-func (*GenericResource_Str) isGenericResource_Resource()      {}
-func (*GenericResource_Discrete) isGenericResource_Resource() {}
+func (*GenericResource_NamedResourceSpec) isGenericResource_Resource()    {}
+func (*GenericResource_DiscreteResourceSpec) isGenericResource_Resource() {}
 
 
 func (m *GenericResource) GetResource() isGenericResource_Resource {
 func (m *GenericResource) GetResource() isGenericResource_Resource {
 	if m != nil {
 	if m != nil {
@@ -833,16 +843,16 @@ func (m *GenericResource) GetResource() isGenericResource_Resource {
 	return nil
 	return nil
 }
 }
 
 
-func (m *GenericResource) GetStr() *GenericString {
-	if x, ok := m.GetResource().(*GenericResource_Str); ok {
-		return x.Str
+func (m *GenericResource) GetNamedResourceSpec() *NamedGenericResource {
+	if x, ok := m.GetResource().(*GenericResource_NamedResourceSpec); ok {
+		return x.NamedResourceSpec
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
-func (m *GenericResource) GetDiscrete() *GenericDiscrete {
-	if x, ok := m.GetResource().(*GenericResource_Discrete); ok {
-		return x.Discrete
+func (m *GenericResource) GetDiscreteResourceSpec() *DiscreteGenericResource {
+	if x, ok := m.GetResource().(*GenericResource_DiscreteResourceSpec); ok {
+		return x.DiscreteResourceSpec
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -850,8 +860,8 @@ func (m *GenericResource) GetDiscrete() *GenericDiscrete {
 // XXX_OneofFuncs is for the internal use of the proto package.
 // XXX_OneofFuncs is for the internal use of the proto package.
 func (*GenericResource) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
 func (*GenericResource) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
 	return _GenericResource_OneofMarshaler, _GenericResource_OneofUnmarshaler, _GenericResource_OneofSizer, []interface{}{
 	return _GenericResource_OneofMarshaler, _GenericResource_OneofUnmarshaler, _GenericResource_OneofSizer, []interface{}{
-		(*GenericResource_Str)(nil),
-		(*GenericResource_Discrete)(nil),
+		(*GenericResource_NamedResourceSpec)(nil),
+		(*GenericResource_DiscreteResourceSpec)(nil),
 	}
 	}
 }
 }
 
 
@@ -859,14 +869,14 @@ func _GenericResource_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
 	m := msg.(*GenericResource)
 	m := msg.(*GenericResource)
 	// resource
 	// resource
 	switch x := m.Resource.(type) {
 	switch x := m.Resource.(type) {
-	case *GenericResource_Str:
+	case *GenericResource_NamedResourceSpec:
 		_ = b.EncodeVarint(1<<3 | proto.WireBytes)
 		_ = b.EncodeVarint(1<<3 | proto.WireBytes)
-		if err := b.EncodeMessage(x.Str); err != nil {
+		if err := b.EncodeMessage(x.NamedResourceSpec); err != nil {
 			return err
 			return err
 		}
 		}
-	case *GenericResource_Discrete:
+	case *GenericResource_DiscreteResourceSpec:
 		_ = b.EncodeVarint(2<<3 | proto.WireBytes)
 		_ = b.EncodeVarint(2<<3 | proto.WireBytes)
-		if err := b.EncodeMessage(x.Discrete); err != nil {
+		if err := b.EncodeMessage(x.DiscreteResourceSpec); err != nil {
 			return err
 			return err
 		}
 		}
 	case nil:
 	case nil:
@@ -879,21 +889,21 @@ func _GenericResource_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
 func _GenericResource_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
 func _GenericResource_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
 	m := msg.(*GenericResource)
 	m := msg.(*GenericResource)
 	switch tag {
 	switch tag {
-	case 1: // resource.str
+	case 1: // resource.named_resource_spec
 		if wire != proto.WireBytes {
 		if wire != proto.WireBytes {
 			return true, proto.ErrInternalBadWireType
 			return true, proto.ErrInternalBadWireType
 		}
 		}
-		msg := new(GenericString)
+		msg := new(NamedGenericResource)
 		err := b.DecodeMessage(msg)
 		err := b.DecodeMessage(msg)
-		m.Resource = &GenericResource_Str{msg}
+		m.Resource = &GenericResource_NamedResourceSpec{msg}
 		return true, err
 		return true, err
-	case 2: // resource.discrete
+	case 2: // resource.discrete_resource_spec
 		if wire != proto.WireBytes {
 		if wire != proto.WireBytes {
 			return true, proto.ErrInternalBadWireType
 			return true, proto.ErrInternalBadWireType
 		}
 		}
-		msg := new(GenericDiscrete)
+		msg := new(DiscreteGenericResource)
 		err := b.DecodeMessage(msg)
 		err := b.DecodeMessage(msg)
-		m.Resource = &GenericResource_Discrete{msg}
+		m.Resource = &GenericResource_DiscreteResourceSpec{msg}
 		return true, err
 		return true, err
 	default:
 	default:
 		return false, nil
 		return false, nil
@@ -904,13 +914,13 @@ func _GenericResource_OneofSizer(msg proto.Message) (n int) {
 	m := msg.(*GenericResource)
 	m := msg.(*GenericResource)
 	// resource
 	// resource
 	switch x := m.Resource.(type) {
 	switch x := m.Resource.(type) {
-	case *GenericResource_Str:
-		s := proto.Size(x.Str)
+	case *GenericResource_NamedResourceSpec:
+		s := proto.Size(x.NamedResourceSpec)
 		n += proto.SizeVarint(1<<3 | proto.WireBytes)
 		n += proto.SizeVarint(1<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(s))
 		n += proto.SizeVarint(uint64(s))
 		n += s
 		n += s
-	case *GenericResource_Discrete:
-		s := proto.Size(x.Discrete)
+	case *GenericResource_DiscreteResourceSpec:
+		s := proto.Size(x.DiscreteResourceSpec)
 		n += proto.SizeVarint(2<<3 | proto.WireBytes)
 		n += proto.SizeVarint(2<<3 | proto.WireBytes)
 		n += proto.SizeVarint(uint64(s))
 		n += proto.SizeVarint(uint64(s))
 		n += s
 		n += s
@@ -2242,8 +2252,8 @@ func init() {
 	proto.RegisterType((*Version)(nil), "docker.swarmkit.v1.Version")
 	proto.RegisterType((*Version)(nil), "docker.swarmkit.v1.Version")
 	proto.RegisterType((*IndexEntry)(nil), "docker.swarmkit.v1.IndexEntry")
 	proto.RegisterType((*IndexEntry)(nil), "docker.swarmkit.v1.IndexEntry")
 	proto.RegisterType((*Annotations)(nil), "docker.swarmkit.v1.Annotations")
 	proto.RegisterType((*Annotations)(nil), "docker.swarmkit.v1.Annotations")
-	proto.RegisterType((*GenericString)(nil), "docker.swarmkit.v1.GenericString")
-	proto.RegisterType((*GenericDiscrete)(nil), "docker.swarmkit.v1.GenericDiscrete")
+	proto.RegisterType((*NamedGenericResource)(nil), "docker.swarmkit.v1.NamedGenericResource")
+	proto.RegisterType((*DiscreteGenericResource)(nil), "docker.swarmkit.v1.DiscreteGenericResource")
 	proto.RegisterType((*GenericResource)(nil), "docker.swarmkit.v1.GenericResource")
 	proto.RegisterType((*GenericResource)(nil), "docker.swarmkit.v1.GenericResource")
 	proto.RegisterType((*Resources)(nil), "docker.swarmkit.v1.Resources")
 	proto.RegisterType((*Resources)(nil), "docker.swarmkit.v1.Resources")
 	proto.RegisterType((*ResourceRequirements)(nil), "docker.swarmkit.v1.ResourceRequirements")
 	proto.RegisterType((*ResourceRequirements)(nil), "docker.swarmkit.v1.ResourceRequirements")
@@ -2379,33 +2389,33 @@ func (m *Annotations) CopyFrom(src interface{}) {
 
 
 }
 }
 
 
-func (m *GenericString) Copy() *GenericString {
+func (m *NamedGenericResource) Copy() *NamedGenericResource {
 	if m == nil {
 	if m == nil {
 		return nil
 		return nil
 	}
 	}
-	o := &GenericString{}
+	o := &NamedGenericResource{}
 	o.CopyFrom(m)
 	o.CopyFrom(m)
 	return o
 	return o
 }
 }
 
 
-func (m *GenericString) CopyFrom(src interface{}) {
+func (m *NamedGenericResource) CopyFrom(src interface{}) {
 
 
-	o := src.(*GenericString)
+	o := src.(*NamedGenericResource)
 	*m = *o
 	*m = *o
 }
 }
 
 
-func (m *GenericDiscrete) Copy() *GenericDiscrete {
+func (m *DiscreteGenericResource) Copy() *DiscreteGenericResource {
 	if m == nil {
 	if m == nil {
 		return nil
 		return nil
 	}
 	}
-	o := &GenericDiscrete{}
+	o := &DiscreteGenericResource{}
 	o.CopyFrom(m)
 	o.CopyFrom(m)
 	return o
 	return o
 }
 }
 
 
-func (m *GenericDiscrete) CopyFrom(src interface{}) {
+func (m *DiscreteGenericResource) CopyFrom(src interface{}) {
 
 
-	o := src.(*GenericDiscrete)
+	o := src.(*DiscreteGenericResource)
 	*m = *o
 	*m = *o
 }
 }
 
 
@@ -2424,17 +2434,17 @@ func (m *GenericResource) CopyFrom(src interface{}) {
 	*m = *o
 	*m = *o
 	if o.Resource != nil {
 	if o.Resource != nil {
 		switch o.Resource.(type) {
 		switch o.Resource.(type) {
-		case *GenericResource_Str:
-			v := GenericResource_Str{
-				Str: &GenericString{},
+		case *GenericResource_NamedResourceSpec:
+			v := GenericResource_NamedResourceSpec{
+				NamedResourceSpec: &NamedGenericResource{},
 			}
 			}
-			github_com_docker_swarmkit_api_deepcopy.Copy(v.Str, o.GetStr())
+			github_com_docker_swarmkit_api_deepcopy.Copy(v.NamedResourceSpec, o.GetNamedResourceSpec())
 			m.Resource = &v
 			m.Resource = &v
-		case *GenericResource_Discrete:
-			v := GenericResource_Discrete{
-				Discrete: &GenericDiscrete{},
+		case *GenericResource_DiscreteResourceSpec:
+			v := GenericResource_DiscreteResourceSpec{
+				DiscreteResourceSpec: &DiscreteGenericResource{},
 			}
 			}
-			github_com_docker_swarmkit_api_deepcopy.Copy(v.Discrete, o.GetDiscrete())
+			github_com_docker_swarmkit_api_deepcopy.Copy(v.DiscreteResourceSpec, o.GetDiscreteResourceSpec())
 			m.Resource = &v
 			m.Resource = &v
 		}
 		}
 	}
 	}
@@ -3762,7 +3772,7 @@ func (m *Annotations) MarshalTo(dAtA []byte) (int, error) {
 	return i, nil
 	return i, nil
 }
 }
 
 
-func (m *GenericString) Marshal() (dAtA []byte, err error) {
+func (m *NamedGenericResource) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	size := m.Size()
 	dAtA = make([]byte, size)
 	dAtA = make([]byte, size)
 	n, err := m.MarshalTo(dAtA)
 	n, err := m.MarshalTo(dAtA)
@@ -3772,7 +3782,7 @@ func (m *GenericString) Marshal() (dAtA []byte, err error) {
 	return dAtA[:n], nil
 	return dAtA[:n], nil
 }
 }
 
 
-func (m *GenericString) MarshalTo(dAtA []byte) (int, error) {
+func (m *NamedGenericResource) MarshalTo(dAtA []byte) (int, error) {
 	var i int
 	var i int
 	_ = i
 	_ = i
 	var l int
 	var l int
@@ -3792,7 +3802,7 @@ func (m *GenericString) MarshalTo(dAtA []byte) (int, error) {
 	return i, nil
 	return i, nil
 }
 }
 
 
-func (m *GenericDiscrete) Marshal() (dAtA []byte, err error) {
+func (m *DiscreteGenericResource) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	size := m.Size()
 	dAtA = make([]byte, size)
 	dAtA = make([]byte, size)
 	n, err := m.MarshalTo(dAtA)
 	n, err := m.MarshalTo(dAtA)
@@ -3802,7 +3812,7 @@ func (m *GenericDiscrete) Marshal() (dAtA []byte, err error) {
 	return dAtA[:n], nil
 	return dAtA[:n], nil
 }
 }
 
 
-func (m *GenericDiscrete) MarshalTo(dAtA []byte) (int, error) {
+func (m *DiscreteGenericResource) MarshalTo(dAtA []byte) (int, error) {
 	var i int
 	var i int
 	_ = i
 	_ = i
 	var l int
 	var l int
@@ -3846,13 +3856,13 @@ func (m *GenericResource) MarshalTo(dAtA []byte) (int, error) {
 	return i, nil
 	return i, nil
 }
 }
 
 
-func (m *GenericResource_Str) MarshalTo(dAtA []byte) (int, error) {
+func (m *GenericResource_NamedResourceSpec) MarshalTo(dAtA []byte) (int, error) {
 	i := 0
 	i := 0
-	if m.Str != nil {
+	if m.NamedResourceSpec != nil {
 		dAtA[i] = 0xa
 		dAtA[i] = 0xa
 		i++
 		i++
-		i = encodeVarintTypes(dAtA, i, uint64(m.Str.Size()))
-		n2, err := m.Str.MarshalTo(dAtA[i:])
+		i = encodeVarintTypes(dAtA, i, uint64(m.NamedResourceSpec.Size()))
+		n2, err := m.NamedResourceSpec.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
@@ -3860,13 +3870,13 @@ func (m *GenericResource_Str) MarshalTo(dAtA []byte) (int, error) {
 	}
 	}
 	return i, nil
 	return i, nil
 }
 }
-func (m *GenericResource_Discrete) MarshalTo(dAtA []byte) (int, error) {
+func (m *GenericResource_DiscreteResourceSpec) MarshalTo(dAtA []byte) (int, error) {
 	i := 0
 	i := 0
-	if m.Discrete != nil {
+	if m.DiscreteResourceSpec != nil {
 		dAtA[i] = 0x12
 		dAtA[i] = 0x12
 		i++
 		i++
-		i = encodeVarintTypes(dAtA, i, uint64(m.Discrete.Size()))
-		n3, err := m.Discrete.MarshalTo(dAtA[i:])
+		i = encodeVarintTypes(dAtA, i, uint64(m.DiscreteResourceSpec.Size()))
+		n3, err := m.DiscreteResourceSpec.MarshalTo(dAtA[i:])
 		if err != nil {
 		if err != nil {
 			return 0, err
 			return 0, err
 		}
 		}
@@ -6303,7 +6313,7 @@ func (m *Annotations) Size() (n int) {
 	return n
 	return n
 }
 }
 
 
-func (m *GenericString) Size() (n int) {
+func (m *NamedGenericResource) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Kind)
 	l = len(m.Kind)
@@ -6317,7 +6327,7 @@ func (m *GenericString) Size() (n int) {
 	return n
 	return n
 }
 }
 
 
-func (m *GenericDiscrete) Size() (n int) {
+func (m *DiscreteGenericResource) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
 	l = len(m.Kind)
 	l = len(m.Kind)
@@ -6339,20 +6349,20 @@ func (m *GenericResource) Size() (n int) {
 	return n
 	return n
 }
 }
 
 
-func (m *GenericResource_Str) Size() (n int) {
+func (m *GenericResource_NamedResourceSpec) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
-	if m.Str != nil {
-		l = m.Str.Size()
+	if m.NamedResourceSpec != nil {
+		l = m.NamedResourceSpec.Size()
 		n += 1 + l + sovTypes(uint64(l))
 		n += 1 + l + sovTypes(uint64(l))
 	}
 	}
 	return n
 	return n
 }
 }
-func (m *GenericResource_Discrete) Size() (n int) {
+func (m *GenericResource_DiscreteResourceSpec) Size() (n int) {
 	var l int
 	var l int
 	_ = l
 	_ = l
-	if m.Discrete != nil {
-		l = m.Discrete.Size()
+	if m.DiscreteResourceSpec != nil {
+		l = m.DiscreteResourceSpec.Size()
 		n += 1 + l + sovTypes(uint64(l))
 		n += 1 + l + sovTypes(uint64(l))
 	}
 	}
 	return n
 	return n
@@ -7458,22 +7468,22 @@ func (this *Annotations) String() string {
 	}, "")
 	}, "")
 	return s
 	return s
 }
 }
-func (this *GenericString) String() string {
+func (this *NamedGenericResource) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
-	s := strings.Join([]string{`&GenericString{`,
+	s := strings.Join([]string{`&NamedGenericResource{`,
 		`Kind:` + fmt.Sprintf("%v", this.Kind) + `,`,
 		`Kind:` + fmt.Sprintf("%v", this.Kind) + `,`,
 		`Value:` + fmt.Sprintf("%v", this.Value) + `,`,
 		`Value:` + fmt.Sprintf("%v", this.Value) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
 	return s
 	return s
 }
 }
-func (this *GenericDiscrete) String() string {
+func (this *DiscreteGenericResource) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
-	s := strings.Join([]string{`&GenericDiscrete{`,
+	s := strings.Join([]string{`&DiscreteGenericResource{`,
 		`Kind:` + fmt.Sprintf("%v", this.Kind) + `,`,
 		`Kind:` + fmt.Sprintf("%v", this.Kind) + `,`,
 		`Value:` + fmt.Sprintf("%v", this.Value) + `,`,
 		`Value:` + fmt.Sprintf("%v", this.Value) + `,`,
 		`}`,
 		`}`,
@@ -7490,22 +7500,22 @@ func (this *GenericResource) String() string {
 	}, "")
 	}, "")
 	return s
 	return s
 }
 }
-func (this *GenericResource_Str) String() string {
+func (this *GenericResource_NamedResourceSpec) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
-	s := strings.Join([]string{`&GenericResource_Str{`,
-		`Str:` + strings.Replace(fmt.Sprintf("%v", this.Str), "GenericString", "GenericString", 1) + `,`,
+	s := strings.Join([]string{`&GenericResource_NamedResourceSpec{`,
+		`NamedResourceSpec:` + strings.Replace(fmt.Sprintf("%v", this.NamedResourceSpec), "NamedGenericResource", "NamedGenericResource", 1) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
 	return s
 	return s
 }
 }
-func (this *GenericResource_Discrete) String() string {
+func (this *GenericResource_DiscreteResourceSpec) String() string {
 	if this == nil {
 	if this == nil {
 		return "nil"
 		return "nil"
 	}
 	}
-	s := strings.Join([]string{`&GenericResource_Discrete{`,
-		`Discrete:` + strings.Replace(fmt.Sprintf("%v", this.Discrete), "GenericDiscrete", "GenericDiscrete", 1) + `,`,
+	s := strings.Join([]string{`&GenericResource_DiscreteResourceSpec{`,
+		`DiscreteResourceSpec:` + strings.Replace(fmt.Sprintf("%v", this.DiscreteResourceSpec), "DiscreteGenericResource", "DiscreteGenericResource", 1) + `,`,
 		`}`,
 		`}`,
 	}, "")
 	}, "")
 	return s
 	return s
@@ -8713,7 +8723,7 @@ func (m *Annotations) Unmarshal(dAtA []byte) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
-func (m *GenericString) Unmarshal(dAtA []byte) error {
+func (m *NamedGenericResource) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	l := len(dAtA)
 	iNdEx := 0
 	iNdEx := 0
 	for iNdEx < l {
 	for iNdEx < l {
@@ -8736,10 +8746,10 @@ func (m *GenericString) Unmarshal(dAtA []byte) error {
 		fieldNum := int32(wire >> 3)
 		fieldNum := int32(wire >> 3)
 		wireType := int(wire & 0x7)
 		wireType := int(wire & 0x7)
 		if wireType == 4 {
 		if wireType == 4 {
-			return fmt.Errorf("proto: GenericString: wiretype end group for non-group")
+			return fmt.Errorf("proto: NamedGenericResource: wiretype end group for non-group")
 		}
 		}
 		if fieldNum <= 0 {
 		if fieldNum <= 0 {
-			return fmt.Errorf("proto: GenericString: illegal tag %d (wire type %d)", fieldNum, wire)
+			return fmt.Errorf("proto: NamedGenericResource: illegal tag %d (wire type %d)", fieldNum, wire)
 		}
 		}
 		switch fieldNum {
 		switch fieldNum {
 		case 1:
 		case 1:
@@ -8821,7 +8831,7 @@ func (m *GenericString) Unmarshal(dAtA []byte) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
-func (m *GenericDiscrete) Unmarshal(dAtA []byte) error {
+func (m *DiscreteGenericResource) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	l := len(dAtA)
 	iNdEx := 0
 	iNdEx := 0
 	for iNdEx < l {
 	for iNdEx < l {
@@ -8844,10 +8854,10 @@ func (m *GenericDiscrete) Unmarshal(dAtA []byte) error {
 		fieldNum := int32(wire >> 3)
 		fieldNum := int32(wire >> 3)
 		wireType := int(wire & 0x7)
 		wireType := int(wire & 0x7)
 		if wireType == 4 {
 		if wireType == 4 {
-			return fmt.Errorf("proto: GenericDiscrete: wiretype end group for non-group")
+			return fmt.Errorf("proto: DiscreteGenericResource: wiretype end group for non-group")
 		}
 		}
 		if fieldNum <= 0 {
 		if fieldNum <= 0 {
-			return fmt.Errorf("proto: GenericDiscrete: illegal tag %d (wire type %d)", fieldNum, wire)
+			return fmt.Errorf("proto: DiscreteGenericResource: illegal tag %d (wire type %d)", fieldNum, wire)
 		}
 		}
 		switch fieldNum {
 		switch fieldNum {
 		case 1:
 		case 1:
@@ -8950,7 +8960,7 @@ func (m *GenericResource) Unmarshal(dAtA []byte) error {
 		switch fieldNum {
 		switch fieldNum {
 		case 1:
 		case 1:
 			if wireType != 2 {
 			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field Str", wireType)
+				return fmt.Errorf("proto: wrong wireType = %d for field NamedResourceSpec", wireType)
 			}
 			}
 			var msglen int
 			var msglen int
 			for shift := uint(0); ; shift += 7 {
 			for shift := uint(0); ; shift += 7 {
@@ -8974,15 +8984,15 @@ func (m *GenericResource) Unmarshal(dAtA []byte) error {
 			if postIndex > l {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 				return io.ErrUnexpectedEOF
 			}
 			}
-			v := &GenericString{}
+			v := &NamedGenericResource{}
 			if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
 			if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
 				return err
 				return err
 			}
 			}
-			m.Resource = &GenericResource_Str{v}
+			m.Resource = &GenericResource_NamedResourceSpec{v}
 			iNdEx = postIndex
 			iNdEx = postIndex
 		case 2:
 		case 2:
 			if wireType != 2 {
 			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field Discrete", wireType)
+				return fmt.Errorf("proto: wrong wireType = %d for field DiscreteResourceSpec", wireType)
 			}
 			}
 			var msglen int
 			var msglen int
 			for shift := uint(0); ; shift += 7 {
 			for shift := uint(0); ; shift += 7 {
@@ -9006,11 +9016,11 @@ func (m *GenericResource) Unmarshal(dAtA []byte) error {
 			if postIndex > l {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 				return io.ErrUnexpectedEOF
 			}
 			}
-			v := &GenericDiscrete{}
+			v := &DiscreteGenericResource{}
 			if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
 			if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
 				return err
 				return err
 			}
 			}
-			m.Resource = &GenericResource_Discrete{v}
+			m.Resource = &GenericResource_DiscreteResourceSpec{v}
 			iNdEx = postIndex
 			iNdEx = postIndex
 		default:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
@@ -17051,306 +17061,307 @@ var (
 func init() { proto.RegisterFile("types.proto", fileDescriptorTypes) }
 func init() { proto.RegisterFile("types.proto", fileDescriptorTypes) }
 
 
 var fileDescriptorTypes = []byte{
 var fileDescriptorTypes = []byte{
-	// 4808 bytes of a gzipped FileDescriptorProto
+	// 4822 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x7a, 0x4d, 0x6c, 0x24, 0x49,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x7a, 0x4d, 0x6c, 0x24, 0x49,
-	0x56, 0xbf, 0xeb, 0xd3, 0x55, 0xaf, 0xca, 0x76, 0x76, 0xb4, 0xb7, 0xd7, 0x5d, 0xd3, 0x63, 0xd7,
-	0xe4, 0x4c, 0xef, 0x7c, 0xec, 0xfc, 0x6b, 0xba, 0xdd, 0x33, 0xa3, 0xee, 0xe9, 0xff, 0x7c, 0xd4,
-	0x97, 0xdb, 0xb5, 0x6d, 0x57, 0x95, 0xa2, 0xca, 0xdd, 0x3b, 0x07, 0x48, 0xa5, 0x33, 0xc3, 0xe5,
-	0x1c, 0x67, 0x65, 0x14, 0x99, 0x59, 0x76, 0x17, 0x0b, 0xa2, 0xc5, 0x01, 0x90, 0x4f, 0x70, 0x62,
-	0x25, 0x64, 0x2e, 0x70, 0x42, 0x48, 0x1c, 0x40, 0x42, 0x70, 0x61, 0x90, 0x38, 0xcc, 0x8d, 0x05,
-	0x24, 0xb4, 0x02, 0xc9, 0x30, 0x3e, 0x70, 0x43, 0x70, 0x59, 0x71, 0x01, 0x09, 0xc5, 0x47, 0x66,
-	0x65, 0xb9, 0xd3, 0x76, 0x0f, 0xb3, 0x17, 0x3b, 0xe3, 0xbd, 0xdf, 0x7b, 0xf1, 0xe2, 0x45, 0xc4,
+	0x56, 0xbf, 0xeb, 0xd3, 0x55, 0xaf, 0xca, 0x76, 0x3a, 0xda, 0xdb, 0xe3, 0xae, 0xed, 0xb1, 0x6b,
+	0x72, 0xa6, 0x77, 0x66, 0x67, 0xe7, 0x5f, 0xd3, 0x1f, 0xbb, 0xab, 0x9e, 0x99, 0xff, 0x7c, 0xd4,
+	0x97, 0xdb, 0xb5, 0x6d, 0x57, 0x95, 0xa2, 0xca, 0xdd, 0x3b, 0x48, 0x90, 0x4a, 0x67, 0x86, 0xcb,
+	0x39, 0xce, 0xca, 0x28, 0x32, 0xb3, 0xec, 0x2e, 0x16, 0x44, 0x8b, 0x03, 0x20, 0x9f, 0xe0, 0xb6,
+	0x12, 0x32, 0x17, 0x38, 0x21, 0x24, 0x0e, 0x20, 0x21, 0xb8, 0x30, 0x48, 0x1c, 0xe6, 0xc6, 0x02,
+	0x12, 0x5a, 0x81, 0x64, 0x18, 0x1f, 0xb8, 0x21, 0xb8, 0xac, 0xb8, 0x80, 0x84, 0xe2, 0x23, 0xb3,
+	0xb2, 0xaa, 0xd3, 0x76, 0x0f, 0xb3, 0x17, 0x3b, 0xe3, 0xbd, 0xdf, 0x7b, 0xf1, 0xe2, 0x45, 0xc4,
 	0x8b, 0xf7, 0x22, 0x0a, 0x0a, 0xfe, 0x64, 0x44, 0xbc, 0xca, 0xc8, 0xa5, 0x3e, 0x45, 0xc8, 0xa4,
 	0x8b, 0xf7, 0x22, 0x0a, 0x0a, 0xfe, 0x64, 0x44, 0xbc, 0xca, 0xc8, 0xa5, 0x3e, 0x45, 0xc8, 0xa4,
-	0xc6, 0x01, 0x71, 0x2b, 0xde, 0x91, 0xee, 0x0e, 0x0f, 0x2c, 0xbf, 0x72, 0x78, 0xb7, 0xb4, 0x36,
-	0xa0, 0x74, 0x60, 0x93, 0xf7, 0x38, 0x62, 0x77, 0xbc, 0xf7, 0x9e, 0x6f, 0x0d, 0x89, 0xe7, 0xeb,
-	0xc3, 0x91, 0x10, 0x2a, 0xad, 0x9e, 0x07, 0x98, 0x63, 0x57, 0xf7, 0x2d, 0xea, 0x48, 0xfe, 0xf2,
-	0x80, 0x0e, 0x28, 0xff, 0x7c, 0x8f, 0x7d, 0x09, 0xaa, 0xba, 0x06, 0xf3, 0x4f, 0x88, 0xeb, 0x59,
-	0xd4, 0x41, 0xcb, 0x90, 0xb1, 0x1c, 0x93, 0x3c, 0x5b, 0x49, 0x94, 0x13, 0x6f, 0xa5, 0xb1, 0x68,
-	0xa8, 0x77, 0x00, 0x5a, 0xec, 0xa3, 0xe9, 0xf8, 0xee, 0x04, 0x29, 0x90, 0x3a, 0x20, 0x13, 0x8e,
-	0xc8, 0x63, 0xf6, 0xc9, 0x28, 0x87, 0xba, 0xbd, 0x92, 0x14, 0x94, 0x43, 0xdd, 0x56, 0xbf, 0x4e,
-	0x40, 0xa1, 0xea, 0x38, 0xd4, 0xe7, 0xbd, 0x7b, 0x08, 0x41, 0xda, 0xd1, 0x87, 0x44, 0x0a, 0xf1,
-	0x6f, 0x54, 0x87, 0xac, 0xad, 0xef, 0x12, 0xdb, 0x5b, 0x49, 0x96, 0x53, 0x6f, 0x15, 0xd6, 0xbf,
-	0x5f, 0x79, 0x71, 0xc8, 0x95, 0x88, 0x92, 0xca, 0x16, 0x47, 0x73, 0x23, 0xb0, 0x14, 0x45, 0x9f,
-	0xc0, 0xbc, 0xe5, 0x98, 0x96, 0x41, 0xbc, 0x95, 0x34, 0xd7, 0xb2, 0x1a, 0xa7, 0x65, 0x6a, 0x7d,
-	0x2d, 0xfd, 0xd5, 0xe9, 0xda, 0x1c, 0x0e, 0x84, 0x4a, 0x0f, 0xa0, 0x10, 0x51, 0x1b, 0x33, 0xb6,
-	0x65, 0xc8, 0x1c, 0xea, 0xf6, 0x98, 0xc8, 0xd1, 0x89, 0xc6, 0x47, 0xc9, 0xfb, 0x09, 0xf5, 0x01,
-	0x2c, 0x3c, 0x22, 0x0e, 0x71, 0x2d, 0xa3, 0xe7, 0xbb, 0x96, 0x33, 0x60, 0x83, 0x3c, 0xb0, 0x1c,
-	0x33, 0x18, 0x24, 0xfb, 0x8e, 0x17, 0x57, 0x1f, 0xc2, 0x92, 0x14, 0x6d, 0x58, 0x9e, 0xe1, 0x12,
-	0x9f, 0x5c, 0x2d, 0x9c, 0x0a, 0x84, 0x7f, 0x37, 0x11, 0x4a, 0x63, 0xe2, 0xd1, 0xb1, 0x6b, 0x10,
-	0xf4, 0x01, 0xa4, 0x3c, 0xdf, 0xe5, 0xc2, 0x85, 0xf5, 0xd7, 0xe2, 0x5c, 0x30, 0x63, 0xea, 0xe6,
-	0x1c, 0x66, 0x78, 0x54, 0x85, 0x9c, 0x29, 0x0d, 0xe0, 0x7d, 0x14, 0xd6, 0x5f, 0xbf, 0x44, 0x36,
-	0xb0, 0x75, 0x73, 0x0e, 0x87, 0x62, 0x35, 0x80, 0x9c, 0x2b, 0xad, 0x50, 0x7f, 0x9c, 0x80, 0x7c,
-	0x60, 0x92, 0x87, 0xde, 0x86, 0xbc, 0xa3, 0x3b, 0x54, 0x33, 0x46, 0x63, 0x8f, 0x5b, 0x96, 0xaa,
-	0x15, 0xcf, 0x4e, 0xd7, 0x72, 0x6d, 0xdd, 0xa1, 0xf5, 0xee, 0x8e, 0x87, 0x73, 0x8c, 0x5d, 0x1f,
-	0x8d, 0x3d, 0xf4, 0x1a, 0x14, 0x87, 0x64, 0x48, 0xdd, 0x89, 0xb6, 0x3b, 0xf1, 0x89, 0x27, 0xc7,
-	0x5b, 0x10, 0xb4, 0x1a, 0x23, 0xa1, 0x8f, 0x61, 0x7e, 0x20, 0xcc, 0x58, 0x49, 0xf1, 0x89, 0xbe,
-	0xcc, 0xd2, 0xc0, 0x08, 0x1c, 0xc8, 0xa8, 0xbf, 0x9d, 0x80, 0xe5, 0x90, 0x4a, 0x7e, 0x69, 0x6c,
-	0xb9, 0x64, 0x48, 0x1c, 0xdf, 0x43, 0x1f, 0x40, 0xd6, 0xb6, 0x86, 0x96, 0xef, 0x49, 0xe7, 0xbd,
-	0x1a, 0xa7, 0x36, 0x1c, 0x14, 0x96, 0x60, 0x54, 0x85, 0xa2, 0x4b, 0x3c, 0xe2, 0x1e, 0x8a, 0xb5,
-	0x29, 0xbd, 0x77, 0x85, 0xf0, 0x8c, 0x88, 0xba, 0x01, 0xb9, 0xae, 0xad, 0xfb, 0x7b, 0xd4, 0x1d,
-	0x22, 0x15, 0x8a, 0xba, 0x6b, 0xec, 0x5b, 0x3e, 0x31, 0xfc, 0xb1, 0x1b, 0xec, 0x93, 0x19, 0x1a,
-	0xba, 0x01, 0x49, 0x2a, 0x3a, 0xca, 0xd7, 0xb2, 0x67, 0xa7, 0x6b, 0xc9, 0x4e, 0x0f, 0x27, 0xa9,
-	0xa7, 0x3e, 0x84, 0x6b, 0x5d, 0x7b, 0x3c, 0xb0, 0x9c, 0x06, 0xf1, 0x0c, 0xd7, 0x1a, 0x31, 0xed,
-	0x6c, 0x39, 0xb1, 0x68, 0x12, 0x2c, 0x27, 0xf6, 0x1d, 0x6e, 0xc2, 0xe4, 0x74, 0x13, 0xaa, 0xbf,
-	0x99, 0x84, 0x6b, 0x4d, 0x67, 0x60, 0x39, 0x24, 0x2a, 0x7d, 0x1b, 0x16, 0x09, 0x27, 0x6a, 0x87,
-	0x22, 0x30, 0x48, 0x3d, 0x0b, 0x82, 0x1a, 0x44, 0x8b, 0xd6, 0xb9, 0x1d, 0x7c, 0x37, 0x6e, 0xf8,
-	0x2f, 0x68, 0x8f, 0xdd, 0xc7, 0x4d, 0x98, 0x1f, 0xf1, 0x41, 0x78, 0x72, 0x7a, 0x6f, 0xc7, 0xe9,
-	0x7a, 0x61, 0x9c, 0xc1, 0x76, 0x96, 0xb2, 0xdf, 0x66, 0x3b, 0xff, 0x71, 0x12, 0x96, 0xda, 0xd4,
-	0x9c, 0xf1, 0x43, 0x09, 0x72, 0xfb, 0xd4, 0xf3, 0x23, 0xa1, 0x2b, 0x6c, 0xa3, 0xfb, 0x90, 0x1b,
-	0xc9, 0xe9, 0x93, 0xb3, 0x7f, 0x2b, 0xde, 0x64, 0x81, 0xc1, 0x21, 0x1a, 0x3d, 0x84, 0x7c, 0xb0,
-	0x65, 0xd8, 0x68, 0x5f, 0x62, 0xe1, 0x4c, 0xf1, 0xe8, 0x63, 0xc8, 0x8a, 0x49, 0x58, 0x49, 0x73,
-	0xc9, 0xdb, 0x2f, 0xe5, 0x73, 0x2c, 0x85, 0xd0, 0x23, 0xc8, 0xf9, 0xb6, 0xa7, 0x59, 0xce, 0x1e,
-	0x5d, 0xc9, 0x70, 0x05, 0x6b, 0x71, 0x0a, 0x98, 0x23, 0xfa, 0x5b, 0xbd, 0x96, 0xb3, 0x47, 0x6b,
-	0x85, 0xb3, 0xd3, 0xb5, 0x79, 0xd9, 0xc0, 0xf3, 0xbe, 0xed, 0xb1, 0x0f, 0xf5, 0x77, 0x12, 0x50,
-	0x88, 0xa0, 0xd0, 0xab, 0x00, 0xbe, 0x3b, 0xf6, 0x7c, 0xcd, 0xa5, 0xd4, 0xe7, 0xce, 0x2a, 0xe2,
-	0x3c, 0xa7, 0x60, 0x4a, 0x7d, 0x54, 0x81, 0xeb, 0x06, 0x71, 0x7d, 0xcd, 0xf2, 0xbc, 0x31, 0x71,
-	0x35, 0x6f, 0xbc, 0xfb, 0x05, 0x31, 0x7c, 0xee, 0xb8, 0x22, 0xbe, 0xc6, 0x58, 0x2d, 0xce, 0xe9,
-	0x09, 0x06, 0xba, 0x07, 0x37, 0xa2, 0xf8, 0xd1, 0x78, 0xd7, 0xb6, 0x0c, 0x8d, 0x4d, 0x66, 0x8a,
-	0x8b, 0x5c, 0x9f, 0x8a, 0x74, 0x39, 0xef, 0x31, 0x99, 0xa8, 0x3f, 0x4d, 0x80, 0x82, 0xf5, 0x3d,
-	0x7f, 0x9b, 0x0c, 0x77, 0x89, 0xdb, 0xf3, 0x75, 0x7f, 0xec, 0xa1, 0x1b, 0x90, 0xb5, 0x89, 0x6e,
-	0x12, 0x11, 0x1d, 0x73, 0x58, 0xb6, 0xd0, 0x0e, 0xdb, 0xc1, 0xba, 0xb1, 0xaf, 0xef, 0x5a, 0xb6,
-	0xe5, 0x4f, 0xb8, 0x29, 0x8b, 0xf1, 0x4b, 0xf8, 0xbc, 0xce, 0x0a, 0x8e, 0x08, 0xe2, 0x19, 0x35,
-	0x68, 0x05, 0xe6, 0x87, 0xc4, 0xf3, 0xf4, 0x01, 0xe1, 0x96, 0xe6, 0x71, 0xd0, 0x54, 0x1f, 0x42,
-	0x31, 0x2a, 0x87, 0x0a, 0x30, 0xbf, 0xd3, 0x7e, 0xdc, 0xee, 0x3c, 0x6d, 0x2b, 0x73, 0x68, 0x09,
-	0x0a, 0x3b, 0x6d, 0xdc, 0xac, 0xd6, 0x37, 0xab, 0xb5, 0xad, 0xa6, 0x92, 0x40, 0x0b, 0x90, 0x9f,
-	0x36, 0x93, 0xea, 0x9f, 0x26, 0x00, 0x98, 0xbb, 0xe5, 0xa0, 0x3e, 0x82, 0x8c, 0xe7, 0xeb, 0xbe,
-	0x58, 0x95, 0x8b, 0xeb, 0x6f, 0x5c, 0x34, 0x87, 0xd2, 0x5e, 0xf6, 0x8f, 0x60, 0x21, 0x12, 0xb5,
-	0x30, 0x39, 0x63, 0x21, 0x0b, 0x10, 0xba, 0x69, 0xba, 0xd2, 0x70, 0xfe, 0xad, 0x3e, 0x84, 0x0c,
-	0x97, 0x9e, 0x35, 0x37, 0x07, 0xe9, 0x06, 0xfb, 0x4a, 0xa0, 0x3c, 0x64, 0x70, 0xb3, 0xda, 0xf8,
-	0x5c, 0x49, 0x22, 0x05, 0x8a, 0x8d, 0x56, 0xaf, 0xde, 0x69, 0xb7, 0x9b, 0xf5, 0x7e, 0xb3, 0xa1,
-	0xa4, 0xd4, 0xdb, 0x90, 0x69, 0x0d, 0x99, 0xe6, 0x5b, 0x6c, 0xc9, 0xef, 0x11, 0x97, 0x38, 0x46,
-	0xb0, 0x93, 0xa6, 0x04, 0xf5, 0x27, 0x79, 0xc8, 0x6c, 0xd3, 0xb1, 0xe3, 0xa3, 0xf5, 0x48, 0xd8,
-	0x5a, 0x8c, 0x3f, 0xcb, 0x39, 0xb0, 0xd2, 0x9f, 0x8c, 0x88, 0x0c, 0x6b, 0x37, 0x20, 0x2b, 0x36,
-	0x87, 0x1c, 0x8e, 0x6c, 0x31, 0xba, 0xaf, 0xbb, 0x03, 0xe2, 0xcb, 0xf1, 0xc8, 0x16, 0x7a, 0x8b,
-	0x9d, 0x58, 0xba, 0x49, 0x1d, 0x7b, 0xc2, 0xf7, 0x50, 0x4e, 0x1c, 0x4b, 0x98, 0xe8, 0x66, 0xc7,
-	0xb1, 0x27, 0x38, 0xe4, 0xa2, 0x4d, 0x28, 0xee, 0x5a, 0x8e, 0xa9, 0xd1, 0x91, 0x08, 0xf2, 0x99,
-	0x8b, 0x77, 0x9c, 0xb0, 0xaa, 0x66, 0x39, 0x66, 0x47, 0x80, 0x71, 0x61, 0x77, 0xda, 0x40, 0x6d,
-	0x58, 0x3c, 0xa4, 0xf6, 0x78, 0x48, 0x42, 0x5d, 0x59, 0xae, 0xeb, 0xcd, 0x8b, 0x75, 0x3d, 0xe1,
-	0xf8, 0x40, 0xdb, 0xc2, 0x61, 0xb4, 0x89, 0x1e, 0xc3, 0x82, 0x3f, 0x1c, 0xed, 0x79, 0xa1, 0xba,
-	0x79, 0xae, 0xee, 0x7b, 0x97, 0x38, 0x8c, 0xc1, 0x03, 0x6d, 0x45, 0x3f, 0xd2, 0x2a, 0xfd, 0x7a,
-	0x0a, 0x0a, 0x11, 0xcb, 0x51, 0x0f, 0x0a, 0x23, 0x97, 0x8e, 0xf4, 0x01, 0x3f, 0xa8, 0xe4, 0x5c,
-	0xdc, 0x7d, 0xa9, 0x51, 0x57, 0xba, 0x53, 0x41, 0x1c, 0xd5, 0xa2, 0x9e, 0x24, 0xa1, 0x10, 0x61,
-	0xa2, 0x77, 0x20, 0x87, 0xbb, 0xb8, 0xf5, 0xa4, 0xda, 0x6f, 0x2a, 0x73, 0xa5, 0x5b, 0xc7, 0x27,
-	0xe5, 0x15, 0xae, 0x2d, 0xaa, 0xa0, 0xeb, 0x5a, 0x87, 0x6c, 0xe9, 0xbd, 0x05, 0xf3, 0x01, 0x34,
-	0x51, 0x7a, 0xe5, 0xf8, 0xa4, 0xfc, 0xdd, 0xf3, 0xd0, 0x08, 0x12, 0xf7, 0x36, 0xab, 0xb8, 0xd9,
-	0x50, 0x92, 0xf1, 0x48, 0xdc, 0xdb, 0xd7, 0x5d, 0x62, 0xa2, 0xef, 0x41, 0x56, 0x02, 0x53, 0xa5,
-	0xd2, 0xf1, 0x49, 0xf9, 0xc6, 0x79, 0xe0, 0x14, 0x87, 0x7b, 0x5b, 0xd5, 0x27, 0x4d, 0x25, 0x1d,
-	0x8f, 0xc3, 0x3d, 0x5b, 0x3f, 0x24, 0xe8, 0x0d, 0xc8, 0x08, 0x58, 0xa6, 0x74, 0xf3, 0xf8, 0xa4,
-	0xfc, 0x9d, 0x17, 0xd4, 0x31, 0x54, 0x69, 0xe5, 0xb7, 0xfe, 0x60, 0x75, 0xee, 0x2f, 0xff, 0x70,
-	0x55, 0x39, 0xcf, 0x2e, 0xfd, 0x77, 0x02, 0x16, 0x66, 0xa6, 0x1c, 0xa9, 0x90, 0x75, 0xa8, 0x41,
-	0x47, 0xe2, 0xfc, 0xca, 0xd5, 0xe0, 0xec, 0x74, 0x2d, 0xdb, 0xa6, 0x75, 0x3a, 0x9a, 0x60, 0xc9,
-	0x41, 0x8f, 0xcf, 0x9d, 0xc0, 0xf7, 0x5e, 0x72, 0x3d, 0xc5, 0x9e, 0xc1, 0x9f, 0xc2, 0x82, 0xe9,
-	0x5a, 0x87, 0xc4, 0xd5, 0x0c, 0xea, 0xec, 0x59, 0x03, 0x79, 0x36, 0x95, 0xe2, 0x74, 0x36, 0x38,
-	0x10, 0x17, 0x85, 0x40, 0x9d, 0xe3, 0xbf, 0xc5, 0xe9, 0x5b, 0x7a, 0x02, 0xc5, 0xe8, 0x0a, 0x65,
-	0xc7, 0x89, 0x67, 0xfd, 0x32, 0x91, 0xf9, 0x20, 0xcf, 0x1e, 0x71, 0x9e, 0x51, 0x44, 0x36, 0xf8,
-	0x26, 0xa4, 0x87, 0xd4, 0x14, 0x7a, 0x16, 0x6a, 0xd7, 0x59, 0x12, 0xf0, 0x4f, 0xa7, 0x6b, 0x05,
-	0xea, 0x55, 0x36, 0x2c, 0x9b, 0x6c, 0x53, 0x93, 0x60, 0x0e, 0x50, 0x0f, 0x21, 0xcd, 0x42, 0x05,
-	0x7a, 0x05, 0xd2, 0xb5, 0x56, 0xbb, 0xa1, 0xcc, 0x95, 0xae, 0x1d, 0x9f, 0x94, 0x17, 0xb8, 0x4b,
-	0x18, 0x83, 0xad, 0x5d, 0xb4, 0x06, 0xd9, 0x27, 0x9d, 0xad, 0x9d, 0x6d, 0xb6, 0xbc, 0xae, 0x1f,
-	0x9f, 0x94, 0x97, 0x42, 0xb6, 0x70, 0x1a, 0x7a, 0x15, 0x32, 0xfd, 0xed, 0xee, 0x46, 0x4f, 0x49,
-	0x96, 0xd0, 0xf1, 0x49, 0x79, 0x31, 0xe4, 0x73, 0x9b, 0x4b, 0xd7, 0xe4, 0xac, 0xe6, 0x43, 0xba,
-	0xfa, 0xb3, 0x24, 0x2c, 0x60, 0x56, 0x9b, 0xb9, 0x7e, 0x97, 0xda, 0x96, 0x31, 0x41, 0x5d, 0xc8,
-	0x1b, 0xd4, 0x31, 0xad, 0xc8, 0x9e, 0x5a, 0xbf, 0xe0, 0xd4, 0x9f, 0x4a, 0x05, 0xad, 0x7a, 0x20,
-	0x89, 0xa7, 0x4a, 0xd0, 0x7b, 0x90, 0x31, 0x89, 0xad, 0x4f, 0x64, 0xfa, 0x71, 0xb3, 0x22, 0xaa,
-	0xbf, 0x4a, 0x50, 0xfd, 0x55, 0x1a, 0xb2, 0xfa, 0xc3, 0x02, 0xc7, 0xd3, 0x6c, 0xfd, 0x99, 0xa6,
-	0xfb, 0x3e, 0x19, 0x8e, 0x7c, 0x91, 0x7b, 0xa4, 0x71, 0x61, 0xa8, 0x3f, 0xab, 0x4a, 0x12, 0xba,
-	0x0b, 0xd9, 0x23, 0xcb, 0x31, 0xe9, 0x91, 0x4c, 0x2f, 0x2e, 0x51, 0x2a, 0x81, 0xea, 0x31, 0x3b,
-	0x75, 0xcf, 0x99, 0xc9, 0xfc, 0xdd, 0xee, 0xb4, 0x9b, 0x81, 0xbf, 0x25, 0xbf, 0xe3, 0xb4, 0xa9,
-	0xc3, 0xf6, 0x0a, 0x74, 0xda, 0xda, 0x46, 0xb5, 0xb5, 0xb5, 0x83, 0x99, 0xcf, 0x97, 0x8f, 0x4f,
-	0xca, 0x4a, 0x08, 0xd9, 0xd0, 0x2d, 0x9b, 0xe5, 0xbb, 0x37, 0x21, 0x55, 0x6d, 0x7f, 0xae, 0x24,
-	0x4b, 0xca, 0xf1, 0x49, 0xb9, 0x18, 0xb2, 0xab, 0xce, 0x64, 0xba, 0x8d, 0xce, 0xf7, 0xab, 0xfe,
-	0x6d, 0x0a, 0x8a, 0x3b, 0x23, 0x53, 0xf7, 0x89, 0x58, 0x93, 0xa8, 0x0c, 0x85, 0x91, 0xee, 0xea,
-	0xb6, 0x4d, 0x6c, 0xcb, 0x1b, 0xca, 0xba, 0x36, 0x4a, 0x42, 0x0f, 0x5e, 0xd6, 0x8d, 0xb5, 0x1c,
-	0x5b, 0x67, 0x3f, 0xfe, 0x97, 0xb5, 0x44, 0xe0, 0xd0, 0x1d, 0x58, 0xdc, 0x13, 0xd6, 0x6a, 0xba,
-	0xc1, 0x27, 0x36, 0xc5, 0x27, 0xb6, 0x12, 0x37, 0xb1, 0x51, 0xb3, 0x2a, 0x72, 0x90, 0x55, 0x2e,
-	0x85, 0x17, 0xf6, 0xa2, 0x4d, 0x74, 0x0f, 0xe6, 0x87, 0xd4, 0xb1, 0x7c, 0xea, 0x5e, 0x3d, 0x0b,
-	0x01, 0x12, 0xbd, 0x03, 0xd7, 0xd8, 0xe4, 0x06, 0xf6, 0x70, 0x36, 0x3f, 0xb1, 0x92, 0x78, 0x69,
-	0xa8, 0x3f, 0x93, 0x1d, 0x62, 0x46, 0x46, 0x35, 0xc8, 0x50, 0x97, 0xa5, 0x44, 0x59, 0x6e, 0xee,
-	0xbb, 0x57, 0x9a, 0x2b, 0x1a, 0x1d, 0x26, 0x83, 0x85, 0xa8, 0xfa, 0x21, 0x2c, 0xcc, 0x0c, 0x82,
-	0x65, 0x02, 0xdd, 0xea, 0x4e, 0xaf, 0xa9, 0xcc, 0xa1, 0x22, 0xe4, 0xea, 0x9d, 0x76, 0xbf, 0xd5,
-	0xde, 0x61, 0xa9, 0x4c, 0x11, 0x72, 0xb8, 0xb3, 0xb5, 0x55, 0xab, 0xd6, 0x1f, 0x2b, 0x49, 0xb5,
-	0x02, 0x85, 0x88, 0x36, 0xb4, 0x08, 0xd0, 0xeb, 0x77, 0xba, 0xda, 0x46, 0x0b, 0xf7, 0xfa, 0x22,
-	0x11, 0xea, 0xf5, 0xab, 0xb8, 0x2f, 0x09, 0x09, 0xf5, 0x3f, 0x92, 0xc1, 0x8c, 0xca, 0xdc, 0xa7,
-	0x36, 0x9b, 0xfb, 0x5c, 0x62, 0xbc, 0xcc, 0x7e, 0xa6, 0x8d, 0x30, 0x07, 0x7a, 0x00, 0xc0, 0x17,
-	0x0e, 0x31, 0x35, 0xdd, 0x97, 0x13, 0x5f, 0x7a, 0xc1, 0xc9, 0xfd, 0xe0, 0x7a, 0x05, 0xe7, 0x25,
-	0xba, 0xea, 0xa3, 0x8f, 0xa1, 0x68, 0xd0, 0xe1, 0xc8, 0x26, 0x52, 0x38, 0x75, 0xa5, 0x70, 0x21,
-	0xc4, 0x57, 0xfd, 0x68, 0xf6, 0x95, 0x9e, 0xcd, 0x0f, 0x7f, 0x23, 0x11, 0x78, 0x26, 0x26, 0xe1,
-	0x2a, 0x42, 0x6e, 0xa7, 0xdb, 0xa8, 0xf6, 0x5b, 0xed, 0x47, 0x4a, 0x02, 0x01, 0x64, 0xb9, 0xab,
-	0x1b, 0x4a, 0x92, 0x25, 0x8a, 0xf5, 0xce, 0x76, 0x77, 0xab, 0xc9, 0x53, 0x2e, 0xb4, 0x0c, 0x4a,
-	0xe0, 0x6c, 0x8d, 0x3b, 0xb2, 0xd9, 0x50, 0xd2, 0xe8, 0x3a, 0x2c, 0x85, 0x54, 0x29, 0x99, 0x41,
-	0x37, 0x00, 0x85, 0xc4, 0xa9, 0x8a, 0xac, 0xfa, 0xab, 0xb0, 0x54, 0xa7, 0x8e, 0xaf, 0x5b, 0x4e,
-	0x98, 0x44, 0xaf, 0xb3, 0x41, 0x4b, 0x92, 0x66, 0xc9, 0x5b, 0x8a, 0xda, 0xd2, 0xd9, 0xe9, 0x5a,
-	0x21, 0x84, 0xb6, 0x1a, 0x6c, 0xa4, 0x41, 0xc3, 0x64, 0xfb, 0x77, 0x64, 0x99, 0xdc, 0xb9, 0x99,
-	0xda, 0xfc, 0xd9, 0xe9, 0x5a, 0xaa, 0xdb, 0x6a, 0x60, 0x46, 0x43, 0xaf, 0x40, 0x9e, 0x3c, 0xb3,
-	0x7c, 0xcd, 0x60, 0x31, 0x9c, 0x39, 0x30, 0x83, 0x73, 0x8c, 0x50, 0x67, 0x21, 0xbb, 0x06, 0xd0,
-	0xa5, 0xae, 0x2f, 0x7b, 0x7e, 0x1f, 0x32, 0x23, 0xea, 0xf2, 0xf2, 0xfc, 0xc2, 0xeb, 0x1d, 0x06,
-	0x17, 0x0b, 0x15, 0x0b, 0xb0, 0xfa, 0x57, 0x49, 0x80, 0xbe, 0xee, 0x1d, 0x48, 0x25, 0xf7, 0x21,
-	0x1f, 0x5e, 0x95, 0xc9, 0x3a, 0xff, 0xd2, 0xd9, 0x0e, 0xc1, 0xe8, 0x5e, 0xb0, 0xd8, 0x44, 0x79,
-	0x10, 0x5b, 0xa7, 0x05, 0x1d, 0xc5, 0x65, 0xd8, 0xb3, 0x35, 0x00, 0x3b, 0x12, 0x89, 0xeb, 0xca,
-	0x99, 0x67, 0x9f, 0xa8, 0xce, 0x8f, 0x05, 0xe1, 0x34, 0x99, 0x60, 0xc6, 0xde, 0x6c, 0x9c, 0x9b,
-	0x91, 0xcd, 0x39, 0x3c, 0x95, 0x43, 0x9f, 0x42, 0x81, 0x8d, 0x5b, 0xf3, 0x38, 0x4f, 0xe6, 0x96,
-	0x17, 0xba, 0x4a, 0x68, 0xc0, 0x30, 0x0a, 0xbf, 0x6b, 0x0a, 0x2c, 0xba, 0x63, 0x87, 0x0d, 0x5b,
-	0xea, 0x50, 0xff, 0x24, 0x09, 0xdf, 0x6d, 0x13, 0xff, 0x88, 0xba, 0x07, 0x55, 0xdf, 0xd7, 0x8d,
-	0xfd, 0x21, 0x71, 0xa4, 0x93, 0x23, 0x99, 0x75, 0x62, 0x26, 0xb3, 0x5e, 0x81, 0x79, 0xdd, 0xb6,
-	0x74, 0x8f, 0x88, 0x74, 0x24, 0x8f, 0x83, 0x26, 0xcb, 0xff, 0x59, 0x35, 0x41, 0x3c, 0x8f, 0x88,
-	0x02, 0x3f, 0x8f, 0xa7, 0x04, 0xf4, 0x23, 0xb8, 0x21, 0x13, 0x0f, 0x3d, 0xec, 0x8a, 0x65, 0xb6,
-	0xc1, 0x9d, 0x5e, 0x33, 0xb6, 0xbc, 0x89, 0x37, 0x4e, 0x66, 0x26, 0x53, 0x72, 0x67, 0xe4, 0xcb,
-	0x3c, 0x67, 0xd9, 0x8c, 0x61, 0x95, 0x1e, 0xc1, 0xcd, 0x0b, 0x45, 0xbe, 0xd1, 0x05, 0xc2, 0x3f,
-	0x24, 0x01, 0x5a, 0xdd, 0xea, 0xb6, 0x74, 0x52, 0x03, 0xb2, 0x7b, 0xfa, 0xd0, 0xb2, 0x27, 0x97,
-	0xc5, 0xa9, 0x29, 0xbe, 0x52, 0x15, 0xee, 0xd8, 0xe0, 0x32, 0x58, 0xca, 0xf2, 0xe2, 0x66, 0xbc,
-	0xeb, 0x10, 0x3f, 0x2c, 0x6e, 0x78, 0x8b, 0x99, 0xe1, 0xea, 0x4e, 0xb8, 0xc0, 0x44, 0x83, 0x4d,
-	0xc0, 0x40, 0xf7, 0xc9, 0x91, 0x3e, 0x09, 0x82, 0x8b, 0x6c, 0xa2, 0x4d, 0x7e, 0x4d, 0x47, 0xdc,
-	0x43, 0x62, 0xae, 0x64, 0xb8, 0x53, 0xaf, 0xb2, 0x07, 0x4b, 0xb8, 0xf0, 0x5d, 0x28, 0x5d, 0x7a,
-	0xc8, 0x13, 0x9b, 0x29, 0xeb, 0x1b, 0xf9, 0xe8, 0x0e, 0x2c, 0xcc, 0x8c, 0xf3, 0x85, 0xaa, 0xb2,
-	0xd5, 0x7d, 0xf2, 0xbe, 0x92, 0x96, 0x5f, 0x1f, 0x2a, 0x59, 0xf5, 0x8f, 0x52, 0x22, 0x1c, 0x48,
-	0xaf, 0xc6, 0x5f, 0x24, 0xe7, 0xf8, 0x26, 0x36, 0xa8, 0x2d, 0xb7, 0xe9, 0x9b, 0x97, 0x47, 0x09,
-	0x56, 0xa5, 0x70, 0x38, 0x0e, 0x05, 0xd1, 0x1a, 0x14, 0xc4, 0x2a, 0xd6, 0xd8, 0xb6, 0xe0, 0x6e,
-	0x5d, 0xc0, 0x20, 0x48, 0x4c, 0x12, 0xdd, 0x86, 0x45, 0x7e, 0x0b, 0xe1, 0xed, 0x13, 0x53, 0x60,
-	0xd2, 0x1c, 0xb3, 0x10, 0x52, 0x39, 0x6c, 0x1b, 0x8a, 0x92, 0xa0, 0xf1, 0x0c, 0x35, 0xc3, 0x0d,
-	0x7a, 0xe7, 0x2a, 0x83, 0x84, 0x08, 0x4f, 0x5c, 0x0b, 0xa3, 0x69, 0x43, 0x6d, 0x40, 0x2e, 0x30,
-	0x16, 0xad, 0x40, 0xaa, 0x5f, 0xef, 0x2a, 0x73, 0xa5, 0xa5, 0xe3, 0x93, 0x72, 0x21, 0x20, 0xf7,
-	0xeb, 0x5d, 0xc6, 0xd9, 0x69, 0x74, 0x95, 0xc4, 0x2c, 0x67, 0xa7, 0xd1, 0x2d, 0xa5, 0x59, 0xa6,
-	0xa4, 0xee, 0x41, 0x21, 0xd2, 0x03, 0x7a, 0x1d, 0xe6, 0x5b, 0xed, 0x47, 0xb8, 0xd9, 0xeb, 0x29,
-	0x73, 0xa5, 0x1b, 0xc7, 0x27, 0x65, 0x14, 0xe1, 0xb6, 0x9c, 0x01, 0x9b, 0x1f, 0xf4, 0x2a, 0xa4,
-	0x37, 0x3b, 0xec, 0x04, 0x16, 0x29, 0x71, 0x04, 0xb1, 0x49, 0x3d, 0xbf, 0x74, 0x5d, 0xa6, 0x60,
-	0x51, 0xc5, 0xea, 0xef, 0x25, 0x20, 0x2b, 0x36, 0x53, 0xec, 0x44, 0x55, 0x61, 0x3e, 0xa8, 0x57,
-	0x45, 0xb9, 0xf2, 0xe6, 0xc5, 0xa5, 0x45, 0x45, 0x56, 0x02, 0x62, 0xf9, 0x05, 0x72, 0xa5, 0x8f,
-	0xa0, 0x18, 0x65, 0x7c, 0xa3, 0xc5, 0xf7, 0x23, 0x28, 0xb0, 0xf5, 0x1d, 0x94, 0x18, 0xeb, 0x90,
-	0x15, 0x01, 0x21, 0x3c, 0x11, 0x2e, 0xae, 0x73, 0x24, 0x12, 0xdd, 0x87, 0x79, 0x51, 0x1b, 0x05,
-	0xd7, 0x94, 0xab, 0x97, 0xef, 0x22, 0x1c, 0xc0, 0xd5, 0x4f, 0x21, 0xdd, 0x25, 0xc4, 0x65, 0xbe,
-	0x77, 0xa8, 0x49, 0xa6, 0x87, 0xa8, 0x2c, 0xeb, 0x4c, 0xd2, 0x6a, 0xb0, 0xb2, 0xce, 0x24, 0x2d,
-	0x33, 0xbc, 0x88, 0x49, 0x46, 0x2e, 0x62, 0xfa, 0x50, 0x7c, 0x4a, 0xac, 0xc1, 0xbe, 0x4f, 0x4c,
-	0xae, 0xe8, 0x5d, 0x48, 0x8f, 0x48, 0x68, 0xfc, 0x4a, 0xec, 0x02, 0x23, 0xc4, 0xc5, 0x1c, 0xc5,
-	0xe2, 0xc8, 0x11, 0x97, 0x96, 0x77, 0xeb, 0xb2, 0xa5, 0xfe, 0x7d, 0x12, 0x16, 0x5b, 0x9e, 0x37,
-	0xd6, 0x1d, 0x23, 0xc8, 0xaf, 0x3e, 0x99, 0xcd, 0xaf, 0xde, 0x8a, 0x1d, 0xe1, 0x8c, 0xc8, 0xec,
-	0xfd, 0x92, 0x3c, 0xe3, 0x92, 0xe1, 0x19, 0xa7, 0xfe, 0x7b, 0x22, 0xb8, 0x44, 0xba, 0x1d, 0xd9,
-	0xee, 0xa5, 0x95, 0xe3, 0x93, 0xf2, 0x72, 0x54, 0x13, 0xd9, 0x71, 0x0e, 0x1c, 0x7a, 0xe4, 0xa0,
-	0xd7, 0x20, 0x83, 0x9b, 0xed, 0xe6, 0x53, 0x25, 0x21, 0x96, 0xe7, 0x0c, 0x08, 0x13, 0x87, 0x1c,
-	0x31, 0x4d, 0xdd, 0x66, 0xbb, 0xc1, 0xf2, 0xa1, 0x64, 0x8c, 0xa6, 0x2e, 0x71, 0x4c, 0xcb, 0x19,
-	0xa0, 0xd7, 0x21, 0xdb, 0xea, 0xf5, 0x76, 0x78, 0x99, 0xff, 0xdd, 0xe3, 0x93, 0xf2, 0xf5, 0x19,
-	0x14, 0xbf, 0x40, 0x34, 0x19, 0x88, 0x15, 0x23, 0x2c, 0x53, 0x8a, 0x01, 0xb1, 0x2c, 0x57, 0x80,
-	0x70, 0xa7, 0x5f, 0xed, 0xb3, 0x0a, 0xff, 0x45, 0x10, 0xa6, 0xec, 0xaf, 0xdc, 0x6e, 0xff, 0x9c,
-	0x04, 0xa5, 0x6a, 0x18, 0x64, 0xe4, 0x33, 0xbe, 0xac, 0xff, 0xfa, 0x90, 0x1b, 0xb1, 0x2f, 0x8b,
-	0x04, 0xb9, 0xcc, 0xfd, 0xd8, 0x07, 0xaf, 0x73, 0x72, 0x15, 0x4c, 0x6d, 0x52, 0x35, 0x87, 0x96,
-	0xe7, 0x59, 0xd4, 0x11, 0x34, 0x1c, 0x6a, 0x2a, 0xfd, 0x67, 0x02, 0xae, 0xc7, 0x20, 0xd0, 0x1d,
-	0x48, 0xbb, 0xd4, 0x0e, 0xe6, 0xf0, 0xd6, 0x45, 0xf7, 0x83, 0x4c, 0x14, 0x73, 0x24, 0x5a, 0x05,
-	0xd0, 0xc7, 0x3e, 0xd5, 0x79, 0xff, 0x7c, 0xf6, 0x72, 0x38, 0x42, 0x41, 0x4f, 0x21, 0xeb, 0x11,
-	0xc3, 0x25, 0x41, 0xc6, 0xfb, 0xe9, 0xff, 0xd5, 0xfa, 0x4a, 0x8f, 0xab, 0xc1, 0x52, 0x5d, 0xa9,
-	0x02, 0x59, 0x41, 0x61, 0xcb, 0xde, 0xd4, 0x7d, 0x5d, 0xde, 0x1e, 0xf3, 0x6f, 0xb6, 0x9a, 0x74,
-	0x7b, 0x10, 0xac, 0x26, 0xdd, 0x1e, 0xa8, 0x7f, 0x93, 0x04, 0x68, 0x3e, 0xf3, 0x89, 0xeb, 0xe8,
-	0x76, 0xbd, 0x8a, 0x9a, 0x91, 0xe8, 0x2f, 0x46, 0xfb, 0x76, 0xec, 0x95, 0x78, 0x28, 0x51, 0xa9,
-	0x57, 0x63, 0xe2, 0xff, 0x4d, 0x48, 0x8d, 0x5d, 0xf9, 0x86, 0x29, 0xb2, 0xd5, 0x1d, 0xbc, 0x85,
-	0x19, 0x0d, 0x35, 0xa7, 0x61, 0x2b, 0x75, 0xf1, 0x4b, 0x65, 0xa4, 0x83, 0xd8, 0xd0, 0xc5, 0x76,
-	0xbe, 0xa1, 0x6b, 0x06, 0x91, 0x27, 0x47, 0x51, 0xec, 0xfc, 0x7a, 0xb5, 0x4e, 0x5c, 0x1f, 0x67,
-	0x0d, 0x9d, 0xfd, 0xff, 0x56, 0xf1, 0xed, 0x5d, 0x80, 0xe9, 0xd0, 0xd0, 0x2a, 0x64, 0xea, 0x1b,
-	0xbd, 0xde, 0x96, 0x32, 0x27, 0x02, 0xf8, 0x94, 0xc5, 0xc9, 0xea, 0x5f, 0x24, 0x21, 0x57, 0xaf,
-	0xca, 0x63, 0xb5, 0x0e, 0x0a, 0x8f, 0x4a, 0xfc, 0xce, 0x9d, 0x3c, 0x1b, 0x59, 0xee, 0x44, 0x06,
-	0x96, 0x4b, 0x4a, 0xcf, 0x45, 0x26, 0xc2, 0xac, 0x6e, 0x72, 0x01, 0x84, 0xa1, 0x48, 0xa4, 0x13,
-	0x34, 0x43, 0x0f, 0x62, 0xfc, 0xea, 0xe5, 0xce, 0x12, 0x45, 0xc4, 0xb4, 0xed, 0xe1, 0x42, 0xa0,
-	0xa4, 0xae, 0x7b, 0xe8, 0x01, 0x2c, 0x79, 0xd6, 0xc0, 0xb1, 0x9c, 0x81, 0x16, 0x38, 0x8f, 0x3f,
-	0x00, 0xd4, 0xae, 0x9d, 0x9d, 0xae, 0x2d, 0xf4, 0x04, 0x4b, 0xfa, 0x70, 0x41, 0x22, 0xeb, 0xdc,
-	0x95, 0xe8, 0x43, 0x58, 0x8c, 0x88, 0x32, 0x2f, 0x0a, 0xb7, 0x2b, 0x67, 0xa7, 0x6b, 0xc5, 0x50,
-	0xf2, 0x31, 0x99, 0xe0, 0x62, 0x28, 0xf8, 0x98, 0xf0, 0x5b, 0x92, 0x3d, 0xea, 0x1a, 0x44, 0x73,
-	0xf9, 0x9e, 0xe6, 0x27, 0x78, 0x1a, 0x17, 0x38, 0x4d, 0x6c, 0x73, 0xf5, 0x09, 0x5c, 0xef, 0xb8,
-	0xc6, 0x3e, 0xf1, 0x7c, 0xe1, 0x0a, 0xe9, 0xc5, 0x4f, 0xe1, 0x96, 0xaf, 0x7b, 0x07, 0xda, 0xbe,
-	0xe5, 0xf9, 0xd4, 0x9d, 0x68, 0x2e, 0xf1, 0x89, 0xc3, 0xf8, 0x1a, 0x7f, 0x35, 0x94, 0xd7, 0x58,
-	0x37, 0x19, 0x66, 0x53, 0x40, 0x70, 0x80, 0xd8, 0x62, 0x00, 0xb5, 0x05, 0x45, 0x56, 0x4c, 0x34,
-	0xc8, 0x9e, 0x3e, 0xb6, 0x7d, 0x36, 0x7a, 0xb0, 0xe9, 0x40, 0x7b, 0xe9, 0x63, 0x2a, 0x6f, 0xd3,
-	0x81, 0xf8, 0x54, 0x7f, 0x08, 0x4a, 0xc3, 0xf2, 0x46, 0xba, 0x6f, 0xec, 0x07, 0xf7, 0x73, 0xa8,
-	0x01, 0xca, 0x3e, 0xd1, 0x5d, 0x7f, 0x97, 0xe8, 0xbe, 0x36, 0x22, 0xae, 0x45, 0xcd, 0xab, 0x67,
-	0x79, 0x29, 0x14, 0xe9, 0x72, 0x09, 0xf5, 0xbf, 0x12, 0x00, 0x58, 0xdf, 0x0b, 0x32, 0xb2, 0xef,
-	0xc3, 0x35, 0xcf, 0xd1, 0x47, 0xde, 0x3e, 0xf5, 0x35, 0xcb, 0xf1, 0x89, 0x7b, 0xa8, 0xdb, 0xf2,
-	0x9a, 0x45, 0x09, 0x18, 0x2d, 0x49, 0x47, 0xef, 0x02, 0x3a, 0x20, 0x64, 0xa4, 0x51, 0xdb, 0xd4,
-	0x02, 0xa6, 0x78, 0xd3, 0x4c, 0x63, 0x85, 0x71, 0x3a, 0xb6, 0xd9, 0x0b, 0xe8, 0xa8, 0x06, 0xab,
-	0x6c, 0xf8, 0xc4, 0xf1, 0x5d, 0x8b, 0x78, 0xda, 0x1e, 0x75, 0x35, 0xcf, 0xa6, 0x47, 0xda, 0x1e,
-	0xb5, 0x6d, 0x7a, 0x44, 0xdc, 0xe0, 0x06, 0xab, 0x64, 0xd3, 0x41, 0x53, 0x80, 0x36, 0xa8, 0xdb,
-	0xb3, 0xe9, 0xd1, 0x46, 0x80, 0x60, 0x69, 0xdb, 0x74, 0xcc, 0xbe, 0x65, 0x1c, 0x04, 0x69, 0x5b,
-	0x48, 0xed, 0x5b, 0xc6, 0x01, 0x7a, 0x1d, 0x16, 0x88, 0x4d, 0xf8, 0x45, 0x86, 0x40, 0x65, 0x38,
-	0xaa, 0x18, 0x10, 0x19, 0x48, 0xfd, 0x0c, 0x94, 0xa6, 0x63, 0xb8, 0x93, 0x51, 0x64, 0xce, 0xdf,
-	0x05, 0xc4, 0x82, 0xa4, 0x66, 0x53, 0xe3, 0x40, 0x1b, 0xea, 0x8e, 0x3e, 0x60, 0x76, 0x89, 0xa7,
-	0x26, 0x85, 0x71, 0xb6, 0xa8, 0x71, 0xb0, 0x2d, 0xe9, 0xea, 0x03, 0x80, 0xde, 0xc8, 0x25, 0xba,
-	0xd9, 0x61, 0xd9, 0x04, 0x73, 0x1d, 0x6f, 0x69, 0xa6, 0x7c, 0xaa, 0xa3, 0xae, 0xdc, 0xea, 0x8a,
-	0x60, 0x34, 0x42, 0xba, 0xfa, 0x0b, 0x70, 0xbd, 0x6b, 0xeb, 0x06, 0x7f, 0xb6, 0xee, 0x86, 0x6f,
-	0x27, 0xe8, 0x3e, 0x64, 0x05, 0x54, 0xce, 0x64, 0xec, 0x76, 0x9b, 0xf6, 0xb9, 0x39, 0x87, 0x25,
-	0xbe, 0x56, 0x04, 0x98, 0xea, 0x51, 0xff, 0x2c, 0x01, 0xf9, 0x50, 0x3f, 0x2a, 0x03, 0x2b, 0xe5,
-	0xd9, 0xf2, 0xb6, 0x1c, 0x59, 0x7b, 0xe7, 0x71, 0x94, 0x84, 0x5a, 0x50, 0x18, 0x85, 0xd2, 0x97,
-	0xe6, 0x73, 0x31, 0x56, 0xe3, 0xa8, 0x2c, 0xfa, 0x08, 0xf2, 0xc1, 0xdb, 0x68, 0x10, 0x61, 0x2f,
-	0x7f, 0x4a, 0x9d, 0xc2, 0xd5, 0x4f, 0x00, 0x7e, 0x40, 0x2d, 0xa7, 0x4f, 0x0f, 0x88, 0xc3, 0xdf,
-	0xfa, 0x58, 0x4d, 0x48, 0x02, 0x2f, 0xca, 0x16, 0x2f, 0xc8, 0xc5, 0x14, 0x84, 0x4f, 0x5e, 0xa2,
-	0xa9, 0xfe, 0x75, 0x12, 0xb2, 0x98, 0x52, 0xbf, 0x5e, 0x45, 0x65, 0xc8, 0xca, 0x38, 0xc1, 0xcf,
-	0x9f, 0x5a, 0xfe, 0xec, 0x74, 0x2d, 0x23, 0x02, 0x44, 0xc6, 0xe0, 0x91, 0x21, 0x12, 0xc1, 0x93,
-	0x17, 0x45, 0x70, 0x74, 0x07, 0x8a, 0x12, 0xa4, 0xed, 0xeb, 0xde, 0xbe, 0x28, 0xd0, 0x6a, 0x8b,
-	0x67, 0xa7, 0x6b, 0x20, 0x90, 0x9b, 0xba, 0xb7, 0x8f, 0x41, 0xa0, 0xd9, 0x37, 0x6a, 0x42, 0xe1,
-	0x0b, 0x6a, 0x39, 0x9a, 0xcf, 0x07, 0x21, 0xaf, 0xfc, 0x62, 0xe7, 0x71, 0x3a, 0x54, 0xf9, 0xf0,
-	0x0d, 0x5f, 0x4c, 0x07, 0xdf, 0x84, 0x05, 0x97, 0x52, 0x5f, 0x84, 0x2d, 0x8b, 0x3a, 0xf2, 0x36,
-	0xa1, 0x1c, 0x7b, 0xc9, 0x4c, 0xa9, 0x8f, 0x25, 0x0e, 0x17, 0xdd, 0x48, 0x0b, 0xdd, 0x81, 0x65,
-	0x5b, 0xf7, 0x7c, 0x8d, 0xc7, 0x3b, 0x73, 0xaa, 0x2d, 0xcb, 0xb7, 0x1a, 0x62, 0xbc, 0x0d, 0xce,
-	0x0a, 0x24, 0xd4, 0x7f, 0x4c, 0x40, 0x81, 0x0d, 0xc6, 0xda, 0xb3, 0x0c, 0x96, 0xe4, 0x7d, 0xf3,
-	0xdc, 0xe3, 0x26, 0xa4, 0x0c, 0xcf, 0x95, 0x4e, 0xe5, 0x87, 0x6f, 0xbd, 0x87, 0x31, 0xa3, 0xa1,
-	0xcf, 0x20, 0x2b, 0x6f, 0x35, 0x44, 0xda, 0xa1, 0x5e, 0x9d, 0x8e, 0x4a, 0xdf, 0x48, 0x39, 0xbe,
-	0x96, 0xa7, 0xd6, 0x89, 0x43, 0x00, 0x47, 0x49, 0xe8, 0x06, 0x24, 0x0d, 0xe1, 0x2e, 0xf9, 0xcb,
-	0x8a, 0x7a, 0x1b, 0x27, 0x0d, 0x47, 0xfd, 0xbb, 0x04, 0x2c, 0x4c, 0x37, 0x3c, 0x5b, 0x01, 0xb7,
-	0x20, 0xef, 0x8d, 0x77, 0xbd, 0x89, 0xe7, 0x93, 0x61, 0xf0, 0x8e, 0x19, 0x12, 0x50, 0x0b, 0xf2,
-	0xba, 0x3d, 0xa0, 0xae, 0xe5, 0xef, 0x0f, 0x65, 0x25, 0x1a, 0x9f, 0x2a, 0x44, 0x75, 0x56, 0xaa,
-	0x81, 0x08, 0x9e, 0x4a, 0x07, 0xe7, 0xbe, 0x78, 0xec, 0xe6, 0xe7, 0xfe, 0x6b, 0x50, 0xb4, 0xf5,
-	0x21, 0xbf, 0xe6, 0xf1, 0xad, 0xa1, 0x18, 0x47, 0x1a, 0x17, 0x24, 0xad, 0x6f, 0x0d, 0x89, 0xaa,
-	0x42, 0x3e, 0x54, 0x86, 0x96, 0xa0, 0x50, 0x6d, 0xf6, 0xb4, 0xbb, 0xeb, 0xf7, 0xb5, 0x47, 0xf5,
-	0x6d, 0x65, 0x4e, 0xe6, 0xa6, 0x7f, 0x9e, 0x80, 0x05, 0x19, 0x8e, 0x64, 0xbe, 0xff, 0x3a, 0xcc,
-	0xbb, 0xfa, 0x9e, 0x1f, 0x54, 0x24, 0x69, 0xb1, 0xaa, 0x59, 0x84, 0x67, 0x15, 0x09, 0x63, 0xc5,
-	0x57, 0x24, 0x91, 0x97, 0xf5, 0xd4, 0xa5, 0x2f, 0xeb, 0xe9, 0x9f, 0xcb, 0xcb, 0xba, 0xfa, 0x6b,
-	0x00, 0x1b, 0x96, 0x4d, 0xfa, 0xe2, 0xae, 0x29, 0xae, 0xbe, 0x64, 0x39, 0x9c, 0xbc, 0x71, 0x0c,
-	0x72, 0xb8, 0x56, 0x03, 0x33, 0x1a, 0x63, 0x0d, 0x2c, 0x53, 0x6e, 0x46, 0xce, 0x7a, 0xc4, 0x58,
-	0x03, 0xcb, 0x0c, 0xdf, 0x92, 0xd2, 0x57, 0xbd, 0x25, 0x9d, 0x24, 0x60, 0x49, 0xe6, 0xae, 0x61,
-	0xf8, 0x7d, 0x1b, 0xf2, 0x22, 0x8d, 0x9d, 0x16, 0x74, 0xfc, 0x35, 0x59, 0xe0, 0x5a, 0x0d, 0x9c,
-	0x13, 0xec, 0x96, 0x89, 0xd6, 0xa0, 0x20, 0xa1, 0x91, 0x5f, 0xe1, 0x80, 0x20, 0xb5, 0x99, 0xf9,
-	0xef, 0x43, 0x7a, 0xcf, 0xb2, 0x89, 0x5c, 0xe8, 0xb1, 0x01, 0x60, 0xea, 0x80, 0xcd, 0x39, 0xcc,
-	0xd1, 0xb5, 0x5c, 0x70, 0x19, 0xc7, 0xed, 0x93, 0x65, 0x67, 0xd4, 0x3e, 0x51, 0x81, 0x9e, 0xb3,
-	0x4f, 0xe0, 0x98, 0x7d, 0x82, 0x2d, 0xec, 0x93, 0xd0, 0xa8, 0x7d, 0x82, 0xf4, 0x73, 0xb1, 0x6f,
-	0x0b, 0x6e, 0xd4, 0x6c, 0xdd, 0x38, 0xb0, 0x2d, 0xcf, 0x27, 0x66, 0x34, 0x62, 0xac, 0x43, 0x76,
-	0x26, 0xe9, 0xbc, 0xec, 0x72, 0x56, 0x22, 0xd5, 0x7f, 0x4b, 0x40, 0x71, 0x93, 0xe8, 0xb6, 0xbf,
-	0x3f, 0xbd, 0x1a, 0xf2, 0x89, 0xe7, 0xcb, 0xc3, 0x8a, 0x7f, 0xa3, 0x0f, 0x20, 0x17, 0xe6, 0x24,
-	0x57, 0xbe, 0x92, 0x85, 0x50, 0x74, 0x0f, 0xe6, 0xd9, 0x1e, 0xa3, 0xe3, 0xa0, 0xd8, 0xb9, 0xec,
-	0x01, 0x46, 0x22, 0xd9, 0x21, 0xe3, 0x12, 0x9e, 0x84, 0xf0, 0xa5, 0x94, 0xc1, 0x41, 0x13, 0xfd,
-	0x7f, 0x28, 0xf2, 0xf7, 0x83, 0x20, 0xe7, 0xca, 0x5c, 0xa5, 0xb3, 0x20, 0x9e, 0x00, 0x45, 0xbe,
-	0xf5, 0x3f, 0x09, 0x58, 0xde, 0xd6, 0x27, 0xbb, 0x44, 0x86, 0x0d, 0x62, 0x62, 0x62, 0x50, 0xd7,
-	0x44, 0xdd, 0x68, 0xb8, 0xb9, 0xe4, 0x45, 0x31, 0x4e, 0x38, 0x3e, 0xea, 0x04, 0x05, 0x58, 0x32,
-	0x52, 0x80, 0x2d, 0x43, 0xc6, 0xa1, 0x8e, 0x41, 0x64, 0x2c, 0x12, 0x0d, 0xd5, 0x8a, 0x86, 0x9a,
-	0x52, 0xf8, 0xd8, 0xc7, 0x9f, 0xea, 0xda, 0xd4, 0x0f, 0x7b, 0x43, 0x9f, 0x41, 0xa9, 0xd7, 0xac,
-	0xe3, 0x66, 0xbf, 0xd6, 0xf9, 0xa1, 0xd6, 0xab, 0x6e, 0xf5, 0xaa, 0xeb, 0x77, 0xb4, 0x6e, 0x67,
-	0xeb, 0xf3, 0xbb, 0xf7, 0xee, 0x7c, 0xa0, 0x24, 0x4a, 0xe5, 0xe3, 0x93, 0xf2, 0xad, 0x76, 0xb5,
-	0xbe, 0x25, 0x76, 0xcc, 0x2e, 0x7d, 0xd6, 0xd3, 0x6d, 0x4f, 0x5f, 0xbf, 0xd3, 0xa5, 0xf6, 0x84,
-	0x61, 0xd8, 0xb2, 0x2e, 0x46, 0xcf, 0xab, 0xe8, 0x31, 0x9c, 0xb8, 0xf0, 0x18, 0x9e, 0x9e, 0xe6,
-	0xc9, 0x0b, 0x4e, 0xf3, 0x0d, 0x58, 0x36, 0x5c, 0xea, 0x79, 0x1a, 0xcb, 0xfe, 0x89, 0x79, 0xae,
-	0xbe, 0xf8, 0xce, 0xd9, 0xe9, 0xda, 0xb5, 0x3a, 0xe3, 0xf7, 0x38, 0x5b, 0xaa, 0xbf, 0x66, 0x44,
-	0x48, 0xbc, 0x27, 0xf5, 0xf7, 0x53, 0x2c, 0x91, 0xb2, 0x0e, 0x2d, 0x9b, 0x0c, 0x88, 0x87, 0x9e,
-	0xc0, 0x92, 0xe1, 0x12, 0x93, 0xa5, 0xf5, 0xba, 0xad, 0x79, 0x23, 0x62, 0xc8, 0x45, 0xfd, 0xff,
-	0x62, 0x73, 0x9a, 0x50, 0xb0, 0x52, 0x0f, 0xa5, 0x7a, 0x23, 0x62, 0xe0, 0x45, 0x63, 0xa6, 0x8d,
-	0xbe, 0x80, 0x25, 0x8f, 0xd8, 0x96, 0x33, 0x7e, 0xa6, 0x19, 0xd4, 0xf1, 0xc9, 0xb3, 0xe0, 0xdd,
-	0xea, 0x2a, 0xbd, 0xbd, 0xe6, 0x16, 0x93, 0xaa, 0x0b, 0xa1, 0x1a, 0x3a, 0x3b, 0x5d, 0x5b, 0x9c,
-	0xa5, 0xe1, 0x45, 0xa9, 0x59, 0xb6, 0x4b, 0x6d, 0x58, 0x9c, 0xb5, 0x06, 0x2d, 0xcb, 0xbd, 0xcf,
-	0x43, 0x48, 0xb0, 0xb7, 0xd1, 0x2d, 0xc8, 0xb9, 0x64, 0x60, 0x79, 0xbe, 0x2b, 0xdc, 0xcc, 0x38,
-	0x21, 0x85, 0xed, 0x7c, 0xf1, 0x53, 0x9c, 0xd2, 0xaf, 0xc0, 0xb9, 0x1e, 0xd9, 0x66, 0x31, 0x2d,
-	0x4f, 0xdf, 0x95, 0x2a, 0x73, 0x38, 0x68, 0xb2, 0x35, 0x38, 0xf6, 0xc2, 0x44, 0x8d, 0x7f, 0x33,
-	0x1a, 0xcf, 0x28, 0xe4, 0x0f, 0x93, 0x78, 0xce, 0x10, 0xfc, 0xc2, 0x31, 0x1d, 0xf9, 0x85, 0xe3,
-	0x32, 0x64, 0x6c, 0x72, 0x48, 0x6c, 0x71, 0x96, 0x63, 0xd1, 0x78, 0xe7, 0x67, 0x29, 0xc8, 0x87,
-	0x6f, 0x34, 0xec, 0x24, 0x68, 0x37, 0x9f, 0x06, 0x6b, 0x35, 0xa4, 0xb7, 0xc9, 0x11, 0x7a, 0x6d,
-	0x7a, 0xa7, 0xf4, 0x99, 0x78, 0x94, 0x0e, 0xd9, 0xc1, 0x7d, 0xd2, 0x1b, 0x90, 0xab, 0xf6, 0x7a,
-	0xad, 0x47, 0xed, 0x66, 0x43, 0xf9, 0x32, 0x51, 0xfa, 0xce, 0xf1, 0x49, 0xf9, 0x5a, 0x08, 0xaa,
-	0x7a, 0x62, 0x29, 0x71, 0x54, 0xbd, 0xde, 0xec, 0xf6, 0x9b, 0x0d, 0xe5, 0x79, 0xf2, 0x3c, 0x8a,
-	0xdf, 0x91, 0xf0, 0x9f, 0x96, 0xe4, 0xbb, 0xb8, 0xd9, 0xad, 0x62, 0xd6, 0xe1, 0x97, 0x49, 0x71,
-	0xd5, 0x35, 0xed, 0xd1, 0x25, 0x23, 0x9d, 0xff, 0xae, 0x78, 0x35, 0xf8, 0x89, 0xd5, 0xf3, 0x94,
-	0xf8, 0xf9, 0xc1, 0xf4, 0xc1, 0x89, 0xe8, 0xe6, 0x84, 0xf5, 0xc6, 0x5f, 0xfa, 0xb8, 0x9a, 0xd4,
-	0xb9, 0xde, 0x7a, 0x2c, 0x92, 0x30, 0x2d, 0x2a, 0xcc, 0xe3, 0x9d, 0x76, 0x9b, 0x81, 0x9e, 0xa7,
-	0xcf, 0x8d, 0x0e, 0x8f, 0x1d, 0x56, 0xff, 0xa2, 0xdb, 0x90, 0x0b, 0x1e, 0x02, 0x95, 0x2f, 0xd3,
-	0xe7, 0x0c, 0xaa, 0x07, 0xaf, 0x98, 0xbc, 0xc3, 0xcd, 0x9d, 0x3e, 0xff, 0x05, 0xd8, 0xf3, 0xcc,
-	0xf9, 0x0e, 0xf7, 0xc7, 0xbe, 0x49, 0x8f, 0x1c, 0xb6, 0x03, 0xe5, 0xad, 0xda, 0x97, 0x19, 0x71,
-	0x05, 0x11, 0x62, 0xe4, 0x95, 0xda, 0x1b, 0x90, 0xc3, 0xcd, 0x1f, 0x88, 0x1f, 0x8b, 0x3d, 0xcf,
-	0x9e, 0xd3, 0x83, 0xc9, 0x17, 0xc4, 0x90, 0xbd, 0x75, 0x70, 0x77, 0xb3, 0xca, 0x5d, 0x7e, 0x1e,
-	0xd5, 0x71, 0x47, 0xfb, 0xba, 0x43, 0xcc, 0xe9, 0x6f, 0x30, 0x42, 0xd6, 0x3b, 0xbf, 0x08, 0xb9,
-	0x20, 0xcf, 0x44, 0xab, 0x90, 0x7d, 0xda, 0xc1, 0x8f, 0x9b, 0x58, 0x99, 0x13, 0x3e, 0x0c, 0x38,
-	0x4f, 0x45, 0x85, 0x50, 0x86, 0xf9, 0xed, 0x6a, 0xbb, 0xfa, 0xa8, 0x89, 0x83, 0x0b, 0xef, 0x00,
-	0x20, 0x93, 0xa5, 0x92, 0x22, 0x3b, 0x08, 0x75, 0xd6, 0x56, 0xbe, 0xfa, 0x7a, 0x75, 0xee, 0xa7,
-	0x5f, 0xaf, 0xce, 0x3d, 0x3f, 0x5b, 0x4d, 0x7c, 0x75, 0xb6, 0x9a, 0xf8, 0xc9, 0xd9, 0x6a, 0xe2,
-	0x5f, 0xcf, 0x56, 0x13, 0xbb, 0x59, 0x1e, 0xd2, 0xef, 0xfd, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff,
-	0xdb, 0x9d, 0xe2, 0x3d, 0xd2, 0x2f, 0x00, 0x00,
+	0xc6, 0x11, 0x71, 0x2b, 0xde, 0x89, 0xee, 0x0e, 0x8f, 0x2c, 0xbf, 0x72, 0x7c, 0xaf, 0xb4, 0x39,
+	0xa0, 0x74, 0x60, 0x93, 0x77, 0x39, 0x62, 0x7f, 0x7c, 0xf0, 0xae, 0x6f, 0x0d, 0x89, 0xe7, 0xeb,
+	0xc3, 0x91, 0x10, 0x2a, 0x6d, 0xcc, 0x03, 0xcc, 0xb1, 0xab, 0xfb, 0x16, 0x75, 0x24, 0x7f, 0x6d,
+	0x40, 0x07, 0x94, 0x7f, 0xbe, 0xcb, 0xbe, 0x04, 0x55, 0xdd, 0x84, 0xc5, 0x27, 0xc4, 0xf5, 0x2c,
+	0xea, 0xa0, 0x35, 0xc8, 0x58, 0x8e, 0x49, 0x9e, 0xad, 0x27, 0xca, 0x89, 0xb7, 0xd2, 0x58, 0x34,
+	0xd4, 0xbb, 0x00, 0x2d, 0xf6, 0xd1, 0x74, 0x7c, 0x77, 0x82, 0x14, 0x48, 0x1d, 0x91, 0x09, 0x47,
+	0xe4, 0x31, 0xfb, 0x64, 0x94, 0x63, 0xdd, 0x5e, 0x4f, 0x0a, 0xca, 0xb1, 0x6e, 0xab, 0x5f, 0x26,
+	0xa0, 0x50, 0x75, 0x1c, 0xea, 0xf3, 0xde, 0x3d, 0x84, 0x20, 0xed, 0xe8, 0x43, 0x22, 0x85, 0xf8,
+	0x37, 0xaa, 0x43, 0xd6, 0xd6, 0xf7, 0x89, 0xed, 0xad, 0x27, 0xcb, 0xa9, 0xb7, 0x0a, 0xf7, 0xbf,
+	0x53, 0x79, 0x71, 0xc8, 0x95, 0x88, 0x92, 0xca, 0x0e, 0x47, 0x73, 0x23, 0xb0, 0x14, 0x45, 0x1f,
+	0xc1, 0xa2, 0xe5, 0x98, 0x96, 0x41, 0xbc, 0xf5, 0x34, 0xd7, 0xb2, 0x11, 0xa7, 0x65, 0x6a, 0x7d,
+	0x2d, 0xfd, 0xc5, 0xf9, 0xe6, 0x02, 0x0e, 0x84, 0x4a, 0xef, 0x41, 0x21, 0xa2, 0x36, 0x66, 0x6c,
+	0x6b, 0x90, 0x39, 0xd6, 0xed, 0x31, 0x91, 0xa3, 0x13, 0x8d, 0xf7, 0x93, 0x0f, 0x13, 0xea, 0x27,
+	0xb0, 0xd6, 0xd6, 0x87, 0xc4, 0x7c, 0x44, 0x1c, 0xe2, 0x5a, 0x06, 0x26, 0x1e, 0x1d, 0xbb, 0x06,
+	0x61, 0x63, 0x3d, 0xb2, 0x1c, 0x33, 0x18, 0x2b, 0xfb, 0x8e, 0xd7, 0xa2, 0xd6, 0xe1, 0x95, 0x86,
+	0xe5, 0x19, 0x2e, 0xf1, 0xc9, 0x57, 0x56, 0x92, 0x0a, 0x94, 0x9c, 0x27, 0x60, 0x65, 0x5e, 0xfa,
+	0x17, 0xe0, 0x06, 0x73, 0xb1, 0xa9, 0xb9, 0x92, 0xa2, 0x79, 0x23, 0x62, 0x70, 0x65, 0x85, 0xfb,
+	0x6f, 0xc5, 0x79, 0x28, 0x6e, 0x24, 0xdb, 0x0b, 0x78, 0x95, 0xab, 0x09, 0x08, 0xbd, 0x11, 0x31,
+	0x90, 0x01, 0x37, 0x4d, 0x69, 0xf4, 0x9c, 0xfa, 0x24, 0x57, 0x1f, 0x3b, 0x8d, 0x97, 0x0c, 0x73,
+	0x7b, 0x01, 0xaf, 0x05, 0xca, 0xa2, 0x9d, 0xd4, 0x00, 0x72, 0x81, 0x6e, 0xf5, 0xc7, 0x09, 0xc8,
+	0x07, 0x4c, 0x0f, 0x7d, 0x1b, 0xf2, 0x8e, 0xee, 0x50, 0xcd, 0x18, 0x8d, 0x3d, 0x3e, 0xa0, 0x54,
+	0xad, 0x78, 0x71, 0xbe, 0x99, 0x6b, 0xeb, 0x0e, 0xad, 0x77, 0xf7, 0x3c, 0x9c, 0x63, 0xec, 0xfa,
+	0x68, 0xec, 0xa1, 0xd7, 0xa0, 0x38, 0x24, 0x43, 0xea, 0x4e, 0xb4, 0xfd, 0x89, 0x4f, 0x3c, 0xe9,
+	0xb6, 0x82, 0xa0, 0xd5, 0x18, 0x09, 0x7d, 0x08, 0x8b, 0x03, 0x61, 0xd2, 0x7a, 0x8a, 0x2f, 0x9f,
+	0xd7, 0xe3, 0xac, 0x9f, 0xb3, 0x1a, 0x07, 0x32, 0xea, 0xef, 0x24, 0x60, 0x2d, 0xa4, 0x92, 0x5f,
+	0x1e, 0x5b, 0x2e, 0x19, 0x12, 0xc7, 0xf7, 0xd0, 0xf7, 0x20, 0x6b, 0x5b, 0x43, 0xcb, 0xf7, 0xa4,
+	0xcf, 0x5f, 0x8d, 0x53, 0x1b, 0x0e, 0x0a, 0x4b, 0x30, 0xaa, 0x42, 0xd1, 0x25, 0x1e, 0x71, 0x8f,
+	0xc5, 0x8a, 0x97, 0x1e, 0xbd, 0x46, 0x78, 0x46, 0x44, 0xdd, 0x82, 0x5c, 0xd7, 0xd6, 0xfd, 0x03,
+	0xea, 0x0e, 0x91, 0x0a, 0x45, 0xdd, 0x35, 0x0e, 0x2d, 0x9f, 0x18, 0xfe, 0xd8, 0x0d, 0x76, 0xdf,
+	0x0c, 0x0d, 0xdd, 0x84, 0x24, 0x15, 0x1d, 0xe5, 0x6b, 0xd9, 0x8b, 0xf3, 0xcd, 0x64, 0xa7, 0x87,
+	0x93, 0xd4, 0x53, 0x3f, 0x80, 0xd5, 0xae, 0x3d, 0x1e, 0x58, 0x4e, 0x83, 0x78, 0x86, 0x6b, 0x8d,
+	0x98, 0x76, 0xb6, 0x2a, 0x59, 0x8c, 0x0a, 0x56, 0x25, 0xfb, 0x0e, 0xb7, 0x76, 0x72, 0xba, 0xb5,
+	0xd5, 0xdf, 0x4a, 0xc2, 0x6a, 0xd3, 0x19, 0x58, 0x0e, 0x89, 0x4a, 0xdf, 0x81, 0x65, 0xc2, 0x89,
+	0xda, 0xb1, 0x08, 0x37, 0x52, 0xcf, 0x92, 0xa0, 0x06, 0x31, 0xa8, 0x35, 0x17, 0x17, 0xee, 0xc5,
+	0x0d, 0xff, 0x05, 0xed, 0xb1, 0xd1, 0xa1, 0x09, 0x8b, 0x23, 0x3e, 0x08, 0x4f, 0x4e, 0xef, 0x9d,
+	0x38, 0x5d, 0x2f, 0x8c, 0x33, 0x08, 0x12, 0x52, 0xf6, 0xeb, 0x04, 0x89, 0x3f, 0x4e, 0xc2, 0x4a,
+	0x9b, 0x9a, 0x33, 0x7e, 0x28, 0x41, 0xee, 0x90, 0x7a, 0x7e, 0x24, 0x20, 0x86, 0x6d, 0xf4, 0x10,
+	0x72, 0x23, 0x39, 0x7d, 0x72, 0xf6, 0x6f, 0xc7, 0x9b, 0x2c, 0x30, 0x38, 0x44, 0xa3, 0x0f, 0x20,
+	0x1f, 0x6c, 0x19, 0x36, 0xda, 0x97, 0x58, 0x38, 0x53, 0x3c, 0xfa, 0x10, 0xb2, 0x62, 0x12, 0xd6,
+	0xd3, 0x5c, 0xf2, 0xce, 0x4b, 0xf9, 0x1c, 0x4b, 0x21, 0xf4, 0x08, 0x72, 0xbe, 0xed, 0x69, 0x96,
+	0x73, 0x40, 0xd7, 0x33, 0x5c, 0xc1, 0x66, 0x6c, 0x90, 0xa1, 0x26, 0xe9, 0xef, 0xf4, 0x5a, 0xce,
+	0x01, 0xad, 0x15, 0x2e, 0xce, 0x37, 0x17, 0x65, 0x03, 0x2f, 0xfa, 0xb6, 0xc7, 0x3e, 0xd4, 0xdf,
+	0x4d, 0x40, 0x21, 0x82, 0x42, 0xaf, 0x02, 0xf8, 0xee, 0xd8, 0xf3, 0x35, 0x97, 0x52, 0x9f, 0x3b,
+	0xab, 0x88, 0xf3, 0x9c, 0x82, 0x29, 0xf5, 0x51, 0x05, 0x6e, 0x18, 0xc4, 0xf5, 0x35, 0xcb, 0xf3,
+	0xc6, 0xc4, 0xd5, 0xbc, 0xf1, 0xfe, 0x67, 0xc4, 0xf0, 0xb9, 0xe3, 0x8a, 0x78, 0x95, 0xb1, 0x5a,
+	0x9c, 0xd3, 0x13, 0x0c, 0xf4, 0x00, 0x6e, 0x46, 0xf1, 0xa3, 0xf1, 0xbe, 0x6d, 0x19, 0x1a, 0x9b,
+	0xcc, 0x14, 0x17, 0xb9, 0x31, 0x15, 0xe9, 0x72, 0xde, 0x63, 0x32, 0x51, 0x7f, 0x9a, 0x00, 0x05,
+	0xeb, 0x07, 0xfe, 0x2e, 0x19, 0xee, 0x13, 0xb7, 0xe7, 0xeb, 0xfe, 0xd8, 0x43, 0x37, 0x21, 0x6b,
+	0x13, 0xdd, 0x24, 0x2e, 0x37, 0x2a, 0x87, 0x65, 0x0b, 0xed, 0xb1, 0x1d, 0xac, 0x1b, 0x87, 0xfa,
+	0xbe, 0x65, 0x5b, 0xfe, 0x84, 0x9b, 0xb2, 0x1c, 0xbf, 0x84, 0xe7, 0x75, 0x56, 0x70, 0x44, 0x10,
+	0xcf, 0xa8, 0x41, 0xeb, 0xb0, 0x38, 0x24, 0x9e, 0xa7, 0x0f, 0x08, 0xb7, 0x34, 0x8f, 0x83, 0xa6,
+	0xfa, 0x01, 0x14, 0xa3, 0x72, 0xa8, 0x00, 0x8b, 0x7b, 0xed, 0xc7, 0xed, 0xce, 0xd3, 0xb6, 0xb2,
+	0x80, 0x56, 0xa0, 0xb0, 0xd7, 0xc6, 0xcd, 0x6a, 0x7d, 0xbb, 0x5a, 0xdb, 0x69, 0x2a, 0x09, 0xb4,
+	0x04, 0xf9, 0x69, 0x33, 0xa9, 0xfe, 0x69, 0x02, 0x80, 0xb9, 0x5b, 0x0e, 0xea, 0x7d, 0xc8, 0x78,
+	0xbe, 0xee, 0x8b, 0x55, 0xb9, 0x7c, 0xff, 0x8d, 0xcb, 0xe6, 0x50, 0xda, 0xcb, 0xfe, 0x11, 0x2c,
+	0x44, 0xa2, 0x16, 0x26, 0x67, 0x2c, 0x64, 0x01, 0x42, 0x37, 0x4d, 0x57, 0x1a, 0xce, 0xbf, 0xd5,
+	0x0f, 0x20, 0xc3, 0xa5, 0x67, 0xcd, 0xcd, 0x41, 0xba, 0xc1, 0xbe, 0x12, 0x28, 0x0f, 0x19, 0xdc,
+	0xac, 0x36, 0x3e, 0x55, 0x92, 0x48, 0x81, 0x62, 0xa3, 0xd5, 0xab, 0x77, 0xda, 0xed, 0x66, 0xbd,
+	0xdf, 0x6c, 0x28, 0x29, 0xf5, 0x0e, 0x64, 0x5a, 0x43, 0xa6, 0xf9, 0x36, 0x5b, 0xf2, 0x07, 0xc4,
+	0x25, 0x8e, 0x11, 0xec, 0xa4, 0x29, 0x41, 0xfd, 0x49, 0x1e, 0x32, 0xbb, 0x74, 0xec, 0xf8, 0xe8,
+	0x7e, 0x24, 0x6c, 0x2d, 0xc7, 0x67, 0x08, 0x1c, 0x58, 0xe9, 0x4f, 0x46, 0x44, 0x86, 0xb5, 0x9b,
+	0x90, 0x15, 0x9b, 0x43, 0x0e, 0x47, 0xb6, 0x18, 0xdd, 0xd7, 0xdd, 0x01, 0xf1, 0xe5, 0x78, 0x64,
+	0x0b, 0xbd, 0xc5, 0x4e, 0x2c, 0xdd, 0xa4, 0x8e, 0x3d, 0xe1, 0x7b, 0x28, 0x27, 0x8e, 0x25, 0x4c,
+	0x74, 0xb3, 0xe3, 0xd8, 0x13, 0x1c, 0x72, 0xd1, 0x36, 0x14, 0xf7, 0x2d, 0xc7, 0xd4, 0xe8, 0x48,
+	0x04, 0xf9, 0xcc, 0xe5, 0x3b, 0x4e, 0x58, 0x55, 0xb3, 0x1c, 0xb3, 0x23, 0xc0, 0xb8, 0xb0, 0x3f,
+	0x6d, 0xa0, 0x36, 0x2c, 0x1f, 0x53, 0x7b, 0x3c, 0x24, 0xa1, 0xae, 0x2c, 0xd7, 0xf5, 0xe6, 0xe5,
+	0xba, 0x9e, 0x70, 0x7c, 0xa0, 0x6d, 0xe9, 0x38, 0xda, 0x44, 0x8f, 0x61, 0xc9, 0x1f, 0x8e, 0x0e,
+	0xbc, 0x50, 0xdd, 0x22, 0x57, 0xf7, 0xad, 0x2b, 0x1c, 0xc6, 0xe0, 0x81, 0xb6, 0xa2, 0x1f, 0x69,
+	0x95, 0x7e, 0x23, 0x05, 0x85, 0x88, 0xe5, 0xa8, 0x07, 0x85, 0x91, 0x4b, 0x47, 0xfa, 0x80, 0x1f,
+	0x54, 0x72, 0x2e, 0xee, 0xbd, 0xd4, 0xa8, 0x2b, 0xdd, 0xa9, 0x20, 0x8e, 0x6a, 0x51, 0xcf, 0x92,
+	0x50, 0x88, 0x30, 0xd1, 0xdb, 0x90, 0xc3, 0x5d, 0xdc, 0x7a, 0x52, 0xed, 0x37, 0x95, 0x85, 0xd2,
+	0xed, 0xd3, 0xb3, 0xf2, 0x3a, 0xd7, 0x16, 0x55, 0xd0, 0x75, 0xad, 0x63, 0xb6, 0xf4, 0xde, 0x82,
+	0xc5, 0x00, 0x9a, 0x28, 0x7d, 0xf3, 0xf4, 0xac, 0xfc, 0xca, 0x3c, 0x34, 0x82, 0xc4, 0xbd, 0xed,
+	0x2a, 0x6e, 0x36, 0x94, 0x64, 0x3c, 0x12, 0xf7, 0x0e, 0x75, 0x97, 0x98, 0xe8, 0x5b, 0x90, 0x95,
+	0xc0, 0x54, 0xa9, 0x74, 0x7a, 0x56, 0xbe, 0x39, 0x0f, 0x9c, 0xe2, 0x70, 0x6f, 0xa7, 0xfa, 0xa4,
+	0xa9, 0xa4, 0xe3, 0x71, 0xb8, 0x67, 0xeb, 0xc7, 0x04, 0xbd, 0x01, 0x19, 0x01, 0xcb, 0x94, 0x6e,
+	0x9d, 0x9e, 0x95, 0xbf, 0xf1, 0x82, 0x3a, 0x86, 0x2a, 0xad, 0xff, 0xf6, 0x1f, 0x6c, 0x2c, 0xfc,
+	0xe5, 0x1f, 0x6e, 0x28, 0xf3, 0xec, 0xd2, 0x7f, 0x27, 0x60, 0x69, 0x66, 0xca, 0x91, 0x0a, 0x59,
+	0x87, 0x1a, 0x74, 0x24, 0xce, 0xaf, 0x5c, 0x0d, 0x2e, 0xce, 0x37, 0xb3, 0x6d, 0x5a, 0xa7, 0xa3,
+	0x09, 0x96, 0x1c, 0xf4, 0x78, 0xee, 0x04, 0x7e, 0xf0, 0x92, 0xeb, 0x29, 0xf6, 0x0c, 0xfe, 0x18,
+	0x96, 0x4c, 0xd7, 0x3a, 0x26, 0xae, 0x66, 0x50, 0xe7, 0xc0, 0x1a, 0xc8, 0xb3, 0xa9, 0x14, 0x9b,
+	0x26, 0x72, 0x20, 0x2e, 0x0a, 0x81, 0x3a, 0xc7, 0x7f, 0x8d, 0xd3, 0xb7, 0xf4, 0x04, 0x8a, 0xd1,
+	0x15, 0xca, 0x8e, 0x13, 0xcf, 0xfa, 0x15, 0x22, 0xf3, 0x41, 0x9e, 0x3d, 0xe2, 0x3c, 0xa3, 0x88,
+	0x6c, 0xf0, 0x4d, 0x48, 0x0f, 0xa9, 0x29, 0xf4, 0x2c, 0xd5, 0x6e, 0xb0, 0x24, 0xe0, 0x9f, 0xce,
+	0x37, 0x0b, 0xd4, 0xab, 0x6c, 0x59, 0x36, 0xd9, 0xa5, 0x26, 0xc1, 0x1c, 0xa0, 0x1e, 0x43, 0x9a,
+	0x85, 0x0a, 0xf4, 0x4d, 0x48, 0xd7, 0x5a, 0xed, 0x86, 0xb2, 0x50, 0x5a, 0x3d, 0x3d, 0x2b, 0x2f,
+	0x71, 0x97, 0x30, 0x06, 0x5b, 0xbb, 0x68, 0x13, 0xb2, 0x4f, 0x3a, 0x3b, 0x7b, 0xbb, 0x6c, 0x79,
+	0xdd, 0x38, 0x3d, 0x2b, 0xaf, 0x84, 0x6c, 0xe1, 0x34, 0xf4, 0x2a, 0x64, 0xfa, 0xbb, 0xdd, 0xad,
+	0x9e, 0x92, 0x2c, 0xa1, 0xd3, 0xb3, 0xf2, 0x72, 0xc8, 0xe7, 0x36, 0x97, 0x56, 0xe5, 0xac, 0xe6,
+	0x43, 0xba, 0xfa, 0xb3, 0x24, 0x2c, 0x61, 0x56, 0xf1, 0xb9, 0x7e, 0x97, 0xda, 0x96, 0x31, 0x41,
+	0x5d, 0xc8, 0x1b, 0xd4, 0x31, 0xad, 0xc8, 0x9e, 0xba, 0x7f, 0xc9, 0xa9, 0x3f, 0x95, 0x0a, 0x5a,
+	0xf5, 0x40, 0x12, 0x4f, 0x95, 0xa0, 0x77, 0x21, 0x63, 0x12, 0x5b, 0x9f, 0xc8, 0xf4, 0xe3, 0x56,
+	0x45, 0xd4, 0x94, 0x95, 0xa0, 0xa6, 0xac, 0x34, 0x64, 0x4d, 0x89, 0x05, 0x8e, 0xa7, 0xd9, 0xfa,
+	0x33, 0x4d, 0xf7, 0x7d, 0x32, 0x1c, 0xf9, 0x22, 0xf7, 0x48, 0xe3, 0xc2, 0x50, 0x7f, 0x56, 0x95,
+	0x24, 0x74, 0x0f, 0xb2, 0x27, 0x96, 0x63, 0xd2, 0x13, 0x99, 0x5e, 0x5c, 0xa1, 0x54, 0x02, 0xd5,
+	0x53, 0x76, 0xea, 0xce, 0x99, 0xc9, 0xfc, 0xdd, 0xee, 0xb4, 0x9b, 0x81, 0xbf, 0x25, 0xbf, 0xe3,
+	0xb4, 0xa9, 0xc3, 0xf6, 0x0a, 0x74, 0xda, 0xda, 0x56, 0xb5, 0xb5, 0xb3, 0x87, 0x99, 0xcf, 0xd7,
+	0x4e, 0xcf, 0xca, 0x4a, 0x08, 0xd9, 0xd2, 0x2d, 0x9b, 0xe5, 0xbb, 0xb7, 0x20, 0x55, 0x6d, 0x7f,
+	0xaa, 0x24, 0x4b, 0xca, 0xe9, 0x59, 0xb9, 0x18, 0xb2, 0xab, 0xce, 0x64, 0xba, 0x8d, 0xe6, 0xfb,
+	0x55, 0xff, 0x36, 0x05, 0xc5, 0xbd, 0x91, 0xa9, 0xfb, 0x44, 0xac, 0x49, 0x54, 0x86, 0xc2, 0x48,
+	0x77, 0x75, 0xdb, 0x26, 0xb6, 0xe5, 0x0d, 0x65, 0xb5, 0x1c, 0x25, 0xa1, 0xf7, 0x5e, 0xd6, 0x8d,
+	0xb5, 0x1c, 0x5b, 0x67, 0x3f, 0xfe, 0x97, 0xcd, 0x44, 0xe0, 0xd0, 0x3d, 0x58, 0x3e, 0x10, 0xd6,
+	0x6a, 0xba, 0xc1, 0x27, 0x36, 0xc5, 0x27, 0xb6, 0x12, 0x37, 0xb1, 0x51, 0xb3, 0x2a, 0x72, 0x90,
+	0x55, 0x2e, 0x85, 0x97, 0x0e, 0xa2, 0x4d, 0xf4, 0x00, 0x16, 0x87, 0xd4, 0xb1, 0x7c, 0xea, 0x5e,
+	0x3f, 0x0b, 0x01, 0x12, 0xbd, 0x0d, 0xab, 0x6c, 0x72, 0x03, 0x7b, 0x38, 0x9b, 0x9f, 0x58, 0x49,
+	0xbc, 0x32, 0xd4, 0x9f, 0xc9, 0x0e, 0x31, 0x23, 0xa3, 0x1a, 0x64, 0xa8, 0xcb, 0x52, 0xa2, 0x2c,
+	0x37, 0xf7, 0x9d, 0x6b, 0xcd, 0x15, 0x8d, 0x0e, 0x93, 0xc1, 0x42, 0x54, 0xfd, 0x3e, 0x2c, 0xcd,
+	0x0c, 0x82, 0x65, 0x02, 0xdd, 0xea, 0x5e, 0xaf, 0xa9, 0x2c, 0xa0, 0x22, 0xe4, 0xea, 0x9d, 0x76,
+	0xbf, 0xd5, 0xde, 0x63, 0xa9, 0x4c, 0x11, 0x72, 0xb8, 0xb3, 0xb3, 0x53, 0xab, 0xd6, 0x1f, 0x2b,
+	0x49, 0xb5, 0x02, 0x85, 0x88, 0x36, 0xb4, 0x0c, 0xd0, 0xeb, 0x77, 0xba, 0xda, 0x56, 0x0b, 0xf7,
+	0xfa, 0x22, 0x11, 0xea, 0xf5, 0xab, 0xb8, 0x2f, 0x09, 0x09, 0xf5, 0x3f, 0x92, 0xc1, 0x8c, 0xca,
+	0xdc, 0xa7, 0x36, 0x9b, 0xfb, 0x5c, 0x61, 0xbc, 0xcc, 0x7e, 0xa6, 0x8d, 0x30, 0x07, 0x7a, 0x0f,
+	0x80, 0x2f, 0x1c, 0x62, 0x6a, 0xba, 0x2f, 0x27, 0xbe, 0xf4, 0x82, 0x93, 0xfb, 0xc1, 0xa5, 0x0d,
+	0xce, 0x4b, 0x74, 0xd5, 0x47, 0x1f, 0x42, 0xd1, 0xa0, 0xc3, 0x91, 0x4d, 0xa4, 0x70, 0xea, 0x5a,
+	0xe1, 0x42, 0x88, 0xaf, 0xfa, 0xd1, 0xec, 0x2b, 0x3d, 0x9b, 0x1f, 0xfe, 0x66, 0x22, 0xf0, 0x4c,
+	0x4c, 0xc2, 0x55, 0x84, 0xdc, 0x5e, 0xb7, 0x51, 0xed, 0xb7, 0xda, 0x8f, 0x94, 0x04, 0x02, 0xc8,
+	0x72, 0x57, 0x37, 0x94, 0x24, 0x4b, 0x14, 0xeb, 0x9d, 0xdd, 0xee, 0x4e, 0x93, 0xa7, 0x5c, 0x68,
+	0x0d, 0x94, 0xc0, 0xd9, 0x1a, 0x77, 0x64, 0xb3, 0xa1, 0xa4, 0xd1, 0x0d, 0x58, 0x09, 0xa9, 0x52,
+	0x32, 0x83, 0x6e, 0x02, 0x0a, 0x89, 0x53, 0x15, 0x59, 0xf5, 0xd7, 0x60, 0xa5, 0x4e, 0x1d, 0x5f,
+	0xb7, 0x9c, 0x30, 0x89, 0xbe, 0xcf, 0x06, 0x2d, 0x49, 0x9a, 0x25, 0x2f, 0x3b, 0x6a, 0x2b, 0x17,
+	0xe7, 0x9b, 0x85, 0x10, 0xda, 0x6a, 0xb0, 0x91, 0x06, 0x0d, 0x93, 0xed, 0xdf, 0x91, 0x65, 0x72,
+	0xe7, 0x66, 0x6a, 0x8b, 0x17, 0xe7, 0x9b, 0xa9, 0x6e, 0xab, 0x81, 0x19, 0x0d, 0x7d, 0x13, 0xf2,
+	0xe4, 0x99, 0xe5, 0x6b, 0x06, 0x8b, 0xe1, 0xcc, 0x81, 0x19, 0x9c, 0x63, 0x84, 0x3a, 0x0b, 0xd9,
+	0x35, 0x80, 0x2e, 0x75, 0x7d, 0xd9, 0xf3, 0x77, 0x21, 0x33, 0xa2, 0x2e, 0x2f, 0xcf, 0x2f, 0xbd,
+	0x34, 0x62, 0x70, 0xb1, 0x50, 0xb1, 0x00, 0xab, 0x7f, 0x95, 0x04, 0xe8, 0xeb, 0xde, 0x91, 0x54,
+	0xf2, 0x10, 0xf2, 0xe1, 0x05, 0x9c, 0xac, 0xf3, 0xaf, 0x9c, 0xed, 0x10, 0x8c, 0x1e, 0x04, 0x8b,
+	0x4d, 0x94, 0x07, 0xb1, 0x75, 0x5a, 0xd0, 0x51, 0x5c, 0x86, 0x3d, 0x5b, 0x03, 0xb0, 0x23, 0x91,
+	0xb8, 0xae, 0x9c, 0x79, 0xf6, 0x89, 0xea, 0xfc, 0x58, 0x10, 0x4e, 0x93, 0x09, 0x66, 0xec, 0xcd,
+	0xc6, 0xdc, 0x8c, 0x6c, 0x2f, 0xe0, 0xa9, 0x1c, 0xfa, 0x18, 0x0a, 0x6c, 0xdc, 0x9a, 0xc7, 0x79,
+	0x32, 0xb7, 0xbc, 0xd4, 0x55, 0x42, 0x03, 0x86, 0x51, 0xf8, 0x5d, 0x53, 0x60, 0xd9, 0x1d, 0x3b,
+	0x6c, 0xd8, 0x52, 0x87, 0xfa, 0x27, 0x49, 0x78, 0xa5, 0x4d, 0xfc, 0x13, 0xea, 0x1e, 0x55, 0x7d,
+	0x5f, 0x37, 0x0e, 0x87, 0xc4, 0x91, 0x4e, 0x8e, 0x64, 0xd6, 0x89, 0x99, 0xcc, 0x7a, 0x1d, 0x16,
+	0x75, 0xdb, 0xd2, 0x3d, 0x22, 0xd2, 0x91, 0x3c, 0x0e, 0x9a, 0x2c, 0xff, 0x67, 0xd5, 0x04, 0xf1,
+	0x3c, 0x22, 0x0a, 0xfc, 0x3c, 0x9e, 0x12, 0xd0, 0x8f, 0xe0, 0xa6, 0x4c, 0x3c, 0xf4, 0xb0, 0x2b,
+	0x96, 0xd9, 0x06, 0x37, 0x85, 0xcd, 0xd8, 0xf2, 0x26, 0xde, 0x38, 0x99, 0x99, 0x4c, 0xc9, 0x9d,
+	0x91, 0x2f, 0xf3, 0x9c, 0x35, 0x33, 0x86, 0x55, 0x7a, 0x04, 0xb7, 0x2e, 0x15, 0xf9, 0x4a, 0x17,
+	0x08, 0xff, 0x90, 0x04, 0x68, 0x75, 0xab, 0xbb, 0xd2, 0x49, 0x0d, 0xc8, 0x1e, 0xe8, 0x43, 0xcb,
+	0x9e, 0x5c, 0x15, 0xa7, 0xa6, 0xf8, 0x4a, 0x55, 0xb8, 0x63, 0x8b, 0xcb, 0x60, 0x29, 0xcb, 0x8b,
+	0x9b, 0xf1, 0xbe, 0x43, 0xfc, 0xb0, 0xb8, 0xe1, 0x2d, 0x66, 0x86, 0xab, 0x3b, 0xe1, 0x02, 0x13,
+	0x0d, 0x36, 0x01, 0x03, 0xdd, 0x27, 0x27, 0xfa, 0x24, 0x08, 0x2e, 0xb2, 0x89, 0xb6, 0xf9, 0x35,
+	0x1d, 0x71, 0x8f, 0x89, 0xb9, 0x9e, 0xe1, 0x4e, 0xbd, 0xce, 0x1e, 0x2c, 0xe1, 0xc2, 0x77, 0xa1,
+	0x74, 0xe9, 0x03, 0x9e, 0xd8, 0x4c, 0x59, 0x5f, 0xc9, 0x47, 0x77, 0x61, 0x69, 0x66, 0x9c, 0x2f,
+	0x54, 0x95, 0xad, 0xee, 0x93, 0xef, 0x2a, 0x69, 0xf9, 0xf5, 0x7d, 0x25, 0xab, 0xfe, 0x51, 0x4a,
+	0x84, 0x03, 0xe9, 0xd5, 0xf8, 0xeb, 0xe9, 0x1c, 0xdf, 0xc4, 0x06, 0xb5, 0xe5, 0x36, 0x7d, 0xf3,
+	0xea, 0x28, 0xc1, 0xaa, 0x14, 0x0e, 0xc7, 0xa1, 0x20, 0xda, 0x84, 0x82, 0x58, 0xc5, 0x1a, 0xdb,
+	0x16, 0xdc, 0xad, 0x4b, 0x18, 0x04, 0x89, 0x49, 0xa2, 0x3b, 0xb0, 0xcc, 0x6f, 0x21, 0xbc, 0x43,
+	0x62, 0x0a, 0x4c, 0x9a, 0x63, 0x96, 0x42, 0x2a, 0x87, 0xed, 0x42, 0x51, 0x12, 0x34, 0x9e, 0xa1,
+	0x66, 0xb8, 0x41, 0x6f, 0x5f, 0x67, 0x90, 0x10, 0xe1, 0x89, 0x6b, 0x61, 0x34, 0x6d, 0xa8, 0x0d,
+	0xc8, 0x05, 0xc6, 0xa2, 0x75, 0x48, 0xf5, 0xeb, 0x5d, 0x65, 0xa1, 0xb4, 0x72, 0x7a, 0x56, 0x2e,
+	0x04, 0xe4, 0x7e, 0xbd, 0xcb, 0x38, 0x7b, 0x8d, 0xae, 0x92, 0x98, 0xe5, 0xec, 0x35, 0xba, 0xa5,
+	0x34, 0xcb, 0x94, 0xd4, 0x03, 0x28, 0x44, 0x7a, 0x40, 0xaf, 0xc3, 0x62, 0xab, 0xfd, 0x08, 0x37,
+	0x7b, 0x3d, 0x65, 0xa1, 0x74, 0xf3, 0xf4, 0xac, 0x8c, 0x22, 0xdc, 0x96, 0x33, 0x60, 0xf3, 0x83,
+	0x5e, 0x85, 0xf4, 0x76, 0x87, 0x9d, 0xc0, 0x22, 0x25, 0x8e, 0x20, 0xb6, 0xa9, 0xe7, 0x97, 0x6e,
+	0xc8, 0x14, 0x2c, 0xaa, 0x58, 0xfd, 0xbd, 0x04, 0x64, 0xc5, 0x66, 0x8a, 0x9d, 0xa8, 0x2a, 0x2c,
+	0x06, 0xf5, 0xaa, 0x28, 0x57, 0xde, 0xbc, 0xbc, 0xb4, 0xa8, 0xc8, 0x4a, 0x40, 0x2c, 0xbf, 0x40,
+	0xae, 0xf4, 0x3e, 0x14, 0xa3, 0x8c, 0xaf, 0xb4, 0xf8, 0x7e, 0x04, 0x05, 0xb6, 0xbe, 0x83, 0x12,
+	0xe3, 0x3e, 0x64, 0x45, 0x40, 0x08, 0x4f, 0x84, 0xcb, 0xeb, 0x1c, 0x89, 0x44, 0x0f, 0x61, 0x51,
+	0xd4, 0x46, 0xc1, 0x35, 0xe5, 0xc6, 0xd5, 0xbb, 0x08, 0x07, 0x70, 0xf5, 0x63, 0x48, 0x77, 0x09,
+	0x71, 0x99, 0xef, 0x1d, 0x6a, 0x92, 0xe9, 0x21, 0x2a, 0xcb, 0x3a, 0x93, 0xb4, 0x1a, 0xac, 0xac,
+	0x33, 0x49, 0xcb, 0x0c, 0x2f, 0x62, 0x92, 0x91, 0x8b, 0x98, 0x3e, 0x14, 0x9f, 0x12, 0x6b, 0x70,
+	0xe8, 0x13, 0x93, 0x2b, 0x7a, 0x07, 0xd2, 0x23, 0x12, 0x1a, 0xbf, 0x1e, 0xbb, 0xc0, 0x08, 0x71,
+	0x31, 0x47, 0xb1, 0x38, 0x72, 0xc2, 0xa5, 0xe5, 0xdd, 0xba, 0x6c, 0xa9, 0x7f, 0x9f, 0x84, 0xe5,
+	0x96, 0xe7, 0x8d, 0x75, 0xc7, 0x08, 0xf2, 0xab, 0x8f, 0x66, 0xf3, 0xab, 0xd8, 0x47, 0x88, 0x59,
+	0x91, 0xd9, 0xfb, 0x25, 0x79, 0xc6, 0x25, 0xc3, 0x33, 0x4e, 0xfd, 0xf7, 0x44, 0x70, 0x89, 0x74,
+	0x27, 0xb2, 0xdd, 0x4b, 0xeb, 0xa7, 0x67, 0xe5, 0xb5, 0xa8, 0x26, 0xb2, 0xe7, 0x1c, 0x39, 0xf4,
+	0xc4, 0x41, 0xaf, 0x41, 0x06, 0x37, 0xdb, 0xcd, 0xa7, 0x4a, 0x42, 0x2c, 0xcf, 0x19, 0x10, 0x26,
+	0x0e, 0x39, 0x61, 0x9a, 0xba, 0xcd, 0x76, 0x83, 0xe5, 0x43, 0xc9, 0x18, 0x4d, 0x5d, 0xe2, 0x98,
+	0x96, 0x33, 0x40, 0xaf, 0x43, 0xb6, 0xd5, 0xeb, 0xed, 0xf1, 0x32, 0xff, 0x95, 0xd3, 0xb3, 0xf2,
+	0x8d, 0x19, 0x14, 0xbf, 0x40, 0x34, 0x19, 0x88, 0x15, 0x23, 0x2c, 0x53, 0x8a, 0x01, 0xb1, 0x2c,
+	0x57, 0x80, 0x70, 0xa7, 0x5f, 0xed, 0xb3, 0x0a, 0xff, 0x45, 0x10, 0xa6, 0xec, 0xaf, 0xdc, 0x6e,
+	0xff, 0x9c, 0x04, 0xa5, 0x6a, 0x18, 0x64, 0xe4, 0x33, 0xbe, 0xac, 0xff, 0xfa, 0x90, 0x1b, 0xb1,
+	0x2f, 0x8b, 0x04, 0xb9, 0xcc, 0xc3, 0xd8, 0x67, 0xb4, 0x39, 0xb9, 0x0a, 0xa6, 0x36, 0xa9, 0x9a,
+	0x43, 0xcb, 0xf3, 0x2c, 0xea, 0x08, 0x1a, 0x0e, 0x35, 0x95, 0xfe, 0x33, 0x01, 0x37, 0x62, 0x10,
+	0xe8, 0x2e, 0xa4, 0x5d, 0x6a, 0x07, 0x73, 0x78, 0xfb, 0xb2, 0xfb, 0x41, 0x26, 0x8a, 0x39, 0x12,
+	0x6d, 0x00, 0xe8, 0x63, 0x9f, 0xea, 0xbc, 0x7f, 0x3e, 0x7b, 0x39, 0x1c, 0xa1, 0xa0, 0xa7, 0x90,
+	0xf5, 0x88, 0xe1, 0x92, 0x20, 0xe3, 0xfd, 0xf8, 0xff, 0x6a, 0x7d, 0xa5, 0xc7, 0xd5, 0x60, 0xa9,
+	0xae, 0x54, 0x81, 0xac, 0xa0, 0xb0, 0x65, 0x6f, 0xea, 0xbe, 0x2e, 0x6f, 0x8f, 0xf9, 0x37, 0x5b,
+	0x4d, 0xba, 0x3d, 0x08, 0x56, 0x93, 0x6e, 0x0f, 0xd4, 0xbf, 0x49, 0x02, 0x34, 0x9f, 0xf9, 0xc4,
+	0x75, 0x74, 0xbb, 0x5e, 0x45, 0xcd, 0x48, 0xf4, 0x17, 0xa3, 0xfd, 0x76, 0xec, 0x95, 0x78, 0x28,
+	0x51, 0xa9, 0x57, 0x63, 0xe2, 0xff, 0x2d, 0x48, 0x8d, 0x5d, 0xf9, 0x32, 0x2a, 0xb2, 0xd5, 0x3d,
+	0xbc, 0x83, 0x19, 0x0d, 0x35, 0xa7, 0x61, 0x2b, 0x75, 0xf9, 0xfb, 0x67, 0xa4, 0x83, 0xd8, 0xd0,
+	0xc5, 0x76, 0xbe, 0xa1, 0x6b, 0x06, 0x91, 0x27, 0x47, 0x51, 0xec, 0xfc, 0x7a, 0xb5, 0x4e, 0x5c,
+	0x1f, 0x67, 0x0d, 0x9d, 0xfd, 0xff, 0x5a, 0xf1, 0xed, 0x1d, 0x80, 0xe9, 0xd0, 0xd0, 0x06, 0x64,
+	0xea, 0x5b, 0xbd, 0xde, 0x8e, 0xb2, 0x20, 0x02, 0xf8, 0x94, 0xc5, 0xc9, 0xea, 0x5f, 0x24, 0x21,
+	0x57, 0xaf, 0xca, 0x63, 0xb5, 0x0e, 0x0a, 0x8f, 0x4a, 0xfc, 0xce, 0x9d, 0x3c, 0x1b, 0x59, 0xee,
+	0x44, 0x06, 0x96, 0x2b, 0x4a, 0xcf, 0x65, 0x26, 0xc2, 0xac, 0x6e, 0x72, 0x01, 0x84, 0xa1, 0x48,
+	0xa4, 0x13, 0x34, 0x43, 0x0f, 0x62, 0xfc, 0xc6, 0xd5, 0xce, 0x12, 0x45, 0xc4, 0xb4, 0xed, 0xe1,
+	0x42, 0xa0, 0xa4, 0xae, 0x7b, 0xe8, 0x3d, 0x58, 0xf1, 0xac, 0x81, 0x63, 0x39, 0x03, 0x2d, 0x70,
+	0x1e, 0x7f, 0x00, 0xa8, 0xad, 0x5e, 0x9c, 0x6f, 0x2e, 0xf5, 0x04, 0x4b, 0xfa, 0x70, 0x49, 0x22,
+	0xeb, 0xdc, 0x95, 0xe8, 0xfb, 0xb0, 0x1c, 0x11, 0x65, 0x5e, 0x14, 0x6e, 0x57, 0x2e, 0xce, 0x37,
+	0x8b, 0xa1, 0xe4, 0x63, 0x32, 0xc1, 0xc5, 0x50, 0xf0, 0x31, 0xe1, 0xb7, 0x24, 0x07, 0xd4, 0x35,
+	0x88, 0xe6, 0xf2, 0x3d, 0xcd, 0x4f, 0xf0, 0x34, 0x2e, 0x70, 0x9a, 0xd8, 0xe6, 0xea, 0x13, 0xb8,
+	0xd1, 0x71, 0x8d, 0x43, 0xe2, 0xf9, 0xc2, 0x15, 0xd2, 0x8b, 0x1f, 0xc3, 0x6d, 0x5f, 0xf7, 0x8e,
+	0xb4, 0x43, 0xcb, 0xf3, 0xa9, 0x3b, 0xd1, 0x5c, 0xe2, 0x13, 0x87, 0xf1, 0x35, 0xfe, 0x6a, 0x28,
+	0xaf, 0xb1, 0x6e, 0x31, 0xcc, 0xb6, 0x80, 0xe0, 0x00, 0xb1, 0xc3, 0x00, 0x6a, 0x0b, 0x8a, 0xac,
+	0x98, 0x68, 0x90, 0x03, 0x7d, 0x6c, 0xfb, 0x6c, 0xf4, 0x60, 0xd3, 0x81, 0xf6, 0xd2, 0xc7, 0x54,
+	0xde, 0xa6, 0x03, 0xf1, 0xa9, 0xfe, 0x10, 0x94, 0x86, 0xe5, 0x8d, 0x74, 0xdf, 0x38, 0x0c, 0xee,
+	0xe7, 0x50, 0x03, 0x94, 0x43, 0xa2, 0xbb, 0xfe, 0x3e, 0xd1, 0x7d, 0x6d, 0x44, 0x5c, 0x8b, 0x9a,
+	0xd7, 0xcf, 0xf2, 0x4a, 0x28, 0xd2, 0xe5, 0x12, 0xea, 0x7f, 0x25, 0x00, 0xb0, 0x7e, 0x10, 0x64,
+	0x64, 0xdf, 0x81, 0x55, 0xcf, 0xd1, 0x47, 0xde, 0x21, 0xf5, 0x35, 0xcb, 0xf1, 0x89, 0x7b, 0xac,
+	0xdb, 0xf2, 0x9a, 0x45, 0x09, 0x18, 0x2d, 0x49, 0x47, 0xef, 0x00, 0x3a, 0x22, 0x64, 0xa4, 0x51,
+	0xdb, 0xd4, 0x02, 0xa6, 0x78, 0xd3, 0x4c, 0x63, 0x85, 0x71, 0x3a, 0xb6, 0xd9, 0x0b, 0xe8, 0xa8,
+	0x06, 0x1b, 0x6c, 0xf8, 0xc4, 0xf1, 0x5d, 0x8b, 0x78, 0xda, 0x01, 0x75, 0x35, 0xcf, 0xa6, 0x27,
+	0xda, 0x01, 0xb5, 0x6d, 0x7a, 0x42, 0xdc, 0xe0, 0x06, 0xab, 0x64, 0xd3, 0x41, 0x53, 0x80, 0xb6,
+	0xa8, 0xdb, 0xb3, 0xe9, 0xc9, 0x56, 0x80, 0x60, 0x69, 0xdb, 0x74, 0xcc, 0xbe, 0x65, 0x1c, 0x05,
+	0x69, 0x5b, 0x48, 0xed, 0x5b, 0xc6, 0x11, 0x7a, 0x1d, 0x96, 0x88, 0x4d, 0xf8, 0x45, 0x86, 0x40,
+	0x65, 0x38, 0xaa, 0x18, 0x10, 0x19, 0x48, 0xfd, 0x04, 0x94, 0xa6, 0x63, 0xb8, 0x93, 0x51, 0x64,
+	0xce, 0xdf, 0x01, 0xc4, 0x82, 0xa4, 0x66, 0x53, 0xe3, 0x48, 0x1b, 0xea, 0x8e, 0x3e, 0x60, 0x76,
+	0x89, 0xa7, 0x26, 0x85, 0x71, 0x76, 0xa8, 0x71, 0xb4, 0x2b, 0xe9, 0xea, 0x7b, 0x00, 0xbd, 0x91,
+	0x4b, 0x74, 0xb3, 0xc3, 0xb2, 0x09, 0xe6, 0x3a, 0xde, 0xd2, 0x4c, 0xf9, 0x54, 0x47, 0x5d, 0xb9,
+	0xd5, 0x15, 0xc1, 0x68, 0x84, 0x74, 0xf5, 0x17, 0xe1, 0x46, 0xd7, 0xd6, 0x0d, 0xfe, 0x6c, 0xdd,
+	0x0d, 0xdf, 0x4e, 0xd0, 0x43, 0xc8, 0x0a, 0xa8, 0x9c, 0xc9, 0xd8, 0xed, 0x36, 0xed, 0x73, 0x7b,
+	0x01, 0x4b, 0x7c, 0xad, 0x08, 0x30, 0xd5, 0xa3, 0xfe, 0x59, 0x02, 0xf2, 0xa1, 0x7e, 0x54, 0x06,
+	0x56, 0xca, 0xb3, 0xe5, 0x6d, 0x39, 0xb2, 0xf6, 0xce, 0xe3, 0x28, 0x09, 0xb5, 0xa0, 0x30, 0x0a,
+	0xa5, 0xaf, 0xcc, 0xe7, 0x62, 0xac, 0xc6, 0x51, 0x59, 0xf4, 0x3e, 0xe4, 0x83, 0xb7, 0xd1, 0x20,
+	0xc2, 0x5e, 0xfd, 0x94, 0x3a, 0x85, 0xab, 0x1f, 0x01, 0xfc, 0x80, 0x5a, 0x4e, 0x9f, 0x1e, 0x11,
+	0x87, 0xbf, 0xf5, 0xb1, 0x9a, 0x90, 0x04, 0x5e, 0x94, 0x2d, 0x5e, 0x90, 0x8b, 0x29, 0x08, 0x9f,
+	0xbc, 0x44, 0x53, 0xfd, 0xeb, 0x24, 0x64, 0x31, 0xa5, 0x7e, 0xbd, 0x8a, 0xca, 0x90, 0x95, 0x71,
+	0x82, 0x9f, 0x3f, 0xb5, 0xfc, 0xc5, 0xf9, 0x66, 0x46, 0x04, 0x88, 0x8c, 0xc1, 0x23, 0x43, 0x24,
+	0x82, 0x27, 0x2f, 0x8b, 0xe0, 0xe8, 0x2e, 0x14, 0x25, 0x48, 0x3b, 0xd4, 0xbd, 0x43, 0x51, 0xa0,
+	0xd5, 0x96, 0x2f, 0xce, 0x37, 0x41, 0x20, 0xb7, 0x75, 0xef, 0x10, 0x83, 0x40, 0xb3, 0x6f, 0xd4,
+	0x84, 0xc2, 0x67, 0xd4, 0x72, 0x34, 0x9f, 0x0f, 0x42, 0x5e, 0xf9, 0xc5, 0xce, 0xe3, 0x74, 0xa8,
+	0xf2, 0xe1, 0x1b, 0x3e, 0x9b, 0x0e, 0xbe, 0x09, 0x4b, 0x2e, 0xa5, 0xbe, 0x08, 0x5b, 0x16, 0x75,
+	0xe4, 0x6d, 0x42, 0x39, 0xf6, 0x92, 0x99, 0x52, 0x1f, 0x4b, 0x1c, 0x2e, 0xba, 0x91, 0x16, 0xba,
+	0x0b, 0x6b, 0xb6, 0xee, 0xf9, 0x1a, 0x8f, 0x77, 0xe6, 0x54, 0x5b, 0x96, 0x6f, 0x35, 0xc4, 0x78,
+	0x5b, 0x9c, 0x15, 0x48, 0xa8, 0xff, 0x98, 0x80, 0x02, 0x1b, 0x8c, 0x75, 0x60, 0x19, 0x2c, 0xc9,
+	0xfb, 0xea, 0xb9, 0xc7, 0x2d, 0x48, 0x19, 0x9e, 0x2b, 0x9d, 0xca, 0x0f, 0xdf, 0x7a, 0x0f, 0x63,
+	0x46, 0x43, 0x9f, 0x40, 0x56, 0xde, 0x6a, 0x88, 0xb4, 0x43, 0xbd, 0x3e, 0x1d, 0x95, 0xbe, 0x91,
+	0x72, 0x7c, 0x2d, 0x4f, 0xad, 0x13, 0x87, 0x00, 0x8e, 0x92, 0xd0, 0x4d, 0x48, 0x1a, 0xc2, 0x5d,
+	0xf2, 0x97, 0x15, 0xf5, 0x36, 0x4e, 0x1a, 0x8e, 0xfa, 0x77, 0x09, 0x58, 0x9a, 0x6e, 0x78, 0xb6,
+	0x02, 0x6e, 0x43, 0xde, 0x1b, 0xef, 0x7b, 0x13, 0xcf, 0x27, 0xc3, 0xe0, 0x1d, 0x33, 0x24, 0xa0,
+	0x16, 0xe4, 0x75, 0x7b, 0x40, 0x5d, 0xcb, 0x3f, 0x1c, 0xca, 0x4a, 0x34, 0x3e, 0x55, 0x88, 0xea,
+	0xac, 0x54, 0x03, 0x11, 0x3c, 0x95, 0x0e, 0xce, 0x7d, 0xf1, 0xd8, 0xcd, 0xcf, 0xfd, 0xd7, 0xa0,
+	0x68, 0xeb, 0x43, 0x7e, 0xcd, 0xe3, 0x5b, 0x43, 0x31, 0x8e, 0x34, 0x2e, 0x48, 0x5a, 0xdf, 0x1a,
+	0x12, 0x55, 0x85, 0x7c, 0xa8, 0x0c, 0xad, 0x40, 0xa1, 0xda, 0xec, 0x69, 0xf7, 0xee, 0x3f, 0xd4,
+	0x1e, 0xd5, 0x77, 0x95, 0x05, 0x99, 0x9b, 0xfe, 0x79, 0x02, 0x96, 0x64, 0x38, 0x92, 0xf9, 0xfe,
+	0xeb, 0xb0, 0xe8, 0xea, 0x07, 0x7e, 0x50, 0x91, 0xa4, 0xc5, 0xaa, 0x66, 0x11, 0x9e, 0x55, 0x24,
+	0x8c, 0x15, 0x5f, 0x91, 0x44, 0x5e, 0xd6, 0x53, 0x57, 0xbe, 0xac, 0xa7, 0x7f, 0x2e, 0x2f, 0xeb,
+	0xea, 0xaf, 0x03, 0x6c, 0x59, 0x36, 0xe9, 0x8b, 0xbb, 0xa6, 0xb8, 0xfa, 0x92, 0xe5, 0x70, 0xf2,
+	0xc6, 0x31, 0xc8, 0xe1, 0x5a, 0x0d, 0xcc, 0x68, 0x8c, 0x35, 0xb0, 0x4c, 0xb9, 0x19, 0x39, 0xeb,
+	0x11, 0x63, 0x0d, 0x2c, 0x33, 0x7c, 0x4b, 0x4a, 0x5f, 0xf7, 0x96, 0x74, 0x96, 0x80, 0x15, 0x99,
+	0xbb, 0x86, 0xe1, 0xf7, 0xdb, 0x90, 0x17, 0x69, 0xec, 0xb4, 0xa0, 0xe3, 0xaf, 0xc9, 0x02, 0xd7,
+	0x6a, 0xe0, 0x9c, 0x60, 0xb7, 0x4c, 0xb4, 0x09, 0x05, 0x09, 0x8d, 0xfc, 0x0a, 0x07, 0x04, 0xa9,
+	0xcd, 0xcc, 0xff, 0x2e, 0xa4, 0x0f, 0x2c, 0x9b, 0xc8, 0x85, 0x1e, 0x1b, 0x00, 0xa6, 0x0e, 0xd8,
+	0x5e, 0xc0, 0x1c, 0x5d, 0xcb, 0x05, 0x97, 0x71, 0xdc, 0x3e, 0x59, 0x76, 0x46, 0xed, 0x13, 0x15,
+	0xe8, 0x9c, 0x7d, 0x02, 0xc7, 0xec, 0x13, 0x6c, 0x61, 0x9f, 0x84, 0x46, 0xed, 0x13, 0xa4, 0x9f,
+	0x8b, 0x7d, 0x3b, 0x70, 0xb3, 0x66, 0xeb, 0xc6, 0x91, 0x6d, 0x79, 0x3e, 0x31, 0xa3, 0x11, 0xe3,
+	0x3e, 0x64, 0x67, 0x92, 0xce, 0xab, 0x2e, 0x67, 0x25, 0x52, 0xfd, 0xb7, 0x04, 0x14, 0xb7, 0x89,
+	0x6e, 0xfb, 0x87, 0xd3, 0xab, 0x21, 0x9f, 0x78, 0xbe, 0x3c, 0xac, 0xf8, 0x37, 0xfa, 0x1e, 0xe4,
+	0xc2, 0x9c, 0xe4, 0xda, 0x57, 0xb2, 0x10, 0x8a, 0x1e, 0xc0, 0x22, 0xdb, 0x63, 0x74, 0x1c, 0x14,
+	0x3b, 0x57, 0x3d, 0xc0, 0x48, 0x24, 0x3b, 0x64, 0x5c, 0xc2, 0x93, 0x10, 0xbe, 0x94, 0x32, 0x38,
+	0x68, 0xa2, 0xff, 0x0f, 0x45, 0xfe, 0x7e, 0x10, 0xe4, 0x5c, 0x99, 0xeb, 0x74, 0x16, 0xc4, 0x13,
+	0xa0, 0xc8, 0xb7, 0xfe, 0x27, 0x01, 0x6b, 0xbb, 0xfa, 0x64, 0x9f, 0xc8, 0xb0, 0x41, 0x4c, 0x4c,
+	0x0c, 0xea, 0x9a, 0xa8, 0x1b, 0x0d, 0x37, 0x57, 0xbc, 0x28, 0xc6, 0x09, 0xc7, 0x47, 0x9d, 0xa0,
+	0x00, 0x4b, 0x46, 0x0a, 0xb0, 0x35, 0xc8, 0x38, 0xd4, 0x31, 0x88, 0x8c, 0x45, 0xa2, 0xa1, 0x5a,
+	0xd1, 0x50, 0x53, 0x0a, 0x1f, 0xfb, 0xf8, 0x53, 0x5d, 0x9b, 0xfa, 0x61, 0x6f, 0xe8, 0x13, 0x28,
+	0xf5, 0x9a, 0x75, 0xdc, 0xec, 0xd7, 0x3a, 0x3f, 0xd4, 0x7a, 0xd5, 0x9d, 0x5e, 0xf5, 0xfe, 0x5d,
+	0xad, 0xdb, 0xd9, 0xf9, 0xf4, 0xde, 0x83, 0xbb, 0xdf, 0x53, 0x12, 0xa5, 0xf2, 0xe9, 0x59, 0xf9,
+	0x76, 0xbb, 0x5a, 0xdf, 0x11, 0x3b, 0x66, 0x9f, 0x3e, 0xeb, 0xe9, 0xb6, 0xa7, 0xdf, 0xbf, 0xdb,
+	0xa5, 0xf6, 0x84, 0x61, 0xd8, 0xb2, 0x2e, 0x46, 0xcf, 0xab, 0xe8, 0x31, 0x9c, 0xb8, 0xf4, 0x18,
+	0x9e, 0x9e, 0xe6, 0xc9, 0x4b, 0x4e, 0xf3, 0x2d, 0x58, 0x33, 0x5c, 0xea, 0x79, 0x1a, 0xcb, 0xfe,
+	0x89, 0x39, 0x57, 0x5f, 0x7c, 0xe3, 0xe2, 0x7c, 0x73, 0xb5, 0xce, 0xf8, 0x3d, 0xce, 0x96, 0xea,
+	0x57, 0x8d, 0x08, 0x89, 0xf7, 0xa4, 0xfe, 0x7e, 0x8a, 0x25, 0x52, 0xd6, 0xb1, 0x65, 0x93, 0x01,
+	0xf1, 0xd0, 0x13, 0x58, 0x31, 0x5c, 0x62, 0xb2, 0xb4, 0x5e, 0xb7, 0xa3, 0xbf, 0xe6, 0xfc, 0x7f,
+	0xb1, 0x39, 0x4d, 0x28, 0x58, 0xa9, 0x87, 0x52, 0xbd, 0x11, 0x31, 0xf0, 0xb2, 0x31, 0xd3, 0x46,
+	0x9f, 0xc1, 0x8a, 0x47, 0x6c, 0xcb, 0x19, 0x3f, 0xd3, 0x0c, 0xea, 0xf8, 0xe4, 0x59, 0xf0, 0x6e,
+	0x75, 0x9d, 0xde, 0x5e, 0x73, 0x87, 0x49, 0xd5, 0x85, 0x50, 0x0d, 0x5d, 0x9c, 0x6f, 0x2e, 0xcf,
+	0xd2, 0xf0, 0xb2, 0xd4, 0x2c, 0xdb, 0xa5, 0x36, 0x2c, 0xcf, 0x5a, 0x83, 0xd6, 0xe4, 0xde, 0xe7,
+	0x21, 0x24, 0xd8, 0xdb, 0xe8, 0x36, 0xe4, 0x5c, 0x32, 0xb0, 0x3c, 0xdf, 0x15, 0x6e, 0x66, 0x9c,
+	0x90, 0xc2, 0x76, 0xbe, 0xf8, 0x29, 0x4e, 0xe9, 0x57, 0x61, 0xae, 0x47, 0xb6, 0x59, 0x4c, 0xcb,
+	0xd3, 0xf7, 0xa5, 0xca, 0x1c, 0x0e, 0x9a, 0x6c, 0x0d, 0x8e, 0xbd, 0x30, 0x51, 0xe3, 0xdf, 0x8c,
+	0xc6, 0x33, 0x0a, 0xf9, 0xc3, 0x24, 0x9e, 0x33, 0x04, 0xbf, 0x70, 0x4c, 0x47, 0x7e, 0xe1, 0xb8,
+	0x06, 0x19, 0x9b, 0x1c, 0x13, 0x5b, 0x9c, 0xe5, 0x58, 0x34, 0xde, 0xfe, 0x59, 0x0a, 0xf2, 0xe1,
+	0x1b, 0x0d, 0x3b, 0x09, 0xda, 0xcd, 0xa7, 0xc1, 0x5a, 0x0d, 0xe9, 0x6d, 0x72, 0x82, 0x5e, 0x9b,
+	0xde, 0x29, 0x7d, 0x22, 0x1e, 0xa5, 0x43, 0x76, 0x70, 0x9f, 0xf4, 0x06, 0xe4, 0xaa, 0xbd, 0x5e,
+	0xeb, 0x51, 0xbb, 0xd9, 0x50, 0x3e, 0x4f, 0x94, 0xbe, 0x71, 0x7a, 0x56, 0x5e, 0x0d, 0x41, 0x55,
+	0x4f, 0x2c, 0x25, 0x8e, 0xaa, 0xd7, 0x9b, 0xdd, 0x7e, 0xb3, 0xa1, 0x3c, 0x4f, 0xce, 0xa3, 0xf8,
+	0x1d, 0x09, 0xff, 0x69, 0x49, 0xbe, 0x8b, 0x9b, 0xdd, 0x2a, 0x66, 0x1d, 0x7e, 0x9e, 0x14, 0x57,
+	0x5d, 0xd3, 0x1e, 0x5d, 0x32, 0xd2, 0x5d, 0xd6, 0xe7, 0x46, 0xf0, 0x13, 0xab, 0xe7, 0x29, 0xf1,
+	0xf3, 0x83, 0xe9, 0x83, 0x13, 0xd1, 0xcd, 0x09, 0xeb, 0x8d, 0xbf, 0xf4, 0x71, 0x35, 0xa9, 0xb9,
+	0xde, 0x7a, 0x2c, 0x92, 0x30, 0x2d, 0x2a, 0x2c, 0xe2, 0xbd, 0x76, 0x9b, 0x81, 0x9e, 0xa7, 0xe7,
+	0x46, 0x87, 0xc7, 0x0e, 0xab, 0x7f, 0xd1, 0x1d, 0xc8, 0x05, 0x0f, 0x81, 0xca, 0xe7, 0xe9, 0x39,
+	0x83, 0xea, 0xc1, 0x2b, 0x26, 0xef, 0x70, 0x7b, 0xaf, 0xcf, 0x7f, 0x01, 0xf6, 0x3c, 0x33, 0xdf,
+	0xe1, 0xe1, 0xd8, 0x37, 0xe9, 0x89, 0xc3, 0x76, 0xa0, 0xbc, 0x55, 0xfb, 0x3c, 0x23, 0xae, 0x20,
+	0x42, 0x8c, 0xbc, 0x52, 0x7b, 0x03, 0x72, 0xb8, 0xf9, 0x03, 0xf1, 0x63, 0xb1, 0xe7, 0xd9, 0x39,
+	0x3d, 0x98, 0x7c, 0x46, 0x0c, 0xd9, 0x5b, 0x07, 0x77, 0xb7, 0xab, 0xdc, 0xe5, 0xf3, 0xa8, 0x8e,
+	0x3b, 0x3a, 0xd4, 0x1d, 0x62, 0x4e, 0x7f, 0x83, 0x11, 0xb2, 0xde, 0xfe, 0x25, 0xc8, 0x05, 0x79,
+	0x26, 0xda, 0x80, 0xec, 0xd3, 0x0e, 0x7e, 0xdc, 0xc4, 0xca, 0x82, 0xf0, 0x61, 0xc0, 0x79, 0x2a,
+	0x2a, 0x84, 0x32, 0x2c, 0xee, 0x56, 0xdb, 0xd5, 0x47, 0x4d, 0x1c, 0x5c, 0x78, 0x07, 0x00, 0x99,
+	0x2c, 0x95, 0x14, 0xd9, 0x41, 0xa8, 0xb3, 0xb6, 0xfe, 0xc5, 0x97, 0x1b, 0x0b, 0x3f, 0xfd, 0x72,
+	0x63, 0xe1, 0xf9, 0xc5, 0x46, 0xe2, 0x8b, 0x8b, 0x8d, 0xc4, 0x4f, 0x2e, 0x36, 0x12, 0xff, 0x7a,
+	0xb1, 0x91, 0xd8, 0xcf, 0xf2, 0x90, 0xfe, 0xe0, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x48, 0x1c,
+	0x30, 0x25, 0x28, 0x30, 0x00, 0x00,
 }
 }

+ 14 - 4
vendor/github.com/docker/swarmkit/api/types.proto

@@ -30,20 +30,30 @@ message Annotations {
 	repeated IndexEntry indices = 4 [(gogoproto.nullable) = false];
 	repeated IndexEntry indices = 4 [(gogoproto.nullable) = false];
 }
 }
 
 
-message GenericString {
+// NamedGenericResource represents a "user defined" resource which is defined
+// as a string.
+// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
+// Value is used to identify the resource (GPU="UUID-1", FPGA="/dev/sdb5", ...)
+message NamedGenericResource {
 	string kind = 1;
 	string kind = 1;
 	string value = 2;
 	string value = 2;
 }
 }
 
 
-message GenericDiscrete {
+// DiscreteGenericResource represents a "user defined" resource which is defined
+// as an integer
+// "Kind" is used to describe the Kind of a resource (e.g: "GPU", "FPGA", "SSD", ...)
+// Value is used to count the resource (SSD=5, HDD=3, ...)
+message DiscreteGenericResource {
 	string kind = 1;
 	string kind = 1;
 	int64 value = 2;
 	int64 value = 2;
 }
 }
 
 
+// GenericResource represents a "user defined" resource which can
+// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1)
 message GenericResource {
 message GenericResource {
 	oneof resource {
 	oneof resource {
-		GenericString str = 1;
-		GenericDiscrete discrete = 2;
+		NamedGenericResource named_resource_spec = 1;
+		DiscreteGenericResource discrete_resource_spec = 2;
 	}
 	}
 }
 }
 
 

+ 22 - 20
vendor/github.com/docker/swarmkit/ca/config.go

@@ -14,6 +14,7 @@ import (
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
 	cfconfig "github.com/cloudflare/cfssl/config"
 	cfconfig "github.com/cloudflare/cfssl/config"
+	events "github.com/docker/go-events"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/api"
 	"github.com/docker/swarmkit/connectionbroker"
 	"github.com/docker/swarmkit/connectionbroker"
 	"github.com/docker/swarmkit/identity"
 	"github.com/docker/swarmkit/identity"
@@ -123,11 +124,11 @@ func validateRootCAAndTLSCert(rootCA *RootCA, externalCARootPool *x509.CertPool,
 }
 }
 
 
 // NewSecurityConfig initializes and returns a new SecurityConfig.
 // NewSecurityConfig initializes and returns a new SecurityConfig.
-func NewSecurityConfig(rootCA *RootCA, krw *KeyReadWriter, tlsKeyPair *tls.Certificate, issuerInfo *IssuerInfo) (*SecurityConfig, error) {
+func NewSecurityConfig(rootCA *RootCA, krw *KeyReadWriter, tlsKeyPair *tls.Certificate, issuerInfo *IssuerInfo) (*SecurityConfig, func() error, error) {
 	// Create the Server TLS Credentials for this node. These will not be used by workers.
 	// Create the Server TLS Credentials for this node. These will not be used by workers.
 	serverTLSCreds, err := rootCA.NewServerTLSCredentials(tlsKeyPair)
 	serverTLSCreds, err := rootCA.NewServerTLSCredentials(tlsKeyPair)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 
 
 	// Create a TLSConfig to be used when this node connects as a client to another remote node.
 	// Create a TLSConfig to be used when this node connects as a client to another remote node.
@@ -135,7 +136,7 @@ func NewSecurityConfig(rootCA *RootCA, krw *KeyReadWriter, tlsKeyPair *tls.Certi
 	// and managers always connect to remote managers.
 	// and managers always connect to remote managers.
 	clientTLSCreds, err := rootCA.NewClientTLSCredentials(tlsKeyPair, ManagerRole)
 	clientTLSCreds, err := rootCA.NewClientTLSCredentials(tlsKeyPair, ManagerRole)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 
 
 	// Make a new TLS config for the external CA client without a
 	// Make a new TLS config for the external CA client without a
@@ -146,18 +147,21 @@ func NewSecurityConfig(rootCA *RootCA, krw *KeyReadWriter, tlsKeyPair *tls.Certi
 		MinVersion:   tls.VersionTLS12,
 		MinVersion:   tls.VersionTLS12,
 	}
 	}
 
 
+	q := watch.NewQueue()
+
 	return &SecurityConfig{
 	return &SecurityConfig{
 		rootCA:        rootCA,
 		rootCA:        rootCA,
 		keyReadWriter: krw,
 		keyReadWriter: krw,
 
 
 		certificate: tlsKeyPair,
 		certificate: tlsKeyPair,
 		issuerInfo:  issuerInfo,
 		issuerInfo:  issuerInfo,
+		queue:       q,
 
 
 		externalCA:               NewExternalCA(rootCA, externalCATLSConfig),
 		externalCA:               NewExternalCA(rootCA, externalCATLSConfig),
 		ClientTLSCreds:           clientTLSCreds,
 		ClientTLSCreds:           clientTLSCreds,
 		ServerTLSCreds:           serverTLSCreds,
 		ServerTLSCreds:           serverTLSCreds,
 		externalCAClientRootPool: rootCA.Pool,
 		externalCAClientRootPool: rootCA.Pool,
-	}, nil
+	}, q.Close, nil
 }
 }
 
 
 // RootCA returns the root CA.
 // RootCA returns the root CA.
@@ -200,11 +204,9 @@ func (s *SecurityConfig) UpdateRootCA(rootCA *RootCA, externalCARootPool *x509.C
 	return s.updateTLSCredentials(s.certificate, s.issuerInfo)
 	return s.updateTLSCredentials(s.certificate, s.issuerInfo)
 }
 }
 
 
-// SetWatch allows you to set a watch on the security config, in order to be notified of any changes
-func (s *SecurityConfig) SetWatch(q *watch.Queue) {
-	s.mu.Lock()
-	defer s.mu.Unlock()
-	s.queue = q
+// Watch allows you to set a watch on the security config, in order to be notified of any changes
+func (s *SecurityConfig) Watch() (chan events.Event, func()) {
+	return s.queue.Watch()
 }
 }
 
 
 // IssuerInfo returns the issuer subject and issuer public key
 // IssuerInfo returns the issuer subject and issuer public key
@@ -382,7 +384,7 @@ func DownloadRootCA(ctx context.Context, paths CertPaths, token string, connBrok
 
 
 // LoadSecurityConfig loads TLS credentials from disk, or returns an error if
 // LoadSecurityConfig loads TLS credentials from disk, or returns an error if
 // these credentials do not exist or are unusable.
 // these credentials do not exist or are unusable.
-func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter, allowExpired bool) (*SecurityConfig, error) {
+func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter, allowExpired bool) (*SecurityConfig, func() error, error) {
 	ctx = log.WithModule(ctx, "tls")
 	ctx = log.WithModule(ctx, "tls")
 
 
 	// At this point we've successfully loaded the CA details from disk, or
 	// At this point we've successfully loaded the CA details from disk, or
@@ -392,13 +394,13 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter,
 	// Read both the Cert and Key from disk
 	// Read both the Cert and Key from disk
 	cert, key, err := krw.Read()
 	cert, key, err := krw.Read()
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 
 
 	// Check to see if this certificate was signed by our CA, and isn't expired
 	// Check to see if this certificate was signed by our CA, and isn't expired
 	_, chains, err := ValidateCertChain(rootCA.Pool, cert, allowExpired)
 	_, chains, err := ValidateCertChain(rootCA.Pool, cert, allowExpired)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 	// ValidateChain, if successful, will always return at least 1 chain containing
 	// ValidateChain, if successful, will always return at least 1 chain containing
 	// at least 2 certificates:  the leaf and the root.
 	// at least 2 certificates:  the leaf and the root.
@@ -408,10 +410,10 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter,
 	// credentials
 	// credentials
 	keyPair, err := tls.X509KeyPair(cert, key)
 	keyPair, err := tls.X509KeyPair(cert, key)
 	if err != nil {
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 
 
-	secConfig, err := NewSecurityConfig(&rootCA, krw, &keyPair, &IssuerInfo{
+	secConfig, cleanup, err := NewSecurityConfig(&rootCA, krw, &keyPair, &IssuerInfo{
 		Subject:   issuer.RawSubject,
 		Subject:   issuer.RawSubject,
 		PublicKey: issuer.RawSubjectPublicKeyInfo,
 		PublicKey: issuer.RawSubjectPublicKeyInfo,
 	})
 	})
@@ -421,7 +423,7 @@ func LoadSecurityConfig(ctx context.Context, rootCA RootCA, krw *KeyReadWriter,
 			"node.role": secConfig.ClientTLSCreds.Role(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 		}).Debug("loaded node credentials")
 		}).Debug("loaded node credentials")
 	}
 	}
-	return secConfig, err
+	return secConfig, cleanup, err
 }
 }
 
 
 // CertificateRequestConfig contains the information needed to request a
 // CertificateRequestConfig contains the information needed to request a
@@ -450,7 +452,7 @@ type CertificateRequestConfig struct {
 
 
 // CreateSecurityConfig creates a new key and cert for this node, either locally
 // CreateSecurityConfig creates a new key and cert for this node, either locally
 // or via a remote CA.
 // or via a remote CA.
-func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWriter, config CertificateRequestConfig) (*SecurityConfig, error) {
+func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWriter, config CertificateRequestConfig) (*SecurityConfig, func() error, error) {
 	ctx = log.WithModule(ctx, "tls")
 	ctx = log.WithModule(ctx, "tls")
 
 
 	// Create a new random ID for this certificate
 	// Create a new random ID for this certificate
@@ -467,7 +469,7 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 		tlsKeyPair, issuerInfo, err = rootCA.RequestAndSaveNewCertificates(ctx, krw, config)
 		tlsKeyPair, issuerInfo, err = rootCA.RequestAndSaveNewCertificates(ctx, krw, config)
 		if err != nil {
 		if err != nil {
 			log.G(ctx).WithError(err).Error("failed to request and save new certificate")
 			log.G(ctx).WithError(err).Error("failed to request and save new certificate")
-			return nil, err
+			return nil, nil, err
 		}
 		}
 	case nil:
 	case nil:
 		log.G(ctx).WithFields(logrus.Fields{
 		log.G(ctx).WithFields(logrus.Fields{
@@ -479,17 +481,17 @@ func (rootCA RootCA) CreateSecurityConfig(ctx context.Context, krw *KeyReadWrite
 			"node.id":   cn,
 			"node.id":   cn,
 			"node.role": proposedRole,
 			"node.role": proposedRole,
 		}).WithError(err).Errorf("failed to issue and save new certificate")
 		}).WithError(err).Errorf("failed to issue and save new certificate")
-		return nil, err
+		return nil, nil, err
 	}
 	}
 
 
-	secConfig, err := NewSecurityConfig(&rootCA, krw, tlsKeyPair, issuerInfo)
+	secConfig, cleanup, err := NewSecurityConfig(&rootCA, krw, tlsKeyPair, issuerInfo)
 	if err == nil {
 	if err == nil {
 		log.G(ctx).WithFields(logrus.Fields{
 		log.G(ctx).WithFields(logrus.Fields{
 			"node.id":   secConfig.ClientTLSCreds.NodeID(),
 			"node.id":   secConfig.ClientTLSCreds.NodeID(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 			"node.role": secConfig.ClientTLSCreds.Role(),
 		}).Debugf("new node credentials generated: %s", krw.Target())
 		}).Debugf("new node credentials generated: %s", krw.Target())
 	}
 	}
-	return secConfig, err
+	return secConfig, cleanup, err
 }
 }
 
 
 // TODO(cyli): currently we have to only update if it's a worker role - if we have a single root CA update path for
 // TODO(cyli): currently we have to only update if it's a worker role - if we have a single root CA update path for

+ 15 - 3
vendor/github.com/docker/swarmkit/ca/external.go

@@ -8,6 +8,7 @@ import (
 	"encoding/hex"
 	"encoding/hex"
 	"encoding/json"
 	"encoding/json"
 	"encoding/pem"
 	"encoding/pem"
+	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
 	"sync"
 	"sync"
@@ -24,8 +25,18 @@ import (
 	"golang.org/x/net/context/ctxhttp"
 	"golang.org/x/net/context/ctxhttp"
 )
 )
 
 
-// ExternalCrossSignProfile is the profile that we will be sending cross-signing CSR sign requests with
-const ExternalCrossSignProfile = "CA"
+const (
+	// ExternalCrossSignProfile is the profile that we will be sending cross-signing CSR sign requests with
+	ExternalCrossSignProfile = "CA"
+
+	// CertificateMaxSize is the maximum expected size of a certificate.
+	// While there is no specced upper limit to the size of an x509 certificate in PEM format,
+	// one with a ridiculous RSA key size (16384) and 26 256-character DNS SAN fields is about 14k.
+	// While there is no upper limit on the length of certificate chains, long chains are impractical.
+	// To be conservative, and to also account for external CA certificate responses in JSON format
+	// from CFSSL, we'll set the max to be 256KiB.
+	CertificateMaxSize int64 = 256 << 10
+)
 
 
 // ErrNoExternalCAURLs is an error used it indicate that an ExternalCA is
 // ErrNoExternalCAURLs is an error used it indicate that an ExternalCA is
 // configured with no URLs to which it can proxy certificate signing requests.
 // configured with no URLs to which it can proxy certificate signing requests.
@@ -191,7 +202,8 @@ func makeExternalSignRequest(ctx context.Context, client *http.Client, url strin
 	}
 	}
 	defer resp.Body.Close()
 	defer resp.Body.Close()
 
 
-	body, err := ioutil.ReadAll(resp.Body)
+	b := io.LimitReader(resp.Body, CertificateMaxSize)
+	body, err := ioutil.ReadAll(b)
 	if err != nil {
 	if err != nil {
 		return nil, recoverableErr{err: errors.Wrap(err, "unable to read CSR response body")}
 		return nil, recoverableErr{err: errors.Wrap(err, "unable to read CSR response body")}
 	}
 	}

+ 7 - 1
vendor/github.com/docker/swarmkit/manager/controlapi/service.go

@@ -128,7 +128,13 @@ func validateContainerSpec(taskSpec api.TaskSpec) error {
 	// Building a empty/dummy Task to validate the templating and
 	// Building a empty/dummy Task to validate the templating and
 	// the resulting container spec as well. This is a *best effort*
 	// the resulting container spec as well. This is a *best effort*
 	// validation.
 	// validation.
-	container, err := template.ExpandContainerSpec(&api.Task{
+	container, err := template.ExpandContainerSpec(&api.NodeDescription{
+		Hostname: "nodeHostname",
+		Platform: &api.Platform{
+			OS:           "os",
+			Architecture: "architecture",
+		},
+	}, &api.Task{
 		Spec:      taskSpec,
 		Spec:      taskSpec,
 		ServiceID: "serviceid",
 		ServiceID: "serviceid",
 		Slot:      1,
 		Slot:      1,

+ 5 - 5
vendor/github.com/docker/swarmkit/manager/dispatcher/dispatcher.go

@@ -475,7 +475,7 @@ func (d *Dispatcher) register(ctx context.Context, nodeID string, description *a
 
 
 	addr, err := nodeIPFromContext(ctx)
 	addr, err := nodeIPFromContext(ctx)
 	if err != nil {
 	if err != nil {
-		log.G(ctx).Debug(err.Error())
+		log.G(ctx).WithError(err).Debug("failed to get remote node IP")
 	}
 	}
 
 
 	if err := d.markNodeReady(dctx, nodeID, description, addr); err != nil {
 	if err := d.markNodeReady(dctx, nodeID, description, addr); err != nil {
@@ -483,7 +483,7 @@ func (d *Dispatcher) register(ctx context.Context, nodeID string, description *a
 	}
 	}
 
 
 	expireFunc := func() {
 	expireFunc := func() {
-		log.G(ctx).Debugf("heartbeat expiration")
+		log.G(ctx).Debug("heartbeat expiration")
 		if err := d.markNodeNotReady(nodeID, api.NodeStatus_DOWN, "heartbeat failure"); err != nil {
 		if err := d.markNodeNotReady(nodeID, api.NodeStatus_DOWN, "heartbeat failure"); err != nil {
 			log.G(ctx).WithError(err).Errorf("failed deregistering node after heartbeat expiration")
 			log.G(ctx).WithError(err).Errorf("failed deregistering node after heartbeat expiration")
 		}
 		}
@@ -703,7 +703,7 @@ func (d *Dispatcher) Tasks(r *api.TasksRequest, stream api.Dispatcher_TasksServe
 	if nodeInfo.ForwardedBy != nil {
 	if nodeInfo.ForwardedBy != nil {
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 	}
 	}
-	log.G(stream.Context()).WithFields(fields).Debugf("")
+	log.G(stream.Context()).WithFields(fields).Debug("")
 
 
 	if _, err = d.nodes.GetWithSession(nodeID, r.SessionID); err != nil {
 	if _, err = d.nodes.GetWithSession(nodeID, r.SessionID); err != nil {
 		return err
 		return err
@@ -827,7 +827,7 @@ func (d *Dispatcher) Assignments(r *api.AssignmentsRequest, stream api.Dispatche
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 		fields["forwarder.id"] = nodeInfo.ForwardedBy.NodeID
 	}
 	}
 	log := log.G(stream.Context()).WithFields(fields)
 	log := log.G(stream.Context()).WithFields(fields)
-	log.Debugf("")
+	log.Debug("")
 
 
 	if _, err = d.nodes.GetWithSession(nodeID, r.SessionID); err != nil {
 	if _, err = d.nodes.GetWithSession(nodeID, r.SessionID); err != nil {
 		return err
 		return err
@@ -1118,7 +1118,7 @@ func (d *Dispatcher) Session(r *api.SessionRequest, stream api.Dispatcher_Sessio
 		// get the node IP addr
 		// get the node IP addr
 		addr, err := nodeIPFromContext(stream.Context())
 		addr, err := nodeIPFromContext(stream.Context())
 		if err != nil {
 		if err != nil {
-			log.G(ctx).Debugf(err.Error())
+			log.G(ctx).WithError(err).Debug("failed to get remote node IP")
 		}
 		}
 		// update the node description
 		// update the node description
 		if err := d.markNodeReady(dctx, nodeID, r.Description, addr); err != nil {
 		if err := d.markNodeReady(dctx, nodeID, r.Description, addr); err != nil {

+ 25 - 16
vendor/github.com/docker/swarmkit/manager/orchestrator/global/global.go

@@ -159,13 +159,13 @@ func (g *Orchestrator) Run(ctx context.Context) error {
 				switch v.Node.Status.State {
 				switch v.Node.Status.State {
 				// NodeStatus_DISCONNECTED is a transient state, no need to make any change
 				// NodeStatus_DISCONNECTED is a transient state, no need to make any change
 				case api.NodeStatus_DOWN:
 				case api.NodeStatus_DOWN:
-					g.removeTasksFromNode(ctx, v.Node)
+					g.foreachTaskFromNode(ctx, v.Node, g.shutdownTask)
 				case api.NodeStatus_READY:
 				case api.NodeStatus_READY:
 					// node could come back to READY from DOWN or DISCONNECT
 					// node could come back to READY from DOWN or DISCONNECT
 					g.reconcileOneNode(ctx, v.Node)
 					g.reconcileOneNode(ctx, v.Node)
 				}
 				}
 			case api.EventDeleteNode:
 			case api.EventDeleteNode:
-				g.removeTasksFromNode(ctx, v.Node)
+				g.foreachTaskFromNode(ctx, v.Node, g.deleteTask)
 				delete(g.nodes, v.Node.ID)
 				delete(g.nodes, v.Node.ID)
 			case api.EventUpdateTask:
 			case api.EventUpdateTask:
 				g.handleTaskChange(ctx, v.Task)
 				g.handleTaskChange(ctx, v.Task)
@@ -201,7 +201,7 @@ func (g *Orchestrator) FixTask(ctx context.Context, batch *store.Batch, t *api.T
 	}
 	}
 	// if the node no longer valid, remove the task
 	// if the node no longer valid, remove the task
 	if t.NodeID == "" || orchestrator.InvalidNode(node) {
 	if t.NodeID == "" || orchestrator.InvalidNode(node) {
-		g.removeTask(ctx, batch, t)
+		g.shutdownTask(ctx, batch, t)
 		return
 		return
 	}
 	}
 
 
@@ -236,7 +236,7 @@ func (g *Orchestrator) Stop() {
 	g.restarts.CancelAll()
 	g.restarts.CancelAll()
 }
 }
 
 
-func (g *Orchestrator) removeTasksFromNode(ctx context.Context, node *api.Node) {
+func (g *Orchestrator) foreachTaskFromNode(ctx context.Context, node *api.Node, cb func(context.Context, *store.Batch, *api.Task)) {
 	var (
 	var (
 		tasks []*api.Task
 		tasks []*api.Task
 		err   error
 		err   error
@@ -245,7 +245,7 @@ func (g *Orchestrator) removeTasksFromNode(ctx context.Context, node *api.Node)
 		tasks, err = store.FindTasks(tx, store.ByNodeID(node.ID))
 		tasks, err = store.FindTasks(tx, store.ByNodeID(node.ID))
 	})
 	})
 	if err != nil {
 	if err != nil {
-		log.G(ctx).WithError(err).Errorf("global orchestrator: removeTasksFromNode failed finding tasks")
+		log.G(ctx).WithError(err).Errorf("global orchestrator: foreachTaskFromNode failed finding tasks")
 		return
 		return
 	}
 	}
 
 
@@ -253,13 +253,13 @@ func (g *Orchestrator) removeTasksFromNode(ctx context.Context, node *api.Node)
 		for _, t := range tasks {
 		for _, t := range tasks {
 			// Global orchestrator only removes tasks from globalServices
 			// Global orchestrator only removes tasks from globalServices
 			if _, exists := g.globalServices[t.ServiceID]; exists {
 			if _, exists := g.globalServices[t.ServiceID]; exists {
-				g.removeTask(ctx, batch, t)
+				cb(ctx, batch, t)
 			}
 			}
 		}
 		}
 		return nil
 		return nil
 	})
 	})
 	if err != nil {
 	if err != nil {
-		log.G(ctx).WithError(err).Errorf("global orchestrator: removeTasksFromNode failed batching tasks")
+		log.G(ctx).WithError(err).Errorf("global orchestrator: foreachTaskFromNode failed batching tasks")
 	}
 	}
 }
 }
 
 
@@ -314,7 +314,7 @@ func (g *Orchestrator) reconcileServices(ctx context.Context, serviceIDs []strin
 				// if restart policy considers this node has finished its task
 				// if restart policy considers this node has finished its task
 				// it should remove all running tasks
 				// it should remove all running tasks
 				if _, exists := nodeCompleted[serviceID][nodeID]; exists || !meetsConstraints {
 				if _, exists := nodeCompleted[serviceID][nodeID]; exists || !meetsConstraints {
-					g.removeTasks(ctx, batch, ntasks)
+					g.shutdownTasks(ctx, batch, ntasks)
 					continue
 					continue
 				}
 				}
 
 
@@ -340,7 +340,7 @@ func (g *Orchestrator) reconcileServices(ctx context.Context, serviceIDs []strin
 			// These must be associated with nodes that are drained, or
 			// These must be associated with nodes that are drained, or
 			// nodes that no longer exist.
 			// nodes that no longer exist.
 			for _, ntasks := range nodeTasks[serviceID] {
 			for _, ntasks := range nodeTasks[serviceID] {
-				g.removeTasks(ctx, batch, ntasks)
+				g.shutdownTasks(ctx, batch, ntasks)
 			}
 			}
 		}
 		}
 		return nil
 		return nil
@@ -382,7 +382,7 @@ func (g *Orchestrator) updateService(service *api.Service) {
 func (g *Orchestrator) reconcileOneNode(ctx context.Context, node *api.Node) {
 func (g *Orchestrator) reconcileOneNode(ctx context.Context, node *api.Node) {
 	if node.Spec.Availability == api.NodeAvailabilityDrain {
 	if node.Spec.Availability == api.NodeAvailabilityDrain {
 		log.G(ctx).Debugf("global orchestrator: node %s in drain state, removing tasks from it", node.ID)
 		log.G(ctx).Debugf("global orchestrator: node %s in drain state, removing tasks from it", node.ID)
-		g.removeTasksFromNode(ctx, node)
+		g.foreachTaskFromNode(ctx, node, g.shutdownTask)
 		return
 		return
 	}
 	}
 
 
@@ -447,7 +447,7 @@ func (g *Orchestrator) reconcileServicesOneNode(ctx context.Context, serviceIDs
 			// if restart policy considers this node has finished its task
 			// if restart policy considers this node has finished its task
 			// it should remove all running tasks
 			// it should remove all running tasks
 			if completed[serviceID] {
 			if completed[serviceID] {
-				g.removeTasks(ctx, batch, tasks[serviceID])
+				g.shutdownTasks(ctx, batch, tasks[serviceID])
 				continue
 				continue
 			}
 			}
 
 
@@ -491,7 +491,7 @@ func (g *Orchestrator) reconcileServicesOneNode(ctx context.Context, serviceIDs
 				} else {
 				} else {
 					dirtyTasks = append(dirtyTasks, cleanTasks[1:]...)
 					dirtyTasks = append(dirtyTasks, cleanTasks[1:]...)
 				}
 				}
-				g.removeTasks(ctx, batch, dirtyTasks)
+				g.shutdownTasks(ctx, batch, dirtyTasks)
 			}
 			}
 		}
 		}
 		return nil
 		return nil
@@ -542,7 +542,7 @@ func (g *Orchestrator) tickTasks(ctx context.Context) {
 	g.restartTasks = make(map[string]struct{})
 	g.restartTasks = make(map[string]struct{})
 }
 }
 
 
-func (g *Orchestrator) removeTask(ctx context.Context, batch *store.Batch, t *api.Task) {
+func (g *Orchestrator) shutdownTask(ctx context.Context, batch *store.Batch, t *api.Task) {
 	// set existing task DesiredState to TaskStateShutdown
 	// set existing task DesiredState to TaskStateShutdown
 	// TODO(aaronl): optimistic update?
 	// TODO(aaronl): optimistic update?
 	err := batch.Update(func(tx store.Tx) error {
 	err := batch.Update(func(tx store.Tx) error {
@@ -554,7 +554,7 @@ func (g *Orchestrator) removeTask(ctx context.Context, batch *store.Batch, t *ap
 		return nil
 		return nil
 	})
 	})
 	if err != nil {
 	if err != nil {
-		log.G(ctx).WithError(err).Errorf("global orchestrator: removeTask failed to remove %s", t.ID)
+		log.G(ctx).WithError(err).Errorf("global orchestrator: shutdownTask failed to shut down %s", t.ID)
 	}
 	}
 }
 }
 
 
@@ -572,9 +572,18 @@ func (g *Orchestrator) addTask(ctx context.Context, batch *store.Batch, service
 	}
 	}
 }
 }
 
 
-func (g *Orchestrator) removeTasks(ctx context.Context, batch *store.Batch, tasks []*api.Task) {
+func (g *Orchestrator) shutdownTasks(ctx context.Context, batch *store.Batch, tasks []*api.Task) {
 	for _, t := range tasks {
 	for _, t := range tasks {
-		g.removeTask(ctx, batch, t)
+		g.shutdownTask(ctx, batch, t)
+	}
+}
+
+func (g *Orchestrator) deleteTask(ctx context.Context, batch *store.Batch, t *api.Task) {
+	err := batch.Update(func(tx store.Tx) error {
+		return store.DeleteTask(tx, t.ID)
+	})
+	if err != nil {
+		log.G(ctx).WithError(err).Errorf("global orchestrator: deleteTask failed to delete %s", t.ID)
 	}
 	}
 }
 }
 
 

+ 55 - 15
vendor/github.com/docker/swarmkit/manager/scheduler/nodeinfo.go

@@ -15,6 +15,15 @@ type hostPortSpec struct {
 	publishedPort uint32
 	publishedPort uint32
 }
 }
 
 
+// versionedService defines a tuple that contains a service ID and a spec
+// version, so that failures can be tracked per spec version. Note that if the
+// task predates spec versioning, specVersion will contain the zero value, and
+// this will still work correctly.
+type versionedService struct {
+	serviceID   string
+	specVersion api.Version
+}
+
 // NodeInfo contains a node and some additional metadata.
 // NodeInfo contains a node and some additional metadata.
 type NodeInfo struct {
 type NodeInfo struct {
 	*api.Node
 	*api.Node
@@ -24,12 +33,14 @@ type NodeInfo struct {
 	AvailableResources        *api.Resources
 	AvailableResources        *api.Resources
 	usedHostPorts             map[hostPortSpec]struct{}
 	usedHostPorts             map[hostPortSpec]struct{}
 
 
-	// recentFailures is a map from service ID to the timestamps of the
-	// most recent failures the node has experienced from replicas of that
-	// service.
-	// TODO(aaronl): When spec versioning is supported, this should track
-	// the version of the spec that failed.
-	recentFailures map[string][]time.Time
+	// recentFailures is a map from service ID/version to the timestamps of
+	// the most recent failures the node has experienced from replicas of
+	// that service.
+	recentFailures map[versionedService][]time.Time
+
+	// lastCleanup is the last time recentFailures was cleaned up. This is
+	// done periodically to avoid recentFailures growing without any limit.
+	lastCleanup time.Time
 }
 }
 
 
 func newNodeInfo(n *api.Node, tasks map[string]*api.Task, availableResources api.Resources) NodeInfo {
 func newNodeInfo(n *api.Node, tasks map[string]*api.Task, availableResources api.Resources) NodeInfo {
@@ -39,7 +50,8 @@ func newNodeInfo(n *api.Node, tasks map[string]*api.Task, availableResources api
 		ActiveTasksCountByService: make(map[string]int),
 		ActiveTasksCountByService: make(map[string]int),
 		AvailableResources:        availableResources.Copy(),
 		AvailableResources:        availableResources.Copy(),
 		usedHostPorts:             make(map[hostPortSpec]struct{}),
 		usedHostPorts:             make(map[hostPortSpec]struct{}),
-		recentFailures:            make(map[string][]time.Time),
+		recentFailures:            make(map[versionedService][]time.Time),
+		lastCleanup:               time.Now(),
 	}
 	}
 
 
 	for _, t := range tasks {
 	for _, t := range tasks {
@@ -148,30 +160,58 @@ func taskReservations(spec api.TaskSpec) (reservations api.Resources) {
 	return
 	return
 }
 }
 
 
+func (nodeInfo *NodeInfo) cleanupFailures(now time.Time) {
+entriesLoop:
+	for key, failuresEntry := range nodeInfo.recentFailures {
+		for _, timestamp := range failuresEntry {
+			if now.Sub(timestamp) < monitorFailures {
+				continue entriesLoop
+			}
+		}
+		delete(nodeInfo.recentFailures, key)
+	}
+	nodeInfo.lastCleanup = now
+}
+
 // taskFailed records a task failure from a given service.
 // taskFailed records a task failure from a given service.
-func (nodeInfo *NodeInfo) taskFailed(ctx context.Context, serviceID string) {
+func (nodeInfo *NodeInfo) taskFailed(ctx context.Context, t *api.Task) {
 	expired := 0
 	expired := 0
 	now := time.Now()
 	now := time.Now()
-	for _, timestamp := range nodeInfo.recentFailures[serviceID] {
+
+	if now.Sub(nodeInfo.lastCleanup) >= monitorFailures {
+		nodeInfo.cleanupFailures(now)
+	}
+
+	versionedService := versionedService{serviceID: t.ServiceID}
+	if t.SpecVersion != nil {
+		versionedService.specVersion = *t.SpecVersion
+	}
+
+	for _, timestamp := range nodeInfo.recentFailures[versionedService] {
 		if now.Sub(timestamp) < monitorFailures {
 		if now.Sub(timestamp) < monitorFailures {
 			break
 			break
 		}
 		}
 		expired++
 		expired++
 	}
 	}
 
 
-	if len(nodeInfo.recentFailures[serviceID])-expired == maxFailures-1 {
-		log.G(ctx).Warnf("underweighting node %s for service %s because it experienced %d failures or rejections within %s", nodeInfo.ID, serviceID, maxFailures, monitorFailures.String())
+	if len(nodeInfo.recentFailures[versionedService])-expired == maxFailures-1 {
+		log.G(ctx).Warnf("underweighting node %s for service %s because it experienced %d failures or rejections within %s", nodeInfo.ID, t.ServiceID, maxFailures, monitorFailures.String())
 	}
 	}
 
 
-	nodeInfo.recentFailures[serviceID] = append(nodeInfo.recentFailures[serviceID][expired:], now)
+	nodeInfo.recentFailures[versionedService] = append(nodeInfo.recentFailures[versionedService][expired:], now)
 }
 }
 
 
 // countRecentFailures returns the number of times the service has failed on
 // countRecentFailures returns the number of times the service has failed on
 // this node within the lookback window monitorFailures.
 // this node within the lookback window monitorFailures.
-func (nodeInfo *NodeInfo) countRecentFailures(now time.Time, serviceID string) int {
-	recentFailureCount := len(nodeInfo.recentFailures[serviceID])
+func (nodeInfo *NodeInfo) countRecentFailures(now time.Time, t *api.Task) int {
+	versionedService := versionedService{serviceID: t.ServiceID}
+	if t.SpecVersion != nil {
+		versionedService.specVersion = *t.SpecVersion
+	}
+
+	recentFailureCount := len(nodeInfo.recentFailures[versionedService])
 	for i := recentFailureCount - 1; i >= 0; i-- {
 	for i := recentFailureCount - 1; i >= 0; i-- {
-		if now.Sub(nodeInfo.recentFailures[serviceID][i]) > monitorFailures {
+		if now.Sub(nodeInfo.recentFailures[versionedService][i]) > monitorFailures {
 			recentFailureCount -= i + 1
 			recentFailureCount -= i + 1
 			break
 			break
 		}
 		}

+ 3 - 3
vendor/github.com/docker/swarmkit/manager/scheduler/scheduler.go

@@ -261,7 +261,7 @@ func (s *Scheduler) updateTask(ctx context.Context, t *api.Task) bool {
 			if _, wasPreassigned := s.preassignedTasks[t.ID]; !wasPreassigned {
 			if _, wasPreassigned := s.preassignedTasks[t.ID]; !wasPreassigned {
 				nodeInfo, err := s.nodeSet.nodeInfo(t.NodeID)
 				nodeInfo, err := s.nodeSet.nodeInfo(t.NodeID)
 				if err == nil {
 				if err == nil {
-					nodeInfo.taskFailed(ctx, t.ServiceID)
+					nodeInfo.taskFailed(ctx, t)
 					s.nodeSet.updateNode(nodeInfo)
 					s.nodeSet.updateNode(nodeInfo)
 				}
 				}
 			}
 			}
@@ -543,8 +543,8 @@ func (s *Scheduler) scheduleTaskGroup(ctx context.Context, taskGroup map[string]
 	nodeLess := func(a *NodeInfo, b *NodeInfo) bool {
 	nodeLess := func(a *NodeInfo, b *NodeInfo) bool {
 		// If either node has at least maxFailures recent failures,
 		// If either node has at least maxFailures recent failures,
 		// that's the deciding factor.
 		// that's the deciding factor.
-		recentFailuresA := a.countRecentFailures(now, t.ServiceID)
-		recentFailuresB := b.countRecentFailures(now, t.ServiceID)
+		recentFailuresA := a.countRecentFailures(now, t)
+		recentFailuresB := b.countRecentFailures(now, t)
 
 
 		if recentFailuresA >= maxFailures || recentFailuresB >= maxFailures {
 		if recentFailuresA >= maxFailures || recentFailuresB >= maxFailures {
 			if recentFailuresA > recentFailuresB {
 			if recentFailuresA > recentFailuresB {

+ 4 - 14
vendor/github.com/docker/swarmkit/manager/state/store/clusters.go

@@ -43,21 +43,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			clusters, err := FindClusters(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Clusters))
+			for i, x := range snapshot.Clusters {
+				toStoreObj[i] = x
 			}
 			}
-			for _, n := range clusters {
-				if err := DeleteCluster(tx, n.ID); err != nil {
-					return err
-				}
-			}
-			for _, n := range snapshot.Clusters {
-				if err := CreateCluster(tx, n); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableCluster, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {

+ 4 - 14
vendor/github.com/docker/swarmkit/manager/state/store/configs.go

@@ -37,21 +37,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			configs, err := FindConfigs(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Configs))
+			for i, x := range snapshot.Configs {
+				toStoreObj[i] = x
 			}
 			}
-			for _, s := range configs {
-				if err := DeleteConfig(tx, s.ID); err != nil {
-					return err
-				}
-			}
-			for _, s := range snapshot.Configs {
-				if err := CreateConfig(tx, s); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableConfig, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {

+ 12 - 14
vendor/github.com/docker/swarmkit/manager/state/store/extensions.go

@@ -38,21 +38,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			extensions, err := FindExtensions(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Extensions))
+			for i, x := range snapshot.Extensions {
+				toStoreObj[i] = extensionEntry{x}
 			}
 			}
-			for _, e := range extensions {
-				if err := DeleteExtension(tx, e.ID); err != nil {
-					return err
-				}
-			}
-			for _, e := range snapshot.Extensions {
-				if err := CreateExtension(tx, e); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableExtension, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {
@@ -80,6 +70,14 @@ func (e extensionEntry) CopyStoreObject() api.StoreObject {
 	return extensionEntry{Extension: e.Extension.Copy()}
 	return extensionEntry{Extension: e.Extension.Copy()}
 }
 }
 
 
+// ensure that when update events are emitted, we unwrap extensionEntry
+func (e extensionEntry) EventUpdate(oldObject api.StoreObject) api.Event {
+	if oldObject != nil {
+		return api.EventUpdateExtension{Extension: e.Extension, OldExtension: oldObject.(extensionEntry).Extension}
+	}
+	return api.EventUpdateExtension{Extension: e.Extension}
+}
+
 // CreateExtension adds a new extension to the store.
 // CreateExtension adds a new extension to the store.
 // Returns ErrExist if the ID is already taken.
 // Returns ErrExist if the ID is already taken.
 func CreateExtension(tx Tx, e *api.Extension) error {
 func CreateExtension(tx Tx, e *api.Extension) error {

+ 4 - 14
vendor/github.com/docker/swarmkit/manager/state/store/networks.go

@@ -37,21 +37,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			networks, err := FindNetworks(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Networks))
+			for i, x := range snapshot.Networks {
+				toStoreObj[i] = x
 			}
 			}
-			for _, n := range networks {
-				if err := DeleteNetwork(tx, n.ID); err != nil {
-					return err
-				}
-			}
-			for _, n := range snapshot.Networks {
-				if err := CreateNetwork(tx, n); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableNetwork, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {

+ 4 - 14
vendor/github.com/docker/swarmkit/manager/state/store/nodes.go

@@ -47,21 +47,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			nodes, err := FindNodes(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Nodes))
+			for i, x := range snapshot.Nodes {
+				toStoreObj[i] = x
 			}
 			}
-			for _, n := range nodes {
-				if err := DeleteNode(tx, n.ID); err != nil {
-					return err
-				}
-			}
-			for _, n := range snapshot.Nodes {
-				if err := CreateNode(tx, n); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableNode, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {

+ 43 - 0
vendor/github.com/docker/swarmkit/manager/state/store/object.go

@@ -13,3 +13,46 @@ type ObjectStoreConfig struct {
 	Restore          func(Tx, *api.StoreSnapshot) error
 	Restore          func(Tx, *api.StoreSnapshot) error
 	ApplyStoreAction func(Tx, api.StoreAction) error
 	ApplyStoreAction func(Tx, api.StoreAction) error
 }
 }
+
+// RestoreTable takes a list of new objects of a particular type (e.g. clusters,
+// nodes, etc., which conform to the StoreObject interface) and replaces the
+// existing objects in the store of that type with the new objects.
+func RestoreTable(tx Tx, table string, newObjects []api.StoreObject) error {
+	checkType := func(by By) error {
+		return nil
+	}
+	var oldObjects []api.StoreObject
+	appendResult := func(o api.StoreObject) {
+		oldObjects = append(oldObjects, o)
+	}
+
+	err := tx.find(table, All, checkType, appendResult)
+	if err != nil {
+		return nil
+	}
+
+	updated := make(map[string]struct{})
+
+	for _, o := range newObjects {
+		objectID := o.GetID()
+		if existing := tx.lookup(table, indexID, objectID); existing != nil {
+			if err := tx.update(table, o); err != nil {
+				return err
+			}
+			updated[objectID] = struct{}{}
+		} else {
+			if err := tx.create(table, o); err != nil {
+				return err
+			}
+		}
+	}
+	for _, o := range oldObjects {
+		objectID := o.GetID()
+		if _, ok := updated[objectID]; !ok {
+			if err := tx.delete(table, objectID); err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}

+ 12 - 14
vendor/github.com/docker/swarmkit/manager/state/store/resources.go

@@ -40,21 +40,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			resources, err := FindResources(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Resources))
+			for i, x := range snapshot.Resources {
+				toStoreObj[i] = resourceEntry{x}
 			}
 			}
-			for _, r := range resources {
-				if err := DeleteResource(tx, r.ID); err != nil {
-					return err
-				}
-			}
-			for _, r := range snapshot.Resources {
-				if err := CreateResource(tx, r); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableResource, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {
@@ -82,6 +72,14 @@ func (r resourceEntry) CopyStoreObject() api.StoreObject {
 	return resourceEntry{Resource: r.Resource.Copy()}
 	return resourceEntry{Resource: r.Resource.Copy()}
 }
 }
 
 
+// ensure that when update events are emitted, we unwrap resourceEntry
+func (r resourceEntry) EventUpdate(oldObject api.StoreObject) api.Event {
+	if oldObject != nil {
+		return api.EventUpdateResource{Resource: r.Resource, OldResource: oldObject.(resourceEntry).Resource}
+	}
+	return api.EventUpdateResource{Resource: r.Resource}
+}
+
 func confirmExtension(tx Tx, r *api.Resource) error {
 func confirmExtension(tx Tx, r *api.Resource) error {
 	// There must be an extension corresponding to the Kind field.
 	// There must be an extension corresponding to the Kind field.
 	extensions, err := FindExtensions(tx, ByName(r.Kind))
 	extensions, err := FindExtensions(tx, ByName(r.Kind))

+ 4 - 14
vendor/github.com/docker/swarmkit/manager/state/store/secrets.go

@@ -37,21 +37,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			secrets, err := FindSecrets(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Secrets))
+			for i, x := range snapshot.Secrets {
+				toStoreObj[i] = x
 			}
 			}
-			for _, s := range secrets {
-				if err := DeleteSecret(tx, s.ID); err != nil {
-					return err
-				}
-			}
-			for _, s := range snapshot.Secrets {
-				if err := CreateSecret(tx, s); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableSecret, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {

+ 4 - 14
vendor/github.com/docker/swarmkit/manager/state/store/services.go

@@ -58,21 +58,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			services, err := FindServices(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Services))
+			for i, x := range snapshot.Services {
+				toStoreObj[i] = x
 			}
 			}
-			for _, s := range services {
-				if err := DeleteService(tx, s.ID); err != nil {
-					return err
-				}
-			}
-			for _, s := range snapshot.Services {
-				if err := CreateService(tx, s); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableService, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {

+ 4 - 14
vendor/github.com/docker/swarmkit/manager/state/store/tasks.go

@@ -82,21 +82,11 @@ func init() {
 			return err
 			return err
 		},
 		},
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
 		Restore: func(tx Tx, snapshot *api.StoreSnapshot) error {
-			tasks, err := FindTasks(tx, All)
-			if err != nil {
-				return err
+			toStoreObj := make([]api.StoreObject, len(snapshot.Tasks))
+			for i, x := range snapshot.Tasks {
+				toStoreObj[i] = x
 			}
 			}
-			for _, t := range tasks {
-				if err := DeleteTask(tx, t.ID); err != nil {
-					return err
-				}
-			}
-			for _, t := range snapshot.Tasks {
-				if err := CreateTask(tx, t); err != nil {
-					return err
-				}
-			}
-			return nil
+			return RestoreTable(tx, tableTask, toStoreObj)
 		},
 		},
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 		ApplyStoreAction: func(tx Tx, sa api.StoreAction) error {
 			switch v := sa.Target.(type) {
 			switch v := sa.Target.(type) {

+ 21 - 21
vendor/github.com/docker/swarmkit/node/node.go

@@ -28,7 +28,6 @@ import (
 	"github.com/docker/swarmkit/manager"
 	"github.com/docker/swarmkit/manager"
 	"github.com/docker/swarmkit/manager/encryption"
 	"github.com/docker/swarmkit/manager/encryption"
 	"github.com/docker/swarmkit/remotes"
 	"github.com/docker/swarmkit/remotes"
-	"github.com/docker/swarmkit/watch"
 	"github.com/docker/swarmkit/xnet"
 	"github.com/docker/swarmkit/xnet"
 	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
 	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -276,10 +275,11 @@ func (n *Node) run(ctx context.Context) (err error) {
 	}(ctx)
 	}(ctx)
 
 
 	paths := ca.NewConfigPaths(filepath.Join(n.config.StateDir, certDirectory))
 	paths := ca.NewConfigPaths(filepath.Join(n.config.StateDir, certDirectory))
-	securityConfig, err := n.loadSecurityConfig(ctx, paths)
+	securityConfig, secConfigCancel, err := n.loadSecurityConfig(ctx, paths)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	defer secConfigCancel()
 
 
 	renewer := ca.NewTLSRenewer(securityConfig, n.connBroker, paths.RootCA)
 	renewer := ca.NewTLSRenewer(securityConfig, n.connBroker, paths.RootCA)
 
 
@@ -509,11 +509,8 @@ waitPeer:
 	default:
 	default:
 	}
 	}
 
 
-	secChangeQueue := watch.NewQueue()
-	defer secChangeQueue.Close()
-	secChangesCh, secChangesCancel := secChangeQueue.Watch()
+	secChangesCh, secChangesCancel := securityConfig.Watch()
 	defer secChangesCancel()
 	defer secChangesCancel()
-	securityConfig.SetWatch(secChangeQueue)
 
 
 	rootCA := securityConfig.RootCA()
 	rootCA := securityConfig.RootCA()
 	issuer := securityConfig.IssuerInfo()
 	issuer := securityConfig.IssuerInfo()
@@ -668,28 +665,31 @@ func (n *Node) Remotes() []api.Peer {
 	return remotes
 	return remotes
 }
 }
 
 
-func (n *Node) loadSecurityConfig(ctx context.Context, paths *ca.SecurityConfigPaths) (*ca.SecurityConfig, error) {
-	var securityConfig *ca.SecurityConfig
+func (n *Node) loadSecurityConfig(ctx context.Context, paths *ca.SecurityConfigPaths) (*ca.SecurityConfig, func() error, error) {
+	var (
+		securityConfig *ca.SecurityConfig
+		cancel         func() error
+	)
 
 
 	krw := ca.NewKeyReadWriter(paths.Node, n.unlockKey, &manager.RaftDEKData{})
 	krw := ca.NewKeyReadWriter(paths.Node, n.unlockKey, &manager.RaftDEKData{})
 	if err := krw.Migrate(); err != nil {
 	if err := krw.Migrate(); err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 
 
 	// Check if we already have a valid certificates on disk.
 	// Check if we already have a valid certificates on disk.
 	rootCA, err := ca.GetLocalRootCA(paths.RootCA)
 	rootCA, err := ca.GetLocalRootCA(paths.RootCA)
 	if err != nil && err != ca.ErrNoLocalRootCA {
 	if err != nil && err != ca.ErrNoLocalRootCA {
-		return nil, err
+		return nil, nil, err
 	}
 	}
 	if err == nil {
 	if err == nil {
 		// if forcing a new cluster, we allow the certificates to be expired - a new set will be generated
 		// if forcing a new cluster, we allow the certificates to be expired - a new set will be generated
-		securityConfig, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
+		securityConfig, cancel, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
 		if err != nil {
 		if err != nil {
 			_, isInvalidKEK := errors.Cause(err).(ca.ErrInvalidKEK)
 			_, isInvalidKEK := errors.Cause(err).(ca.ErrInvalidKEK)
 			if isInvalidKEK {
 			if isInvalidKEK {
-				return nil, ErrInvalidUnlockKey
+				return nil, nil, ErrInvalidUnlockKey
 			} else if !os.IsNotExist(err) {
 			} else if !os.IsNotExist(err) {
-				return nil, errors.Wrapf(err, "error while loading TLS certificate in %s", paths.Node.Cert)
+				return nil, nil, errors.Wrapf(err, "error while loading TLS certificate in %s", paths.Node.Cert)
 			}
 			}
 		}
 		}
 	}
 	}
@@ -704,16 +704,16 @@ func (n *Node) loadSecurityConfig(ctx context.Context, paths *ca.SecurityConfigP
 			krw = ca.NewKeyReadWriter(paths.Node, n.unlockKey, &manager.RaftDEKData{})
 			krw = ca.NewKeyReadWriter(paths.Node, n.unlockKey, &manager.RaftDEKData{})
 			rootCA, err = ca.CreateRootCA(ca.DefaultRootCN)
 			rootCA, err = ca.CreateRootCA(ca.DefaultRootCN)
 			if err != nil {
 			if err != nil {
-				return nil, err
+				return nil, nil, err
 			}
 			}
 			if err := ca.SaveRootCA(rootCA, paths.RootCA); err != nil {
 			if err := ca.SaveRootCA(rootCA, paths.RootCA); err != nil {
-				return nil, err
+				return nil, nil, err
 			}
 			}
 			log.G(ctx).Debug("generated CA key and certificate")
 			log.G(ctx).Debug("generated CA key and certificate")
 		} else if err == ca.ErrNoLocalRootCA { // from previous error loading the root CA from disk
 		} else if err == ca.ErrNoLocalRootCA { // from previous error loading the root CA from disk
 			rootCA, err = ca.DownloadRootCA(ctx, paths.RootCA, n.config.JoinToken, n.connBroker)
 			rootCA, err = ca.DownloadRootCA(ctx, paths.RootCA, n.config.JoinToken, n.connBroker)
 			if err != nil {
 			if err != nil {
-				return nil, err
+				return nil, nil, err
 			}
 			}
 			log.G(ctx).Debug("downloaded CA certificate")
 			log.G(ctx).Debug("downloaded CA certificate")
 		}
 		}
@@ -724,25 +724,25 @@ func (n *Node) loadSecurityConfig(ctx context.Context, paths *ca.SecurityConfigP
 		// - We wait for CreateSecurityConfig to finish since we need a certificate to operate.
 		// - We wait for CreateSecurityConfig to finish since we need a certificate to operate.
 
 
 		// Attempt to load certificate from disk
 		// Attempt to load certificate from disk
-		securityConfig, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
+		securityConfig, cancel, err = ca.LoadSecurityConfig(ctx, rootCA, krw, n.config.ForceNewCluster)
 		if err == nil {
 		if err == nil {
 			log.G(ctx).WithFields(logrus.Fields{
 			log.G(ctx).WithFields(logrus.Fields{
 				"node.id": securityConfig.ClientTLSCreds.NodeID(),
 				"node.id": securityConfig.ClientTLSCreds.NodeID(),
 			}).Debugf("loaded TLS certificate")
 			}).Debugf("loaded TLS certificate")
 		} else {
 		} else {
 			if _, ok := errors.Cause(err).(ca.ErrInvalidKEK); ok {
 			if _, ok := errors.Cause(err).(ca.ErrInvalidKEK); ok {
-				return nil, ErrInvalidUnlockKey
+				return nil, nil, ErrInvalidUnlockKey
 			}
 			}
 			log.G(ctx).WithError(err).Debugf("no node credentials found in: %s", krw.Target())
 			log.G(ctx).WithError(err).Debugf("no node credentials found in: %s", krw.Target())
 
 
-			securityConfig, err = rootCA.CreateSecurityConfig(ctx, krw, ca.CertificateRequestConfig{
+			securityConfig, cancel, err = rootCA.CreateSecurityConfig(ctx, krw, ca.CertificateRequestConfig{
 				Token:        n.config.JoinToken,
 				Token:        n.config.JoinToken,
 				Availability: n.config.Availability,
 				Availability: n.config.Availability,
 				ConnBroker:   n.connBroker,
 				ConnBroker:   n.connBroker,
 			})
 			})
 
 
 			if err != nil {
 			if err != nil {
-				return nil, err
+				return nil, nil, err
 			}
 			}
 		}
 		}
 	}
 	}
@@ -753,7 +753,7 @@ func (n *Node) loadSecurityConfig(ctx context.Context, paths *ca.SecurityConfigP
 	n.roleCond.Broadcast()
 	n.roleCond.Broadcast()
 	n.Unlock()
 	n.Unlock()
 
 
-	return securityConfig, nil
+	return securityConfig, cancel, nil
 }
 }
 
 
 func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{}) error {
 func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{}) error {

+ 25 - 7
vendor/github.com/docker/swarmkit/template/context.go

@@ -14,6 +14,12 @@ import (
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
 )
 )
 
 
+// Platform holds information about the underlying platform of the node
+type Platform struct {
+	Architecture string
+	OS           string
+}
+
 // Context defines the strict set of values that can be injected into a
 // Context defines the strict set of values that can be injected into a
 // template expression in SwarmKit data structure.
 // template expression in SwarmKit data structure.
 // NOTE: Be very careful adding any fields to this structure with types
 // NOTE: Be very careful adding any fields to this structure with types
@@ -27,7 +33,9 @@ type Context struct {
 	}
 	}
 
 
 	Node struct {
 	Node struct {
-		ID string
+		ID       string
+		Hostname string
+		Platform Platform
 	}
 	}
 
 
 	Task struct {
 	Task struct {
@@ -41,16 +49,25 @@ type Context struct {
 	}
 	}
 }
 }
 
 
-// NewContextFromTask returns a new template context from the data available in
-// task. The provided context can then be used to populate runtime values in a
+// NewContext returns a new template context from the data available in the
+// task and the node where it is scheduled to run.
+// The provided context can then be used to populate runtime values in a
 // ContainerSpec.
 // ContainerSpec.
-func NewContextFromTask(t *api.Task) (ctx Context) {
+func NewContext(n *api.NodeDescription, t *api.Task) (ctx Context) {
 	ctx.Service.ID = t.ServiceID
 	ctx.Service.ID = t.ServiceID
 	ctx.Service.Name = t.ServiceAnnotations.Name
 	ctx.Service.Name = t.ServiceAnnotations.Name
 	ctx.Service.Labels = t.ServiceAnnotations.Labels
 	ctx.Service.Labels = t.ServiceAnnotations.Labels
 
 
 	ctx.Node.ID = t.NodeID
 	ctx.Node.ID = t.NodeID
 
 
+	// Add node information to context only if we have them available
+	if n != nil {
+		ctx.Node.Hostname = n.Hostname
+		ctx.Node.Platform = Platform{
+			Architecture: n.Platform.Architecture,
+			OS:           n.Platform.OS,
+		}
+	}
 	ctx.Task.ID = t.ID
 	ctx.Task.ID = t.ID
 	ctx.Task.Name = naming.Task(t)
 	ctx.Task.Name = naming.Task(t)
 
 
@@ -157,12 +174,13 @@ func (ctx PayloadContext) envGetter(variable string) (string, error) {
 }
 }
 
 
 // NewPayloadContextFromTask returns a new template context from the data
 // NewPayloadContextFromTask returns a new template context from the data
-// available in the task. This context also provides access to the configs
+// available in the task and the node where it is scheduled to run.
+// This context also provides access to the configs
 // and secrets that the task has access to. The provided context can then
 // and secrets that the task has access to. The provided context can then
 // be used to populate runtime values in a templated config or secret.
 // be used to populate runtime values in a templated config or secret.
-func NewPayloadContextFromTask(t *api.Task, dependencies exec.DependencyGetter) (ctx PayloadContext) {
+func NewPayloadContextFromTask(node *api.NodeDescription, t *api.Task, dependencies exec.DependencyGetter) (ctx PayloadContext) {
 	return PayloadContext{
 	return PayloadContext{
-		Context:           NewContextFromTask(t),
+		Context:           NewContext(node, t),
 		t:                 t,
 		t:                 t,
 		restrictedSecrets: secrets.Restrict(dependencies.Secrets(), t),
 		restrictedSecrets: secrets.Restrict(dependencies.Secrets(), t),
 		restrictedConfigs: configs.Restrict(dependencies.Configs(), t),
 		restrictedConfigs: configs.Restrict(dependencies.Configs(), t),

+ 8 - 7
vendor/github.com/docker/swarmkit/template/expand.go

@@ -10,18 +10,19 @@ import (
 )
 )
 
 
 // ExpandContainerSpec expands templated fields in the runtime using the task
 // ExpandContainerSpec expands templated fields in the runtime using the task
-// state. Templating is all evaluated on the agent-side, before execution.
+// state and the node where it is scheduled to run.
+// Templating is all evaluated on the agent-side, before execution.
 //
 //
 // Note that these are projected only on runtime values, since active task
 // Note that these are projected only on runtime values, since active task
 // values are typically manipulated in the manager.
 // values are typically manipulated in the manager.
-func ExpandContainerSpec(t *api.Task) (*api.ContainerSpec, error) {
+func ExpandContainerSpec(n *api.NodeDescription, t *api.Task) (*api.ContainerSpec, error) {
 	container := t.Spec.GetContainer()
 	container := t.Spec.GetContainer()
 	if container == nil {
 	if container == nil {
 		return nil, errors.Errorf("task missing ContainerSpec to expand")
 		return nil, errors.Errorf("task missing ContainerSpec to expand")
 	}
 	}
 
 
 	container = container.Copy()
 	container = container.Copy()
-	ctx := NewContextFromTask(t)
+	ctx := NewContext(n, t)
 
 
 	var err error
 	var err error
 	container.Env, err = expandEnv(ctx, container.Env)
 	container.Env, err = expandEnv(ctx, container.Env)
@@ -128,12 +129,12 @@ func expandPayload(ctx PayloadContext, payload []byte) ([]byte, error) {
 
 
 // ExpandSecretSpec expands the template inside the secret payload, if any.
 // ExpandSecretSpec expands the template inside the secret payload, if any.
 // Templating is evaluated on the agent-side.
 // Templating is evaluated on the agent-side.
-func ExpandSecretSpec(s *api.Secret, t *api.Task, dependencies exec.DependencyGetter) (*api.SecretSpec, error) {
+func ExpandSecretSpec(s *api.Secret, node *api.NodeDescription, t *api.Task, dependencies exec.DependencyGetter) (*api.SecretSpec, error) {
 	if s.Spec.Templating == nil {
 	if s.Spec.Templating == nil {
 		return &s.Spec, nil
 		return &s.Spec, nil
 	}
 	}
 	if s.Spec.Templating.Name == "golang" {
 	if s.Spec.Templating.Name == "golang" {
-		ctx := NewPayloadContextFromTask(t, dependencies)
+		ctx := NewPayloadContextFromTask(node, t, dependencies)
 		secretSpec := s.Spec.Copy()
 		secretSpec := s.Spec.Copy()
 
 
 		var err error
 		var err error
@@ -145,12 +146,12 @@ func ExpandSecretSpec(s *api.Secret, t *api.Task, dependencies exec.DependencyGe
 
 
 // ExpandConfigSpec expands the template inside the config payload, if any.
 // ExpandConfigSpec expands the template inside the config payload, if any.
 // Templating is evaluated on the agent-side.
 // Templating is evaluated on the agent-side.
-func ExpandConfigSpec(c *api.Config, t *api.Task, dependencies exec.DependencyGetter) (*api.ConfigSpec, error) {
+func ExpandConfigSpec(c *api.Config, node *api.NodeDescription, t *api.Task, dependencies exec.DependencyGetter) (*api.ConfigSpec, error) {
 	if c.Spec.Templating == nil {
 	if c.Spec.Templating == nil {
 		return &c.Spec, nil
 		return &c.Spec, nil
 	}
 	}
 	if c.Spec.Templating.Name == "golang" {
 	if c.Spec.Templating.Name == "golang" {
-		ctx := NewPayloadContextFromTask(t, dependencies)
+		ctx := NewPayloadContextFromTask(node, t, dependencies)
 		configSpec := c.Spec.Copy()
 		configSpec := c.Spec.Copy()
 
 
 		var err error
 		var err error

+ 11 - 9
vendor/github.com/docker/swarmkit/template/getter.go

@@ -9,11 +9,12 @@ import (
 type templatedSecretGetter struct {
 type templatedSecretGetter struct {
 	dependencies exec.DependencyGetter
 	dependencies exec.DependencyGetter
 	t            *api.Task
 	t            *api.Task
+	node         *api.NodeDescription
 }
 }
 
 
 // NewTemplatedSecretGetter returns a SecretGetter that evaluates templates.
 // NewTemplatedSecretGetter returns a SecretGetter that evaluates templates.
-func NewTemplatedSecretGetter(dependencies exec.DependencyGetter, t *api.Task) exec.SecretGetter {
-	return templatedSecretGetter{dependencies: dependencies, t: t}
+func NewTemplatedSecretGetter(dependencies exec.DependencyGetter, t *api.Task, node *api.NodeDescription) exec.SecretGetter {
+	return templatedSecretGetter{dependencies: dependencies, t: t, node: node}
 }
 }
 
 
 func (t templatedSecretGetter) Get(secretID string) (*api.Secret, error) {
 func (t templatedSecretGetter) Get(secretID string) (*api.Secret, error) {
@@ -31,7 +32,7 @@ func (t templatedSecretGetter) Get(secretID string) (*api.Secret, error) {
 		return secret, err
 		return secret, err
 	}
 	}
 
 
-	newSpec, err := ExpandSecretSpec(secret, t.t, t.dependencies)
+	newSpec, err := ExpandSecretSpec(secret, t.node, t.t, t.dependencies)
 	if err != nil {
 	if err != nil {
 		return secret, errors.Wrapf(err, "failed to expand templated secret %s", secretID)
 		return secret, errors.Wrapf(err, "failed to expand templated secret %s", secretID)
 	}
 	}
@@ -44,11 +45,12 @@ func (t templatedSecretGetter) Get(secretID string) (*api.Secret, error) {
 type templatedConfigGetter struct {
 type templatedConfigGetter struct {
 	dependencies exec.DependencyGetter
 	dependencies exec.DependencyGetter
 	t            *api.Task
 	t            *api.Task
+	node         *api.NodeDescription
 }
 }
 
 
 // NewTemplatedConfigGetter returns a ConfigGetter that evaluates templates.
 // NewTemplatedConfigGetter returns a ConfigGetter that evaluates templates.
-func NewTemplatedConfigGetter(dependencies exec.DependencyGetter, t *api.Task) exec.ConfigGetter {
-	return templatedConfigGetter{dependencies: dependencies, t: t}
+func NewTemplatedConfigGetter(dependencies exec.DependencyGetter, t *api.Task, node *api.NodeDescription) exec.ConfigGetter {
+	return templatedConfigGetter{dependencies: dependencies, t: t, node: node}
 }
 }
 
 
 func (t templatedConfigGetter) Get(configID string) (*api.Config, error) {
 func (t templatedConfigGetter) Get(configID string) (*api.Config, error) {
@@ -66,7 +68,7 @@ func (t templatedConfigGetter) Get(configID string) (*api.Config, error) {
 		return config, err
 		return config, err
 	}
 	}
 
 
-	newSpec, err := ExpandConfigSpec(config, t.t, t.dependencies)
+	newSpec, err := ExpandConfigSpec(config, t.node, t.t, t.dependencies)
 	if err != nil {
 	if err != nil {
 		return config, errors.Wrapf(err, "failed to expand templated config %s", configID)
 		return config, errors.Wrapf(err, "failed to expand templated config %s", configID)
 	}
 	}
@@ -82,10 +84,10 @@ type templatedDependencyGetter struct {
 }
 }
 
 
 // NewTemplatedDependencyGetter returns a DependencyGetter that evaluates templates.
 // NewTemplatedDependencyGetter returns a DependencyGetter that evaluates templates.
-func NewTemplatedDependencyGetter(dependencies exec.DependencyGetter, t *api.Task) exec.DependencyGetter {
+func NewTemplatedDependencyGetter(dependencies exec.DependencyGetter, t *api.Task, node *api.NodeDescription) exec.DependencyGetter {
 	return templatedDependencyGetter{
 	return templatedDependencyGetter{
-		secrets: NewTemplatedSecretGetter(dependencies, t),
-		configs: NewTemplatedConfigGetter(dependencies, t),
+		secrets: NewTemplatedSecretGetter(dependencies, t, node),
+		configs: NewTemplatedConfigGetter(dependencies, t, node),
 	}
 	}
 }
 }
 
 

+ 5 - 7
vendor/github.com/docker/swarmkit/vendor.conf

@@ -10,7 +10,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f
 github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
 github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
 
 
 # etcd/raft
 # etcd/raft
-github.com/coreos/etcd ea5389a79f40206170582c1ea076191b8622cb8e https://github.com/aaronlehmann/etcd # for https://github.com/coreos/etcd/pull/7830
+github.com/coreos/etcd v3.2.1
 github.com/coreos/go-systemd v12
 github.com/coreos/go-systemd v12
 github.com/coreos/pkg v3
 github.com/coreos/pkg v3
 github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
 github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
@@ -28,18 +28,16 @@ github.com/docker/libnetwork 37e20af882e13dd01ade3658b7aabdae3412118b
 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
 github.com/opencontainers/runc b6b70e53451794e8333e9b602cc096b47a20bd0f
 github.com/opencontainers/runc b6b70e53451794e8333e9b602cc096b47a20bd0f
 github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
 github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
-github.com/opencontainers/image-spec f03dbe35d449c54915d235f1a3cf8f585a24babe
+github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13
 
 
 # containerd executor
 # containerd executor
-github.com/containerd/containerd 7fc91b05917e93d474fab9465547d44eacd10ce3
-github.com/containerd/continuity f4ad4294c92f596c9241947c416d1297f9faf3ea
+github.com/containerd/containerd 76697ac8cbf357a19beb58e4805a81fe48cf7974
 github.com/containerd/fifo 69b99525e472735860a5269b75af1970142b3062
 github.com/containerd/fifo 69b99525e472735860a5269b75af1970142b3062
 github.com/opencontainers/runtime-spec v1.0.0-rc5
 github.com/opencontainers/runtime-spec v1.0.0-rc5
-github.com/nightlyone/lockfile 1d49c987357a327b5b03aa84cbddd582c328615d
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
 
 
 github.com/davecgh/go-spew 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
 github.com/davecgh/go-spew 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d
-github.com/Microsoft/go-winio f778f05015353be65d242f3fedc18695756153bb
+github.com/Microsoft/go-winio v0.4.2
 github.com/Sirupsen/logrus v0.11.0
 github.com/Sirupsen/logrus v0.11.0
 github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
 github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
 github.com/boltdb/bolt e72f08ddb5a52992c0a44c7dda9316c7333938b2
 github.com/boltdb/bolt e72f08ddb5a52992c0a44c7dda9316c7333938b2
@@ -52,7 +50,7 @@ github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
 github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
 github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
 github.com/phayes/permbits f7e3ac5e859d0b919c5068d581cc4c5d4f4f9bc5
 github.com/phayes/permbits f7e3ac5e859d0b919c5068d581cc4c5d4f4f9bc5
 github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
 github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
-github.com/pkg/errors 01fa4104b9c248c8945d14d9f128454d5b28d595
+github.com/pkg/errors 645ef00459ed84a119197bfb8d8205042c6df63d
 github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2
 github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2
 github.com/rcrowley/go-metrics 51425a2415d21afadfd55cd93432c0bc69e9598d
 github.com/rcrowley/go-metrics 51425a2415d21afadfd55cd93432c0bc69e9598d
 github.com/spf13/cobra 8e91712f174ced10270cf66615e0a9127e7c4de5
 github.com/spf13/cobra 8e91712f174ced10270cf66615e0a9127e7c4de5

+ 158 - 0
vendor/github.com/docker/swarmkit/watch/queue/queue.go

@@ -0,0 +1,158 @@
+package queue
+
+import (
+	"container/list"
+	"fmt"
+	"sync"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/go-events"
+)
+
+// ErrQueueFull is returned by a Write operation when that Write causes the
+// queue to reach its size limit.
+var ErrQueueFull = fmt.Errorf("queue closed due to size limit")
+
+// LimitQueue accepts all messages into a queue for asynchronous consumption by
+// a sink until an upper limit of messages is reached. When that limit is
+// reached, the entire Queue is Closed. It is thread safe but the
+// sink must be reliable or events will be dropped.
+// If a size of 0 is provided, the LimitQueue is considered limitless.
+type LimitQueue struct {
+	dst        events.Sink
+	events     *list.List
+	limit      uint64
+	cond       *sync.Cond
+	mu         sync.Mutex
+	closed     bool
+	full       chan struct{}
+	fullClosed bool
+}
+
+// NewLimitQueue returns a queue to the provided Sink dst.
+func NewLimitQueue(dst events.Sink, limit uint64) *LimitQueue {
+	eq := LimitQueue{
+		dst:    dst,
+		events: list.New(),
+		limit:  limit,
+		full:   make(chan struct{}),
+	}
+
+	eq.cond = sync.NewCond(&eq.mu)
+	go eq.run()
+	return &eq
+}
+
+// Write accepts the events into the queue, only failing if the queue has
+// been closed or has reached its size limit.
+func (eq *LimitQueue) Write(event events.Event) error {
+	eq.mu.Lock()
+	defer eq.mu.Unlock()
+
+	if eq.closed {
+		return events.ErrSinkClosed
+	}
+
+	if eq.limit > 0 && uint64(eq.events.Len()) >= eq.limit {
+		// If the limit has been reached, don't write the event to the queue,
+		// and close the Full channel. This notifies listeners that the queue
+		// is now full, but the sink is still permitted to consume events. It's
+		// the responsibility of the listener to decide whether they want to
+		// live with dropped events or whether they want to Close() the
+		// LimitQueue
+		if !eq.fullClosed {
+			eq.fullClosed = true
+			close(eq.full)
+		}
+		return ErrQueueFull
+	}
+
+	eq.events.PushBack(event)
+	eq.cond.Signal() // signal waiters
+
+	return nil
+}
+
+// Full returns a channel that is closed when the queue becomes full for the
+// first time.
+func (eq *LimitQueue) Full() chan struct{} {
+	return eq.full
+}
+
+// Close shuts down the event queue, flushing all events
+func (eq *LimitQueue) Close() error {
+	eq.mu.Lock()
+	defer eq.mu.Unlock()
+
+	if eq.closed {
+		return nil
+	}
+
+	// set the closed flag
+	eq.closed = true
+	eq.cond.Signal() // signal flushes queue
+	eq.cond.Wait()   // wait for signal from last flush
+	return eq.dst.Close()
+}
+
+// run is the main goroutine to flush events to the target sink.
+func (eq *LimitQueue) run() {
+	for {
+		event := eq.next()
+
+		if event == nil {
+			return // nil block means event queue is closed.
+		}
+
+		if err := eq.dst.Write(event); err != nil {
+			// TODO(aaronl): Dropping events could be bad depending
+			// on the application. We should have a way of
+			// communicating this condition. However, logging
+			// at a log level above debug may not be appropriate.
+			// Eventually, go-events should not use logrus at all,
+			// and should bubble up conditions like this through
+			// error values.
+			logrus.WithFields(logrus.Fields{
+				"event": event,
+				"sink":  eq.dst,
+			}).WithError(err).Debug("eventqueue: dropped event")
+		}
+	}
+}
+
+// Len returns the number of items that are currently stored in the queue and
+// not consumed by its sink.
+func (eq *LimitQueue) Len() int {
+	eq.mu.Lock()
+	defer eq.mu.Unlock()
+	return eq.events.Len()
+}
+
+func (eq *LimitQueue) String() string {
+	eq.mu.Lock()
+	defer eq.mu.Unlock()
+	return fmt.Sprintf("%v", eq.events)
+}
+
+// next encompasses the critical section of the run loop. When the queue is
+// empty, it will block on the condition. If new data arrives, it will wake
+// and return a block. When closed, a nil slice will be returned.
+func (eq *LimitQueue) next() events.Event {
+	eq.mu.Lock()
+	defer eq.mu.Unlock()
+
+	for eq.events.Len() < 1 {
+		if eq.closed {
+			eq.cond.Broadcast()
+			return nil
+		}
+
+		eq.cond.Wait()
+	}
+
+	front := eq.events.Front()
+	block := front.Value.(events.Event)
+	eq.events.Remove(front)
+
+	return block
+}

+ 95 - 0
vendor/github.com/docker/swarmkit/watch/sinks.go

@@ -0,0 +1,95 @@
+package watch
+
+import (
+	"fmt"
+	"time"
+
+	events "github.com/docker/go-events"
+)
+
+// ErrSinkTimeout is returned from the Write method when a sink times out.
+var ErrSinkTimeout = fmt.Errorf("timeout exceeded, tearing down sink")
+
+// timeoutSink is a sink that wraps another sink with a timeout. If the
+// embedded sink fails to complete a Write operation within the specified
+// timeout, the Write operation of the timeoutSink fails.
+type timeoutSink struct {
+	timeout time.Duration
+	sink    events.Sink
+}
+
+func (s timeoutSink) Write(event events.Event) error {
+	errChan := make(chan error)
+	go func(c chan<- error) {
+		c <- s.sink.Write(event)
+	}(errChan)
+
+	timer := time.NewTimer(s.timeout)
+	select {
+	case err := <-errChan:
+		timer.Stop()
+		return err
+	case <-timer.C:
+		s.sink.Close()
+		return ErrSinkTimeout
+	}
+}
+
+func (s timeoutSink) Close() error {
+	return s.sink.Close()
+}
+
+// dropErrClosed is a sink that suppresses ErrSinkClosed from Write, to avoid
+// debug log messages that may be confusing. It is possible that the queue
+// will try to write an event to its destination channel while the queue is
+// being removed from the broadcaster. Since the channel is closed before the
+// queue, there is a narrow window when this is possible. In some event-based
+// dropping events when a sink is removed from a broadcaster is a problem, but
+// for the usage in this watch package that's the expected behavior.
+type dropErrClosed struct {
+	sink events.Sink
+}
+
+func (s dropErrClosed) Write(event events.Event) error {
+	err := s.sink.Write(event)
+	if err == events.ErrSinkClosed {
+		return nil
+	}
+	return err
+}
+
+func (s dropErrClosed) Close() error {
+	return s.sink.Close()
+}
+
+// dropErrClosedChanGen is a ChannelSinkGenerator for dropErrClosed sinks wrapping
+// unbuffered channels.
+type dropErrClosedChanGen struct{}
+
+func (s *dropErrClosedChanGen) NewChannelSink() (events.Sink, *events.Channel) {
+	ch := events.NewChannel(0)
+	return dropErrClosed{sink: ch}, ch
+}
+
+// TimeoutDropErrChanGen is a ChannelSinkGenerator that creates a channel,
+// wrapped by the dropErrClosed sink and a timeout.
+type TimeoutDropErrChanGen struct {
+	timeout time.Duration
+}
+
+// NewChannelSink creates a new sink chain of timeoutSink->dropErrClosed->Channel
+func (s *TimeoutDropErrChanGen) NewChannelSink() (events.Sink, *events.Channel) {
+	ch := events.NewChannel(0)
+	return timeoutSink{
+		timeout: s.timeout,
+		sink: dropErrClosed{
+			sink: ch,
+		},
+	}, ch
+}
+
+// NewTimeoutDropErrSinkGen returns a generator of timeoutSinks wrapping dropErrClosed
+// sinks, wrapping unbuffered channel sinks.
+func NewTimeoutDropErrSinkGen(timeout time.Duration) ChannelSinkGenerator {
+	return &TimeoutDropErrChanGen{timeout: timeout}
+}

+ 125 - 35
vendor/github.com/docker/swarmkit/watch/watch.go

@@ -1,48 +1,81 @@
 package watch
 package watch
 
 
 import (
 import (
+	"context"
+	"fmt"
 	"sync"
 	"sync"
+	"time"
 
 
 	"github.com/docker/go-events"
 	"github.com/docker/go-events"
+	"github.com/docker/swarmkit/watch/queue"
 )
 )
 
 
-// dropErrClosed is a sink that suppresses ErrSinkClosed from Write, to avoid
-// debug log messages that may be confusing. It is possible that the queue
-// will try to write an event to its destination channel while the queue is
-// being removed from the broadcaster. Since the channel is closed before the
-// queue, there is a narrow window when this is possible. In some event-based
-// dropping events when a sink is removed from a broadcaster is a problem, but
-// for the usage in this watch package that's the expected behavior.
-type dropErrClosed struct {
-	sink events.Sink
-}
-
-func (s dropErrClosed) Write(event events.Event) error {
-	err := s.sink.Write(event)
-	if err == events.ErrSinkClosed {
-		return nil
-	}
-	return err
-}
-
-func (s dropErrClosed) Close() error {
-	return s.sink.Close()
+// ChannelSinkGenerator is a constructor of sinks that eventually lead to a
+// channel.
+type ChannelSinkGenerator interface {
+	NewChannelSink() (events.Sink, *events.Channel)
 }
 }
 
 
 // Queue is the structure used to publish events and watch for them.
 // Queue is the structure used to publish events and watch for them.
 type Queue struct {
 type Queue struct {
+	sinkGen ChannelSinkGenerator
+	// limit is the max number of items to be held in memory for a watcher
+	limit       uint64
 	mu          sync.Mutex
 	mu          sync.Mutex
 	broadcast   *events.Broadcaster
 	broadcast   *events.Broadcaster
-	cancelFuncs map[*events.Channel]func()
+	cancelFuncs map[events.Sink]func()
+
+	// closeOutChan indicates whether the watchers' channels should be closed
+	// when a watcher queue reaches its limit or when the Close method of the
+	// sink is called.
+	closeOutChan bool
 }
 }
 
 
 // NewQueue creates a new publish/subscribe queue which supports watchers.
 // NewQueue creates a new publish/subscribe queue which supports watchers.
 // The channels that it will create for subscriptions will have the buffer
 // The channels that it will create for subscriptions will have the buffer
 // size specified by buffer.
 // size specified by buffer.
-func NewQueue() *Queue {
-	return &Queue{
-		broadcast:   events.NewBroadcaster(),
-		cancelFuncs: make(map[*events.Channel]func()),
+func NewQueue(options ...func(*Queue) error) *Queue {
+	// Create a queue with the default values
+	q := &Queue{
+		sinkGen:      &dropErrClosedChanGen{},
+		broadcast:    events.NewBroadcaster(),
+		cancelFuncs:  make(map[events.Sink]func()),
+		limit:        0,
+		closeOutChan: false,
+	}
+
+	for _, option := range options {
+		err := option(q)
+		if err != nil {
+			panic(fmt.Sprintf("Failed to apply options to queue: %s", err))
+		}
+	}
+
+	return q
+}
+
+// WithTimeout returns a functional option for a queue that sets a write timeout
+func WithTimeout(timeout time.Duration) func(*Queue) error {
+	return func(q *Queue) error {
+		q.sinkGen = NewTimeoutDropErrSinkGen(timeout)
+		return nil
+	}
+}
+
+// WithCloseOutChan returns a functional option for a queue whose watcher
+// channel is closed when no more events are expected to be sent to the watcher.
+func WithCloseOutChan() func(*Queue) error {
+	return func(q *Queue) error {
+		q.closeOutChan = true
+		return nil
+	}
+}
+
+// WithLimit returns a functional option for a queue with a max size limit.
+func WithLimit(limit uint64) func(*Queue) error {
+	return func(q *Queue) error {
+		q.limit = limit
+		return nil
 	}
 	}
 }
 }
 
 
@@ -52,13 +85,21 @@ func (q *Queue) Watch() (eventq chan events.Event, cancel func()) {
 	return q.CallbackWatch(nil)
 	return q.CallbackWatch(nil)
 }
 }
 
 
+// WatchContext returns a channel where all items published to the queue will
+// be received. The channel will be closed when the provided context is
+// cancelled.
+func (q *Queue) WatchContext(ctx context.Context) (eventq chan events.Event) {
+	return q.CallbackWatchContext(ctx, nil)
+}
+
 // CallbackWatch returns a channel which will receive all events published to
 // CallbackWatch returns a channel which will receive all events published to
 // the queue from this point that pass the check in the provided callback
 // the queue from this point that pass the check in the provided callback
 // function. The returned cancel function will stop the flow of events and
 // function. The returned cancel function will stop the flow of events and
 // close the channel.
 // close the channel.
 func (q *Queue) CallbackWatch(matcher events.Matcher) (eventq chan events.Event, cancel func()) {
 func (q *Queue) CallbackWatch(matcher events.Matcher) (eventq chan events.Event, cancel func()) {
-	ch := events.NewChannel(0)
-	sink := events.Sink(events.NewQueue(dropErrClosed{sink: ch}))
+	chanSink, ch := q.sinkGen.NewChannelSink()
+	lq := queue.NewLimitQueue(chanSink, q.limit)
+	sink := events.Sink(lq)
 
 
 	if matcher != nil {
 	if matcher != nil {
 		sink = events.NewFilter(sink, matcher)
 		sink = events.NewFilter(sink, matcher)
@@ -72,19 +113,68 @@ func (q *Queue) CallbackWatch(matcher events.Matcher) (eventq chan events.Event,
 		sink.Close()
 		sink.Close()
 	}
 	}
 
 
-	q.mu.Lock()
-	q.cancelFuncs[ch] = cancelFunc
-	q.mu.Unlock()
-	return ch.C, func() {
+	externalCancelFunc := func() {
 		q.mu.Lock()
 		q.mu.Lock()
-		cancelFunc := q.cancelFuncs[ch]
-		delete(q.cancelFuncs, ch)
+		cancelFunc := q.cancelFuncs[sink]
+		delete(q.cancelFuncs, sink)
 		q.mu.Unlock()
 		q.mu.Unlock()
 
 
 		if cancelFunc != nil {
 		if cancelFunc != nil {
 			cancelFunc()
 			cancelFunc()
 		}
 		}
 	}
 	}
+
+	q.mu.Lock()
+	q.cancelFuncs[sink] = cancelFunc
+	q.mu.Unlock()
+
+	// If the output channel shouldn't be closed and the queue is limitless,
+	// there's no need for an additional goroutine.
+	if !q.closeOutChan && q.limit == 0 {
+		return ch.C, externalCancelFunc
+	}
+
+	outChan := make(chan events.Event)
+	go func() {
+		for {
+			select {
+			case <-ch.Done():
+				// Close the output channel if the ChannelSink is Done for any
+				// reason. This can happen if the cancelFunc is called
+				// externally or if it has been closed by a wrapper sink, such
+				// as the TimeoutSink.
+				if q.closeOutChan {
+					close(outChan)
+				}
+				externalCancelFunc()
+				return
+			case <-lq.Full():
+				// Close the output channel and tear down the Queue if the
+				// LimitQueue becomes full.
+				if q.closeOutChan {
+					close(outChan)
+				}
+				externalCancelFunc()
+				return
+			case event := <-ch.C:
+				outChan <- event
+			}
+		}
+	}()
+
+	return outChan, externalCancelFunc
+}
+
+// CallbackWatchContext returns a channel where all items published to the queue will
+// be received. The channel will be closed when the provided context is
+// cancelled.
+func (q *Queue) CallbackWatchContext(ctx context.Context, matcher events.Matcher) (eventq chan events.Event) {
+	c, cancel := q.CallbackWatch(matcher)
+	go func() {
+		<-ctx.Done()
+		cancel()
+	}()
+	return c
 }
 }
 
 
 // Publish adds an item to the queue.
 // Publish adds an item to the queue.
@@ -100,7 +190,7 @@ func (q *Queue) Close() error {
 	for _, cancelFunc := range q.cancelFuncs {
 	for _, cancelFunc := range q.cancelFuncs {
 		cancelFunc()
 		cancelFunc()
 	}
 	}
-	q.cancelFuncs = make(map[*events.Channel]func())
+	q.cancelFuncs = make(map[events.Sink]func())
 	q.mu.Unlock()
 	q.mu.Unlock()
 
 
 	return q.broadcast.Close()
 	return q.broadcast.Close()