Browse Source

*: support watch with filters

Now user can filter events with types. The API is also extensible.
It might make sense for the proxy to filter out events based on
more expensive/customized filter.
Xiang Li 9 years ago
parent
commit
dced92f8bd

+ 16 - 0
Documentation/dev-guide/apispec/swagger/rpc.swagger.json

@@ -181,6 +181,15 @@
       ],
       ],
       "default": "KEY"
       "default": "KEY"
     },
     },
+    "WatchCreateRequestFilterType": {
+      "type": "string",
+      "enum": [
+        "NOPUT",
+        "NODELETE"
+      ],
+      "default": "NOPUT",
+      "description": "- NOPUT: filter out put event.\n - NODELETE: filter out delete event."
+    },
     "authpbPermission": {
     "authpbPermission": {
       "type": "object",
       "type": "object",
       "properties": {
       "properties": {
@@ -1171,6 +1180,13 @@
     "etcdserverpbWatchCreateRequest": {
     "etcdserverpbWatchCreateRequest": {
       "type": "object",
       "type": "object",
       "properties": {
       "properties": {
+        "filters": {
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/WatchCreateRequestFilterType"
+          },
+          "description": "filters filter the events at server side before it sends back to the watcher."
+        },
         "key": {
         "key": {
           "type": "string",
           "type": "string",
           "format": "byte",
           "format": "byte",

+ 20 - 1
etcdserver/api/v3rpc/watch.go

@@ -164,12 +164,23 @@ func (sws *serverWatchStream) recvLoop() error {
 				// support  >= key queries
 				// support  >= key queries
 				creq.RangeEnd = []byte{}
 				creq.RangeEnd = []byte{}
 			}
 			}
+			filters := make([]mvcc.FilterFunc, 0, len(creq.Filters))
+			for _, ft := range creq.Filters {
+				switch ft {
+				case pb.WatchCreateRequest_NOPUT:
+					filters = append(filters, filterNoPut)
+				case pb.WatchCreateRequest_NODELETE:
+					filters = append(filters, filterNoDelete)
+				default:
+				}
+			}
+
 			wsrev := sws.watchStream.Rev()
 			wsrev := sws.watchStream.Rev()
 			rev := creq.StartRevision
 			rev := creq.StartRevision
 			if rev == 0 {
 			if rev == 0 {
 				rev = wsrev + 1
 				rev = wsrev + 1
 			}
 			}
-			id := sws.watchStream.Watch(creq.Key, creq.RangeEnd, rev)
+			id := sws.watchStream.Watch(creq.Key, creq.RangeEnd, rev, filters...)
 			if id != -1 && creq.ProgressNotify {
 			if id != -1 && creq.ProgressNotify {
 				sws.progress[id] = true
 				sws.progress[id] = true
 			}
 			}
@@ -322,3 +333,11 @@ func (sws *serverWatchStream) newResponseHeader(rev int64) *pb.ResponseHeader {
 		RaftTerm:  sws.raftTimer.Term(),
 		RaftTerm:  sws.raftTimer.Term(),
 	}
 	}
 }
 }
+
+func filterNoDelete(e mvccpb.Event) bool {
+	return e.Type == mvccpb.DELETE
+}
+
+func filterNoPut(e mvccpb.Event) bool {
+	return e.Type == mvccpb.PUT
+}

+ 257 - 194
etcdserver/etcdserverpb/rpc.pb.go

@@ -154,6 +154,31 @@ func (x Compare_CompareTarget) String() string {
 }
 }
 func (Compare_CompareTarget) EnumDescriptor() ([]byte, []int) { return fileDescriptorRpc, []int{9, 1} }
 func (Compare_CompareTarget) EnumDescriptor() ([]byte, []int) { return fileDescriptorRpc, []int{9, 1} }
 
 
+type WatchCreateRequest_FilterType int32
+
+const (
+	// filter out put event.
+	WatchCreateRequest_NOPUT WatchCreateRequest_FilterType = 0
+	// filter out delete event.
+	WatchCreateRequest_NODELETE WatchCreateRequest_FilterType = 1
+)
+
+var WatchCreateRequest_FilterType_name = map[int32]string{
+	0: "NOPUT",
+	1: "NODELETE",
+}
+var WatchCreateRequest_FilterType_value = map[string]int32{
+	"NOPUT":    0,
+	"NODELETE": 1,
+}
+
+func (x WatchCreateRequest_FilterType) String() string {
+	return proto.EnumName(WatchCreateRequest_FilterType_name, int32(x))
+}
+func (WatchCreateRequest_FilterType) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptorRpc, []int{19, 0}
+}
+
 type AlarmRequest_AlarmAction int32
 type AlarmRequest_AlarmAction int32
 
 
 const (
 const (
@@ -1119,6 +1144,8 @@ type WatchCreateRequest struct {
 	// wish to recover a disconnected watcher starting from a recent known revision.
 	// wish to recover a disconnected watcher starting from a recent known revision.
 	// The etcd server may decide how often it will send notifications based on current load.
 	// The etcd server may decide how often it will send notifications based on current load.
 	ProgressNotify bool `protobuf:"varint,4,opt,name=progress_notify,json=progressNotify,proto3" json:"progress_notify,omitempty"`
 	ProgressNotify bool `protobuf:"varint,4,opt,name=progress_notify,json=progressNotify,proto3" json:"progress_notify,omitempty"`
+	// filters filter the events at server side before it sends back to the watcher.
+	Filters []WatchCreateRequest_FilterType `protobuf:"varint,5,rep,name=filters,enum=etcdserverpb.WatchCreateRequest_FilterType" json:"filters,omitempty"`
 }
 }
 
 
 func (m *WatchCreateRequest) Reset()                    { *m = WatchCreateRequest{} }
 func (m *WatchCreateRequest) Reset()                    { *m = WatchCreateRequest{} }
@@ -2044,6 +2071,7 @@ func init() {
 	proto.RegisterEnum("etcdserverpb.RangeRequest_SortTarget", RangeRequest_SortTarget_name, RangeRequest_SortTarget_value)
 	proto.RegisterEnum("etcdserverpb.RangeRequest_SortTarget", RangeRequest_SortTarget_name, RangeRequest_SortTarget_value)
 	proto.RegisterEnum("etcdserverpb.Compare_CompareResult", Compare_CompareResult_name, Compare_CompareResult_value)
 	proto.RegisterEnum("etcdserverpb.Compare_CompareResult", Compare_CompareResult_name, Compare_CompareResult_value)
 	proto.RegisterEnum("etcdserverpb.Compare_CompareTarget", Compare_CompareTarget_name, Compare_CompareTarget_value)
 	proto.RegisterEnum("etcdserverpb.Compare_CompareTarget", Compare_CompareTarget_name, Compare_CompareTarget_value)
+	proto.RegisterEnum("etcdserverpb.WatchCreateRequest_FilterType", WatchCreateRequest_FilterType_name, WatchCreateRequest_FilterType_value)
 	proto.RegisterEnum("etcdserverpb.AlarmRequest_AlarmAction", AlarmRequest_AlarmAction_name, AlarmRequest_AlarmAction_value)
 	proto.RegisterEnum("etcdserverpb.AlarmRequest_AlarmAction", AlarmRequest_AlarmAction_name, AlarmRequest_AlarmAction_value)
 }
 }
 
 
@@ -4433,6 +4461,13 @@ func (m *WatchCreateRequest) MarshalTo(data []byte) (int, error) {
 		}
 		}
 		i++
 		i++
 	}
 	}
+	if len(m.Filters) > 0 {
+		for _, num := range m.Filters {
+			data[i] = 0x28
+			i++
+			i = encodeVarintRpc(data, i, uint64(num))
+		}
+	}
 	return i, nil
 	return i, nil
 }
 }
 
 
@@ -6585,6 +6620,11 @@ func (m *WatchCreateRequest) Size() (n int) {
 	if m.ProgressNotify {
 	if m.ProgressNotify {
 		n += 2
 		n += 2
 	}
 	}
+	if len(m.Filters) > 0 {
+		for _, e := range m.Filters {
+			n += 1 + sovRpc(uint64(e))
+		}
+	}
 	return n
 	return n
 }
 }
 
 
@@ -9770,6 +9810,26 @@ func (m *WatchCreateRequest) Unmarshal(data []byte) error {
 				}
 				}
 			}
 			}
 			m.ProgressNotify = bool(v != 0)
 			m.ProgressNotify = bool(v != 0)
