Merge pull request #5578 from mitake/auth-v3-range

auth, etcdserver: permission of range requests
This commit is contained in:
Xiang Li 2016-06-08 16:33:25 -07:00
commit 77dee97c2f
10 changed files with 656 additions and 236 deletions

View File

@ -72,8 +72,9 @@ func (*User) Descriptor() ([]byte, []int) { return fileDescriptorAuth, []int{0}
// Permission is a single entity
type Permission struct {
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
PermType Permission_Type `protobuf:"varint,2,opt,name=permType,proto3,enum=authpb.Permission_Type" json:"permType,omitempty"`
PermType Permission_Type `protobuf:"varint,1,opt,name=permType,proto3,enum=authpb.Permission_Type" json:"permType,omitempty"`
Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
RangeEnd []byte `protobuf:"bytes,3,opt,name=range_end,json=rangeEnd,proto3" json:"range_end,omitempty"`
}
func (m *Permission) Reset() { *m = Permission{} }
@ -158,16 +159,22 @@ func (m *Permission) MarshalTo(data []byte) (int, error) {
_ = i
var l int
_ = l
if m.PermType != 0 {
data[i] = 0x8
i++
i = encodeVarintAuth(data, i, uint64(m.PermType))
}
if len(m.Key) > 0 {
data[i] = 0xa
data[i] = 0x12
i++
i = encodeVarintAuth(data, i, uint64(len(m.Key)))
i += copy(data[i:], m.Key)
}
if m.PermType != 0 {
data[i] = 0x10
if len(m.RangeEnd) > 0 {
data[i] = 0x1a
i++
i = encodeVarintAuth(data, i, uint64(m.PermType))
i = encodeVarintAuth(data, i, uint64(len(m.RangeEnd)))
i += copy(data[i:], m.RangeEnd)
}
return i, nil
}
@ -258,12 +265,16 @@ func (m *User) Size() (n int) {
func (m *Permission) Size() (n int) {
var l int
_ = l
if m.PermType != 0 {
n += 1 + sovAuth(uint64(m.PermType))
}
l = len(m.Key)
if l > 0 {
n += 1 + l + sovAuth(uint64(l))
}
if m.PermType != 0 {
n += 1 + sovAuth(uint64(m.PermType))
l = len(m.RangeEnd)
if l > 0 {
n += 1 + l + sovAuth(uint64(l))
}
return n
}
@ -468,6 +479,25 @@ func (m *Permission) Unmarshal(data []byte) error {
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field PermType", wireType)
}
m.PermType = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuth
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.PermType |= (Permission_Type(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
}
@ -498,11 +528,11 @@ func (m *Permission) Unmarshal(data []byte) error {
m.Key = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field PermType", wireType)
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field RangeEnd", wireType)
}
m.PermType = 0
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuth
@ -512,11 +542,23 @@ func (m *Permission) Unmarshal(data []byte) error {
}
b := data[iNdEx]
iNdEx++
m.PermType |= (Permission_Type(b) & 0x7F) << shift
byteLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthAuth
}
postIndex := iNdEx + byteLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.RangeEnd = append(m.RangeEnd[:0], data[iNdEx:postIndex]...)
if m.RangeEnd == nil {
m.RangeEnd = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipAuth(data[iNdEx:])
@ -756,22 +798,23 @@ var (
)
var fileDescriptorAuth = []byte{
// 265 bytes of a gzipped FileDescriptorProto
// 276 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x2c, 0x2d, 0xc9,
0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0xb1, 0x0b, 0x92, 0xa4, 0x44, 0xd2, 0xf3,
0xd3, 0xf3, 0xc1, 0x42, 0xfa, 0x20, 0x16, 0x44, 0x56, 0xc9, 0x87, 0x8b, 0x25, 0xb4, 0x38, 0xb5,
0x48, 0x48, 0x88, 0x8b, 0x25, 0x2f, 0x31, 0x37, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x27, 0x08,
0xcc, 0x16, 0x92, 0xe2, 0xe2, 0x28, 0x48, 0x2c, 0x2e, 0x2e, 0xcf, 0x2f, 0x4a, 0x91, 0x60, 0x02,
0x8b, 0xc3, 0xf9, 0x42, 0x22, 0x5c, 0xac, 0x45, 0xf9, 0x39, 0xa9, 0xc5, 0x12, 0xcc, 0x0a, 0xcc,
0x1a, 0x9c, 0x41, 0x10, 0x8e, 0x52, 0x3d, 0x17, 0x57, 0x40, 0x6a, 0x51, 0x6e, 0x66, 0x71, 0x71,
0x66, 0x7e, 0x9e, 0x90, 0x00, 0x17, 0x73, 0x76, 0x6a, 0x25, 0xd4, 0x48, 0x10, 0x53, 0xc8, 0x98,
0x8b, 0xa3, 0x20, 0xb5, 0x28, 0x37, 0xa4, 0xb2, 0x20, 0x15, 0x6c, 0x22, 0x9f, 0x91, 0xb8, 0x1e,
0xc4, 0x79, 0x7a, 0x08, 0x7d, 0x7a, 0x20, 0xe9, 0x20, 0xb8, 0x42, 0x25, 0x2d, 0x2e, 0x16, 0x10,
0x2d, 0xc4, 0xc1, 0xc5, 0x12, 0xe4, 0xea, 0xe8, 0x22, 0xc0, 0x20, 0xc4, 0xc9, 0xc5, 0x1a, 0x1e,
0xe4, 0x19, 0xe2, 0x2a, 0xc0, 0x28, 0xc4, 0xcb, 0xc5, 0x09, 0x12, 0x84, 0x70, 0x99, 0x94, 0x42,
0xb8, 0x58, 0x82, 0xf2, 0x73, 0x52, 0xb1, 0x7a, 0xc7, 0x82, 0x8b, 0x37, 0x3b, 0xb5, 0x12, 0x61,
0x8f, 0x04, 0x93, 0x02, 0xb3, 0x06, 0xb7, 0x91, 0x10, 0xa6, 0x0b, 0x82, 0x50, 0x15, 0x3a, 0x89,
0x9c, 0x78, 0x28, 0xc7, 0x70, 0xe1, 0xa1, 0x1c, 0xc3, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9,
0x31, 0x3e, 0x78, 0x24, 0xc7, 0x98, 0xc4, 0x06, 0x0e, 0x41, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff,
0xff, 0x92, 0x06, 0xa1, 0xed, 0x6d, 0x01, 0x00, 0x00,
0x1a, 0x9c, 0x41, 0x10, 0x8e, 0xd2, 0x1c, 0x46, 0x2e, 0xae, 0x80, 0xd4, 0xa2, 0xdc, 0xcc, 0xe2,
0xe2, 0xcc, 0xfc, 0x3c, 0x21, 0x63, 0xa0, 0x01, 0x40, 0x5e, 0x48, 0x65, 0x01, 0xc4, 0x60, 0x3e,
0x23, 0x71, 0x3d, 0x88, 0x6b, 0xf4, 0x10, 0xaa, 0xf4, 0x40, 0xd2, 0x41, 0x70, 0x85, 0x42, 0x02,
0x5c, 0xcc, 0xd9, 0xa9, 0x95, 0x50, 0x0b, 0x41, 0x4c, 0x21, 0x69, 0x2e, 0xce, 0xa2, 0xc4, 0xbc,
0xf4, 0xd4, 0xf8, 0xd4, 0xbc, 0x14, 0xa0, 0x7d, 0x60, 0x87, 0x80, 0x05, 0x5c, 0xf3, 0x52, 0x94,
0xb4, 0xb8, 0x58, 0xc0, 0xda, 0x38, 0xb8, 0x58, 0x82, 0x5c, 0x1d, 0x5d, 0x04, 0x18, 0x84, 0x38,
0xb9, 0x58, 0xc3, 0x83, 0x3c, 0x43, 0x5c, 0x05, 0x18, 0x85, 0x78, 0xb9, 0x38, 0x41, 0x82, 0x10,
0x2e, 0x93, 0x52, 0x08, 0x50, 0x0d, 0xd0, 0x9d, 0x58, 0x3d, 0x6b, 0xc1, 0xc5, 0x0b, 0xb4, 0x0b,
0xe1, 0x2c, 0xa0, 0x03, 0x98, 0x35, 0xb8, 0x8d, 0x84, 0x30, 0x1d, 0x1c, 0x84, 0xaa, 0xd0, 0x49,
0xe4, 0xc4, 0x43, 0x39, 0x86, 0x0b, 0x40, 0x7c, 0xe2, 0x91, 0x1c, 0xe3, 0x05, 0x20, 0x7e, 0x00,
0xc4, 0x49, 0x6c, 0xe0, 0xf0, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x31, 0x53, 0xfd,
0x8b, 0x01, 0x00, 0x00,
}

View File

@ -18,14 +18,15 @@ message User {
// Permission is a single entity
message Permission {
bytes key = 1;
enum Type {
READ = 0;
WRITE = 1;
READWRITE = 2;
}
Type permType = 2;
Type permType = 1;
bytes key = 2;
bytes range_end = 3;
}
// Role is a single entry in the bucket authRoles

195
auth/range_perm_cache.go Normal file
View File

@ -0,0 +1,195 @@
// Copyright 2016 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth
import (
"sort"
"strings"
"github.com/coreos/etcd/auth/authpb"
"github.com/coreos/etcd/mvcc/backend"
)
func isSubset(a, b *rangePerm) bool {
// return true if a is a subset of b
return 0 <= strings.Compare(a.begin, b.begin) && strings.Compare(a.end, b.end) <= 0
}
func reduceSubsets(perms []*rangePerm) []*rangePerm {
// TODO(mitake): currently it is O(n^2), we need a better algorithm
ret := make([]*rangePerm, 0)
for i := range perms {
subset := false
for j := range perms {
if i != j && isSubset(perms[i], perms[j]) {
subset = true
break
}
}
if subset {
continue
}
ret = append(ret, perms[i])
}
return ret
}
func unifyPerms(perms []*rangePerm) []*rangePerm {
ret := make([]*rangePerm, 0)
perms = reduceSubsets(perms)
sort.Sort(RangePermSliceByBegin(perms))
i := 0
for i < len(perms) {
begin := i
for i+1 < len(perms) && perms[i].end >= perms[i+1].begin {
i++
}
if i == begin {
ret = append(ret, &rangePerm{begin: perms[i].begin, end: perms[i].end})
} else {
ret = append(ret, &rangePerm{begin: perms[begin].begin, end: perms[i].end})
}
i++
}
return ret
}
func (as *authStore) makeUnifiedPerms(tx backend.BatchTx, userName string) *unifiedRangePermissions {
user := getUser(tx, userName)
if user == nil {
plog.Errorf("invalid user name %s", userName)
return nil
}
var readPerms, writePerms []*rangePerm
for _, roleName := range user.Roles {
_, vs := tx.UnsafeRange(authRolesBucketName, []byte(roleName), nil, 0)
if len(vs) != 1 {
plog.Errorf("invalid role name %s", roleName)
return nil
}
role := &authpb.Role{}
err := role.Unmarshal(vs[0])
if err != nil {
plog.Errorf("failed to unmarshal a role %s: %s", roleName, err)
return nil
}
for _, perm := range role.KeyPermission {
if len(perm.RangeEnd) == 0 {
continue
}
if perm.PermType == authpb.READWRITE || perm.PermType == authpb.READ {
readPerms = append(readPerms, &rangePerm{begin: string(perm.Key), end: string(perm.RangeEnd)})
}
if perm.PermType == authpb.READWRITE || perm.PermType == authpb.WRITE {
writePerms = append(writePerms, &rangePerm{begin: string(perm.Key), end: string(perm.RangeEnd)})
}
}
}
return &unifiedRangePermissions{readPerms: unifyPerms(readPerms), writePerms: unifyPerms(writePerms)}
}
func checkCachedPerm(cachedPerms *unifiedRangePermissions, userName string, key, rangeEnd string, write, read bool) bool {
var perms []*rangePerm
if write {
perms = cachedPerms.writePerms
} else {
perms = cachedPerms.readPerms
}
for _, perm := range perms {
if strings.Compare(rangeEnd, "") != 0 {
if strings.Compare(perm.begin, key) <= 0 && strings.Compare(rangeEnd, perm.end) <= 0 {
return true
}
} else {
if strings.Compare(perm.begin, key) <= 0 && strings.Compare(key, perm.end) <= 0 {
return true
}
}
}
return false
}
func (as *authStore) isRangeOpPermitted(tx backend.BatchTx, userName string, key, rangeEnd string, write, read bool) bool {
// assumption: tx is Lock()ed
_, ok := as.rangePermCache[userName]
if ok {
return checkCachedPerm(as.rangePermCache[userName], userName, key, rangeEnd, write, read)
}
perms := as.makeUnifiedPerms(tx, userName)
if perms == nil {
plog.Errorf("failed to create a unified permission of user %s", userName)
return false
}
as.rangePermCache[userName] = perms
return checkCachedPerm(as.rangePermCache[userName], userName, key, rangeEnd, write, read)
}
func (as *authStore) clearCachedPerm() {
as.rangePermCache = make(map[string]*unifiedRangePermissions)
}
func (as *authStore) invalidateCachedPerm(userName string) {
delete(as.rangePermCache, userName)
}
type unifiedRangePermissions struct {
// readPerms[i] and readPerms[j] (i != j) don't overlap
readPerms []*rangePerm
// writePerms[i] and writePerms[j] (i != j) don't overlap, too
writePerms []*rangePerm
}
type rangePerm struct {
begin, end string
}
type RangePermSliceByBegin []*rangePerm
func (slice RangePermSliceByBegin) Len() int {
return len(slice)
}
func (slice RangePermSliceByBegin) Less(i, j int) bool {
if slice[i].begin == slice[j].begin {
return slice[i].end < slice[j].end
}
return slice[i].begin < slice[j].begin
}
func (slice RangePermSliceByBegin) Swap(i, j int) {
slice[i], slice[j] = slice[j], slice[i]
}

View File

@ -0,0 +1,96 @@
// Copyright 2016 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth
import (
"testing"
)
func isPermsEqual(a, b []*rangePerm) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if len(b) <= i {
return false
}
if a[i].begin != b[i].begin || a[i].end != b[i].end {
return false
}
}
return true
}
func TestUnifyParams(t *testing.T) {
tests := []struct {
params []*rangePerm
want []*rangePerm
}{
{
[]*rangePerm{{"a", "b"}},
[]*rangePerm{{"a", "b"}},
},
{
[]*rangePerm{{"a", "b"}, {"b", "c"}},
[]*rangePerm{{"a", "c"}},
},
{
[]*rangePerm{{"a", "c"}, {"b", "d"}},
[]*rangePerm{{"a", "d"}},
},
{
[]*rangePerm{{"a", "b"}, {"b", "c"}, {"d", "e"}},
[]*rangePerm{{"a", "c"}, {"d", "e"}},
},
{
[]*rangePerm{{"a", "b"}, {"c", "d"}, {"e", "f"}},
[]*rangePerm{{"a", "b"}, {"c", "d"}, {"e", "f"}},
},
{
[]*rangePerm{{"e", "f"}, {"c", "d"}, {"a", "b"}},
[]*rangePerm{{"a", "b"}, {"c", "d"}, {"e", "f"}},
},
{
[]*rangePerm{{"a", "b"}, {"c", "d"}, {"a", "z"}},
[]*rangePerm{{"a", "z"}},
},
{
[]*rangePerm{{"a", "b"}, {"c", "d"}, {"a", "z"}, {"1", "9"}},
[]*rangePerm{{"1", "9"}, {"a", "z"}},
},
{
[]*rangePerm{{"a", "b"}, {"c", "d"}, {"a", "z"}, {"1", "a"}},
[]*rangePerm{{"1", "z"}},
},
{
[]*rangePerm{{"a", "b"}, {"a", "z"}, {"5", "6"}, {"1", "9"}},
[]*rangePerm{{"1", "9"}, {"a", "z"}},
},
{
[]*rangePerm{{"a", "b"}, {"b", "c"}, {"c", "d"}, {"d", "f"}, {"1", "9"}},
[]*rangePerm{{"1", "9"}, {"a", "f"}},
},
}
for i, tt := range tests {
result := unifyPerms(tt.params)
if !isPermsEqual(result, tt.want) {
t.Errorf("#%d: result=%q, want=%q", i, result, tt.want)
}
}
}

View File

@ -103,13 +103,15 @@ type AuthStore interface {
IsPutPermitted(header *pb.RequestHeader, key string) bool
// IsRangePermitted checks range permission of the user
IsRangePermitted(header *pb.RequestHeader, key string) bool
IsRangePermitted(header *pb.RequestHeader, key, rangeEnd string) bool
}
type authStore struct {
be backend.Backend
enabled bool
enabledMu sync.RWMutex
rangePermCache map[string]*unifiedRangePermissions // username -> unifiedRangePermissions
}
func (as *authStore) AuthEnable() {
@ -126,6 +128,8 @@ func (as *authStore) AuthEnable() {
as.enabled = true
as.enabledMu.Unlock()
as.rangePermCache = make(map[string]*unifiedRangePermissions)
plog.Noticef("Authentication enabled")
}
@ -301,6 +305,8 @@ func (as *authStore) UserGrantRole(r *pb.AuthUserGrantRoleRequest) (*pb.AuthUser
tx.UnsafePut(authUsersBucketName, user.Name, marshaledUser)
as.invalidateCachedPerm(r.User)
plog.Noticef("granted role %s to user %s", r.Role, r.User)
return &pb.AuthUserGrantRoleResponse{}, nil
}
@ -357,6 +363,8 @@ func (as *authStore) UserRevokeRole(r *pb.AuthUserRevokeRoleRequest) (*pb.AuthUs
tx.UnsafePut(authUsersBucketName, updatedUser.Name, marshaledUser)
as.invalidateCachedPerm(r.Name)
plog.Noticef("revoked role %s from user %s", r.Role, r.Name)
return &pb.AuthUserRevokeRoleResponse{}, nil
}
@ -406,7 +414,7 @@ func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest)
revoked := false
for _, perm := range role.KeyPermission {
if !bytes.Equal(perm.Key, []byte(r.Key)) {
if !bytes.Equal(perm.Key, []byte(r.Key)) || !bytes.Equal(perm.RangeEnd, []byte(r.RangeEnd)) {
updatedRole.KeyPermission = append(updatedRole.KeyPermission, perm)
} else {
revoked = true
@ -424,6 +432,10 @@ func (as *authStore) RoleRevokePermission(r *pb.AuthRoleRevokePermissionRequest)
tx.UnsafePut(authRolesBucketName, updatedRole.Name, marshaledRole)
// TODO(mitake): currently single role update invalidates every cache
// It should be optimized.
as.clearCachedPerm()
plog.Noticef("revoked key %s from role %s", r.Key, r.Role)
return &pb.AuthRoleRevokePermissionResponse{}, nil
}
@ -524,13 +536,14 @@ func (as *authStore) RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) (
return bytes.Compare(role.KeyPermission[i].Key, []byte(r.Perm.Key)) >= 0
})
if idx < len(role.KeyPermission) && bytes.Equal(role.KeyPermission[idx].Key, r.Perm.Key) {
if idx < len(role.KeyPermission) && bytes.Equal(role.KeyPermission[idx].Key, r.Perm.Key) && bytes.Equal(role.KeyPermission[idx].RangeEnd, r.Perm.RangeEnd) {
// update existing permission
role.KeyPermission[idx].PermType = r.Perm.PermType
} else {
// append new permission to the role
newPerm := &authpb.Permission{
Key: []byte(r.Perm.Key),
RangeEnd: []byte(r.Perm.RangeEnd),
PermType: r.Perm.PermType,
}
@ -546,12 +559,16 @@ func (as *authStore) RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) (
tx.UnsafePut(authRolesBucketName, []byte(r.Name), marshaledRole)
// TODO(mitake): currently single role update invalidates every cache
// It should be optimized.
as.clearCachedPerm()
plog.Noticef("role %s's permission of key %s is updated as %s", r.Name, r.Perm.Key, authpb.Permission_Type_name[int32(r.Perm.PermType)])
return &pb.AuthRoleGrantPermissionResponse{}, nil
}
func (as *authStore) isOpPermitted(userName string, key string, write bool, read bool) bool {
func (as *authStore) isOpPermitted(userName string, key, rangeEnd string, write bool, read bool) bool {
// TODO(mitake): this function would be costly so we need a caching mechanism
if !as.isAuthEnabled() {
return true
@ -567,22 +584,26 @@ func (as *authStore) isOpPermitted(userName string, key string, write bool, read
return false
}
for _, roleName := range user.Roles {
_, vs := tx.UnsafeRange(authRolesBucketName, []byte(roleName), nil, 0)
if len(vs) != 1 {
plog.Errorf("invalid role name %s for permission checking", roleName)
return false
}
if strings.Compare(rangeEnd, "") == 0 {
for _, roleName := range user.Roles {
_, vs := tx.UnsafeRange(authRolesBucketName, []byte(roleName), nil, 0)
if len(vs) != 1 {
plog.Errorf("invalid role name %s for permission checking", roleName)
return false
}
role := &authpb.Role{}
err := role.Unmarshal(vs[0])
if err != nil {
plog.Errorf("failed to unmarshal a role %s: %s", roleName, err)
return false
}
role := &authpb.Role{}
err := role.Unmarshal(vs[0])
if err != nil {
plog.Errorf("failed to unmarshal a role %s: %s", roleName, err)
return false
}
for _, perm := range role.KeyPermission {
if !bytes.Equal(perm.Key, []byte(key)) {
continue
}
for _, perm := range role.KeyPermission {
if bytes.Equal(perm.Key, []byte(key)) {
if perm.PermType == authpb.READWRITE {
return true
}
@ -598,15 +619,19 @@ func (as *authStore) isOpPermitted(userName string, key string, write bool, read
}
}
if as.isRangeOpPermitted(tx, userName, key, rangeEnd, write, read) {
return true
}
return false
}
func (as *authStore) IsPutPermitted(header *pb.RequestHeader, key string) bool {
return as.isOpPermitted(header.Username, key, true, false)
return as.isOpPermitted(header.Username, key, "", true, false)
}
func (as *authStore) IsRangePermitted(header *pb.RequestHeader, key string) bool {
return as.isOpPermitted(header.Username, key, false, true)
func (as *authStore) IsRangePermitted(header *pb.RequestHeader, key, rangeEnd string) bool {
return as.isOpPermitted(header.Username, key, rangeEnd, false, true)
}
func getUser(tx backend.BatchTx, username string) *authpb.User {

View File

@ -78,13 +78,13 @@ type Auth interface {
RoleAdd(ctx context.Context, name string) (*AuthRoleAddResponse, error)
// RoleGrantPermission grants a permission to a role.
RoleGrantPermission(ctx context.Context, name string, key string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error)
RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error)
// RoleGet gets a detailed information of a role.
RoleGet(ctx context.Context, role string) (*AuthRoleGetResponse, error)
// RoleRevokePermission revokes a key from a user.
RoleRevokePermission(ctx context.Context, role string, key string) (*AuthRoleRevokePermissionResponse, error)
// RoleRevokePermission revokes a permission from a role.
RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error)
// RoleDelete deletes a role.
RoleDelete(ctx context.Context, role string) (*AuthRoleDeleteResponse, error)
@ -151,9 +151,10 @@ func (auth *auth) RoleAdd(ctx context.Context, name string) (*AuthRoleAddRespons
return (*AuthRoleAddResponse)(resp), toErr(ctx, err)
}
func (auth *auth) RoleGrantPermission(ctx context.Context, name string, key string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error) {
func (auth *auth) RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error) {
perm := &authpb.Permission{
Key: []byte(key),
RangeEnd: []byte(rangeEnd),
PermType: authpb.Permission_Type(permType),
}
resp, err := auth.remote.RoleGrantPermission(ctx, &pb.AuthRoleGrantPermissionRequest{Name: name, Perm: perm})
@ -165,8 +166,8 @@ func (auth *auth) RoleGet(ctx context.Context, role string) (*AuthRoleGetRespons
return (*AuthRoleGetResponse)(resp), toErr(ctx, err)
}
func (auth *auth) RoleRevokePermission(ctx context.Context, role string, key string) (*AuthRoleRevokePermissionResponse, error) {
resp, err := auth.remote.RoleRevokePermission(ctx, &pb.AuthRoleRevokePermissionRequest{Role: role, Key: key})
func (auth *auth) RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error) {
resp, err := auth.remote.RoleRevokePermission(ctx, &pb.AuthRoleRevokePermissionRequest{Role: role, Key: key, RangeEnd: rangeEnd})
return (*AuthRoleRevokePermissionResponse)(resp), toErr(ctx, err)
}

View File

@ -64,7 +64,7 @@ func newRoleGetCommand() *cobra.Command {
func newRoleGrantPermissionCommand() *cobra.Command {
return &cobra.Command{
Use: "grant-permission <role name> <permission type> <key>",
Use: "grant-permission <role name> <permission type> <key> [endkey]",
Short: "grant a key to a role",
Run: roleGrantPermissionCommandFunc,
}
@ -72,7 +72,7 @@ func newRoleGrantPermissionCommand() *cobra.Command {
func newRoleRevokePermissionCommand() *cobra.Command {
return &cobra.Command{
Use: "revoke-permission <role name> <key>",
Use: "revoke-permission <role name> <key> [endkey]",
Short: "revoke a key from a role",
Run: roleRevokePermissionCommandFunc,
}
@ -121,21 +121,29 @@ func roleGetCommandFunc(cmd *cobra.Command, args []string) {
fmt.Println("KV Read:")
for _, perm := range resp.Perm {
if perm.PermType == clientv3.PermRead || perm.PermType == clientv3.PermReadWrite {
fmt.Printf("\t%s\n", string(perm.Key))
if len(perm.RangeEnd) == 0 {
fmt.Printf("\t%s\n", string(perm.Key))
} else {
fmt.Printf("\t[%s, %s)\n", string(perm.Key), string(perm.RangeEnd))
}
}
}
fmt.Println("KV Write:")
for _, perm := range resp.Perm {
if perm.PermType == clientv3.PermWrite || perm.PermType == clientv3.PermReadWrite {
fmt.Printf("\t%s\n", string(perm.Key))
if len(perm.RangeEnd) == 0 {
fmt.Printf("\t%s\n", string(perm.Key))
} else {
fmt.Printf("\t[%s, %s)\n", string(perm.Key), string(perm.RangeEnd))
}
}
}
}
// roleGrantPermissionCommandFunc executes the "role grant-permission" command.
func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) {
if len(args) != 3 {
ExitWithError(ExitBadArgs, fmt.Errorf("role grant command requires role name, permission type, and key as its argument."))
if len(args) < 3 {
ExitWithError(ExitBadArgs, fmt.Errorf("role grant command requires role name, permission type, and key [endkey] as its argument."))
}
perm, err := clientv3.StrToPermissionType(args[1])
@ -143,7 +151,12 @@ func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) {
ExitWithError(ExitBadArgs, err)
}
_, err = mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], args[2], perm)
rangeEnd := ""
if 4 <= len(args) {
rangeEnd = args[3]
}
_, err = mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], args[2], rangeEnd, perm)
if err != nil {
ExitWithError(ExitError, err)
}
@ -153,11 +166,16 @@ func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) {
// roleRevokePermissionCommandFunc executes the "role revoke-permission" command.
func roleRevokePermissionCommandFunc(cmd *cobra.Command, args []string) {
if len(args) != 2 {
ExitWithError(ExitBadArgs, fmt.Errorf("role revoke-permission command requires role name and key as its argument."))
if len(args) < 2 {
ExitWithError(ExitBadArgs, fmt.Errorf("role revoke-permission command requires role name and key [endkey] as its argument."))
}
_, err := mustClientFromCmd(cmd).Auth.RoleRevokePermission(context.TODO(), args[0], args[1])
rangeEnd := ""
if 3 <= len(args) {
rangeEnd = args[2]
}
_, err := mustClientFromCmd(cmd).Auth.RoleRevokePermission(context.TODO(), args[0], args[1], rangeEnd)
if err != nil {
ExitWithError(ExitError, err)
}

View File

@ -81,7 +81,7 @@ func (s *EtcdServer) applyV3Request(r *pb.InternalRaftRequest) *applyResult {
ar := &applyResult{}
switch {
case r.Range != nil:
if s.AuthStore().IsRangePermitted(r.Header, string(r.Range.Key)) {
if s.AuthStore().IsRangePermitted(r.Header, string(r.Range.Key), string(r.Range.RangeEnd)) {
ar.resp, ar.err = s.applyV3.Range(noTxn, r.Range)
} else {
ar.err = auth.ErrPermissionDenied

View File

@ -1652,8 +1652,9 @@ func (m *AuthRoleGrantPermissionRequest) GetPerm() *authpb.Permission {
}
type AuthRoleRevokePermissionRequest struct {
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
RangeEnd string `protobuf:"bytes,3,opt,name=range_end,json=rangeEnd,proto3" json:"range_end,omitempty"`
}
func (m *AuthRoleRevokePermissionRequest) Reset() { *m = AuthRoleRevokePermissionRequest{} }
@ -5441,6 +5442,12 @@ func (m *AuthRoleRevokePermissionRequest) MarshalTo(data []byte) (int, error) {
i = encodeVarintRpc(data, i, uint64(len(m.Key)))
i += copy(data[i:], m.Key)
}
if len(m.RangeEnd) > 0 {
data[i] = 0x1a
i++
i = encodeVarintRpc(data, i, uint64(len(m.RangeEnd)))
i += copy(data[i:], m.RangeEnd)
}
return i, nil
}
@ -6766,6 +6773,10 @@ func (m *AuthRoleRevokePermissionRequest) Size() (n int) {
if l > 0 {
n += 1 + l + sovRpc(uint64(l))
}
l = len(m.RangeEnd)
if l > 0 {
n += 1 + l + sovRpc(uint64(l))
}
return n
}
@ -12987,6 +12998,35 @@ func (m *AuthRoleRevokePermissionRequest) Unmarshal(data []byte) error {
}
m.Key = string(data[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field RangeEnd", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRpc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRpc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.RangeEnd = string(data[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRpc(data[iNdEx:])
@ -14365,172 +14405,172 @@ var (
)
var fileDescriptorRpc = []byte{
// 2671 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x5a, 0x4f, 0x6f, 0xdb, 0xc8,
0x15, 0x17, 0x25, 0x59, 0xb2, 0x9e, 0xfe, 0x58, 0x19, 0x3b, 0xa9, 0xc2, 0x24, 0x8e, 0x77, 0xf2,
0xcf, 0xdb, 0xcd, 0x2a, 0x1b, 0x77, 0xdb, 0x4b, 0x17, 0x5b, 0xc8, 0x92, 0xd6, 0xf6, 0xda, 0xb1,
0x1d, 0x5a, 0x71, 0xb2, 0x40, 0x01, 0x83, 0x92, 0x26, 0x36, 0x11, 0x89, 0xd4, 0x92, 0x94, 0x13,
0x07, 0xe8, 0xa5, 0x40, 0x3f, 0xc1, 0xf6, 0xd2, 0x5e, 0xfb, 0x11, 0x8a, 0x7e, 0x87, 0xa2, 0x97,
0xf6, 0x13, 0x14, 0x45, 0x4e, 0x45, 0xd1, 0x7b, 0x0f, 0xbd, 0x14, 0xf3, 0x8f, 0x1c, 0x52, 0x94,
0x93, 0x2d, 0xdb, 0x4b, 0xcc, 0x79, 0x7c, 0xef, 0x37, 0x6f, 0xde, 0xbc, 0xf9, 0xf1, 0xbd, 0x51,
0xa0, 0xe4, 0x4e, 0x06, 0xcd, 0x89, 0xeb, 0xf8, 0x0e, 0xaa, 0x10, 0x7f, 0x30, 0xf4, 0x88, 0x7b,
0x4e, 0xdc, 0x49, 0x5f, 0x5f, 0x39, 0x75, 0x4e, 0x1d, 0xf6, 0xe2, 0x11, 0x7d, 0xe2, 0x3a, 0xfa,
0x75, 0xaa, 0xf3, 0x68, 0x7c, 0x3e, 0x18, 0xb0, 0x7f, 0x26, 0xfd, 0x47, 0xaf, 0xce, 0xc5, 0xab,
0x1b, 0xec, 0x95, 0x39, 0xf5, 0xcf, 0xd8, 0x3f, 0x93, 0x3e, 0xfb, 0xc3, 0x5f, 0xe2, 0x5f, 0x69,
0x50, 0x33, 0x88, 0x37, 0x71, 0x6c, 0x8f, 0x6c, 0x13, 0x73, 0x48, 0x5c, 0x74, 0x0b, 0x60, 0x30,
0x9a, 0x7a, 0x3e, 0x71, 0x4f, 0xac, 0x61, 0x43, 0x5b, 0xd3, 0xd6, 0xf3, 0x46, 0x49, 0x48, 0x76,
0x86, 0xe8, 0x06, 0x94, 0xc6, 0x64, 0xdc, 0xe7, 0x6f, 0xb3, 0xec, 0xed, 0x22, 0x17, 0xec, 0x0c,
0x91, 0x0e, 0x8b, 0x2e, 0x39, 0xb7, 0x3c, 0xcb, 0xb1, 0x1b, 0xb9, 0x35, 0x6d, 0x3d, 0x67, 0x04,
0x63, 0x6a, 0xe8, 0x9a, 0x2f, 0xfd, 0x13, 0x9f, 0xb8, 0xe3, 0x46, 0x9e, 0x1b, 0x52, 0x41, 0x8f,
0xb8, 0x63, 0xfc, 0xeb, 0x1c, 0x54, 0x0c, 0xd3, 0x3e, 0x25, 0x06, 0xf9, 0x76, 0x4a, 0x3c, 0x1f,
0xd5, 0x21, 0xf7, 0x8a, 0x5c, 0xb0, 0xe9, 0x2b, 0x06, 0x7d, 0xe4, 0xf6, 0xf6, 0x29, 0x39, 0x21,
0x36, 0x9f, 0xb8, 0x42, 0xed, 0xed, 0x53, 0xd2, 0xb5, 0x87, 0x68, 0x05, 0x16, 0x46, 0xd6, 0xd8,
0xf2, 0xc5, 0xac, 0x7c, 0x10, 0x71, 0x27, 0x1f, 0x73, 0xa7, 0x0d, 0xe0, 0x39, 0xae, 0x7f, 0xe2,
0xb8, 0x43, 0xe2, 0x36, 0x16, 0xd6, 0xb4, 0xf5, 0xda, 0xc6, 0xdd, 0xa6, 0x1a, 0xea, 0xa6, 0xea,
0x50, 0xf3, 0xc8, 0x71, 0xfd, 0x03, 0xaa, 0x6b, 0x94, 0x3c, 0xf9, 0x88, 0xbe, 0x82, 0x32, 0x03,
0xf1, 0x4d, 0xf7, 0x94, 0xf8, 0x8d, 0x02, 0x43, 0xb9, 0xf7, 0x1e, 0x94, 0x1e, 0x53, 0x36, 0xd8,
0xf4, 0xfc, 0x19, 0x61, 0xa8, 0x78, 0xc4, 0xb5, 0xcc, 0x91, 0xf5, 0xd6, 0xec, 0x8f, 0x48, 0xa3,
0xb8, 0xa6, 0xad, 0x2f, 0x1a, 0x11, 0x19, 0x6e, 0x42, 0x29, 0xf0, 0x01, 0x2d, 0x42, 0x7e, 0xff,
0x60, 0xbf, 0x5b, 0xcf, 0x20, 0x80, 0x42, 0xeb, 0xa8, 0xdd, 0xdd, 0xef, 0xd4, 0x35, 0x54, 0x86,
0x62, 0xa7, 0xcb, 0x07, 0x59, 0xbc, 0x09, 0x10, 0xce, 0x86, 0x8a, 0x90, 0xdb, 0xed, 0x7e, 0x53,
0xcf, 0x50, 0x9d, 0xe3, 0xae, 0x71, 0xb4, 0x73, 0xb0, 0x5f, 0xd7, 0xa8, 0x71, 0xdb, 0xe8, 0xb6,
0x7a, 0xdd, 0x7a, 0x96, 0x6a, 0x3c, 0x39, 0xe8, 0xd4, 0x73, 0xa8, 0x04, 0x0b, 0xc7, 0xad, 0xbd,
0x67, 0xdd, 0x7a, 0x1e, 0xff, 0x02, 0xaa, 0xc2, 0x7d, 0x9e, 0x22, 0xe8, 0x73, 0x28, 0x9c, 0xb1,
0x34, 0x61, 0x3b, 0x53, 0xde, 0xb8, 0x19, 0x5b, 0x6b, 0x24, 0x95, 0x0c, 0xa1, 0x8b, 0x30, 0xe4,
0x5e, 0x9d, 0x7b, 0x8d, 0xec, 0x5a, 0x6e, 0xbd, 0xbc, 0x51, 0x6f, 0xf2, 0x0c, 0x6d, 0xee, 0x92,
0x8b, 0x63, 0x73, 0x34, 0x25, 0x06, 0x7d, 0x89, 0x10, 0xe4, 0xc7, 0x8e, 0x4b, 0xd8, 0x06, 0x2e,
0x1a, 0xec, 0x19, 0x7f, 0x0d, 0x70, 0x38, 0xf5, 0xe7, 0xa7, 0xc4, 0x0a, 0x2c, 0x9c, 0x53, 0x04,
0x91, 0x0e, 0x7c, 0xc0, 0x72, 0x81, 0x98, 0x1e, 0x09, 0x72, 0x81, 0x0e, 0x70, 0x1b, 0xca, 0x0c,
0x2b, 0xcd, 0x42, 0x70, 0x1b, 0x50, 0x87, 0x8c, 0x88, 0x4f, 0x52, 0xe4, 0x2a, 0x26, 0xb0, 0x1c,
0x01, 0x49, 0x15, 0xda, 0x06, 0x14, 0x87, 0x0c, 0x8c, 0xcf, 0x93, 0x33, 0xe4, 0x10, 0xff, 0x53,
0x83, 0x92, 0xf0, 0xf0, 0x60, 0x82, 0x5a, 0x50, 0x75, 0xf9, 0xe0, 0x84, 0x39, 0x22, 0x26, 0xd1,
0xe7, 0xe7, 0xea, 0x76, 0xc6, 0xa8, 0x08, 0x13, 0x26, 0x46, 0x3f, 0x85, 0xb2, 0x84, 0x98, 0x4c,
0x7d, 0x36, 0x5d, 0x79, 0xa3, 0x11, 0x05, 0x08, 0xb7, 0x6b, 0x3b, 0x63, 0x80, 0x50, 0x3f, 0x9c,
0xfa, 0xa8, 0x07, 0x2b, 0xd2, 0x98, 0x3b, 0x28, 0xdc, 0xc8, 0x31, 0x94, 0xb5, 0x28, 0xca, 0x6c,
0x8c, 0xb7, 0x33, 0x06, 0x12, 0xf6, 0xca, 0xcb, 0xcd, 0x12, 0x14, 0x85, 0x14, 0xff, 0x4b, 0x03,
0x90, 0x31, 0x3a, 0x98, 0xa0, 0x0e, 0xd4, 0x5c, 0x31, 0x8a, 0x2c, 0xf8, 0x46, 0xe2, 0x82, 0x45,
0x68, 0x33, 0x46, 0x55, 0x1a, 0xf1, 0x25, 0x7f, 0x09, 0x95, 0x00, 0x25, 0x5c, 0xf3, 0xf5, 0x84,
0x35, 0x07, 0x08, 0x65, 0x69, 0x40, 0x57, 0xfd, 0x1c, 0xae, 0x06, 0xf6, 0x09, 0xcb, 0xfe, 0xe8,
0x92, 0x65, 0x07, 0x80, 0xcb, 0x12, 0x41, 0x5d, 0x38, 0x50, 0x66, 0xe3, 0x62, 0xfc, 0xdb, 0x1c,
0x14, 0xdb, 0xce, 0x78, 0x62, 0xba, 0x74, 0x8f, 0x0a, 0x2e, 0xf1, 0xa6, 0x23, 0x9f, 0x2d, 0xb7,
0xb6, 0x71, 0x27, 0x3a, 0x83, 0x50, 0x93, 0x7f, 0x0d, 0xa6, 0x6a, 0x08, 0x13, 0x6a, 0x2c, 0x88,
0x2c, 0xfb, 0x01, 0xc6, 0x82, 0xc6, 0x84, 0x89, 0x3c, 0x04, 0xb9, 0xf0, 0x10, 0xe8, 0x50, 0x3c,
0x27, 0x6e, 0x48, 0xbe, 0xdb, 0x19, 0x43, 0x0a, 0xd0, 0xc7, 0xb0, 0x34, 0x70, 0x89, 0x49, 0xe3,
0x21, 0x09, 0x7a, 0x41, 0xe8, 0xd4, 0xf8, 0x0b, 0x43, 0x12, 0xf5, 0x1d, 0xa8, 0x8c, 0x9d, 0x61,
0xa8, 0x57, 0x10, 0x7a, 0xe5, 0xb1, 0x33, 0x0c, 0x94, 0xae, 0x49, 0x26, 0xa0, 0xcc, 0x59, 0xd9,
0xce, 0x08, 0x2e, 0xc0, 0x8f, 0xa1, 0x1a, 0x59, 0x2b, 0x25, 0xb7, 0xee, 0xd3, 0x67, 0xad, 0x3d,
0xce, 0x84, 0x5b, 0x8c, 0xfc, 0x8c, 0xba, 0x46, 0x09, 0x75, 0xaf, 0x7b, 0x74, 0x54, 0xcf, 0xe2,
0x2f, 0x02, 0x13, 0x41, 0x9d, 0x0a, 0x63, 0x66, 0x14, 0xc6, 0xd4, 0x24, 0x63, 0x66, 0x43, 0xc6,
0xcc, 0x6d, 0xd6, 0xa0, 0xc2, 0x03, 0x72, 0x32, 0xb5, 0x2d, 0xc7, 0xc6, 0xbf, 0xd3, 0x00, 0x7a,
0x6f, 0x6c, 0x49, 0x15, 0x8f, 0xa0, 0x38, 0xe0, 0xe0, 0x0d, 0x8d, 0xb1, 0xe1, 0xd5, 0xc4, 0x18,
0x1b, 0x52, 0x0b, 0x3d, 0x86, 0xa2, 0x37, 0x1d, 0x0c, 0x88, 0x27, 0xe9, 0xf3, 0x07, 0x71, 0x5a,
0x10, 0x27, 0xdc, 0x90, 0x7a, 0xd4, 0xe4, 0xa5, 0x69, 0x8d, 0xa6, 0x8c, 0x4c, 0x2f, 0x37, 0x11,
0x7a, 0xf8, 0x37, 0x1a, 0x94, 0x99, 0x97, 0xa9, 0xb8, 0xe8, 0x26, 0x94, 0x98, 0x0f, 0x64, 0x28,
0xd8, 0x68, 0xd1, 0x08, 0x05, 0xe8, 0x27, 0x50, 0x92, 0x29, 0xeb, 0x09, 0xc7, 0x1a, 0xc9, 0xb0,
0x07, 0x13, 0x23, 0x54, 0xc5, 0xbb, 0x70, 0x85, 0x45, 0x65, 0xe0, 0x5b, 0x4e, 0x10, 0x47, 0xf5,
0xcb, 0xae, 0xc5, 0xbe, 0xec, 0x3a, 0x2c, 0x4e, 0xce, 0x2e, 0x3c, 0x6b, 0x60, 0x8e, 0x84, 0x17,
0xc1, 0x18, 0x7f, 0x0d, 0x48, 0x05, 0x4b, 0xf5, 0x31, 0xa8, 0x42, 0x79, 0xdb, 0xf4, 0xce, 0x84,
0x4b, 0xf8, 0x05, 0x54, 0xf8, 0x30, 0x55, 0x0c, 0x11, 0xe4, 0xcf, 0x4c, 0xef, 0x8c, 0x39, 0x5e,
0x35, 0xd8, 0x33, 0xbe, 0x02, 0x4b, 0x47, 0xb6, 0x39, 0xf1, 0xce, 0x1c, 0x49, 0xae, 0xb4, 0x6e,
0xab, 0x87, 0xb2, 0x54, 0x33, 0x3e, 0x80, 0x25, 0x97, 0x8c, 0x4d, 0xcb, 0xb6, 0xec, 0xd3, 0x93,
0xfe, 0x85, 0x4f, 0x3c, 0x51, 0xd6, 0xd5, 0x02, 0xf1, 0x26, 0x95, 0x52, 0xd7, 0xfa, 0x23, 0xa7,
0x2f, 0x8e, 0x38, 0x7b, 0xc6, 0x7f, 0xd0, 0xa0, 0xf2, 0xdc, 0xf4, 0x07, 0x32, 0x0a, 0x68, 0x07,
0x6a, 0xc1, 0xc1, 0x66, 0x12, 0xe1, 0x4b, 0x8c, 0xe1, 0x99, 0x4d, 0x5b, 0x1c, 0x74, 0xc9, 0xf0,
0xd5, 0x81, 0x2a, 0x60, 0x50, 0xa6, 0x3d, 0x20, 0xa3, 0x00, 0x2a, 0x3b, 0x1f, 0x8a, 0x29, 0xaa,
0x50, 0xaa, 0x60, 0x73, 0x29, 0xfc, 0xfa, 0xf1, 0x63, 0xf9, 0x9d, 0x06, 0x68, 0xd6, 0x87, 0xef,
0x5b, 0x75, 0xde, 0x83, 0x9a, 0xe7, 0x9b, 0xae, 0x7f, 0x12, 0x2b, 0x7a, 0xab, 0x4c, 0x1a, 0x90,
0xd3, 0x03, 0x58, 0x9a, 0xb8, 0xce, 0xa9, 0x4b, 0x3c, 0xef, 0xc4, 0x76, 0x7c, 0xeb, 0xe5, 0x05,
0x23, 0xc4, 0x45, 0xa3, 0x26, 0xc5, 0xfb, 0x4c, 0x8a, 0x1f, 0x49, 0xa7, 0x54, 0xe7, 0xd1, 0x75,
0x58, 0x7c, 0x4d, 0xa5, 0xb2, 0x1c, 0xcf, 0x19, 0x45, 0x36, 0xde, 0x19, 0xe2, 0xbf, 0x6b, 0x50,
0x15, 0xe1, 0x4f, 0x95, 0x03, 0xea, 0x14, 0xd9, 0xc8, 0x14, 0xb4, 0xc0, 0xe0, 0xdb, 0x32, 0x14,
0xa5, 0x99, 0x1c, 0xd2, 0x73, 0xc6, 0xa3, 0x4c, 0x86, 0x62, 0x3d, 0xc1, 0x18, 0x7d, 0x0c, 0xf5,
0x01, 0x3f, 0x67, 0x31, 0x82, 0x37, 0x96, 0x84, 0x3c, 0x88, 0xce, 0x3d, 0x28, 0x90, 0x73, 0x62,
0xfb, 0x5e, 0xa3, 0xcc, 0x48, 0xa1, 0x2a, 0xeb, 0xc3, 0x2e, 0x95, 0x1a, 0xe2, 0x25, 0xfe, 0x31,
0x5c, 0xd9, 0xa3, 0x85, 0xdc, 0x96, 0x6b, 0xda, 0x6a, 0x49, 0xd8, 0xeb, 0xed, 0x89, 0xa8, 0xe4,
0xfc, 0xde, 0x1e, 0xaa, 0x41, 0x76, 0xa7, 0x23, 0xd6, 0x90, 0xb5, 0x3a, 0xf8, 0x97, 0x1a, 0x20,
0xd5, 0x2e, 0x55, 0x98, 0x62, 0xe0, 0x72, 0xfa, 0x5c, 0x38, 0xfd, 0x0a, 0x2c, 0x10, 0xd7, 0x75,
0x5c, 0x16, 0x90, 0x92, 0xc1, 0x07, 0xf8, 0xae, 0xf0, 0xc1, 0x20, 0xe7, 0xce, 0xab, 0x20, 0xd9,
0x38, 0x9a, 0x16, 0xb8, 0xba, 0x0b, 0xcb, 0x11, 0xad, 0x54, 0xe4, 0xf4, 0x00, 0xae, 0x32, 0xb0,
0x5d, 0x42, 0x26, 0xad, 0x91, 0x75, 0x3e, 0x77, 0xd6, 0x09, 0x5c, 0x8b, 0x2b, 0xfe, 0x7f, 0x63,
0x84, 0xcf, 0xa0, 0xf0, 0x84, 0x35, 0x8c, 0x8a, 0x2f, 0x79, 0xa6, 0x8b, 0x20, 0x6f, 0x9b, 0x63,
0x5e, 0xce, 0x97, 0x0c, 0xf6, 0xcc, 0xd8, 0x9c, 0x10, 0xf7, 0x99, 0xb1, 0xc7, 0xbf, 0x1a, 0x25,
0x23, 0x18, 0xa3, 0x55, 0xda, 0xaa, 0x5a, 0xc4, 0xf6, 0xd9, 0xdb, 0x3c, 0x7b, 0xab, 0x48, 0x70,
0x13, 0xea, 0x7c, 0xa6, 0xd6, 0x70, 0xa8, 0x7c, 0x39, 0x02, 0x3c, 0x2d, 0x8a, 0x87, 0x5f, 0xc3,
0x15, 0x45, 0x3f, 0x55, 0x18, 0x1e, 0x42, 0x81, 0x77, 0xc5, 0x82, 0xb4, 0x56, 0xa2, 0x56, 0x7c,
0x1a, 0x43, 0xe8, 0xe0, 0x7b, 0xb0, 0x2c, 0x24, 0x64, 0xec, 0x24, 0xed, 0x15, 0x8b, 0x0f, 0xde,
0x83, 0x95, 0xa8, 0x5a, 0xaa, 0x14, 0x69, 0xc9, 0x49, 0x9f, 0x4d, 0x86, 0x0a, 0x07, 0xc6, 0x37,
0x45, 0x0d, 0x58, 0x36, 0x16, 0xb0, 0xc0, 0x21, 0x09, 0x91, 0xca, 0xa1, 0x65, 0x19, 0xfe, 0x3d,
0xcb, 0x0b, 0xbe, 0x74, 0x6f, 0x01, 0xa9, 0xc2, 0x54, 0x9b, 0xd2, 0x84, 0x22, 0x0f, 0xb8, 0x2c,
0xa6, 0x92, 0x77, 0x45, 0x2a, 0x51, 0x87, 0x3a, 0xe4, 0xa5, 0x6b, 0x9e, 0x8e, 0x49, 0xc0, 0x39,
0xb4, 0x84, 0x50, 0x85, 0xa9, 0x56, 0xfc, 0x67, 0x0d, 0x2a, 0xad, 0x91, 0xe9, 0x8e, 0x65, 0xf0,
0xbf, 0x84, 0x02, 0xaf, 0x4d, 0x44, 0xfd, 0x7e, 0x3f, 0x0a, 0xa3, 0xea, 0xf2, 0x41, 0x8b, 0x57,
0x32, 0xc2, 0x8a, 0x6e, 0x96, 0xb8, 0x8c, 0xe9, 0xc4, 0x2e, 0x67, 0x3a, 0xe8, 0x53, 0x58, 0x30,
0xa9, 0x09, 0x3b, 0x8b, 0xb5, 0x78, 0x55, 0xc8, 0xd0, 0x7a, 0x17, 0x13, 0x62, 0x70, 0x2d, 0xfc,
0x39, 0x94, 0x95, 0x19, 0x68, 0xb1, 0xbb, 0xd5, 0xed, 0xd5, 0x33, 0xa8, 0x02, 0x8b, 0xad, 0x76,
0x6f, 0xe7, 0x98, 0xd7, 0xc0, 0x35, 0x80, 0x4e, 0x37, 0x18, 0x67, 0xf1, 0x0b, 0x61, 0x25, 0x4e,
0xb8, 0xea, 0x8f, 0x36, 0xcf, 0x9f, 0xec, 0x07, 0xf9, 0xf3, 0x06, 0xaa, 0x62, 0xf9, 0xa9, 0x72,
0xe0, 0x31, 0x14, 0x18, 0x9e, 0x4c, 0x81, 0xeb, 0x09, 0xd3, 0xca, 0xd3, 0xc9, 0x15, 0xf1, 0x12,
0x54, 0x8f, 0x7c, 0xd3, 0x9f, 0x7a, 0x32, 0x05, 0xfe, 0xa4, 0x41, 0x4d, 0x4a, 0xd2, 0x76, 0xef,
0xb2, 0x45, 0xe2, 0x9c, 0x17, 0x34, 0x48, 0xd7, 0xa0, 0x30, 0xec, 0x1f, 0x59, 0x6f, 0xe5, 0x2d,
0x86, 0x18, 0x51, 0xf9, 0x88, 0xcf, 0xc3, 0xaf, 0xd0, 0xc4, 0x88, 0xd6, 0xde, 0xae, 0xf9, 0xd2,
0xdf, 0xb1, 0x87, 0xe4, 0x0d, 0xfb, 0xd2, 0xe6, 0x8d, 0x50, 0xc0, 0xca, 0x65, 0x71, 0xd5, 0xc6,
0xfa, 0x27, 0xf5, 0xea, 0x6d, 0x19, 0xae, 0xb4, 0xa6, 0xfe, 0x59, 0xd7, 0x36, 0xfb, 0x23, 0x49,
0x02, 0x78, 0x05, 0x10, 0x15, 0x76, 0x2c, 0x4f, 0x95, 0x76, 0x61, 0x99, 0x4a, 0x89, 0xed, 0x5b,
0x03, 0x85, 0x31, 0x24, 0x6d, 0x6b, 0x31, 0xda, 0x36, 0x3d, 0xef, 0xb5, 0xe3, 0x0e, 0xc5, 0xd2,
0x82, 0x31, 0xee, 0x70, 0xf0, 0x67, 0x5e, 0x84, 0x98, 0xbf, 0x2f, 0xca, 0x7a, 0x88, 0xb2, 0x45,
0xfc, 0x4b, 0x50, 0xf0, 0x27, 0x70, 0x55, 0x6a, 0x8a, 0x1e, 0xfa, 0x12, 0xe5, 0x03, 0xb8, 0x25,
0x95, 0xdb, 0x67, 0xb4, 0xd0, 0x3b, 0x14, 0x13, 0xfe, 0xb7, 0x7e, 0x6e, 0x42, 0x23, 0xf0, 0x93,
0xd5, 0x20, 0xce, 0x48, 0x75, 0x60, 0xea, 0x89, 0x9c, 0x29, 0x19, 0xec, 0x99, 0xca, 0x5c, 0x67,
0x14, 0x7c, 0x04, 0xe9, 0x33, 0x6e, 0xc3, 0x75, 0x89, 0x21, 0xaa, 0x83, 0x28, 0xc8, 0x8c, 0x43,
0x49, 0x20, 0x22, 0x60, 0xd4, 0xf4, 0xf2, 0xb0, 0xab, 0x9a, 0xd1, 0xd0, 0x32, 0x4c, 0x4d, 0xc1,
0x14, 0xa1, 0xa5, 0x9a, 0x33, 0xa1, 0x9d, 0x51, 0xfe, 0x39, 0xac, 0x06, 0xb0, 0x34, 0x12, 0x87,
0xc4, 0x1d, 0x5b, 0x9e, 0xa7, 0xb4, 0x75, 0x49, 0x4b, 0xb9, 0x0f, 0xf9, 0x09, 0x11, 0x2c, 0x51,
0xde, 0x40, 0x4d, 0x7e, 0x89, 0xdd, 0x54, 0x8c, 0xd9, 0x7b, 0xbc, 0x05, 0xb7, 0x25, 0x3a, 0x8f,
0x51, 0x22, 0x7c, 0xdc, 0x29, 0x59, 0xf2, 0xf3, 0x40, 0xd1, 0x47, 0x4a, 0xf0, 0xea, 0x81, 0x48,
0x45, 0xf0, 0xbb, 0xfc, 0xc4, 0x04, 0xe7, 0x28, 0x15, 0x58, 0x1f, 0x56, 0xa2, 0xc7, 0x2f, 0x15,
0xf7, 0xac, 0xc0, 0x82, 0xef, 0xbc, 0x22, 0x92, 0x79, 0xf8, 0x40, 0x3a, 0x1c, 0x9c, 0xcd, 0x54,
0x0e, 0x9b, 0x21, 0x18, 0xcb, 0xa3, 0xb4, 0xfe, 0xd2, 0x0d, 0x93, 0x45, 0x08, 0x1f, 0xe0, 0x7d,
0xb8, 0x16, 0x3f, 0xdb, 0xa9, 0x5c, 0x3e, 0xe6, 0x39, 0x9a, 0x74, 0xfc, 0x53, 0xe1, 0x3e, 0x0d,
0x4f, 0xb0, 0xc2, 0x02, 0xa9, 0x20, 0x0d, 0xd0, 0x93, 0x48, 0xe1, 0x7f, 0x91, 0xaf, 0x01, 0x47,
0xa4, 0x02, 0xf3, 0x42, 0xb0, 0xf4, 0xdb, 0x1f, 0xd2, 0x40, 0xee, 0x52, 0x1a, 0x10, 0x09, 0xa1,
0x32, 0x52, 0xaa, 0x45, 0x3c, 0x0f, 0x69, 0x65, 0x86, 0xb4, 0x52, 0x01, 0xbf, 0x80, 0xb5, 0xf9,
0x7c, 0x95, 0x06, 0xf9, 0x87, 0x18, 0x4a, 0x41, 0xf5, 0xa4, 0xfc, 0x52, 0x54, 0x86, 0xe2, 0xfe,
0xc1, 0xd1, 0x61, 0xab, 0xdd, 0xad, 0x6b, 0x1b, 0xff, 0xc8, 0x42, 0x76, 0xf7, 0x18, 0x6d, 0xc2,
0x02, 0xbf, 0xe9, 0xbe, 0xe4, 0x87, 0x00, 0xfd, 0xb2, 0x3b, 0x73, 0x9c, 0x41, 0x5f, 0x40, 0xee,
0x70, 0xea, 0xa3, 0xb9, 0xbf, 0x04, 0xe8, 0xf3, 0xef, 0xcb, 0x71, 0x06, 0xf5, 0xa0, 0xac, 0x5c,
0x6c, 0xa3, 0xf7, 0xfe, 0x12, 0xa0, 0xbf, 0xff, 0xd2, 0x9c, 0xfb, 0xd4, 0x7b, 0x63, 0xc7, 0x7d,
0x0a, 0x2f, 0x62, 0xe3, 0x3e, 0x29, 0x97, 0x9f, 0x38, 0x83, 0xf6, 0xc5, 0x85, 0xfa, 0xc0, 0x47,
0xb7, 0x13, 0xee, 0x67, 0xd5, 0x9b, 0x48, 0x7d, 0x6d, 0xbe, 0x82, 0xc4, 0xdb, 0x38, 0x80, 0x05,
0x76, 0x4b, 0x83, 0xbe, 0x92, 0x0f, 0x7a, 0xc2, 0x1d, 0xd6, 0x9c, 0x70, 0x47, 0xee, 0x77, 0x70,
0x66, 0x5d, 0xfb, 0x4c, 0xdb, 0xf8, 0x2e, 0x0b, 0x0b, 0xac, 0x6b, 0x47, 0x4f, 0x01, 0xc2, 0xeb,
0x8d, 0xb8, 0xb7, 0x33, 0x17, 0x26, 0x71, 0x6f, 0x67, 0x6f, 0x46, 0xf8, 0x8e, 0x28, 0xf7, 0x10,
0x28, 0xc9, 0x24, 0x72, 0x91, 0x11, 0xdf, 0x91, 0x84, 0x4b, 0x0c, 0x9c, 0x41, 0x26, 0xd4, 0xa2,
0xf7, 0x0c, 0xe8, 0x4e, 0x82, 0x59, 0xfc, 0xba, 0x42, 0xbf, 0x7b, 0xb9, 0x52, 0x24, 0x2a, 0x7f,
0xcd, 0x42, 0xb1, 0xcd, 0x7f, 0xa8, 0x46, 0xfb, 0x50, 0x0a, 0x5a, 0x79, 0xb4, 0x9a, 0xd4, 0xe6,
0x85, 0x35, 0x90, 0x7e, 0x7b, 0xee, 0xfb, 0xc0, 0xfd, 0xe7, 0x50, 0x51, 0x5b, 0x6f, 0xf4, 0x51,
0x62, 0xe7, 0xa8, 0x76, 0xef, 0x3a, 0xbe, 0x4c, 0x65, 0x16, 0x98, 0xb7, 0xd0, 0xc9, 0xc0, 0x91,
0x0e, 0x3d, 0x19, 0x38, 0xda, 0x81, 0xe3, 0x0c, 0xcd, 0x8c, 0xb0, 0x71, 0x46, 0x89, 0x4b, 0x54,
0xfa, 0xec, 0x78, 0x66, 0xcc, 0xf6, 0xdc, 0x38, 0xb3, 0xf1, 0xef, 0x2c, 0x94, 0x9f, 0x98, 0x96,
0xed, 0x13, 0xdb, 0xb4, 0x07, 0x84, 0xb2, 0x07, 0x23, 0x9a, 0x78, 0x3a, 0xab, 0x6d, 0x6a, 0x3c,
0x9d, 0x23, 0x3d, 0x1c, 0xce, 0xa0, 0x2e, 0x14, 0x78, 0x2b, 0x85, 0x62, 0x8a, 0x91, 0x96, 0x4b,
0xbf, 0x99, 0xfc, 0x52, 0x5d, 0x6d, 0xd8, 0x95, 0xc7, 0x57, 0x3b, 0xd3, 0xc4, 0xeb, 0x6b, 0xf3,
0x15, 0x02, 0xc8, 0x9f, 0x41, 0x7e, 0xdb, 0xf4, 0xce, 0x50, 0x8c, 0x2a, 0x94, 0x3b, 0x7f, 0x5d,
0x4f, 0x7a, 0x15, 0x00, 0x3c, 0x81, 0x45, 0x79, 0x47, 0x8f, 0x6e, 0xc5, 0xfc, 0x8f, 0xde, 0xe7,
0xeb, 0xab, 0xf3, 0x5e, 0x4b, 0xb0, 0xcf, 0xb4, 0x8d, 0xdf, 0x03, 0xe4, 0xe9, 0x17, 0x83, 0xae,
0x35, 0x2c, 0x50, 0xe3, 0x6b, 0x9d, 0xe9, 0xe5, 0xe2, 0x6b, 0x9d, 0xad, 0x6d, 0xf9, 0x99, 0x57,
0xea, 0x54, 0x94, 0x60, 0x12, 0x6d, 0x05, 0xe3, 0x67, 0x3e, 0xa1, 0xc8, 0xe5, 0xb9, 0xad, 0x16,
0xac, 0x28, 0xc1, 0x28, 0xd6, 0x4b, 0xc6, 0x73, 0x3b, 0xa9, 0xde, 0xc5, 0x19, 0x74, 0x08, 0x45,
0x51, 0xa1, 0x26, 0xb9, 0x1a, 0x6d, 0x2c, 0x93, 0x5c, 0x8d, 0x95, 0xb7, 0x21, 0xe2, 0x16, 0xf1,
0xe7, 0x21, 0x86, 0x9d, 0xd0, 0x3c, 0x44, 0xa5, 0xc8, 0xc1, 0x19, 0xf4, 0x0d, 0x40, 0x58, 0x95,
0xc6, 0xc9, 0x2e, 0xb1, 0x1f, 0x8d, 0x93, 0x5d, 0x72, 0x61, 0x8b, 0x33, 0xe8, 0x5b, 0x40, 0xb3,
0x05, 0x2a, 0xfa, 0x24, 0xd9, 0x3a, 0xb1, 0x8b, 0xd5, 0x1f, 0x7e, 0x98, 0x72, 0x30, 0x65, 0x1f,
0xaa, 0x91, 0xda, 0x15, 0xdd, 0x9f, 0x13, 0x83, 0x58, 0x8b, 0xab, 0x3f, 0x78, 0xaf, 0x5e, 0x30,
0x07, 0x81, 0x5a, 0xb4, 0x98, 0x45, 0x73, 0x8c, 0x67, 0x7a, 0x60, 0x7d, 0xfd, 0xfd, 0x8a, 0xea,
0x56, 0x8b, 0xfa, 0x36, 0x69, 0xab, 0xa3, 0xed, 0x71, 0xd2, 0x56, 0xc7, 0x8a, 0xe3, 0x10, 0x71,
0x4e, 0xf2, 0x44, 0xdb, 0xe8, 0x79, 0x88, 0x33, 0xc9, 0x13, 0x56, 0xb0, 0x49, 0xc9, 0x33, 0xd3,
0x71, 0x27, 0x25, 0xcf, 0x6c, 0x11, 0x8c, 0x33, 0xc8, 0x87, 0xe5, 0x84, 0x62, 0x16, 0x3d, 0x9c,
0xe3, 0x56, 0x62, 0xa3, 0xae, 0x7f, 0xfa, 0x81, 0xda, 0xc1, 0xac, 0xaf, 0x61, 0x25, 0xa9, 0xd2,
0x45, 0x73, 0x80, 0xe6, 0x74, 0xf0, 0x7a, 0xf3, 0x43, 0xd5, 0xe5, 0xc4, 0x9b, 0x95, 0x3f, 0xbe,
0x5b, 0xd5, 0xfe, 0xf2, 0x6e, 0x55, 0xfb, 0xdb, 0xbb, 0x55, 0xad, 0x5f, 0x60, 0xff, 0xed, 0xed,
0x47, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x7a, 0xd6, 0x18, 0xf9, 0x5f, 0x27, 0x00, 0x00,
// 2657 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x5a, 0x4b, 0x6f, 0x1b, 0xc9,
0xf1, 0xd7, 0x90, 0x14, 0x29, 0x16, 0x1f, 0x96, 0x5b, 0xb2, 0xff, 0xf4, 0xec, 0xfa, 0xb1, 0xe3,
0xe7, 0x3f, 0xeb, 0xa5, 0x63, 0x65, 0x93, 0x4b, 0x16, 0x1b, 0x50, 0x22, 0xd7, 0xd6, 0x4a, 0x96,
0xec, 0x11, 0x2d, 0xef, 0x02, 0x01, 0x84, 0x21, 0xd9, 0x96, 0x08, 0xf3, 0xb5, 0x33, 0x43, 0xd9,
0x32, 0x90, 0x4b, 0x80, 0x7c, 0x82, 0xcd, 0x25, 0xb9, 0xe6, 0x23, 0x04, 0xf9, 0x0e, 0x41, 0x2e,
0xc9, 0x27, 0x08, 0x82, 0x9c, 0x82, 0x20, 0xf7, 0x1c, 0x72, 0x49, 0xf5, 0x6b, 0xa6, 0x67, 0x38,
0x23, 0x7b, 0x33, 0xc9, 0xc1, 0xf6, 0x74, 0x75, 0xd5, 0xaf, 0xab, 0xab, 0xab, 0xab, 0xab, 0x8a,
0x86, 0xb2, 0x3b, 0xeb, 0x37, 0x67, 0xee, 0xd4, 0x9f, 0x92, 0x2a, 0xf5, 0xfb, 0x03, 0x8f, 0xba,
0xa7, 0xd4, 0x9d, 0xf5, 0xcc, 0xf5, 0xe3, 0xe9, 0xf1, 0x94, 0x4f, 0x3c, 0x60, 0x5f, 0x82, 0xc7,
0xbc, 0xc2, 0x78, 0x1e, 0x8c, 0x4f, 0xfb, 0x7d, 0xfe, 0xd7, 0xac, 0xf7, 0xe0, 0xd5, 0xa9, 0x9c,
0xfa, 0x80, 0x4f, 0x39, 0x73, 0xff, 0x84, 0xff, 0x85, 0x53, 0xec, 0x1f, 0x31, 0x69, 0xfd, 0xc2,
0x80, 0xba, 0x4d, 0xbd, 0xd9, 0x74, 0xe2, 0xd1, 0xc7, 0xd4, 0x19, 0x50, 0x97, 0x5c, 0x05, 0xe8,
0x8f, 0xe6, 0x9e, 0x4f, 0xdd, 0xa3, 0xe1, 0xa0, 0x61, 0xdc, 0x30, 0xee, 0x15, 0xec, 0xb2, 0xa4,
0x6c, 0x0f, 0xc8, 0x07, 0x50, 0x1e, 0xd3, 0x71, 0x4f, 0xcc, 0xe6, 0xf8, 0xec, 0x8a, 0x20, 0xe0,
0xa4, 0x09, 0x2b, 0x2e, 0x3d, 0x1d, 0x7a, 0xc3, 0xe9, 0xa4, 0x91, 0xc7, 0xb9, 0xbc, 0x1d, 0x8c,
0x99, 0xa0, 0xeb, 0xbc, 0xf4, 0x8f, 0x10, 0x66, 0xdc, 0x28, 0x08, 0x41, 0x46, 0xe8, 0xe2, 0xd8,
0xfa, 0x65, 0x1e, 0xaa, 0xb6, 0x33, 0x39, 0xa6, 0x36, 0xfd, 0x66, 0x4e, 0x3d, 0x9f, 0xac, 0x42,
0xfe, 0x15, 0x3d, 0xe3, 0xcb, 0x57, 0x6d, 0xf6, 0x29, 0xe4, 0x91, 0xe3, 0x88, 0x4e, 0xc4, 0xc2,
0x55, 0x26, 0x8f, 0x84, 0xce, 0x64, 0x40, 0xd6, 0x61, 0x79, 0x34, 0x1c, 0x0f, 0x7d, 0xb9, 0xaa,
0x18, 0x44, 0xd4, 0x29, 0xc4, 0xd4, 0xd9, 0x02, 0xf0, 0xa6, 0xae, 0x7f, 0x34, 0x75, 0x71, 0xd3,
0x8d, 0x65, 0x9c, 0xad, 0x6f, 0xdc, 0x6a, 0xea, 0xa6, 0x6e, 0xea, 0x0a, 0x35, 0x0f, 0x90, 0x79,
0x9f, 0xf1, 0xda, 0x65, 0x4f, 0x7d, 0x92, 0x2f, 0xa0, 0xc2, 0x41, 0x7c, 0xc7, 0x3d, 0xa6, 0x7e,
0xa3, 0xc8, 0x51, 0x6e, 0xbf, 0x03, 0xa5, 0xcb, 0x99, 0x6d, 0xbe, 0xbc, 0xf8, 0x26, 0x16, 0x54,
0x91, 0x7f, 0xe8, 0x8c, 0x86, 0x6f, 0x9d, 0xde, 0x88, 0x36, 0x4a, 0x08, 0xb4, 0x62, 0x47, 0x68,
0x56, 0x13, 0xca, 0x81, 0x0e, 0x64, 0x05, 0x0a, 0x7b, 0xfb, 0x7b, 0x9d, 0xd5, 0x25, 0x02, 0x50,
0x6c, 0x1d, 0x6c, 0x75, 0xf6, 0xda, 0xab, 0x06, 0xa9, 0x40, 0xa9, 0xdd, 0x11, 0x83, 0x9c, 0xb5,
0x09, 0x10, 0xae, 0x46, 0x4a, 0x90, 0xdf, 0xe9, 0x7c, 0x8d, 0xfc, 0xc8, 0x73, 0xd8, 0xb1, 0x0f,
0xb6, 0xf7, 0xf7, 0x50, 0x00, 0x85, 0xb7, 0xec, 0x4e, 0xab, 0xdb, 0x59, 0xcd, 0x31, 0x8e, 0x27,
0xfb, 0xed, 0xd5, 0x3c, 0x29, 0xc3, 0xf2, 0x61, 0x6b, 0xf7, 0x79, 0x67, 0xb5, 0x60, 0xfd, 0x0c,
0x6a, 0x52, 0x7d, 0xe1, 0x22, 0xe4, 0x53, 0x28, 0x9e, 0x70, 0x37, 0xe1, 0x27, 0x53, 0xd9, 0xf8,
0x30, 0xb6, 0xd7, 0x88, 0x2b, 0xd9, 0x92, 0x17, 0xb7, 0x97, 0x7f, 0x75, 0xea, 0xe1, 0xa1, 0xe5,
0x51, 0x64, 0xb5, 0x29, 0x3c, 0xb4, 0xb9, 0x43, 0xcf, 0x0e, 0x9d, 0xd1, 0x9c, 0xda, 0x6c, 0x92,
0x10, 0x28, 0x8c, 0xa7, 0x2e, 0xe5, 0x07, 0xb8, 0x62, 0xf3, 0x6f, 0xeb, 0x4b, 0x80, 0xa7, 0x73,
0x3f, 0xdd, 0x25, 0xf0, 0xd4, 0x4f, 0x19, 0x82, 0x74, 0x07, 0x31, 0xe0, 0xbe, 0x40, 0x1d, 0x8f,
0x06, 0xbe, 0xc0, 0x06, 0xd6, 0x16, 0x54, 0x38, 0x56, 0x96, 0x8d, 0x20, 0x08, 0x69, 0xd3, 0x11,
0xf5, 0x69, 0x06, 0x5f, 0xb5, 0x28, 0xac, 0x45, 0x40, 0x32, 0x99, 0xb6, 0x01, 0xa5, 0x01, 0x07,
0x13, 0xeb, 0xe4, 0x6d, 0x35, 0xb4, 0xfe, 0x61, 0x40, 0x59, 0x6a, 0xb8, 0x3f, 0x23, 0x2d, 0xa8,
0xb9, 0x62, 0x70, 0xc4, 0x15, 0x91, 0x8b, 0x98, 0xe9, 0xbe, 0xfa, 0x78, 0xc9, 0xae, 0x4a, 0x11,
0x4e, 0x26, 0x3f, 0x86, 0x8a, 0x82, 0x98, 0xcd, 0x7d, 0xbe, 0x5c, 0x65, 0xa3, 0x11, 0x05, 0x08,
0x8f, 0x0b, 0xc5, 0x41, 0xb2, 0x23, 0x91, 0x74, 0x61, 0x5d, 0x09, 0x0b, 0x05, 0xa5, 0x1a, 0x79,
0x8e, 0x72, 0x23, 0x8a, 0xb2, 0x68, 0x63, 0x44, 0x23, 0x52, 0x5e, 0x9b, 0xdc, 0x2c, 0x43, 0x49,
0x52, 0xad, 0x7f, 0x1a, 0x00, 0xca, 0x46, 0xb8, 0xdf, 0x36, 0xd4, 0x5d, 0x39, 0x8a, 0x6c, 0xf8,
0x83, 0xc4, 0x0d, 0x4b, 0xd3, 0x2e, 0xd9, 0x35, 0x25, 0x24, 0xb6, 0xfc, 0x39, 0x54, 0x03, 0x94,
0x70, 0xcf, 0x57, 0x12, 0xf6, 0x1c, 0x20, 0x54, 0x94, 0x00, 0xdb, 0xf5, 0x0b, 0xb8, 0x14, 0xc8,
0x27, 0x6c, 0xfb, 0xa3, 0x73, 0xb6, 0x1d, 0x00, 0xae, 0x29, 0x04, 0x7d, 0xe3, 0xc0, 0x22, 0x9b,
0x20, 0x5b, 0xbf, 0xce, 0x43, 0x69, 0x6b, 0x3a, 0x9e, 0x39, 0x2e, 0x3b, 0xa3, 0x22, 0xd2, 0xe7,
0x23, 0x9f, 0x6f, 0xb7, 0xbe, 0x71, 0x33, 0xba, 0x82, 0x64, 0x53, 0xff, 0xda, 0x9c, 0xd5, 0x96,
0x22, 0x4c, 0x58, 0x06, 0xb2, 0xdc, 0x7b, 0x08, 0xcb, 0x30, 0x26, 0x45, 0xd4, 0x25, 0xc8, 0x87,
0x97, 0xc0, 0x84, 0x12, 0x0a, 0x86, 0xc1, 0x17, 0xf7, 0xa2, 0x08, 0xe4, 0xff, 0xe1, 0x42, 0xdf,
0xa5, 0x0e, 0xb3, 0x87, 0x0a, 0xd0, 0xcb, 0x92, 0xa7, 0x2e, 0x26, 0x6c, 0x15, 0xa8, 0x6f, 0x42,
0x75, 0x3c, 0x1d, 0x84, 0x7c, 0x45, 0xc9, 0x57, 0x41, 0x6a, 0xc0, 0x74, 0x59, 0x45, 0x02, 0x16,
0x39, 0xab, 0x38, 0x2b, 0x86, 0xd6, 0x43, 0xa8, 0x45, 0xf6, 0xca, 0x82, 0x5b, 0xe7, 0xd9, 0xf3,
0xd6, 0xae, 0x88, 0x84, 0x8f, 0x78, 0xf0, 0xb3, 0x31, 0x12, 0x62, 0x40, 0xdd, 0xed, 0x1c, 0x1c,
0x60, 0xdc, 0xfc, 0x2c, 0x10, 0x91, 0xa1, 0x53, 0x8b, 0x98, 0x4b, 0x5a, 0xc4, 0x34, 0x54, 0xc4,
0xcc, 0x85, 0x11, 0x33, 0xbf, 0x59, 0x87, 0xaa, 0x30, 0xc8, 0xd1, 0x7c, 0x82, 0x8a, 0x59, 0xbf,
0x41, 0xb7, 0xec, 0xbe, 0x99, 0xa8, 0x50, 0xf1, 0x00, 0x4a, 0x7d, 0x01, 0x8e, 0x07, 0xc4, 0xa2,
0xe1, 0xa5, 0x44, 0x1b, 0xdb, 0x8a, 0x8b, 0x3c, 0x84, 0x92, 0x37, 0xef, 0xf7, 0xa9, 0xa7, 0xc2,
0xe7, 0xff, 0xc5, 0xc3, 0x82, 0xbc, 0xe1, 0xb6, 0xe2, 0x63, 0x22, 0x2f, 0x9d, 0xe1, 0x68, 0xce,
0x83, 0xe9, 0xf9, 0x22, 0x92, 0xcf, 0xfa, 0x95, 0x01, 0x15, 0xae, 0x65, 0xa6, 0x58, 0xf4, 0x21,
0x94, 0xb9, 0x0e, 0x74, 0x20, 0xa3, 0xd1, 0x8a, 0x1d, 0x12, 0xc8, 0x8f, 0x30, 0x26, 0x4a, 0x39,
0x4f, 0x2a, 0xd6, 0x48, 0x86, 0x45, 0xcd, 0x42, 0x56, 0x6b, 0x07, 0x2e, 0x72, 0xab, 0xf4, 0x7d,
0xb4, 0xa7, 0xb2, 0xa3, 0xfe, 0xb2, 0x1b, 0xb1, 0x97, 0x1d, 0xe7, 0x66, 0x27, 0x67, 0xde, 0xb0,
0xef, 0x8c, 0xa4, 0x16, 0xc1, 0x18, 0x5f, 0x14, 0xa2, 0x83, 0x65, 0x7a, 0x0c, 0x6a, 0x50, 0x79,
0xec, 0x78, 0x27, 0x52, 0x25, 0xeb, 0x2b, 0xa8, 0x8a, 0x61, 0x26, 0x1b, 0xe2, 0x33, 0x78, 0x82,
0x28, 0x5c, 0xf1, 0x9a, 0xcd, 0xbf, 0xad, 0x8b, 0x70, 0xe1, 0x60, 0xe2, 0xcc, 0xbc, 0x93, 0xa9,
0x0a, 0xae, 0x2c, 0x6f, 0x5b, 0x0d, 0x69, 0x99, 0x56, 0xbc, 0x0b, 0x17, 0x5c, 0x3a, 0x76, 0x86,
0x93, 0xe1, 0xe4, 0xf8, 0xa8, 0x77, 0xe6, 0x53, 0x4f, 0xa6, 0x75, 0xf5, 0x80, 0xbc, 0xc9, 0xa8,
0x4c, 0xb5, 0xde, 0x68, 0xda, 0x93, 0x57, 0x9c, 0x7f, 0x5b, 0xbf, 0x33, 0xa0, 0xfa, 0xc2, 0xf1,
0xfb, 0xca, 0x0a, 0x64, 0x1b, 0xea, 0xc1, 0xc5, 0xe6, 0x14, 0xa9, 0x4b, 0x2c, 0xc2, 0x73, 0x99,
0x2d, 0x79, 0xd1, 0x55, 0x84, 0xaf, 0xf5, 0x75, 0x02, 0x87, 0x72, 0x26, 0x7d, 0x3a, 0x0a, 0xa0,
0x72, 0xe9, 0x50, 0x9c, 0x51, 0x87, 0xd2, 0x09, 0x9b, 0x17, 0xc2, 0xd7, 0x4f, 0x5c, 0xcb, 0x6f,
0x0d, 0x20, 0x8b, 0x3a, 0x7c, 0xd7, 0xac, 0xf3, 0x36, 0xd4, 0x3d, 0xbc, 0xed, 0xfe, 0x51, 0x2c,
0xe9, 0xad, 0x71, 0x6a, 0x10, 0x9c, 0xd0, 0xc2, 0x98, 0x6d, 0x1f, 0xa3, 0x4b, 0x7b, 0x47, 0x93,
0xa9, 0x3f, 0x7c, 0x79, 0xc6, 0x03, 0xe2, 0x8a, 0x5d, 0x57, 0xe4, 0x3d, 0x4e, 0xb5, 0x1e, 0x28,
0xa5, 0x74, 0xe5, 0xc9, 0x15, 0x58, 0x79, 0xcd, 0xa8, 0x2a, 0x1d, 0xc7, 0x37, 0x9e, 0x8f, 0xb7,
0x07, 0xd6, 0xdf, 0x0c, 0xa8, 0x49, 0xf3, 0x67, 0xf2, 0x01, 0x7d, 0x89, 0x5c, 0x64, 0x09, 0x96,
0x60, 0x88, 0x63, 0x19, 0xc8, 0xd4, 0x4c, 0x0d, 0xd9, 0x3d, 0x13, 0x56, 0xc6, 0x29, 0xb1, 0x9f,
0x60, 0x8c, 0xf1, 0x7d, 0xb5, 0x2f, 0xee, 0x59, 0x2c, 0xc0, 0xdb, 0x17, 0x24, 0x3d, 0xb0, 0xce,
0x6d, 0x28, 0xd2, 0x53, 0x3a, 0xf1, 0xbd, 0x46, 0x85, 0x07, 0x85, 0x9a, 0xca, 0x0f, 0x3b, 0x8c,
0x6a, 0xcb, 0x49, 0xeb, 0x87, 0x70, 0x71, 0x97, 0x25, 0x72, 0x8f, 0xd0, 0xfa, 0x7a, 0x4a, 0xd8,
0xed, 0xee, 0x4a, 0xab, 0xe4, 0xfd, 0xee, 0x2e, 0xa9, 0x43, 0x6e, 0xbb, 0x2d, 0xf7, 0x90, 0x1b,
0xb6, 0xad, 0x9f, 0xe3, 0x41, 0xeb, 0x72, 0x99, 0xcc, 0x14, 0x03, 0x57, 0xcb, 0xe7, 0xc3, 0xe5,
0x31, 0xf7, 0xa4, 0xae, 0x3b, 0x75, 0xb9, 0x41, 0xca, 0xb6, 0x18, 0x58, 0xb7, 0xa4, 0x0e, 0xb8,
0xe7, 0xe9, 0xab, 0xc0, 0xd9, 0x04, 0x9a, 0x11, 0xa8, 0xba, 0x03, 0x6b, 0x11, 0xae, 0x4c, 0xc1,
0xe9, 0x2e, 0x5c, 0xe2, 0x60, 0x3b, 0x94, 0xce, 0x5a, 0xa3, 0xe1, 0x69, 0xea, 0xaa, 0x33, 0xb8,
0x1c, 0x67, 0xfc, 0xdf, 0xda, 0xc8, 0x3a, 0x81, 0xe2, 0x13, 0x5e, 0x30, 0x6a, 0xba, 0x14, 0x38,
0x2f, 0x46, 0x98, 0x89, 0x33, 0x16, 0xe9, 0x7c, 0xd9, 0xe6, 0xdf, 0x3c, 0x9a, 0x53, 0xea, 0x3e,
0xb7, 0x77, 0xc5, 0xab, 0x51, 0xb6, 0x83, 0x31, 0xb9, 0xc6, 0x4a, 0xd5, 0x21, 0xba, 0x07, 0x9f,
0x2d, 0xf0, 0x59, 0x8d, 0x82, 0x25, 0xd3, 0xaa, 0x58, 0xa9, 0x35, 0x18, 0x68, 0x2f, 0x47, 0x80,
0x67, 0x44, 0xf1, 0xac, 0xd7, 0x70, 0x51, 0xe3, 0xcf, 0x64, 0x86, 0xfb, 0x50, 0x14, 0x55, 0xb1,
0x0c, 0x5a, 0xeb, 0x51, 0x29, 0xb1, 0x8c, 0x2d, 0x79, 0xac, 0xdb, 0xb0, 0x26, 0x29, 0x74, 0x3c,
0x4d, 0x3a, 0x2b, 0x6e, 0x1f, 0x6b, 0x17, 0xd6, 0xa3, 0x6c, 0x99, 0x5c, 0xa4, 0xa5, 0x16, 0x7d,
0x3e, 0x1b, 0x68, 0x31, 0x30, 0x7e, 0x28, 0xba, 0xc1, 0x72, 0x31, 0x83, 0x05, 0x0a, 0x29, 0x88,
0x4c, 0x0a, 0xad, 0x29, 0xf3, 0xef, 0x0e, 0xbd, 0xe0, 0xa5, 0x7b, 0x0b, 0x44, 0x27, 0x66, 0x3a,
0x94, 0x26, 0x94, 0x84, 0xc1, 0x55, 0x32, 0x95, 0x7c, 0x2a, 0x8a, 0x89, 0x29, 0xd4, 0xa6, 0x2f,
0x5d, 0xe7, 0x78, 0x4c, 0x83, 0x98, 0xc3, 0x52, 0x08, 0x9d, 0x98, 0x69, 0xc7, 0x7f, 0xc4, 0xe7,
0xb3, 0x35, 0x72, 0xdc, 0xb1, 0x32, 0xfe, 0xe7, 0x50, 0x14, 0xb9, 0x89, 0xcc, 0xdf, 0xef, 0x44,
0x61, 0x74, 0x5e, 0x31, 0x68, 0x89, 0x4c, 0x46, 0x4a, 0xb1, 0xc3, 0x92, 0xcd, 0x98, 0x76, 0xac,
0x39, 0xd3, 0x26, 0x9f, 0xc0, 0xb2, 0xc3, 0x44, 0xf8, 0x5d, 0xac, 0xc7, 0xb3, 0x42, 0x8e, 0xd6,
0x3d, 0x9b, 0x51, 0x5b, 0x70, 0x59, 0x9f, 0x42, 0x45, 0x5b, 0x81, 0x25, 0xbb, 0x8f, 0x3a, 0x5d,
0xcc, 0x80, 0xab, 0xb0, 0xd2, 0xda, 0xea, 0x6e, 0x1f, 0x8a, 0x1c, 0xb8, 0x0e, 0xd0, 0xee, 0x04,
0xe3, 0x1c, 0x66, 0x41, 0x42, 0x4a, 0xde, 0x70, 0x5d, 0x1f, 0x23, 0x4d, 0x9f, 0xdc, 0x7b, 0xe9,
0xf3, 0x06, 0x6a, 0x72, 0xfb, 0x99, 0x7c, 0xe0, 0x21, 0x5a, 0x98, 0xc1, 0x28, 0x17, 0xb8, 0x92,
0xb0, 0xac, 0xba, 0x9d, 0x82, 0xd1, 0xc2, 0xec, 0xe1, 0xc0, 0x77, 0xfc, 0xb9, 0xa7, 0x5c, 0xe0,
0x0f, 0x06, 0xd4, 0x15, 0x25, 0x6b, 0xf5, 0xae, 0x4a, 0x24, 0x11, 0xf3, 0x82, 0x02, 0xe9, 0x32,
0x14, 0x07, 0xbd, 0x83, 0xe1, 0x5b, 0xd5, 0xc5, 0x90, 0x23, 0x46, 0x1f, 0x89, 0x75, 0x44, 0x0b,
0x4d, 0x8e, 0x58, 0xee, 0xcd, 0x9a, 0x69, 0xdb, 0x93, 0x01, 0x7d, 0xc3, 0x5f, 0xda, 0x82, 0x1d,
0x12, 0x78, 0xba, 0x2c, 0x5b, 0x6d, 0xbc, 0x7e, 0xd2, 0x5b, 0x6f, 0xe8, 0xe4, 0xad, 0xb9, 0x7f,
0xd2, 0x99, 0xb0, 0x2e, 0x93, 0xda, 0xe1, 0x3a, 0x10, 0x46, 0x6c, 0x0f, 0x3d, 0x9d, 0xda, 0x81,
0x35, 0x46, 0x45, 0xbf, 0xc7, 0x64, 0x3a, 0x8c, 0x18, 0x2a, 0x6c, 0x1b, 0xb1, 0xb0, 0xed, 0x78,
0xde, 0xeb, 0xa9, 0x3b, 0x90, 0x5b, 0x0b, 0xc6, 0x56, 0x5b, 0x80, 0x3f, 0xf7, 0x22, 0x81, 0xf9,
0xbb, 0xa2, 0xdc, 0x0b, 0x51, 0x1e, 0x51, 0xff, 0x1c, 0x14, 0xeb, 0x63, 0xb8, 0xa4, 0x38, 0x65,
0x0d, 0x7d, 0x0e, 0xf3, 0x3e, 0x5c, 0x55, 0xcc, 0x5b, 0x27, 0x2c, 0xd1, 0x7b, 0x2a, 0x17, 0xfc,
0x4f, 0xf5, 0xdc, 0x84, 0x46, 0xa0, 0x27, 0xcf, 0x41, 0xa6, 0x23, 0x5d, 0x81, 0xb9, 0x27, 0x7d,
0x06, 0xb1, 0xd8, 0x37, 0xa3, 0xb9, 0xc8, 0xa2, 0x1e, 0x41, 0xf6, 0x6d, 0x6d, 0xc1, 0x15, 0x85,
0x21, 0xb3, 0x83, 0x28, 0xc8, 0x82, 0x42, 0x49, 0x20, 0xd2, 0x60, 0x4c, 0xf4, 0x7c, 0xb3, 0xeb,
0x9c, 0x51, 0xd3, 0x72, 0x4c, 0x43, 0xc3, 0x94, 0xa6, 0x65, 0x9c, 0x0b, 0xa6, 0x5d, 0x60, 0xfe,
0x29, 0x5c, 0x0b, 0x60, 0x99, 0x25, 0x9e, 0xa2, 0xfb, 0x0d, 0x3d, 0x4f, 0x2b, 0xeb, 0x92, 0xb6,
0x72, 0x07, 0x0a, 0x33, 0x2a, 0xa3, 0x44, 0x65, 0x83, 0x34, 0x45, 0x13, 0xbb, 0xa9, 0x09, 0xf3,
0x79, 0x6b, 0x00, 0xd7, 0x15, 0xba, 0xb0, 0x51, 0x22, 0x7c, 0x5c, 0x29, 0x95, 0xf2, 0x0b, 0x43,
0x2d, 0xa6, 0xfc, 0x79, 0x71, 0x9a, 0x41, 0xf3, 0xee, 0x4b, 0x61, 0x1a, 0x75, 0x5b, 0x32, 0x45,
0xff, 0x1d, 0x71, 0x9d, 0x82, 0x4b, 0x96, 0x09, 0xac, 0x07, 0xeb, 0xd1, 0xbb, 0x99, 0x29, 0x30,
0x61, 0x1e, 0xeb, 0xa3, 0x09, 0x55, 0x58, 0x12, 0x03, 0xa5, 0x70, 0x70, 0x71, 0x33, 0x29, 0xec,
0x84, 0x60, 0xdc, 0xc9, 0xb2, 0xea, 0xcb, 0x4e, 0x53, 0x65, 0x28, 0x62, 0x60, 0xed, 0xc1, 0xe5,
0xf8, 0xc5, 0xcf, 0xa4, 0xf2, 0xa1, 0x70, 0xe0, 0xa4, 0xd8, 0x90, 0x09, 0xf7, 0x59, 0x78, 0xbd,
0xb5, 0x10, 0x91, 0x09, 0xd2, 0x06, 0x33, 0x29, 0x62, 0xfc, 0x37, 0xfc, 0x35, 0x08, 0x20, 0x99,
0xc0, 0xbc, 0x10, 0x2c, 0xfb, 0xf1, 0x87, 0x31, 0x22, 0x7f, 0x6e, 0x8c, 0x90, 0x0e, 0xa1, 0x87,
0xab, 0x4c, 0x9b, 0x78, 0x11, 0xc6, 0x9c, 0x85, 0x88, 0x96, 0x09, 0xf8, 0x2b, 0xb8, 0x91, 0x1e,
0xcc, 0xb2, 0x20, 0x7f, 0xcf, 0x82, 0x72, 0x90, 0x5a, 0x69, 0x3f, 0x23, 0x55, 0xa0, 0xb4, 0xb7,
0x7f, 0xf0, 0xb4, 0xb5, 0x85, 0x49, 0xdd, 0xc6, 0xdf, 0x73, 0x90, 0xdb, 0x39, 0x24, 0x9b, 0xb0,
0x2c, 0xda, 0xe0, 0xe7, 0xfc, 0x4a, 0x60, 0x9e, 0xd7, 0x50, 0xb7, 0x96, 0xc8, 0x67, 0x90, 0x67,
0x8d, 0xf0, 0xd4, 0x9f, 0x09, 0xcc, 0xf4, 0x66, 0x3a, 0x4a, 0x77, 0xa1, 0xa2, 0x75, 0xbd, 0xc9,
0x3b, 0x7f, 0x26, 0x30, 0xdf, 0xdd, 0x51, 0x17, 0x3a, 0x75, 0xdf, 0x4c, 0xe2, 0x3a, 0x85, 0x5d,
0xda, 0xb8, 0x4e, 0x5a, 0x67, 0x14, 0xa5, 0xf7, 0x64, 0xb7, 0xbd, 0xef, 0x93, 0xeb, 0x09, 0xcd,
0x5b, 0xbd, 0x4d, 0x69, 0xde, 0x48, 0x67, 0x50, 0x78, 0x1b, 0xfb, 0xb0, 0xcc, 0x5b, 0x38, 0xe4,
0x0b, 0xf5, 0x61, 0x26, 0x34, 0xb8, 0x52, 0xcc, 0x1d, 0x69, 0xfe, 0x58, 0x4b, 0xf7, 0x8c, 0xef,
0x1b, 0x1b, 0xdf, 0xe6, 0x60, 0x99, 0x97, 0xf4, 0xe4, 0x19, 0x40, 0xd8, 0xfb, 0x88, 0x6b, 0xbb,
0xd0, 0x4d, 0x89, 0x6b, 0xbb, 0xd8, 0x36, 0x11, 0x27, 0xa2, 0x35, 0x29, 0x48, 0x92, 0x48, 0xa4,
0xcb, 0x11, 0x3f, 0x91, 0x84, 0x0e, 0x07, 0xa2, 0x3a, 0x50, 0x8f, 0x36, 0x21, 0xc8, 0xcd, 0x04,
0xb1, 0x78, 0x2f, 0xc3, 0xbc, 0x75, 0x3e, 0x53, 0xc4, 0x2a, 0x7f, 0xce, 0xe1, 0xb9, 0x89, 0x5f,
0xb1, 0xf1, 0x08, 0xcb, 0x41, 0x9d, 0x4f, 0xae, 0x25, 0xd5, 0x80, 0x61, 0x82, 0x64, 0x5e, 0x4f,
0x9d, 0x0f, 0xd4, 0x7f, 0x01, 0x55, 0xbd, 0x2e, 0x27, 0x1f, 0x25, 0x96, 0x95, 0x7a, 0x69, 0x6f,
0x5a, 0xe7, 0xb1, 0x2c, 0x02, 0x8b, 0xfa, 0x3a, 0x19, 0x38, 0x52, 0xbe, 0x27, 0x03, 0x47, 0xcb,
0x73, 0x04, 0x46, 0xcf, 0x08, 0xab, 0x6a, 0x92, 0xb8, 0x45, 0xad, 0x08, 0x8f, 0x7b, 0xc6, 0x62,
0x41, 0x8e, 0x7e, 0xfc, 0xaf, 0x1c, 0x54, 0x9e, 0x38, 0xc3, 0x89, 0x4f, 0x27, 0xac, 0x0b, 0xc8,
0xa2, 0x07, 0x0f, 0x34, 0x71, 0x77, 0xd6, 0x6b, 0xd8, 0xb8, 0x3b, 0x47, 0x0a, 0x3c, 0x54, 0xb3,
0x03, 0x45, 0x51, 0x67, 0x91, 0x18, 0x63, 0xa4, 0x1e, 0x33, 0x3f, 0x4c, 0x9e, 0xd4, 0x77, 0x1b,
0x96, 0xec, 0xf1, 0xdd, 0x2e, 0x54, 0xf8, 0xe6, 0x8d, 0x74, 0x86, 0x00, 0xf2, 0x27, 0x50, 0x60,
0xdd, 0x7e, 0x12, 0x0b, 0x15, 0xda, 0x0f, 0x02, 0xa6, 0x99, 0x34, 0x15, 0x00, 0x3c, 0x81, 0x15,
0xd5, 0xc0, 0x27, 0x57, 0x63, 0xfa, 0x47, 0x9b, 0xfd, 0xe6, 0xb5, 0xb4, 0x69, 0x05, 0x86, 0xee,
0xfd, 0x5b, 0x80, 0x02, 0x7b, 0x31, 0xd8, 0x5e, 0xc3, 0x04, 0x35, 0xbe, 0xd7, 0x85, 0x42, 0x2f,
0xbe, 0xd7, 0xc5, 0xdc, 0x56, 0xdc, 0x79, 0x2d, 0x4f, 0x25, 0x09, 0x22, 0xd1, 0x3a, 0x31, 0x7e,
0xe7, 0x13, 0x92, 0x5c, 0xe1, 0xdb, 0x7a, 0xc2, 0x4a, 0x12, 0x84, 0x62, 0x85, 0x66, 0xdc, 0xb7,
0x93, 0xf2, 0x5d, 0x04, 0x7e, 0x0a, 0x25, 0x99, 0xa1, 0x26, 0xa9, 0x1a, 0xad, 0x3a, 0x93, 0x54,
0x8d, 0xa5, 0xb7, 0x21, 0x22, 0xe6, 0x29, 0x69, 0x88, 0x61, 0x99, 0x94, 0x86, 0xa8, 0x25, 0x39,
0x88, 0xf8, 0x35, 0x40, 0x98, 0x95, 0xc6, 0x83, 0x5d, 0x62, 0xb1, 0x1a, 0x0f, 0x76, 0xc9, 0x89,
0x2d, 0x42, 0x7f, 0x03, 0x64, 0x31, 0x41, 0x25, 0x1f, 0x27, 0x4b, 0x27, 0x96, 0xb8, 0xe6, 0xfd,
0xf7, 0x63, 0x0e, 0x96, 0xec, 0x41, 0x2d, 0x92, 0xbb, 0x92, 0x3b, 0x29, 0x36, 0x88, 0xd5, 0xbf,
0xe6, 0xdd, 0x77, 0xf2, 0x05, 0x6b, 0x50, 0xa8, 0x47, 0x93, 0x59, 0x92, 0x22, 0xbc, 0x50, 0x20,
0x9b, 0xf7, 0xde, 0xcd, 0xa8, 0x1f, 0xb5, 0xcc, 0x6f, 0x93, 0x8e, 0x3a, 0x5a, 0x3b, 0x27, 0x1d,
0x75, 0x2c, 0x39, 0x0e, 0x11, 0x53, 0x9c, 0x27, 0x5a, 0x63, 0xa7, 0x21, 0x2e, 0x38, 0x4f, 0x98,
0xc1, 0x26, 0x39, 0xcf, 0x42, 0x39, 0x9e, 0xe4, 0x3c, 0x8b, 0x49, 0x30, 0x42, 0xfb, 0xb0, 0x96,
0x90, 0xcc, 0x92, 0xfb, 0x29, 0x6a, 0x25, 0x56, 0xf1, 0xe6, 0x27, 0xef, 0xc9, 0x1d, 0xac, 0xfa,
0x1a, 0xd6, 0x93, 0x32, 0x5d, 0x92, 0x02, 0x94, 0x52, 0xde, 0x9b, 0xcd, 0xf7, 0x65, 0x57, 0x0b,
0x6f, 0x56, 0x7f, 0xff, 0xd7, 0x6b, 0xc6, 0x9f, 0xf0, 0xcf, 0x5f, 0xf0, 0x4f, 0xaf, 0xc8, 0xff,
0x4f, 0xdc, 0x0f, 0xfe, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xf4, 0x4d, 0x3d, 0xa0, 0x7c, 0x27, 0x00,
0x00,
}

View File

@ -622,6 +622,7 @@ message AuthRoleGrantPermissionRequest {
message AuthRoleRevokePermissionRequest {
string role = 1;
string key = 2;
string range_end = 3;
}
message AuthEnableResponse {