+		case 5:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType)
+			}
+			var v WatchCreateRequest_FilterType
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRpc
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := data[iNdEx]
+				iNdEx++
+				v |= (WatchCreateRequest_FilterType(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.Filters = append(m.Filters, v)
 		default:
 		default:
 			iNdEx = preIndex
 			iNdEx = preIndex
 			skippy, err := skipRpc(data[iNdEx:])
 			skippy, err := skipRpc(data[iNdEx:])
@@ -15125,200 +15185,203 @@ var (
 )
 )
 
 
 var fileDescriptorRpc = []byte{
 var fileDescriptorRpc = []byte{
-	// 3116 bytes of a gzipped FileDescriptorProto
+	// 3167 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x5a, 0x4b, 0x73, 0x24, 0x47,
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x5a, 0x4b, 0x73, 0x24, 0x47,
 	0x11, 0xde, 0x79, 0xe8, 0x31, 0x39, 0xa3, 0x59, 0x6d, 0x49, 0xbb, 0x1e, 0xf5, 0x6a, 0xb5, 0xda,
 	0x11, 0xde, 0x79, 0xe8, 0x31, 0x39, 0xa3, 0x59, 0x6d, 0x49, 0xbb, 0x1e, 0xf5, 0x6a, 0xb5, 0xda,
-	0xda, 0xa7, 0x5f, 0x1a, 0x2c, 0x1b, 0x0e, 0x40, 0x38, 0x62, 0xa4, 0x19, 0xd6, 0xb2, 0x64, 0x69,
-	0xdd, 0x9a, 0x95, 0x4d, 0x04, 0x81, 0xa2, 0x35, 0x53, 0x2b, 0x4d, 0x68, 0x5e, 0xee, 0xee, 0xd1,
-	0x4a, 0x06, 0x22, 0x08, 0x07, 0x3e, 0xc0, 0xd5, 0x07, 0x02, 0x38, 0xf2, 0x1b, 0xb8, 0xf1, 0x03,
-	0x08, 0x2e, 0x38, 0x82, 0x23, 0x17, 0x82, 0xe0, 0xc0, 0x81, 0x3b, 0xc1, 0x09, 0xea, 0xd9, 0x5d,
-	0xdd, 0x53, 0x3d, 0x92, 0x69, 0x7c, 0xd8, 0x55, 0x57, 0x56, 0x56, 0x7e, 0x59, 0x59, 0x95, 0xd9,
-	0x99, 0xd9, 0x03, 0x05, 0x77, 0xd8, 0x5a, 0x1b, 0xba, 0x03, 0x7f, 0x80, 0x4a, 0xc4, 0x6f, 0xb5,
-	0x3d, 0xe2, 0x9e, 0x11, 0x77, 0x78, 0x64, 0x2d, 0x1e, 0x0f, 0x8e, 0x07, 0x7c, 0xa2, 0xca, 0x9e,
-	0x04, 0x8f, 0xb5, 0xc4, 0x78, 0xaa, 0xbd, 0xb3, 0x56, 0x8b, 0xff, 0x37, 0x3c, 0xaa, 0x9e, 0x9e,
-	0xc9, 0xa9, 0xdb, 0x7c, 0xca, 0x19, 0xf9, 0x27, 0xfc, 0x3f, 0x3a, 0xc5, 0xfe, 0xc8, 0xc9, 0xe5,
-	0xe3, 0xc1, 0xe0, 0xb8, 0x4b, 0xaa, 0xce, 0xb0, 0x53, 0x75, 0xfa, 0xfd, 0x81, 0xef, 0xf8, 0x9d,
-	0x41, 0xdf, 0x13, 0xb3, 0xf8, 0xf3, 0x0c, 0x94, 0x6d, 0xe2, 0x0d, 0x29, 0x85, 0xbc, 0x47, 0x9c,
-	0x36, 0x71, 0xd1, 0x1d, 0x80, 0x56, 0x77, 0xe4, 0xf9, 0xc4, 0x3d, 0xec, 0xb4, 0x2b, 0x99, 0xd5,
-	0xcc, 0x93, 0xbc, 0x5d, 0x90, 0x94, 0xad, 0x36, 0xba, 0x0d, 0x85, 0x1e, 0xe9, 0x1d, 0x89, 0xd9,
-	0x2c, 0x9f, 0x9d, 0x15, 0x04, 0x3a, 0x69, 0xc1, 0xac, 0x4b, 0xce, 0x3a, 0x1e, 0x45, 0xa8, 0xe4,
-	0xe8, 0x5c, 0xce, 0x0e, 0xc6, 0x6c, 0xa1, 0xeb, 0xbc, 0xf0, 0x0f, 0xa9, 0x98, 0x5e, 0x25, 0x2f,
-	0x16, 0x32, 0x42, 0x93, 0x8e, 0xf1, 0x97, 0x39, 0x28, 0xd9, 0x4e, 0xff, 0x98, 0xd8, 0xe4, 0x93,
-	0x11, 0xf1, 0x7c, 0x34, 0x0f, 0xb9, 0x53, 0x72, 0xc1, 0xe1, 0x4b, 0x36, 0x7b, 0x14, 0xeb, 0x29,
-	0xc7, 0x21, 0xe9, 0x0b, 0xe0, 0x12, 0x5b, 0x4f, 0x09, 0x8d, 0x7e, 0x1b, 0x2d, 0xc2, 0x54, 0xb7,
-	0xd3, 0xeb, 0xf8, 0x12, 0x55, 0x0c, 0x22, 0xea, 0xe4, 0x63, 0xea, 0x6c, 0x02, 0x78, 0x03, 0xd7,
-	0x3f, 0x1c, 0xb8, 0x74, 0xd3, 0x95, 0x29, 0x3a, 0x5b, 0x5e, 0x7f, 0xb0, 0xa6, 0x1f, 0xc4, 0x9a,
-	0xae, 0xd0, 0xda, 0x3e, 0x65, 0xde, 0x63, 0xbc, 0x76, 0xc1, 0x53, 0x8f, 0xe8, 0x7b, 0x50, 0xe4,
-	0x42, 0x7c, 0xc7, 0x3d, 0x26, 0x7e, 0x65, 0x9a, 0x4b, 0x79, 0x78, 0x89, 0x94, 0x26, 0x67, 0xb6,
-	0x39, 0xbc, 0x78, 0x46, 0x18, 0x4a, 0x94, 0xbf, 0xe3, 0x74, 0x3b, 0x9f, 0x3a, 0x47, 0x5d, 0x52,
-	0x99, 0xa1, 0x82, 0x66, 0xed, 0x08, 0x8d, 0xed, 0x9f, 0x9a, 0xc1, 0x3b, 0x1c, 0xf4, 0xbb, 0x17,
-	0x95, 0x59, 0xce, 0x30, 0xcb, 0x08, 0x7b, 0x74, 0xcc, 0x0f, 0x6d, 0x30, 0xea, 0xfb, 0x62, 0xb6,
-	0xc0, 0x67, 0x0b, 0x9c, 0xc2, 0xa6, 0xf1, 0x1a, 0x14, 0x02, 0xfd, 0xd1, 0x2c, 0xe4, 0x77, 0xf7,
-	0x76, 0x1b, 0xf3, 0xd7, 0x10, 0xc0, 0x74, 0x6d, 0x7f, 0xb3, 0xb1, 0x5b, 0x9f, 0xcf, 0xa0, 0x22,
-	0xcc, 0xd4, 0x1b, 0x62, 0x90, 0xc5, 0x1b, 0x00, 0xa1, 0xa6, 0x68, 0x06, 0x72, 0xdb, 0x8d, 0xef,
-	0x53, 0x7e, 0xca, 0x73, 0xd0, 0xb0, 0xf7, 0xb7, 0xf6, 0x76, 0xe9, 0x02, 0xba, 0x78, 0xd3, 0x6e,
-	0xd4, 0x9a, 0x8d, 0xf9, 0x2c, 0xe3, 0xf8, 0x60, 0xaf, 0x3e, 0x9f, 0x43, 0x05, 0x98, 0x3a, 0xa8,
-	0xed, 0x3c, 0x6f, 0xcc, 0xe7, 0xf1, 0x17, 0x19, 0x98, 0x93, 0x7b, 0x17, 0xf7, 0x0b, 0xbd, 0x03,
-	0xd3, 0x27, 0xfc, 0x8e, 0xf1, 0x63, 0x2d, 0xae, 0x2f, 0xc7, 0x0c, 0x15, 0xb9, 0x87, 0xb6, 0xe4,
-	0xa5, 0xb6, 0xc9, 0x9d, 0x9e, 0x79, 0xf4, 0xc4, 0x73, 0x74, 0xc9, 0xfc, 0x9a, 0xb8, 0xfc, 0x6b,
-	0xdb, 0xe4, 0xe2, 0xc0, 0xe9, 0x8e, 0x88, 0xcd, 0x26, 0x11, 0x82, 0x7c, 0x6f, 0xe0, 0x12, 0x7e,
-	0xfa, 0xb3, 0x36, 0x7f, 0x66, 0x57, 0x82, 0x1b, 0x40, 0x9e, 0xbc, 0x18, 0xe0, 0xf7, 0x01, 0x9e,
-	0x8d, 0xfc, 0xe4, 0x5b, 0x46, 0x57, 0x9d, 0x31, 0xb9, 0xf2, 0x86, 0x89, 0x01, 0xbf, 0x5e, 0xc4,
-	0xf1, 0x48, 0x70, 0xbd, 0xd8, 0x00, 0x6f, 0x42, 0x91, 0xcb, 0x4a, 0xb3, 0x3d, 0x2a, 0x04, 0xd5,
-	0x49, 0x97, 0xf8, 0x24, 0xc5, 0xf5, 0xc7, 0x04, 0x16, 0x22, 0x42, 0x52, 0x19, 0xbc, 0x02, 0x33,
-	0x6d, 0x2e, 0x4c, 0xe0, 0xe4, 0x6c, 0x35, 0xc4, 0xff, 0xcc, 0x40, 0x41, 0x6a, 0xb8, 0x37, 0x44,
-	0x35, 0x98, 0x73, 0xc5, 0xe0, 0x90, 0x2b, 0x22, 0x41, 0xac, 0xe4, 0xeb, 0xff, 0xde, 0x35, 0xbb,
-	0x24, 0x97, 0x70, 0x32, 0xfa, 0x0e, 0x14, 0x95, 0x88, 0xe1, 0xc8, 0xe7, 0x70, 0xc5, 0xf5, 0x4a,
-	0x54, 0x40, 0x78, 0x5c, 0x74, 0x39, 0x48, 0x76, 0x4a, 0x44, 0x4d, 0x58, 0x54, 0x8b, 0x85, 0x82,
-	0x52, 0x8d, 0x1c, 0x97, 0xb2, 0x1a, 0x95, 0x32, 0x6e, 0x63, 0x2a, 0x0d, 0xc9, 0xf5, 0xda, 0xe4,
-	0x46, 0x01, 0x66, 0x24, 0x15, 0xff, 0x2b, 0x03, 0xa0, 0x6c, 0x44, 0xf7, 0x5b, 0x87, 0xb2, 0x2b,
-	0x47, 0x91, 0x0d, 0xdf, 0x36, 0x6e, 0x58, 0x9a, 0xf6, 0x9a, 0x3d, 0xa7, 0x16, 0x89, 0x2d, 0xbf,
-	0x0b, 0xa5, 0x40, 0x4a, 0xb8, 0xe7, 0x25, 0xc3, 0x9e, 0x03, 0x09, 0x45, 0xb5, 0x80, 0xed, 0xfa,
-	0x23, 0xb8, 0x19, 0xac, 0x37, 0x6c, 0xfb, 0xde, 0x84, 0x6d, 0x07, 0x02, 0x17, 0x94, 0x04, 0x7d,
-	0xe3, 0xc0, 0x82, 0xa5, 0x20, 0xe3, 0x5f, 0xe7, 0x60, 0x66, 0x73, 0xd0, 0x1b, 0x3a, 0x2e, 0x3b,
-	0xa3, 0x69, 0x4a, 0x1f, 0x75, 0x7d, 0xbe, 0xdd, 0xf2, 0xfa, 0xfd, 0x28, 0x82, 0x64, 0x53, 0x7f,
-	0x6d, 0xce, 0x6a, 0xcb, 0x25, 0x6c, 0xb1, 0x8c, 0x8d, 0xd9, 0x2b, 0x2c, 0x96, 0x91, 0x51, 0x2e,
-	0x51, 0x4e, 0x90, 0x0b, 0x9d, 0xc0, 0x82, 0x19, 0xba, 0x30, 0x8c, 0xe7, 0x74, 0x2f, 0x8a, 0x80,
-	0x5e, 0x85, 0xeb, 0x2d, 0x97, 0x38, 0xcc, 0x1e, 0x2a, 0xe6, 0x4f, 0x49, 0x9e, 0xb2, 0x98, 0xb0,
-	0x55, 0xec, 0xbf, 0x0f, 0xa5, 0xde, 0xa0, 0x1d, 0xf2, 0x4d, 0x4b, 0xbe, 0x22, 0xa5, 0x06, 0x4c,
-	0xb7, 0x54, 0x24, 0x60, 0xc1, 0xb8, 0x44, 0x67, 0xc5, 0x10, 0xbf, 0x05, 0x73, 0x91, 0xbd, 0xb2,
-	0x98, 0xd7, 0xf8, 0xf0, 0x79, 0x6d, 0x47, 0x04, 0xc8, 0xa7, 0x3c, 0x26, 0xda, 0x34, 0x40, 0xd2,
-	0x38, 0xbb, 0xd3, 0xd8, 0xdf, 0xa7, 0xe1, 0xf4, 0xbb, 0xc1, 0x12, 0x19, 0x51, 0xb5, 0x40, 0x7a,
-	0x4d, 0x0b, 0xa4, 0x19, 0x15, 0x48, 0xb3, 0x61, 0x20, 0xcd, 0x6d, 0x94, 0xa1, 0x24, 0x0c, 0x72,
-	0x38, 0xea, 0x53, 0xc5, 0xf0, 0x6f, 0xe9, 0xb5, 0x6c, 0x9e, 0xf7, 0x55, 0xa8, 0xa8, 0xc2, 0x4c,
-	0x4b, 0x08, 0xa7, 0x07, 0xc4, 0x62, 0xe4, 0x4d, 0xa3, 0x8d, 0x6d, 0xc5, 0x85, 0xde, 0x82, 0x19,
-	0x6f, 0xd4, 0x6a, 0x11, 0x4f, 0x05, 0xd5, 0x57, 0xe2, 0x61, 0x41, 0x7a, 0xb8, 0xad, 0xf8, 0xd8,
-	0x92, 0x17, 0x4e, 0xa7, 0x3b, 0xe2, 0x21, 0x76, 0xf2, 0x12, 0xc9, 0x87, 0x7f, 0x95, 0x81, 0x22,
-	0xd7, 0x32, 0x55, 0x2c, 0x5a, 0x86, 0x02, 0xd7, 0x81, 0xb4, 0x65, 0x34, 0xa2, 0xaf, 0xb5, 0x80,
-	0x80, 0xbe, 0x45, 0x63, 0xa2, 0x5c, 0xe7, 0x49, 0xc5, 0x2a, 0x66, 0xb1, 0x54, 0xb3, 0x90, 0x15,
-	0x6f, 0xc3, 0x0d, 0x6e, 0x95, 0x16, 0x4b, 0x85, 0x94, 0x1d, 0xf5, 0x64, 0x21, 0x13, 0x4b, 0x16,
-	0xe8, 0xdc, 0xf0, 0xe4, 0xc2, 0xeb, 0xb4, 0x9c, 0xae, 0xd4, 0x22, 0x18, 0xd3, 0x37, 0x0a, 0xd2,
-	0x85, 0xa5, 0x7a, 0x19, 0xcc, 0x41, 0xf1, 0x3d, 0xc7, 0x3b, 0x91, 0x2a, 0xe1, 0x8f, 0xa1, 0x24,
-	0x86, 0xa9, 0x6c, 0x48, 0x5f, 0x8e, 0x27, 0x54, 0x0a, 0x57, 0x7c, 0xce, 0xe6, 0xcf, 0xf8, 0x06,
-	0x5c, 0xdf, 0xef, 0x3b, 0x43, 0xef, 0x64, 0xa0, 0x82, 0x2b, 0x4b, 0x05, 0xe7, 0x43, 0x5a, 0x2a,
-	0xc4, 0xc7, 0x70, 0xdd, 0x25, 0x3d, 0xa7, 0xd3, 0xef, 0xf4, 0x8f, 0x0f, 0x8f, 0x2e, 0x7c, 0xe2,
-	0xc9, 0x4c, 0xb1, 0x1c, 0x90, 0x37, 0x18, 0x95, 0xa9, 0x76, 0xd4, 0x1d, 0x1c, 0x49, 0x17, 0xe7,
-	0xcf, 0xf8, 0x77, 0x19, 0x28, 0x7d, 0xe4, 0xf8, 0x2d, 0x65, 0x05, 0xb4, 0x05, 0xe5, 0xc0, 0xb1,
-	0x39, 0x45, 0xea, 0x12, 0x8b, 0xf0, 0x7c, 0xcd, 0xa6, 0x74, 0x74, 0x15, 0xe1, 0xe7, 0x5a, 0x3a,
-	0x81, 0x8b, 0x72, 0xfa, 0x2d, 0xd2, 0x0d, 0x44, 0x65, 0x93, 0x45, 0x71, 0x46, 0x5d, 0x94, 0x4e,
-	0xd8, 0xb8, 0x1e, 0xbe, 0xfd, 0x84, 0x5b, 0xd2, 0x7c, 0x07, 0x8d, 0xeb, 0xf0, 0x55, 0x13, 0xd9,
-	0x87, 0x50, 0xf6, 0xa8, 0xb7, 0xfb, 0x87, 0xb1, 0x3c, 0x7a, 0x8e, 0x53, 0x83, 0xe0, 0x44, 0x2d,
-	0x4c, 0x13, 0xf8, 0x63, 0x7a, 0xa5, 0xbd, 0x43, 0x9a, 0xd3, 0x77, 0x5e, 0x5c, 0xf0, 0x80, 0x38,
-	0x6b, 0x97, 0x15, 0x79, 0x97, 0x53, 0x71, 0x55, 0x29, 0xa5, 0x2b, 0x8f, 0x96, 0x60, 0xf6, 0x25,
-	0xa3, 0xaa, 0x0c, 0x9f, 0xbe, 0xe3, 0xf9, 0x78, 0xab, 0x8d, 0xff, 0x41, 0xd3, 0x36, 0x69, 0xfe,
-	0x54, 0x77, 0x40, 0x87, 0xc8, 0x46, 0x20, 0x58, 0x82, 0x21, 0x8e, 0xa5, 0x2d, 0x13, 0x36, 0x35,
-	0x64, 0x7e, 0x26, 0xac, 0x4c, 0xa7, 0xc4, 0x7e, 0x82, 0x31, 0x8d, 0xef, 0xf3, 0x2d, 0xe1, 0x67,
-	0xb1, 0x00, 0x6f, 0x5f, 0x97, 0xf4, 0xc0, 0x3a, 0x0f, 0x61, 0x9a, 0x9c, 0x91, 0xbe, 0xef, 0x55,
-	0x8a, 0x3c, 0x28, 0xcc, 0xa9, 0xac, 0xb1, 0xc1, 0xa8, 0xb6, 0x9c, 0xc4, 0xdf, 0x84, 0x1b, 0x3b,
-	0x2c, 0x91, 0x7b, 0x4a, 0xad, 0xaf, 0xa7, 0x84, 0xcd, 0xe6, 0x8e, 0xb4, 0x4a, 0xce, 0x6f, 0xee,
-	0xa0, 0x32, 0x64, 0xb7, 0xea, 0x72, 0x0f, 0xd9, 0x4e, 0x1d, 0x7f, 0x46, 0x0f, 0x5a, 0x5f, 0x97,
-	0xca, 0x4c, 0x31, 0xe1, 0x0a, 0x3e, 0x17, 0xc2, 0xd3, 0xdc, 0x93, 0xb8, 0xee, 0xc0, 0xe5, 0x06,
-	0x29, 0xd8, 0x62, 0x80, 0x1f, 0x48, 0x1d, 0xe8, 0x9e, 0x07, 0xa7, 0xc1, 0x65, 0x13, 0xd2, 0x32,
-	0x81, 0xaa, 0xdb, 0xb0, 0x10, 0xe1, 0x4a, 0x15, 0x9c, 0x1e, 0xc3, 0x4d, 0x2e, 0x6c, 0x9b, 0x90,
-	0x61, 0xad, 0xdb, 0x39, 0x4b, 0x44, 0x1d, 0xc2, 0xad, 0x38, 0xe3, 0xd7, 0x6b, 0x23, 0x7c, 0x02,
-	0xd3, 0x1f, 0xf0, 0x1a, 0x54, 0xd3, 0x25, 0xcf, 0x79, 0x69, 0x84, 0xe9, 0x3b, 0x3d, 0x91, 0xce,
-	0x17, 0x6c, 0xfe, 0xcc, 0xa3, 0x39, 0x21, 0xee, 0x73, 0x7b, 0x47, 0xbc, 0x35, 0x0a, 0x76, 0x30,
-	0x46, 0x2b, 0xac, 0xfa, 0xed, 0xd0, 0xeb, 0xc1, 0x67, 0xf3, 0x7c, 0x56, 0xa3, 0xd0, 0x4a, 0x6a,
-	0x5e, 0x20, 0xd5, 0xda, 0x6d, 0xed, 0xcd, 0x11, 0xc8, 0xcb, 0x44, 0xe5, 0xe1, 0x97, 0x70, 0x43,
-	0xe3, 0x4f, 0x65, 0x86, 0x37, 0x60, 0x5a, 0x14, 0xda, 0x32, 0x68, 0x2d, 0x46, 0x57, 0x09, 0x18,
-	0x5b, 0xf2, 0xe0, 0x87, 0xb0, 0x20, 0x29, 0xa4, 0x37, 0x30, 0x9d, 0x15, 0xb7, 0x0f, 0xde, 0x81,
-	0xc5, 0x28, 0x5b, 0xaa, 0x2b, 0x52, 0x53, 0xa0, 0xcf, 0x87, 0x6d, 0x2d, 0x06, 0xc6, 0x0f, 0x45,
-	0x37, 0x58, 0x36, 0x66, 0xb0, 0x40, 0x21, 0x25, 0x22, 0x95, 0x42, 0x0b, 0xca, 0xfc, 0x3b, 0x1d,
-	0x2f, 0x78, 0xd3, 0x7d, 0x0a, 0x48, 0x27, 0xa6, 0x3a, 0x94, 0x35, 0x98, 0x11, 0x06, 0x57, 0xc9,
-	0x94, 0xf9, 0x54, 0x14, 0x13, 0x53, 0xa8, 0x4e, 0x5e, 0xb8, 0xce, 0x71, 0x8f, 0x04, 0x31, 0x87,
-	0xa5, 0x10, 0x3a, 0x31, 0xd5, 0x8e, 0xff, 0x44, 0x5f, 0x9f, 0xb5, 0xae, 0xe3, 0xf6, 0x94, 0xf1,
-	0xdf, 0x85, 0x69, 0x91, 0x9b, 0xc8, 0xfc, 0xfd, 0x51, 0x54, 0x8c, 0xce, 0x2b, 0x06, 0x35, 0x91,
-	0xc9, 0xc8, 0x55, 0xec, 0xb0, 0x64, 0x7f, 0xa7, 0x1e, 0xeb, 0xf7, 0xd4, 0xd1, 0x9b, 0x30, 0xe5,
-	0xb0, 0x25, 0xdc, 0x17, 0xcb, 0xf1, 0xac, 0x90, 0x4b, 0x6b, 0x5e, 0x0c, 0x89, 0x2d, 0xb8, 0xf0,
-	0x3b, 0x50, 0xd4, 0x10, 0x58, 0xb2, 0xfb, 0xb4, 0xd1, 0xa4, 0x19, 0x70, 0x09, 0x66, 0x6b, 0x9b,
-	0xcd, 0xad, 0x03, 0x91, 0x03, 0x97, 0x01, 0xea, 0x8d, 0x60, 0x9c, 0xa5, 0x59, 0x90, 0x58, 0x25,
-	0x3d, 0x5c, 0xd7, 0x27, 0x93, 0xa4, 0x4f, 0xf6, 0x4a, 0xfa, 0x9c, 0xc3, 0x9c, 0xdc, 0x7e, 0xaa,
-	0x3b, 0xf0, 0x16, 0xb5, 0x30, 0x13, 0xa3, 0xae, 0xc0, 0x92, 0x01, 0x56, 0x79, 0xa7, 0x60, 0xc4,
-	0x34, 0x7b, 0xd8, 0xf7, 0x1d, 0x7f, 0xe4, 0xa9, 0x2b, 0xf0, 0xc7, 0x0c, 0x94, 0x15, 0x25, 0x6d,
-	0xf5, 0xae, 0x4a, 0x24, 0x11, 0xf3, 0x82, 0x02, 0xe9, 0x16, 0x4c, 0xb7, 0x8f, 0xf6, 0x3b, 0x9f,
-	0xaa, 0x2e, 0x86, 0x1c, 0x31, 0x7a, 0x57, 0xe0, 0x88, 0xae, 0x9c, 0x1c, 0xb1, 0xdc, 0x9b, 0xf5,
-	0xe7, 0xb6, 0xfa, 0x6d, 0x72, 0xce, 0xdf, 0xb4, 0x79, 0x3b, 0x24, 0xf0, 0x74, 0x59, 0x76, 0xef,
-	0x78, 0xfd, 0xa4, 0x77, 0xf3, 0xe8, 0x25, 0xaf, 0x8d, 0xfc, 0x93, 0x46, 0x9f, 0x35, 0xae, 0xd4,
-	0x0e, 0x17, 0x01, 0x31, 0x62, 0xbd, 0xe3, 0xe9, 0xd4, 0x06, 0x2c, 0x30, 0x2a, 0xbd, 0xf7, 0x34,
-	0x99, 0x0e, 0x23, 0x86, 0x0a, 0xdb, 0x99, 0x58, 0xd8, 0x76, 0x3c, 0xef, 0xe5, 0xc0, 0x6d, 0xcb,
-	0xad, 0x05, 0x63, 0x5c, 0x17, 0xc2, 0x9f, 0x7b, 0x91, 0xc0, 0xfc, 0x55, 0xa5, 0x3c, 0x09, 0xa5,
-	0x3c, 0x25, 0xfe, 0x04, 0x29, 0xf8, 0x75, 0xb8, 0xa9, 0x38, 0x65, 0x0d, 0x3d, 0x81, 0x79, 0x0f,
-	0xee, 0x28, 0xe6, 0xcd, 0x13, 0x96, 0xe8, 0x3d, 0x93, 0x80, 0xff, 0xab, 0x9e, 0x1b, 0x50, 0x09,
-	0xf4, 0xe4, 0x39, 0xc8, 0xa0, 0xab, 0x2b, 0x30, 0xf2, 0xe4, 0x9d, 0xa1, 0xb2, 0xd8, 0x33, 0xa3,
-	0xb9, 0x94, 0x45, 0xbd, 0x04, 0xd9, 0x33, 0xde, 0x84, 0x25, 0x25, 0x43, 0x66, 0x07, 0x51, 0x21,
-	0x63, 0x0a, 0x99, 0x84, 0x48, 0x83, 0xb1, 0xa5, 0x93, 0xcd, 0xae, 0x73, 0x46, 0x4d, 0xcb, 0x65,
-	0x66, 0x34, 0x99, 0x37, 0xc5, 0x8d, 0x60, 0x8a, 0xe9, 0x41, 0x5b, 0x92, 0x99, 0x00, 0x9d, 0x2c,
-	0x0f, 0x82, 0x91, 0xc7, 0x0e, 0x62, 0x4c, 0xf4, 0x0f, 0x60, 0x25, 0x50, 0x82, 0xd9, 0xed, 0x19,
-	0xbd, 0xac, 0x1d, 0xcf, 0xd3, 0x8a, 0x40, 0xd3, 0xc6, 0x1f, 0x41, 0x7e, 0x48, 0x64, 0x4c, 0x29,
-	0xae, 0xa3, 0x35, 0xd1, 0x63, 0x5f, 0xd3, 0x16, 0xf3, 0x79, 0xdc, 0x86, 0xbb, 0x4a, 0xba, 0xb0,
-	0xa8, 0x51, 0x7c, 0x5c, 0x29, 0x55, 0x20, 0x08, 0xb3, 0x8e, 0x17, 0x08, 0x39, 0x71, 0xf6, 0x41,
-	0xab, 0xef, 0x7d, 0x61, 0x48, 0xe5, 0x5b, 0xa9, 0xde, 0x15, 0xdb, 0xc2, 0xa6, 0x81, 0x4b, 0xa6,
-	0x12, 0x76, 0x04, 0x8b, 0x51, 0x4f, 0x4e, 0x15, 0xc6, 0x68, 0xd6, 0xeb, 0x53, 0x13, 0xaa, 0x20,
-	0x26, 0x06, 0x4a, 0xe1, 0xc0, 0xcd, 0x53, 0x29, 0xec, 0x84, 0xc2, 0xf8, 0x95, 0x4c, 0xab, 0x2f,
-	0x3b, 0x4d, 0x95, 0xcf, 0x88, 0x01, 0xde, 0x85, 0x5b, 0xf1, 0x30, 0x91, 0x4a, 0xe5, 0x03, 0x71,
-	0x81, 0x4d, 0x91, 0x24, 0x95, 0xdc, 0x0f, 0xc3, 0x60, 0xa0, 0x05, 0x94, 0x54, 0x22, 0x6d, 0xb0,
-	0x4c, 0xf1, 0xe5, 0xff, 0x71, 0x5f, 0x83, 0x70, 0x93, 0x4a, 0x98, 0x17, 0x0a, 0x4b, 0x7f, 0xfc,
-	0x61, 0x8c, 0xc8, 0x4d, 0x8c, 0x11, 0xd2, 0x49, 0xc2, 0x28, 0xf6, 0x35, 0x5c, 0x3a, 0x89, 0x11,
-	0x06, 0xd0, 0xb4, 0x18, 0xec, 0x1d, 0x12, 0x60, 0xf0, 0x81, 0xba, 0xd8, 0x7a, 0xd8, 0x4d, 0x75,
-	0x18, 0x1f, 0x85, 0xb1, 0x73, 0x2c, 0x32, 0xa7, 0x12, 0xfc, 0x31, 0xac, 0x26, 0x07, 0xe5, 0x34,
-	0x92, 0x5f, 0xc3, 0x50, 0x08, 0x12, 0x4a, 0xed, 0x9b, 0x5a, 0x11, 0x66, 0x76, 0xf7, 0xf6, 0x9f,
-	0xd5, 0x36, 0x69, 0x2a, 0xbb, 0xfe, 0x97, 0x1c, 0x64, 0xb7, 0x0f, 0xd0, 0x0f, 0x61, 0x4a, 0x34,
-	0xff, 0x27, 0x7c, 0x1b, 0xb1, 0x26, 0x7d, 0x46, 0xc0, 0xcb, 0x9f, 0xfd, 0xf9, 0xef, 0x5f, 0x64,
-	0x6f, 0xe1, 0x1b, 0xd5, 0xb3, 0xb7, 0x9d, 0xee, 0xf0, 0xc4, 0xa9, 0x9e, 0x9e, 0x55, 0xf9, 0x3b,
-	0xe1, 0xdb, 0x99, 0xd7, 0xd0, 0x01, 0xe4, 0xd8, 0xa7, 0x81, 0xc4, 0x0f, 0x27, 0x56, 0xf2, 0xe7,
-	0x05, 0x6c, 0x71, 0xc9, 0x8b, 0xf8, 0xba, 0x2e, 0x79, 0x38, 0xf2, 0x99, 0xdc, 0x26, 0x14, 0xb5,
-	0x2f, 0x04, 0xe8, 0xd2, 0x4f, 0x2a, 0xd6, 0xe5, 0x5f, 0x1f, 0xf0, 0x35, 0xa6, 0x6d, 0xf3, 0xbc,
-	0x1f, 0xd7, 0x36, 0xec, 0x68, 0xc7, 0xb5, 0xd5, 0xba, 0xc8, 0x66, 0x6d, 0xfd, 0xf3, 0x3e, 0xd3,
-	0x76, 0x20, 0xbf, 0x59, 0xb4, 0x7c, 0x74, 0xd7, 0xd0, 0x02, 0xd7, 0x9b, 0xbd, 0xd6, 0x6a, 0x32,
-	0x83, 0x44, 0xba, 0xc7, 0x91, 0x6e, 0xe3, 0x5b, 0x3a, 0x52, 0x2b, 0xe0, 0xa3, 0x80, 0xeb, 0x27,
-	0x30, 0xc5, 0x3b, 0x65, 0xe8, 0x50, 0x3d, 0x58, 0x86, 0x3e, 0x62, 0xc2, 0xf9, 0x46, 0x7a, 0x6c,
-	0x78, 0x89, 0xa3, 0x2d, 0xe0, 0x72, 0x80, 0xc6, 0x9b, 0x65, 0x14, 0xe5, 0x49, 0xe6, 0x1b, 0x99,
-	0xf5, 0x7f, 0x67, 0x61, 0x8a, 0xb7, 0x54, 0xd0, 0x10, 0x20, 0xec, 0x3d, 0xc5, 0xf7, 0x39, 0xd6,
-	0xcd, 0x8a, 0xef, 0x73, 0xbc, 0x6d, 0x85, 0xef, 0x72, 0xe4, 0x25, 0xbc, 0x18, 0x20, 0xf3, 0x8f,
-	0x9b, 0xd5, 0x63, 0xc6, 0xc5, 0xcc, 0xfa, 0x12, 0x8a, 0x5a, 0x0f, 0x09, 0x99, 0x24, 0x46, 0x9a,
-	0x50, 0xf1, 0x4b, 0x60, 0x68, 0x40, 0xe1, 0xfb, 0x1c, 0xf4, 0x0e, 0xae, 0xe8, 0xc6, 0x15, 0xb8,
-	0x2e, 0xe7, 0x64, 0xc0, 0x3f, 0xa3, 0x25, 0x51, 0xb4, 0x8f, 0x84, 0xee, 0x1b, 0x44, 0xc7, 0xdb,
-	0x51, 0xd6, 0x83, 0xc9, 0x4c, 0x89, 0x2a, 0x08, 0xfc, 0x53, 0xca, 0xe9, 0x30, 0x4e, 0x65, 0xfb,
-	0xff, 0xb0, 0x6f, 0x61, 0xe2, 0xe7, 0x0f, 0xc8, 0x87, 0x42, 0xd0, 0xcd, 0x41, 0x2b, 0xa6, 0x4a,
-	0x3f, 0x4c, 0x83, 0xad, 0xbb, 0x89, 0xf3, 0x52, 0x85, 0x47, 0x5c, 0x85, 0x55, 0x7c, 0x3b, 0x50,
-	0x41, 0xfe, 0xcc, 0xa2, 0x2a, 0x0a, 0xda, 0xaa, 0xd3, 0x6e, 0x33, 0x43, 0xfc, 0x94, 0x96, 0xf4,
-	0x7a, 0x93, 0x06, 0xdd, 0x33, 0xf6, 0x18, 0xf4, 0x3e, 0x8f, 0x85, 0x27, 0xb1, 0x48, 0xfc, 0x57,
-	0x39, 0xfe, 0x7d, 0xbc, 0x92, 0x84, 0xef, 0x72, 0xfe, 0xa8, 0x0a, 0xa2, 0x2d, 0x63, 0x56, 0x21,
-	0xd2, 0xf5, 0x31, 0xab, 0x10, 0xed, 0xea, 0x5c, 0xae, 0xc2, 0x88, 0xf3, 0x33, 0x15, 0xce, 0x01,
-	0xc2, 0xae, 0x0d, 0x32, 0x1a, 0x57, 0x2b, 0x0c, 0xe2, 0x37, 0x7f, 0xbc, 0xe1, 0x83, 0x1f, 0x73,
-	0xec, 0x7b, 0x78, 0x39, 0x09, 0xbb, 0x4b, 0xb9, 0x99, 0x9f, 0xff, 0x3e, 0x0f, 0xc5, 0x0f, 0x9c,
-	0x4e, 0xdf, 0x27, 0x7d, 0xd6, 0x8c, 0x46, 0xc7, 0x30, 0xc5, 0x23, 0x7f, 0xdc, 0xdd, 0xf5, 0x56,
-	0x4a, 0xdc, 0xdd, 0x23, 0x7d, 0x06, 0xfc, 0x90, 0x43, 0xdf, 0xc5, 0x56, 0x00, 0xdd, 0x0b, 0xe5,
-	0x57, 0x79, 0x8f, 0x80, 0x6d, 0xf9, 0x14, 0xa6, 0x45, 0x4f, 0x00, 0xc5, 0xa4, 0x45, 0x7a, 0x07,
-	0xd6, 0xb2, 0x79, 0x32, 0xf1, 0x96, 0xe9, 0x58, 0x1e, 0x67, 0x66, 0x60, 0x3f, 0x02, 0x08, 0x9b,
-	0x50, 0x71, 0xfb, 0x8e, 0xf5, 0xac, 0xac, 0xd5, 0x64, 0x06, 0x09, 0xfc, 0x1a, 0x07, 0x7e, 0x80,
-	0xef, 0x1a, 0x81, 0xdb, 0xc1, 0x02, 0x06, 0xde, 0x82, 0x3c, 0xfb, 0xd2, 0x85, 0x62, 0xa1, 0x5f,
-	0xfb, 0x18, 0x66, 0x59, 0xa6, 0x29, 0x09, 0xf5, 0x80, 0x43, 0xad, 0xe0, 0x25, 0x23, 0x14, 0xfb,
-	0xe2, 0xc5, 0x40, 0x46, 0x30, 0xab, 0x3e, 0x70, 0xa1, 0x3b, 0x31, 0x9b, 0x45, 0x3f, 0x86, 0x59,
-	0x2b, 0x49, 0xd3, 0x12, 0xf0, 0x09, 0x07, 0xc4, 0xf8, 0x8e, 0xd9, 0xa8, 0x92, 0x9d, 0x82, 0xd2,
-	0x00, 0xf2, 0x8b, 0x79, 0xc8, 0xb3, 0x1c, 0x84, 0xc5, 0xee, 0xb0, 0x74, 0x8b, 0x5b, 0x78, 0xac,
-	0x61, 0x12, 0xb7, 0xf0, 0x78, 0xd5, 0x67, 0x88, 0xdd, 0xfc, 0x47, 0x60, 0x84, 0x73, 0xb1, 0x1d,
-	0xfb, 0x50, 0xd4, 0x0a, 0x3c, 0x64, 0x90, 0x18, 0x6d, 0xc7, 0xc4, 0x63, 0xb7, 0xa1, 0x3a, 0xc4,
-	0xab, 0x1c, 0xd4, 0xc2, 0x37, 0xa3, 0xa0, 0x6d, 0xc1, 0xc6, 0x50, 0x7f, 0x0c, 0x25, 0xbd, 0x12,
-	0x44, 0x06, 0xa1, 0xb1, 0x7e, 0x4f, 0x3c, 0x56, 0x98, 0x0a, 0x49, 0x83, 0xd3, 0x04, 0x3f, 0x79,
-	0x53, 0xbc, 0x0c, 0xfd, 0x13, 0x98, 0x91, 0xf5, 0xa1, 0x69, 0xbf, 0xd1, 0x0e, 0x91, 0x69, 0xbf,
-	0xb1, 0xe2, 0xd2, 0x90, 0x08, 0x70, 0x58, 0x96, 0x07, 0xab, 0x00, 0x2d, 0x21, 0x69, 0x19, 0x91,
-	0x04, 0x19, 0xf6, 0x3c, 0x92, 0x20, 0xb5, 0x1a, 0x64, 0x22, 0xe4, 0x31, 0xf1, 0xe5, 0x5d, 0x56,
-	0x09, 0x3e, 0x4a, 0x90, 0xa8, 0x47, 0x43, 0x3c, 0x89, 0x45, 0xa2, 0x62, 0x8e, 0xba, 0x8c, 0x5f,
-	0x31, 0xa0, 0xca, 0x50, 0x88, 0x7e, 0x02, 0x10, 0x16, 0xb3, 0xf1, 0xd7, 0xb1, 0xb1, 0x23, 0x16,
-	0x7f, 0x1d, 0x9b, 0xeb, 0x61, 0x83, 0x07, 0x87, 0xe0, 0xe2, 0x67, 0x2e, 0x0c, 0xfe, 0x97, 0x19,
-	0x40, 0xe3, 0xc5, 0x2f, 0x7a, 0xdd, 0x0c, 0x61, 0x6c, 0xb6, 0x59, 0x6f, 0x5c, 0x8d, 0x39, 0x31,
-	0x7a, 0x86, 0x7a, 0xb5, 0xf8, 0x92, 0xe1, 0x4b, 0xa6, 0xd9, 0xe7, 0x19, 0x98, 0x8b, 0x94, 0xcf,
-	0xe8, 0x51, 0xc2, 0x39, 0xc7, 0x1a, 0x76, 0xd6, 0xe3, 0x4b, 0xf9, 0x12, 0x33, 0x16, 0xed, 0x56,
-	0xa8, 0x6c, 0xed, 0xe7, 0x34, 0x69, 0x8a, 0xd6, 0xdc, 0x28, 0x01, 0x60, 0xac, 0xeb, 0x67, 0x3d,
-	0xb9, 0x9c, 0xf1, 0x0a, 0xa7, 0x15, 0x26, 0x70, 0xd4, 0x2d, 0x64, 0xa9, 0x6e, 0x72, 0x8b, 0x68,
-	0xd3, 0xd0, 0xe4, 0x16, 0xb1, 0x3a, 0x3f, 0xc9, 0x2d, 0x58, 0xd5, 0xab, 0x79, 0xa2, 0x2c, 0xe8,
-	0x93, 0x20, 0x27, 0x7b, 0x62, 0xac, 0x1b, 0x30, 0x11, 0x32, 0xf4, 0x44, 0x55, 0xce, 0xa3, 0x04,
-	0x89, 0x97, 0x78, 0x62, 0xbc, 0x1b, 0x90, 0xe4, 0x89, 0x1c, 0x55, 0xf3, 0xc4, 0xb0, 0xfa, 0x36,
-	0x79, 0xe2, 0x58, 0x4b, 0xd4, 0xe4, 0x89, 0xe3, 0x05, 0x7c, 0xd2, 0xd9, 0x72, 0xf0, 0x88, 0x27,
-	0x2e, 0x18, 0xaa, 0x75, 0xf4, 0x46, 0x82, 0x4d, 0x8d, 0xed, 0x56, 0xeb, 0xcd, 0x2b, 0x72, 0x4f,
-	0xf6, 0x00, 0x71, 0x1a, 0xca, 0x03, 0x7e, 0x93, 0x81, 0x45, 0x53, 0xb9, 0x8f, 0x12, 0xc0, 0x12,
-	0x7a, 0xb5, 0xd6, 0xda, 0x55, 0xd9, 0xaf, 0x60, 0xb7, 0xc0, 0x27, 0x36, 0x4a, 0x7f, 0xf8, 0xdb,
-	0x4a, 0xe6, 0x4b, 0xfa, 0xef, 0xaf, 0xf4, 0xdf, 0xd1, 0x34, 0xff, 0x15, 0xf6, 0xdb, 0xff, 0x0d,
-	0x00, 0x00, 0xff, 0xff, 0x7b, 0x02, 0x74, 0xf8, 0x0c, 0x2e, 0x00, 0x00,
+	0xda, 0xa7, 0x5f, 0x1a, 0x2c, 0x1b, 0x0e, 0x40, 0x38, 0x62, 0xa4, 0x19, 0xaf, 0x65, 0xc9, 0xd2,
+	0xba, 0x35, 0x2b, 0x9b, 0x08, 0x02, 0x45, 0x6b, 0xa6, 0x56, 0x9a, 0xd0, 0xbc, 0xdc, 0xdd, 0xa3,
+	0x5d, 0x2d, 0x10, 0x01, 0x0e, 0x7c, 0x80, 0xab, 0x0f, 0x04, 0x70, 0xe4, 0x37, 0x70, 0xe3, 0x07,
+	0x10, 0x5c, 0x70, 0x04, 0x47, 0x2e, 0x04, 0xc1, 0x81, 0x03, 0x77, 0x82, 0x13, 0xd4, 0xb3, 0xbb,
+	0xba, 0xa7, 0x7a, 0x24, 0xd3, 0xf8, 0xb0, 0xab, 0xae, 0xac, 0xac, 0xcc, 0xac, 0xac, 0xca, 0xaf,
+	0x33, 0xb3, 0x07, 0x0a, 0xee, 0xb0, 0xb5, 0x36, 0x74, 0x07, 0xfe, 0x00, 0x95, 0x88, 0xdf, 0x6a,
+	0x7b, 0xc4, 0x3d, 0x23, 0xee, 0xf0, 0xc8, 0x5a, 0x3c, 0x1e, 0x1c, 0x0f, 0xf8, 0x44, 0x95, 0x3d,
+	0x09, 0x1e, 0x6b, 0x89, 0xf1, 0x54, 0x7b, 0x67, 0xad, 0x16, 0xff, 0x6f, 0x78, 0x54, 0x3d, 0x3d,
+	0x93, 0x53, 0x37, 0xf9, 0x94, 0x33, 0xf2, 0x4f, 0xf8, 0x7f, 0x74, 0x8a, 0xfd, 0x91, 0x93, 0xcb,
+	0xc7, 0x83, 0xc1, 0x71, 0x97, 0x54, 0x9d, 0x61, 0xa7, 0xea, 0xf4, 0xfb, 0x03, 0xdf, 0xf1, 0x3b,
+	0x83, 0xbe, 0x27, 0x66, 0xf1, 0xe7, 0x19, 0x28, 0xdb, 0xc4, 0x1b, 0x52, 0x0a, 0x79, 0x9f, 0x38,
+	0x6d, 0xe2, 0xa2, 0x5b, 0x00, 0xad, 0xee, 0xc8, 0xf3, 0x89, 0x7b, 0xd8, 0x69, 0x57, 0x32, 0xab,
+	0x99, 0x47, 0x79, 0xbb, 0x20, 0x29, 0x5b, 0x6d, 0x74, 0x13, 0x0a, 0x3d, 0xd2, 0x3b, 0x12, 0xb3,
+	0x59, 0x3e, 0x3b, 0x2b, 0x08, 0x74, 0xd2, 0x82, 0x59, 0x97, 0x9c, 0x75, 0x3c, 0xaa, 0xa1, 0x92,
+	0xa3, 0x73, 0x39, 0x3b, 0x18, 0xb3, 0x85, 0xae, 0xf3, 0xcc, 0x3f, 0xa4, 0x62, 0x7a, 0x95, 0xbc,
+	0x58, 0xc8, 0x08, 0x4d, 0x3a, 0xc6, 0x5f, 0xe6, 0xa0, 0x64, 0x3b, 0xfd, 0x63, 0x62, 0x93, 0x4f,
+	0x47, 0xc4, 0xf3, 0xd1, 0x3c, 0xe4, 0x4e, 0xc9, 0x39, 0x57, 0x5f, 0xb2, 0xd9, 0xa3, 0x58, 0x4f,
+	0x39, 0x0e, 0x49, 0x5f, 0x28, 0x2e, 0xb1, 0xf5, 0x94, 0xd0, 0xe8, 0xb7, 0xd1, 0x22, 0x4c, 0x75,
+	0x3b, 0xbd, 0x8e, 0x2f, 0xb5, 0x8a, 0x41, 0xc4, 0x9c, 0x7c, 0xcc, 0x9c, 0x4d, 0x00, 0x6f, 0xe0,
+	0xfa, 0x87, 0x03, 0x97, 0x6e, 0xba, 0x32, 0x45, 0x67, 0xcb, 0xeb, 0xf7, 0xd6, 0xf4, 0x83, 0x58,
+	0xd3, 0x0d, 0x5a, 0xdb, 0xa7, 0xcc, 0x7b, 0x8c, 0xd7, 0x2e, 0x78, 0xea, 0x11, 0xbd, 0x07, 0x45,
+	0x2e, 0xc4, 0x77, 0xdc, 0x63, 0xe2, 0x57, 0xa6, 0xb9, 0x94, 0xfb, 0x17, 0x48, 0x69, 0x72, 0x66,
+	0x9b, 0xab, 0x17, 0xcf, 0x08, 0x43, 0x89, 0xf2, 0x77, 0x9c, 0x6e, 0xe7, 0xa5, 0x73, 0xd4, 0x25,
+	0x95, 0x19, 0x2a, 0x68, 0xd6, 0x8e, 0xd0, 0xd8, 0xfe, 0xa9, 0x1b, 0xbc, 0xc3, 0x41, 0xbf, 0x7b,
+	0x5e, 0x99, 0xe5, 0x0c, 0xb3, 0x8c, 0xb0, 0x47, 0xc7, 0xfc, 0xd0, 0x06, 0xa3, 0xbe, 0x2f, 0x66,
+	0x0b, 0x7c, 0xb6, 0xc0, 0x29, 0x6c, 0x1a, 0xaf, 0x41, 0x21, 0xb0, 0x1f, 0xcd, 0x42, 0x7e, 0x77,
+	0x6f, 0xb7, 0x31, 0x7f, 0x05, 0x01, 0x4c, 0xd7, 0xf6, 0x37, 0x1b, 0xbb, 0xf5, 0xf9, 0x0c, 0x2a,
+	0xc2, 0x4c, 0xbd, 0x21, 0x06, 0x59, 0xbc, 0x01, 0x10, 0x5a, 0x8a, 0x66, 0x20, 0xb7, 0xdd, 0xf8,
+	0x1e, 0xe5, 0xa7, 0x3c, 0x07, 0x0d, 0x7b, 0x7f, 0x6b, 0x6f, 0x97, 0x2e, 0xa0, 0x8b, 0x37, 0xed,
+	0x46, 0xad, 0xd9, 0x98, 0xcf, 0x32, 0x8e, 0x0f, 0xf7, 0xea, 0xf3, 0x39, 0x54, 0x80, 0xa9, 0x83,
+	0xda, 0xce, 0xd3, 0xc6, 0x7c, 0x1e, 0x7f, 0x91, 0x81, 0x39, 0xb9, 0x77, 0x71, 0xbf, 0xd0, 0x3b,
+	0x30, 0x7d, 0xc2, 0xef, 0x18, 0x3f, 0xd6, 0xe2, 0xfa, 0x72, 0xcc, 0x51, 0x91, 0x7b, 0x68, 0x4b,
+	0x5e, 0xea, 0x9b, 0xdc, 0xe9, 0x99, 0x47, 0x4f, 0x3c, 0x47, 0x97, 0xcc, 0xaf, 0x89, 0xcb, 0xbf,
+	0xb6, 0x4d, 0xce, 0x0f, 0x9c, 0xee, 0x88, 0xd8, 0x6c, 0x12, 0x21, 0xc8, 0xf7, 0x06, 0x2e, 0xe1,
+	0xa7, 0x3f, 0x6b, 0xf3, 0x67, 0x76, 0x25, 0xb8, 0x03, 0xe4, 0xc9, 0x8b, 0x01, 0xfe, 0x00, 0xe0,
+	0xc9, 0xc8, 0x4f, 0xbe, 0x65, 0x74, 0xd5, 0x19, 0x93, 0x2b, 0x6f, 0x98, 0x18, 0xf0, 0xeb, 0x45,
+	0x1c, 0x8f, 0x04, 0xd7, 0x8b, 0x0d, 0xf0, 0x26, 0x14, 0xb9, 0xac, 0x34, 0xdb, 0xa3, 0x42, 0x50,
+	0x9d, 0x74, 0x89, 0x4f, 0x52, 0x5c, 0x7f, 0x4c, 0x60, 0x21, 0x22, 0x24, 0x95, 0xc3, 0x2b, 0x30,
+	0xd3, 0xe6, 0xc2, 0x84, 0x9e, 0x9c, 0xad, 0x86, 0xf8, 0x9f, 0x19, 0x28, 0x48, 0x0b, 0xf7, 0x86,
+	0xa8, 0x06, 0x73, 0xae, 0x18, 0x1c, 0x72, 0x43, 0xa4, 0x12, 0x2b, 0xf9, 0xfa, 0xbf, 0x7f, 0xc5,
+	0x2e, 0xc9, 0x25, 0x9c, 0x8c, 0xbe, 0x03, 0x45, 0x25, 0x62, 0x38, 0xf2, 0xb9, 0xba, 0xe2, 0x7a,
+	0x25, 0x2a, 0x20, 0x3c, 0x2e, 0xba, 0x1c, 0x24, 0x3b, 0x25, 0xa2, 0x26, 0x2c, 0xaa, 0xc5, 0xc2,
+	0x40, 0x69, 0x46, 0x8e, 0x4b, 0x59, 0x8d, 0x4a, 0x19, 0xf7, 0x31, 0x95, 0x86, 0xe4, 0x7a, 0x6d,
+	0x72, 0xa3, 0x00, 0x33, 0x92, 0x8a, 0xff, 0x95, 0x01, 0x50, 0x3e, 0xa2, 0xfb, 0xad, 0x43, 0xd9,
+	0x95, 0xa3, 0xc8, 0x86, 0x6f, 0x1a, 0x37, 0x2c, 0x5d, 0x7b, 0xc5, 0x9e, 0x53, 0x8b, 0xc4, 0x96,
+	0xdf, 0x85, 0x52, 0x20, 0x25, 0xdc, 0xf3, 0x92, 0x61, 0xcf, 0x81, 0x84, 0xa2, 0x5a, 0xc0, 0x76,
+	0xfd, 0x31, 0x5c, 0x0f, 0xd6, 0x1b, 0xb6, 0x7d, 0x67, 0xc2, 0xb6, 0x03, 0x81, 0x0b, 0x4a, 0x82,
+	0xbe, 0x71, 0x60, 0x60, 0x29, 0xc8, 0xf8, 0xd7, 0x39, 0x98, 0xd9, 0x1c, 0xf4, 0x86, 0x8e, 0xcb,
+	0xce, 0x68, 0x9a, 0xd2, 0x47, 0x5d, 0x9f, 0x6f, 0xb7, 0xbc, 0x7e, 0x37, 0xaa, 0x41, 0xb2, 0xa9,
+	0xbf, 0x36, 0x67, 0xb5, 0xe5, 0x12, 0xb6, 0x58, 0x62, 0x63, 0xf6, 0x12, 0x8b, 0x25, 0x32, 0xca,
+	0x25, 0x2a, 0x08, 0x72, 0x61, 0x10, 0x58, 0x30, 0x43, 0x17, 0x86, 0x78, 0x4e, 0xf7, 0xa2, 0x08,
+	0xe8, 0x55, 0xb8, 0xda, 0x72, 0x89, 0xc3, 0xfc, 0xa1, 0x30, 0x7f, 0x4a, 0xf2, 0x94, 0xc5, 0x84,
+	0xad, 0xb0, 0xff, 0x2e, 0x94, 0x7a, 0x83, 0x76, 0xc8, 0x37, 0x2d, 0xf9, 0x8a, 0x94, 0x1a, 0x30,
+	0xdd, 0x50, 0x48, 0xc0, 0xc0, 0xb8, 0x44, 0x67, 0xc5, 0x10, 0xbf, 0x05, 0x73, 0x91, 0xbd, 0x32,
+	0xcc, 0x6b, 0x7c, 0xf4, 0xb4, 0xb6, 0x23, 0x00, 0xf2, 0x31, 0xc7, 0x44, 0x9b, 0x02, 0x24, 0xc5,
+	0xd9, 0x9d, 0xc6, 0xfe, 0x3e, 0x85, 0xd3, 0xef, 0x06, 0x4b, 0x24, 0xa2, 0x6a, 0x40, 0x7a, 0x45,
+	0x03, 0xd2, 0x8c, 0x02, 0xd2, 0x6c, 0x08, 0xa4, 0xb9, 0x8d, 0x32, 0x94, 0x84, 0x43, 0x0e, 0x47,
+	0x7d, 0x6a, 0x18, 0xfe, 0x2d, 0xbd, 0x96, 0xcd, 0x17, 0x7d, 0x05, 0x15, 0x55, 0x98, 0x69, 0x09,
+	0xe1, 0xf4, 0x80, 0x18, 0x46, 0x5e, 0x37, 0xfa, 0xd8, 0x56, 0x5c, 0xe8, 0x2d, 0x98, 0xf1, 0x46,
+	0xad, 0x16, 0xf1, 0x14, 0xa8, 0xbe, 0x12, 0x87, 0x05, 0x19, 0xe1, 0xb6, 0xe2, 0x63, 0x4b, 0x9e,
+	0x39, 0x9d, 0xee, 0x88, 0x43, 0xec, 0xe4, 0x25, 0x92, 0x0f, 0xff, 0x2a, 0x03, 0x45, 0x6e, 0x65,
+	0x2a, 0x2c, 0x5a, 0x86, 0x02, 0xb7, 0x81, 0xb4, 0x25, 0x1a, 0xd1, 0xd7, 0x5a, 0x40, 0x40, 0xdf,
+	0xa2, 0x98, 0x28, 0xd7, 0x79, 0xd2, 0xb0, 0x8a, 0x59, 0x2c, 0xb5, 0x2c, 0x64, 0xc5, 0xdb, 0x70,
+	0x8d, 0x7b, 0xa5, 0xc5, 0x52, 0x21, 0xe5, 0x47, 0x3d, 0x59, 0xc8, 0xc4, 0x92, 0x05, 0x3a, 0x37,
+	0x3c, 0x39, 0xf7, 0x3a, 0x2d, 0xa7, 0x2b, 0xad, 0x08, 0xc6, 0xf4, 0x8d, 0x82, 0x74, 0x61, 0xa9,
+	0x5e, 0x06, 0x73, 0x50, 0x7c, 0xdf, 0xf1, 0x4e, 0xa4, 0x49, 0xf8, 0x13, 0x28, 0x89, 0x61, 0x2a,
+	0x1f, 0xd2, 0x97, 0xe3, 0x09, 0x95, 0xc2, 0x0d, 0x9f, 0xb3, 0xf9, 0x33, 0xbe, 0x06, 0x57, 0xf7,
+	0xfb, 0xce, 0xd0, 0x3b, 0x19, 0x28, 0x70, 0x65, 0xa9, 0xe0, 0x7c, 0x48, 0x4b, 0xa5, 0xf1, 0x21,
+	0x5c, 0x75, 0x49, 0xcf, 0xe9, 0xf4, 0x3b, 0xfd, 0xe3, 0xc3, 0xa3, 0x73, 0x9f, 0x78, 0x32, 0x53,
+	0x2c, 0x07, 0xe4, 0x0d, 0x46, 0x65, 0xa6, 0x1d, 0x75, 0x07, 0x47, 0x32, 0xc4, 0xf9, 0x33, 0xfe,
+	0x5d, 0x06, 0x4a, 0x1f, 0x3b, 0x7e, 0x4b, 0x79, 0x01, 0x6d, 0x41, 0x39, 0x08, 0x6c, 0x4e, 0x91,
+	0xb6, 0xc4, 0x10, 0x9e, 0xaf, 0xd9, 0x94, 0x81, 0xae, 0x10, 0x7e, 0xae, 0xa5, 0x13, 0xb8, 0x28,
+	0xa7, 0xdf, 0x22, 0xdd, 0x40, 0x54, 0x36, 0x59, 0x14, 0x67, 0xd4, 0x45, 0xe9, 0x84, 0x8d, 0xab,
+	0xe1, 0xdb, 0x4f, 0x84, 0xe5, 0x4f, 0xb3, 0x80, 0xc6, 0x6d, 0xf8, 0xaa, 0x89, 0xec, 0x7d, 0x28,
+	0x7b, 0x34, 0xda, 0xfd, 0xc3, 0x58, 0x1e, 0x3d, 0xc7, 0xa9, 0x01, 0x38, 0x51, 0x0f, 0xd3, 0x04,
+	0xfe, 0x98, 0x5e, 0x69, 0xef, 0x90, 0xe6, 0xf4, 0x9d, 0x67, 0xe7, 0x1c, 0x10, 0x67, 0xed, 0xb2,
+	0x22, 0xef, 0x72, 0x2a, 0x6a, 0xd0, 0xc8, 0xed, 0x74, 0x69, 0xce, 0xed, 0x51, 0x34, 0xcc, 0x51,
+	0x04, 0x7e, 0xfd, 0x22, 0xaf, 0xad, 0xbd, 0xc7, 0xf9, 0x9b, 0xe7, 0x43, 0x8a, 0x19, 0x72, 0x2d,
+	0xbe, 0x0f, 0x10, 0x92, 0x19, 0x38, 0xed, 0xee, 0x3d, 0x79, 0xda, 0xa4, 0xe0, 0x55, 0x82, 0xd9,
+	0xdd, 0xbd, 0x7a, 0x63, 0xa7, 0xc1, 0xe0, 0x0b, 0x57, 0x95, 0x0b, 0x74, 0x57, 0xa1, 0x25, 0x98,
+	0x7d, 0xce, 0xa8, 0xaa, 0x9e, 0xa0, 0x19, 0x05, 0x1f, 0x6f, 0xb5, 0xf1, 0x3f, 0x68, 0x92, 0x28,
+	0x0f, 0x3b, 0xd5, 0x8d, 0xd3, 0x55, 0x64, 0x23, 0x2a, 0x58, 0x3a, 0x23, 0x2e, 0x41, 0x5b, 0xa6,
+	0x87, 0x6a, 0xc8, 0xa2, 0x5a, 0x9c, 0x29, 0x9d, 0x12, 0xde, 0x0b, 0xc6, 0xf4, 0x6d, 0x32, 0xdf,
+	0x12, 0x51, 0x1d, 0x7b, 0x9d, 0xd8, 0x57, 0x25, 0x3d, 0x38, 0x8b, 0xfb, 0x30, 0x4d, 0xce, 0x48,
+	0xdf, 0xf7, 0x2a, 0x45, 0x0e, 0x41, 0x73, 0x2a, 0x47, 0x6d, 0x30, 0xaa, 0x2d, 0x27, 0xf1, 0x37,
+	0xe1, 0xda, 0x0e, 0x4b, 0x1b, 0x1f, 0xd3, 0xb3, 0xd6, 0x13, 0xd0, 0x66, 0x73, 0x47, 0x7a, 0x25,
+	0xe7, 0x37, 0x77, 0x50, 0x19, 0xb2, 0x5b, 0x75, 0xb9, 0x87, 0x6c, 0xa7, 0x8e, 0x3f, 0xcb, 0x00,
+	0xd2, 0xd7, 0xa5, 0x72, 0x53, 0x4c, 0xb8, 0x52, 0x9f, 0x0b, 0xd5, 0xd3, 0x4c, 0x97, 0xb8, 0xee,
+	0xc0, 0xe5, 0x0e, 0x29, 0xd8, 0x62, 0x80, 0xef, 0x49, 0x1b, 0xe8, 0x9e, 0x07, 0xa7, 0xc1, 0xd5,
+	0x16, 0xd2, 0x32, 0x81, 0xa9, 0xdb, 0xb0, 0x10, 0xe1, 0x4a, 0x05, 0x85, 0x0f, 0xe1, 0x3a, 0x17,
+	0xb6, 0x4d, 0xc8, 0xb0, 0xd6, 0xed, 0x9c, 0x25, 0x6a, 0x1d, 0xc2, 0x8d, 0x38, 0xe3, 0xd7, 0xeb,
+	0x23, 0x7c, 0x02, 0xd3, 0x1f, 0xf2, 0x8a, 0x57, 0xb3, 0x25, 0xcf, 0x79, 0x29, 0x9e, 0xf5, 0x9d,
+	0x9e, 0x28, 0x1e, 0x0a, 0x36, 0x7f, 0xe6, 0xef, 0x0e, 0x42, 0xdc, 0xa7, 0xf6, 0x8e, 0x78, 0x47,
+	0x15, 0xec, 0x60, 0x8c, 0x56, 0x58, 0xad, 0xdd, 0xa1, 0xd7, 0x83, 0xcf, 0xe6, 0xf9, 0xac, 0x46,
+	0xa1, 0x75, 0xdb, 0xbc, 0xd0, 0x54, 0x6b, 0xb7, 0xb5, 0xf7, 0x54, 0x20, 0x2f, 0x13, 0x95, 0x87,
+	0x9f, 0xc3, 0x35, 0x8d, 0x3f, 0x95, 0x1b, 0xde, 0x80, 0x69, 0x51, 0xd6, 0x4b, 0x88, 0x5c, 0x8c,
+	0xae, 0x12, 0x6a, 0x6c, 0xc9, 0x43, 0xf1, 0x61, 0x41, 0x52, 0x48, 0x6f, 0x60, 0x3a, 0x2b, 0xee,
+	0x1f, 0xbc, 0x03, 0x8b, 0x51, 0xb6, 0x54, 0x57, 0xa4, 0xa6, 0x94, 0x3e, 0x1d, 0xb6, 0x35, 0xc4,
+	0x8d, 0x1f, 0x8a, 0xee, 0xb0, 0x6c, 0xcc, 0x61, 0x81, 0x41, 0x4a, 0x44, 0x2a, 0x83, 0x16, 0x94,
+	0xfb, 0x77, 0x3a, 0x5e, 0xf0, 0x5e, 0x7d, 0x09, 0x48, 0x27, 0xa6, 0x3a, 0x94, 0x35, 0x98, 0x11,
+	0x0e, 0x57, 0xa9, 0x9b, 0xf9, 0x54, 0x14, 0x13, 0x33, 0xa8, 0x4e, 0x9e, 0xb9, 0xce, 0x71, 0x8f,
+	0x04, 0x98, 0xc3, 0x12, 0x16, 0x9d, 0x98, 0x6a, 0xc7, 0x7f, 0xa2, 0x2f, 0xeb, 0x5a, 0xd7, 0x71,
+	0x7b, 0xca, 0xf9, 0xef, 0xc2, 0xb4, 0xc8, 0x84, 0x64, 0xb5, 0xf0, 0x20, 0x2a, 0x46, 0xe7, 0x15,
+	0x83, 0x9a, 0xc8, 0x9b, 0xe4, 0x2a, 0x76, 0x58, 0xb2, 0x9b, 0x54, 0x8f, 0x75, 0x97, 0xea, 0xe8,
+	0x4d, 0x98, 0x72, 0xd8, 0x12, 0x1e, 0x8b, 0xe5, 0x78, 0x0e, 0xca, 0xa5, 0xf1, 0xb7, 0x96, 0xe0,
+	0xc2, 0xef, 0x40, 0x51, 0xd3, 0xc0, 0x52, 0xeb, 0xc7, 0x0d, 0xf9, 0xca, 0xaa, 0x6d, 0x36, 0xb7,
+	0x0e, 0x44, 0xc6, 0x5d, 0x06, 0xa8, 0x37, 0x82, 0x71, 0x96, 0xe6, 0x5c, 0x62, 0x95, 0x8c, 0x70,
+	0xdd, 0x9e, 0x4c, 0x92, 0x3d, 0xd9, 0x4b, 0xd9, 0xf3, 0x02, 0xe6, 0xe4, 0xf6, 0x53, 0xdd, 0x81,
+	0xb7, 0xa8, 0x87, 0x99, 0x18, 0x75, 0x05, 0x96, 0x0c, 0x6a, 0x55, 0x74, 0x0a, 0x46, 0x4c, 0x73,
+	0x95, 0x7d, 0xdf, 0xf1, 0x47, 0x9e, 0xba, 0x02, 0x7f, 0xcc, 0x40, 0x59, 0x51, 0xd2, 0xf6, 0x0a,
+	0x54, 0x41, 0x26, 0x30, 0x2f, 0x28, 0xc7, 0x6e, 0xc0, 0x74, 0xfb, 0x68, 0xbf, 0xf3, 0x52, 0xf5,
+	0x4c, 0xe4, 0x88, 0xd1, 0xbb, 0x42, 0x8f, 0xe8, 0x01, 0xca, 0x11, 0xcb, 0xf4, 0x59, 0x37, 0x70,
+	0xab, 0xdf, 0x26, 0x2f, 0xf8, 0x9b, 0x36, 0x6f, 0x87, 0x04, 0x9e, 0x9c, 0xcb, 0x5e, 0x21, 0xaf,
+	0xd6, 0xf4, 0xde, 0x21, 0xbd, 0xe4, 0xb5, 0x91, 0x7f, 0xd2, 0xe8, 0xb3, 0x36, 0x99, 0xda, 0xe1,
+	0x22, 0x20, 0x46, 0xac, 0x77, 0x3c, 0x9d, 0xda, 0x80, 0x05, 0x46, 0xa5, 0xf7, 0x9e, 0xa6, 0xee,
+	0x21, 0x62, 0x28, 0xd8, 0xce, 0xc4, 0x60, 0xdb, 0xf1, 0xbc, 0xe7, 0x03, 0xb7, 0x2d, 0xb7, 0x16,
+	0x8c, 0x71, 0x5d, 0x08, 0x7f, 0xea, 0x45, 0x80, 0xf9, 0xab, 0x4a, 0x79, 0x14, 0x4a, 0x79, 0x4c,
+	0xfc, 0x09, 0x52, 0xf0, 0xeb, 0x70, 0x5d, 0x71, 0xca, 0x8a, 0x7d, 0x02, 0xf3, 0x1e, 0xdc, 0x52,
+	0xcc, 0x9b, 0x27, 0x2c, 0xad, 0x7c, 0x22, 0x15, 0xfe, 0xaf, 0x76, 0x6e, 0x40, 0x25, 0xb0, 0x93,
+	0xe7, 0x20, 0x83, 0xae, 0x6e, 0xc0, 0xc8, 0x93, 0x77, 0x86, 0xca, 0x62, 0xcf, 0x8c, 0xe6, 0x52,
+	0x16, 0xf5, 0x12, 0x64, 0xcf, 0x78, 0x13, 0x96, 0x94, 0x0c, 0x99, 0x1d, 0x44, 0x85, 0x8c, 0x19,
+	0x64, 0x12, 0x22, 0x1d, 0xc6, 0x96, 0x4e, 0x76, 0xbb, 0xce, 0x19, 0x75, 0x2d, 0x97, 0x99, 0xd1,
+	0x64, 0x5e, 0x17, 0x37, 0x82, 0x19, 0xa6, 0x83, 0xb6, 0x24, 0x33, 0x01, 0x3a, 0x59, 0x1e, 0x04,
+	0x23, 0x8f, 0x1d, 0xc4, 0x98, 0xe8, 0xef, 0xc3, 0x4a, 0x60, 0x04, 0xf3, 0xdb, 0x13, 0x7a, 0x59,
+	0x3b, 0x9e, 0xa7, 0x95, 0x9c, 0xa6, 0x8d, 0x3f, 0x80, 0xfc, 0x90, 0x48, 0x4c, 0x29, 0xae, 0xa3,
+	0x35, 0xd1, 0xd1, 0x5f, 0xd3, 0x16, 0xf3, 0x79, 0xdc, 0x86, 0xdb, 0x4a, 0xba, 0xf0, 0xa8, 0x51,
+	0x7c, 0xdc, 0x28, 0x55, 0x8e, 0x08, 0xb7, 0x8e, 0x97, 0x23, 0x39, 0x71, 0xf6, 0x41, 0x63, 0xf1,
+	0x03, 0xe1, 0x48, 0x15, 0x5b, 0xa9, 0xde, 0x15, 0xdb, 0xc2, 0xa7, 0x41, 0x48, 0xa6, 0x12, 0x76,
+	0x04, 0x8b, 0xd1, 0x48, 0x4e, 0x05, 0x63, 0x34, 0xeb, 0xf5, 0xa9, 0x0b, 0x15, 0x88, 0x89, 0x81,
+	0x32, 0x38, 0x08, 0xf3, 0x54, 0x06, 0x3b, 0xa1, 0x30, 0x7e, 0x25, 0xd3, 0xda, 0xcb, 0x4e, 0x53,
+	0xe5, 0x33, 0x62, 0x80, 0x77, 0xe1, 0x46, 0x1c, 0x26, 0x52, 0x99, 0x7c, 0x20, 0x2e, 0xb0, 0x09,
+	0x49, 0x52, 0xc9, 0xfd, 0x28, 0x04, 0x03, 0x0d, 0x50, 0x52, 0x89, 0xb4, 0xc1, 0x32, 0xe1, 0xcb,
+	0xff, 0xe3, 0xbe, 0x06, 0x70, 0x93, 0x4a, 0x98, 0x17, 0x0a, 0x4b, 0x7f, 0xfc, 0x21, 0x46, 0xe4,
+	0x26, 0x62, 0x84, 0x0c, 0x92, 0x10, 0xc5, 0xbe, 0x86, 0x4b, 0x27, 0x75, 0x84, 0x00, 0x9a, 0x56,
+	0x07, 0x7b, 0x87, 0x04, 0x3a, 0xf8, 0x40, 0x5d, 0x6c, 0x1d, 0x76, 0x53, 0x1d, 0xc6, 0xc7, 0x21,
+	0x76, 0x8e, 0x21, 0x73, 0x2a, 0xc1, 0x9f, 0xc0, 0x6a, 0x32, 0x28, 0xa7, 0x91, 0xfc, 0x1a, 0x86,
+	0x42, 0x90, 0x50, 0x6a, 0x5f, 0xf0, 0x8a, 0x30, 0xb3, 0xbb, 0xb7, 0xff, 0xa4, 0xb6, 0x49, 0x53,
+	0xd9, 0xf5, 0xbf, 0xe4, 0x20, 0xbb, 0x7d, 0x80, 0x7e, 0x00, 0x53, 0xe2, 0x53, 0xc3, 0x84, 0x2f,
+	0x31, 0xd6, 0xa4, 0x8f, 0x16, 0x78, 0xf9, 0xb3, 0x3f, 0xff, 0xfd, 0x8b, 0xec, 0x0d, 0x7c, 0xad,
+	0x7a, 0xf6, 0xb6, 0xd3, 0x1d, 0x9e, 0x38, 0xd5, 0xd3, 0xb3, 0x2a, 0x7f, 0x27, 0x7c, 0x3b, 0xf3,
+	0x1a, 0x3a, 0x80, 0x1c, 0xfb, 0x10, 0x91, 0xf8, 0x99, 0xc6, 0x4a, 0xfe, 0x98, 0x81, 0x2d, 0x2e,
+	0x79, 0x11, 0x5f, 0xd5, 0x25, 0x0f, 0x47, 0x3e, 0x93, 0xdb, 0x84, 0xa2, 0xf6, 0x3d, 0x02, 0x5d,
+	0xf8, 0x01, 0xc7, 0xba, 0xf8, 0x5b, 0x07, 0xbe, 0xc2, 0xac, 0x6d, 0xbe, 0xe8, 0xc7, 0xad, 0x0d,
+	0xfb, 0xe7, 0x71, 0x6b, 0xb5, 0x9e, 0xb5, 0xd9, 0x5a, 0xff, 0x45, 0x9f, 0x59, 0x3b, 0x90, 0x5f,
+	0x48, 0x5a, 0x3e, 0xba, 0x6d, 0x68, 0xb8, 0xeb, 0xad, 0x65, 0x6b, 0x35, 0x99, 0x41, 0x6a, 0xba,
+	0xc3, 0x35, 0xdd, 0xc4, 0x37, 0x74, 0x4d, 0xad, 0x80, 0x8f, 0x2a, 0x5c, 0x3f, 0x81, 0x29, 0xde,
+	0x29, 0x43, 0x87, 0xea, 0xc1, 0x32, 0xb4, 0xf2, 0x12, 0xce, 0x37, 0xd2, 0x63, 0xc3, 0x4b, 0x5c,
+	0xdb, 0x02, 0x2e, 0x07, 0xda, 0x78, 0xb3, 0x8c, 0x6a, 0x79, 0x94, 0xf9, 0x46, 0x66, 0xfd, 0xdf,
+	0x59, 0x98, 0xe2, 0x2d, 0x15, 0x34, 0x04, 0x08, 0x7b, 0x4f, 0xf1, 0x7d, 0x8e, 0x75, 0xb3, 0xe2,
+	0xfb, 0x1c, 0x6f, 0x5b, 0xe1, 0xdb, 0x5c, 0xf3, 0x12, 0x5e, 0x0c, 0x34, 0xf3, 0x4f, 0xa9, 0xd5,
+	0x63, 0xc6, 0xc5, 0xdc, 0xfa, 0x1c, 0x8a, 0x5a, 0x0f, 0x09, 0x99, 0x24, 0x46, 0x9a, 0x50, 0xf1,
+	0x4b, 0x60, 0x68, 0x40, 0xe1, 0xbb, 0x5c, 0xe9, 0x2d, 0x5c, 0xd1, 0x9d, 0x2b, 0xf4, 0xba, 0x9c,
+	0x93, 0x29, 0xfe, 0x19, 0x2d, 0x89, 0xa2, 0x7d, 0x24, 0x74, 0xd7, 0x20, 0x3a, 0xde, 0x8e, 0xb2,
+	0xee, 0x4d, 0x66, 0x4a, 0x34, 0x41, 0xe8, 0x3f, 0xa5, 0x9c, 0x0e, 0xe3, 0x54, 0xbe, 0xff, 0x0f,
+	0xfb, 0xf2, 0x26, 0x7e, 0x6c, 0x81, 0x7c, 0x28, 0x04, 0xdd, 0x1c, 0xb4, 0x62, 0xaa, 0xf4, 0xc3,
+	0x34, 0xd8, 0xba, 0x9d, 0x38, 0x2f, 0x4d, 0x78, 0xc0, 0x4d, 0x58, 0xc5, 0x37, 0x03, 0x13, 0xe4,
+	0x8f, 0x3a, 0xaa, 0xa2, 0xa0, 0xad, 0x3a, 0xed, 0x36, 0x73, 0xc4, 0x4f, 0x68, 0x49, 0xaf, 0x37,
+	0x69, 0xd0, 0x1d, 0x63, 0x8f, 0x41, 0xef, 0xf3, 0x58, 0x78, 0x12, 0x8b, 0xd4, 0xff, 0x2a, 0xd7,
+	0x7f, 0x17, 0xaf, 0x24, 0xe9, 0x77, 0x39, 0x7f, 0xd4, 0x04, 0xd1, 0x96, 0x31, 0x9b, 0x10, 0xe9,
+	0xfa, 0x98, 0x4d, 0x88, 0x76, 0x75, 0x2e, 0x36, 0x61, 0xc4, 0xf9, 0x99, 0x09, 0x2f, 0x00, 0xc2,
+	0xae, 0x0d, 0x32, 0x3a, 0x57, 0x2b, 0x0c, 0xe2, 0x37, 0x7f, 0xbc, 0xe1, 0x83, 0x1f, 0x72, 0xdd,
+	0x77, 0xf0, 0x72, 0x92, 0xee, 0x2e, 0xe5, 0x66, 0x71, 0xfe, 0xfb, 0x3c, 0x14, 0x3f, 0x74, 0x3a,
+	0x7d, 0x9f, 0xf4, 0x59, 0x33, 0x1a, 0x1d, 0xc3, 0x14, 0x47, 0xfe, 0x78, 0xb8, 0xeb, 0xad, 0x94,
+	0x78, 0xb8, 0x47, 0xfa, 0x0c, 0xf8, 0x3e, 0x57, 0x7d, 0x1b, 0x5b, 0x81, 0xea, 0x5e, 0x28, 0xbf,
+	0xca, 0x7b, 0x04, 0x6c, 0xcb, 0xa7, 0x30, 0x2d, 0x7a, 0x02, 0x28, 0x26, 0x2d, 0xd2, 0x3b, 0xb0,
+	0x96, 0xcd, 0x93, 0x89, 0xb7, 0x4c, 0xd7, 0xe5, 0x71, 0x66, 0xa6, 0xec, 0x87, 0x00, 0x61, 0x13,
+	0x2a, 0xee, 0xdf, 0xb1, 0x9e, 0x95, 0xb5, 0x9a, 0xcc, 0x20, 0x15, 0xbf, 0xc6, 0x15, 0xdf, 0xc3,
+	0xb7, 0x8d, 0x8a, 0xdb, 0xc1, 0x02, 0xa6, 0xbc, 0x05, 0x79, 0xf6, 0x5d, 0x0d, 0xc5, 0xa0, 0x5f,
+	0xfb, 0xf4, 0x66, 0x59, 0xa6, 0x29, 0xa9, 0xea, 0x1e, 0x57, 0xb5, 0x82, 0x97, 0x8c, 0xaa, 0xd8,
+	0xf7, 0x35, 0xa6, 0x64, 0x04, 0xb3, 0xea, 0x73, 0x1a, 0xba, 0x15, 0xf3, 0x59, 0xf4, 0xd3, 0x9b,
+	0xb5, 0x92, 0x34, 0x2d, 0x15, 0x3e, 0xe2, 0x0a, 0x31, 0xbe, 0x65, 0x76, 0xaa, 0x64, 0xa7, 0x4a,
+	0x29, 0x80, 0xfc, 0x62, 0x1e, 0xf2, 0x2c, 0x07, 0x61, 0xd8, 0x1d, 0x96, 0x6e, 0x71, 0x0f, 0x8f,
+	0x35, 0x4c, 0xe2, 0x1e, 0x1e, 0xaf, 0xfa, 0x0c, 0xd8, 0xcd, 0x7f, 0x72, 0x46, 0x38, 0x17, 0xdb,
+	0xb1, 0x0f, 0x45, 0xad, 0xc0, 0x43, 0x06, 0x89, 0xd1, 0x76, 0x4c, 0x1c, 0xbb, 0x0d, 0xd5, 0x21,
+	0x5e, 0xe5, 0x4a, 0x2d, 0x7c, 0x3d, 0xaa, 0xb4, 0x2d, 0xd8, 0x98, 0xd6, 0x1f, 0x41, 0x49, 0xaf,
+	0x04, 0x91, 0x41, 0x68, 0xac, 0xdf, 0x13, 0xc7, 0x0a, 0x53, 0x21, 0x69, 0x08, 0x9a, 0xe0, 0x07,
+	0x76, 0x8a, 0x97, 0x69, 0xff, 0x14, 0x66, 0x64, 0x7d, 0x68, 0xda, 0x6f, 0xb4, 0x43, 0x64, 0xda,
+	0x6f, 0xac, 0xb8, 0x34, 0x24, 0x02, 0x5c, 0x2d, 0xcb, 0x83, 0x15, 0x40, 0x4b, 0x95, 0xb4, 0x8c,
+	0x48, 0x52, 0x19, 0xf6, 0x3c, 0x92, 0x54, 0x6a, 0x35, 0xc8, 0x44, 0x95, 0xc7, 0xc4, 0x97, 0x77,
+	0x59, 0x25, 0xf8, 0x28, 0x41, 0xa2, 0x8e, 0x86, 0x78, 0x12, 0x8b, 0xd4, 0x8a, 0xb9, 0xd6, 0x65,
+	0xfc, 0x8a, 0x41, 0xab, 0x84, 0x42, 0xf4, 0x63, 0x80, 0xb0, 0x98, 0x8d, 0xbf, 0x8e, 0x8d, 0x1d,
+	0xb1, 0xf8, 0xeb, 0xd8, 0x5c, 0x0f, 0x1b, 0x22, 0x38, 0x54, 0x2e, 0x7e, 0x54, 0xc3, 0xd4, 0xff,
+	0x32, 0x03, 0x68, 0xbc, 0xf8, 0x45, 0xaf, 0x9b, 0x55, 0x18, 0x9b, 0x6d, 0xd6, 0x1b, 0x97, 0x63,
+	0x4e, 0x44, 0xcf, 0xd0, 0xae, 0x16, 0x5f, 0x32, 0x7c, 0xce, 0x2c, 0xfb, 0x3c, 0x03, 0x73, 0x91,
+	0xf2, 0x19, 0x3d, 0x48, 0x38, 0xe7, 0x58, 0xc3, 0xce, 0x7a, 0x78, 0x21, 0x5f, 0x62, 0xc6, 0xa2,
+	0xdd, 0x0a, 0x95, 0xad, 0xfd, 0x9c, 0x26, 0x4d, 0xd1, 0x9a, 0x1b, 0x25, 0x28, 0x18, 0xeb, 0xfa,
+	0x59, 0x8f, 0x2e, 0x66, 0xbc, 0xc4, 0x69, 0x85, 0x09, 0x1c, 0x0d, 0x0b, 0x59, 0xaa, 0x9b, 0xc2,
+	0x22, 0xda, 0x34, 0x34, 0x85, 0x45, 0xac, 0xce, 0x4f, 0x0a, 0x0b, 0x56, 0xf5, 0x6a, 0x91, 0x28,
+	0x0b, 0xfa, 0x24, 0x95, 0x93, 0x23, 0x31, 0xd6, 0x0d, 0x98, 0xa8, 0x32, 0x8c, 0x44, 0x55, 0xce,
+	0xa3, 0x04, 0x89, 0x17, 0x44, 0x62, 0xbc, 0x1b, 0x90, 0x14, 0x89, 0x5c, 0xab, 0x16, 0x89, 0x61,
+	0xf5, 0x6d, 0x8a, 0xc4, 0xb1, 0x96, 0xa8, 0x29, 0x12, 0xc7, 0x0b, 0xf8, 0xa4, 0xb3, 0xe5, 0xca,
+	0x23, 0x91, 0xb8, 0x60, 0xa8, 0xd6, 0xd1, 0x1b, 0x09, 0x3e, 0x35, 0xb6, 0x5b, 0xad, 0x37, 0x2f,
+	0xc9, 0x3d, 0x39, 0x02, 0xc4, 0x69, 0xa8, 0x08, 0xf8, 0x4d, 0x06, 0x16, 0x4d, 0xe5, 0x3e, 0x4a,
+	0x50, 0x96, 0xd0, 0xab, 0xb5, 0xd6, 0x2e, 0xcb, 0x7e, 0x09, 0xbf, 0x05, 0x31, 0xb1, 0x51, 0xfa,
+	0xc3, 0xdf, 0x56, 0x32, 0x5f, 0xd2, 0x7f, 0x7f, 0xa5, 0xff, 0x8e, 0xa6, 0xf9, 0x6f, 0xbe, 0xdf,
+	0xfe, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9d, 0xf9, 0x46, 0x39, 0x7a, 0x2e, 0x00, 0x00,
 }
 }

+ 9 - 0
etcdserver/etcdserverpb/rpc.proto

@@ -558,6 +558,15 @@ message WatchCreateRequest {
   // wish to recover a disconnected watcher starting from a recent known revision.
   // wish to recover a disconnected watcher starting from a recent known revision.
   // The etcd server may decide how often it will send notifications based on current load.
   // The etcd server may decide how often it will send notifications based on current load.
   bool progress_notify = 4;
   bool progress_notify = 4;
+
+  enum FilterType {
+  // filter out put event.
+  NOPUT = 0;
+  // filter out delete event.
+  NODELETE = 1;
+  }
+  // filters filter the events at server side before it sends back to the watcher.
+  repeated FilterType filters = 5;
 }
 }
 
 
 message WatchCancelRequest {
 message WatchCancelRequest {

+ 68 - 0
integration/v3_watch_test.go

@@ -1011,3 +1011,71 @@ func TestV3WatchClose(t *testing.T) {
 	clus.Members[0].DropConnections()
 	clus.Members[0].DropConnections()
 	wg.Wait()
 	wg.Wait()
 }
 }
+
+// TestV3WatchWithFilter ensures watcher filters out the events correctly.
+func TestV3WatchWithFilter(t *testing.T) {
+	clus := NewClusterV3(t, &ClusterConfig{Size: 1})
+	defer clus.Terminate(t)
+
+	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
+	defer cancel()
+
+	ws, werr := toGRPC(clus.RandClient()).Watch.Watch(ctx)
+	if werr != nil {
+		t.Fatal(werr)
+	}
+	req := &pb.WatchRequest{RequestUnion: &pb.WatchRequest_CreateRequest{
+		CreateRequest: &pb.WatchCreateRequest{
+			Key:     []byte("foo"),
+			Filters: []pb.WatchCreateRequest_FilterType{pb.WatchCreateRequest_NOPUT},
+		}}}
+	if err := ws.Send(req); err != nil {
+		t.Fatal(err)
+	}
+	if _, err := ws.Recv(); err != nil {
+		t.Fatal(err)
+	}
+
+	recv := make(chan *pb.WatchResponse)
+	go func() {
+		// check received PUT
+		resp, rerr := ws.Recv()
+		if rerr != nil {
+			t.Fatal(rerr)
+		}
+		recv <- resp
+	}()
+
+	// put a key with empty value
+	kvc := toGRPC(clus.RandClient()).KV
+	preq := &pb.PutRequest{Key: []byte("foo")}
+	if _, err := kvc.Put(context.TODO(), preq); err != nil {
+		t.Fatal(err)
+	}
+
+	select {
+	case <-recv:
+		t.Fatal("failed to filter out put event")
+	case <-time.After(100 * time.Millisecond):
+	}
+
+	dreq := &pb.DeleteRangeRequest{Key: []byte("foo")}
+	if _, err := kvc.DeleteRange(context.TODO(), dreq); err != nil {
+		t.Fatal(err)
+	}
+
+	select {
+	case resp := <-recv:
+		wevs := []*mvccpb.Event{
+			{
+				Type: mvccpb.DELETE,
+				Kv:   &mvccpb.KeyValue{Key: []byte("foo"), ModRevision: 3},
+			},
+		}
+		if !reflect.DeepEqual(resp.Events, wevs) {
+			t.Fatalf("got %v, expected %v", resp.Events, wevs)
+		}
+	case <-time.After(100 * time.Millisecond):
+		t.Fatal("failed to receive delete event")
+	}
+}

+ 46 - 17
mvcc/watchable_store.go

@@ -35,7 +35,7 @@ const (
 )
 )
 
 
 type watchable interface {
 type watchable interface {
-	watch(key, end []byte, startRev int64, id WatchID, ch chan<- WatchResponse) (*watcher, cancelFunc)
+	watch(key, end []byte, startRev int64, id WatchID, ch chan<- WatchResponse, fcs ...FilterFunc) (*watcher, cancelFunc)
 	progress(w *watcher)
 	progress(w *watcher)
 	rev() int64
 	rev() int64
 }
 }
@@ -185,7 +185,7 @@ func (s *watchableStore) NewWatchStream() WatchStream {
 	}
 	}
 }
 }
 
 
-func (s *watchableStore) watch(key, end []byte, startRev int64, id WatchID, ch chan<- WatchResponse) (*watcher, cancelFunc) {
+func (s *watchableStore) watch(key, end []byte, startRev int64, id WatchID, ch chan<- WatchResponse, fcs ...FilterFunc) (*watcher, cancelFunc) {
 	s.mu.Lock()
 	s.mu.Lock()
 	defer s.mu.Unlock()
 	defer s.mu.Unlock()
 
 
@@ -195,6 +195,7 @@ func (s *watchableStore) watch(key, end []byte, startRev int64, id WatchID, ch c
 		minRev: startRev,
 		minRev: startRev,
 		id:     id,
 		id:     id,
 		ch:     ch,
 		ch:     ch,
+		fcs:    fcs,
 	}
 	}
 
 
 	s.store.mu.Lock()
 	s.store.mu.Lock()
@@ -325,10 +326,9 @@ func (s *watchableStore) moveVictims() (moved int) {
 		for w, eb := range wb {
 		for w, eb := range wb {
 			// watcher has observed the store up to, but not including, w.minRev
 			// watcher has observed the store up to, but not including, w.minRev
 			rev := w.minRev - 1
 			rev := w.minRev - 1
-			select {
-			case w.ch <- WatchResponse{WatchID: w.id, Events: eb.evs, Revision: rev}:
+			if w.send(WatchResponse{WatchID: w.id, Events: eb.evs, Revision: rev}) {
 				pendingEventsGauge.Add(float64(len(eb.evs)))
 				pendingEventsGauge.Add(float64(len(eb.evs)))
-			default:
+			} else {
 				if newVictim == nil {
 				if newVictim == nil {
 					newVictim = make(watcherBatch)
 					newVictim = make(watcherBatch)
 				}
 				}
@@ -419,10 +419,9 @@ func (s *watchableStore) syncWatchers() {
 			w.minRev = eb.moreRev
 			w.minRev = eb.moreRev
 		}
 		}
 
 
-		select {
-		case w.ch <- WatchResponse{WatchID: w.id, Events: eb.evs, Revision: curRev}:
+		if w.send(WatchResponse{WatchID: w.id, Events: eb.evs, Revision: curRev}) {
 			pendingEventsGauge.Add(float64(len(eb.evs)))
 			pendingEventsGauge.Add(float64(len(eb.evs)))
-		default:
+		} else {
 			if victims == nil {
 			if victims == nil {
 				victims = make(watcherBatch)
 				victims = make(watcherBatch)
 			}
 			}
@@ -480,10 +479,10 @@ func (s *watchableStore) notify(rev int64, evs []mvccpb.Event) {
 		if eb.revs != 1 {
 		if eb.revs != 1 {
 			plog.Panicf("unexpected multiple revisions in notification")
 			plog.Panicf("unexpected multiple revisions in notification")
 		}
 		}
-		select {
-		case w.ch <- WatchResponse{WatchID: w.id, Events: eb.evs, Revision: rev}:
+
+		if w.send(WatchResponse{WatchID: w.id, Events: eb.evs, Revision: rev}) {
 			pendingEventsGauge.Add(float64(len(eb.evs)))
 			pendingEventsGauge.Add(float64(len(eb.evs)))
-		default:
+		} else {
 			// move slow watcher to victims
 			// move slow watcher to victims
 			w.minRev = rev + 1
 			w.minRev = rev + 1
 			if victim == nil {
 			if victim == nil {
@@ -516,12 +515,9 @@ func (s *watchableStore) progress(w *watcher) {
 	defer s.mu.Unlock()
 	defer s.mu.Unlock()
 
 
 	if _, ok := s.synced.watchers[w]; ok {
 	if _, ok := s.synced.watchers[w]; ok {
-		select {
-		case w.ch <- WatchResponse{WatchID: w.id, Revision: s.rev()}:
-		default:
-			// If the ch is full, this watcher is receiving events.
-			// We do not need to send progress at all.
-		}
+		w.send(WatchResponse{WatchID: w.id, Revision: s.rev()})
+		// If the ch is full, this watcher is receiving events.
+		// We do not need to send progress at all.
 	}
 	}
 }
 }
 
 
@@ -542,7 +538,40 @@ type watcher struct {
 	minRev int64
 	minRev int64
 	id     WatchID
 	id     WatchID
 
 
+	fcs []FilterFunc
 	// a chan to send out the watch response.
 	// a chan to send out the watch response.
 	// The chan might be shared with other watchers.
 	// The chan might be shared with other watchers.
 	ch chan<- WatchResponse
 	ch chan<- WatchResponse
 }
 }
+
+func (w *watcher) send(wr WatchResponse) bool {
+	progressEvent := len(wr.Events) == 0
+
+	if len(w.fcs) != 0 {
+		ne := make([]mvccpb.Event, 0, len(wr.Events))
+		for i := range wr.Events {
+			filtered := false
+			for _, filter := range w.fcs {
+				if filter(wr.Events[i]) {
+					filtered = true
+					break
+				}
+			}
+			if !filtered {
+				ne = append(ne, wr.Events[i])
+			}
+		}
+		wr.Events = ne
+	}
+
+	// if all events are filtered out, we should send nothing.
+	if !progressEvent && len(wr.Events) == 0 {
+		return true
+	}
+	select {
+	case w.ch <- wr:
+		return true
+	default:
+		return false
+	}
+}

+ 6 - 3
mvcc/watcher.go

@@ -27,6 +27,9 @@ var (
 
 
 type WatchID int64
 type WatchID int64
 
 
+// FilterFunc returns true if the given event should be filtered out.
+type FilterFunc func(e mvccpb.Event) bool
+
 type WatchStream interface {
 type WatchStream interface {
 	// Watch creates a watcher. The watcher watches the events happening or
 	// Watch creates a watcher. The watcher watches the events happening or
 	// happened on the given key or range [key, end) from the given startRev.
 	// happened on the given key or range [key, end) from the given startRev.
@@ -37,7 +40,7 @@ type WatchStream interface {
 	// The returned `id` is the ID of this watcher. It appears as WatchID
 	// The returned `id` is the ID of this watcher. It appears as WatchID
 	// in events that are sent to the created watcher through stream channel.
 	// in events that are sent to the created watcher through stream channel.
 	//
 	//
-	Watch(key, end []byte, startRev int64) WatchID
+	Watch(key, end []byte, startRev int64, fcs ...FilterFunc) WatchID
 
 
 	// Chan returns a chan. All watch response will be sent to the returned chan.
 	// Chan returns a chan. All watch response will be sent to the returned chan.
 	Chan() <-chan WatchResponse
 	Chan() <-chan WatchResponse
@@ -95,7 +98,7 @@ type watchStream struct {
 
 
 // Watch creates a new watcher in the stream and returns its WatchID.
 // Watch creates a new watcher in the stream and returns its WatchID.
 // TODO: return error if ws is closed?
 // TODO: return error if ws is closed?
-func (ws *watchStream) Watch(key, end []byte, startRev int64) WatchID {
+func (ws *watchStream) Watch(key, end []byte, startRev int64, fcs ...FilterFunc) WatchID {
 	ws.mu.Lock()
 	ws.mu.Lock()
 	defer ws.mu.Unlock()
 	defer ws.mu.Unlock()
 	if ws.closed {
 	if ws.closed {
@@ -105,7 +108,7 @@ func (ws *watchStream) Watch(key, end []byte, startRev int64) WatchID {
 	id := ws.nextID
 	id := ws.nextID
 	ws.nextID++
 	ws.nextID++
 
 
-	w, c := ws.watchable.watch(key, end, startRev, id, ws.ch)
+	w, c := ws.watchable.watch(key, end, startRev, id, ws.ch, fcs...)
 
 
 	ws.cancels[id] = c
 	ws.cancels[id] = c
 	ws.watchers[id] = w
 	ws.watchers[id] = w

+ 37 - 0
mvcc/watcher_test.go

@@ -283,3 +283,40 @@ func TestWatcherRequestProgress(t *testing.T) {
 		t.Fatal("failed to receive progress")
 		t.Fatal("failed to receive progress")
 	}
 	}
 }
 }
+
+func TestWatcherWatchWithFilter(t *testing.T) {
+	b, tmpPath := backend.NewDefaultTmpBackend()
+	s := WatchableKV(newWatchableStore(b, &lease.FakeLessor{}, nil))
+	defer cleanup(s, b, tmpPath)
+
+	w := s.NewWatchStream()
+	defer w.Close()
+
+	filterPut := func(e mvccpb.Event) bool {
+		return e.Type == mvccpb.PUT
+	}
+
+	w.Watch([]byte("foo"), nil, 0, filterPut)
+	done := make(chan struct{})
+
+	go func() {
+		<-w.Chan()
+		done <- struct{}{}
+	}()
+
+	s.Put([]byte("foo"), []byte("bar"), 0)
+
+	select {
+	case <-done:
+		t.Fatal("failed to filter put request")
+	case <-time.After(100 * time.Millisecond):
+	}
+
+	s.DeleteRange([]byte("foo"), nil)
+
+	select {
+	case <-done:
+	case <-time.After(100 * time.Millisecond):
+		t.Fatal("failed to receive delete request")
+	}
+}