satellite/metainfo: add UserAgent support to endpoints (#3548)

This commit is contained in:
Egon Elbre 2019-11-26 13:12:37 +02:00 committed by Michal Niewrzal
parent 59385aff66
commit 36fead0093
17 changed files with 661 additions and 378 deletions

View File

@ -9,6 +9,7 @@ import (
"testing"
"time"
"github.com/skyrings/skyring-common/tools/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
@ -56,14 +57,14 @@ func testPlanetWithLibUplink(t *testing.T, cfg testConfig,
}
// check that partner bucket attributes are stored and retrieved correctly.
func TestPartnerBucketAttrs(t *testing.T) {
func TestBucket_PartnerAttribution(t *testing.T) {
var (
access = uplink.NewEncryptionAccessWithDefaultKey(storj.Key{0, 1, 2, 3, 4})
bucketName = "mightynein"
)
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 5, UplinkCount: 1,
SatelliteCount: 1, StorageNodeCount: 0, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
satellite := planet.Satellites[0]
apikey, err := uplink.ParseAPIKey(planet.Uplinks[0].APIKey[satellite.ID()].Serialize())
@ -141,6 +142,94 @@ func TestPartnerBucketAttrs(t *testing.T) {
})
}
// check that partner bucket attributes are stored and retrieved correctly.
func TestBucket_UserAgent(t *testing.T) {
var (
access = uplink.NewEncryptionAccessWithDefaultKey(storj.Key{0, 1, 2, 3, 4})
bucketName = "mightynein"
)
testplanet.Run(t, testplanet.Config{
SatelliteCount: 1, StorageNodeCount: 5, UplinkCount: 1,
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
satellite := planet.Satellites[0]
apikey, err := uplink.ParseAPIKey(planet.Uplinks[0].APIKey[satellite.ID()].Serialize())
require.NoError(t, err)
t.Run("without user agent", func(t *testing.T) {
config := uplink.Config{}
config.Volatile.Log = zaptest.NewLogger(t)
config.Volatile.TLS.SkipPeerCAWhitelist = true
up, err := uplink.NewUplink(ctx, &config)
require.NoError(t, err)
defer ctx.Check(up.Close)
project, err := up.OpenProject(ctx, satellite.Addr(), apikey)
require.NoError(t, err)
defer ctx.Check(project.Close)
bucketInfo, err := project.CreateBucket(ctx, bucketName, nil)
require.NoError(t, err)
assert.True(t, bucketInfo.PartnerID.IsZero())
_, err = project.CreateBucket(ctx, bucketName, nil)
require.Error(t, err)
})
t.Run("open with user agent", func(t *testing.T) {
config := uplink.Config{}
config.Volatile.Log = zaptest.NewLogger(t)
config.Volatile.TLS.SkipPeerCAWhitelist = true
config.Volatile.UserAgent = "Zenko"
up, err := uplink.NewUplink(ctx, &config)
require.NoError(t, err)
defer ctx.Check(up.Close)
project, err := up.OpenProject(ctx, satellite.Addr(), apikey)
require.NoError(t, err)
defer ctx.Check(project.Close)
bucket, err := project.OpenBucket(ctx, bucketName, access)
require.NoError(t, err)
defer ctx.Check(bucket.Close)
bucketInfo, _, err := project.GetBucketInfo(ctx, bucketName)
require.NoError(t, err)
partnerID, err := uuid.Parse("8cd605fa-ad00-45b6-823e-550eddc611d6")
require.NoError(t, err)
assert.Equal(t, *partnerID, bucketInfo.PartnerID)
})
t.Run("open with different user agent", func(t *testing.T) {
config := uplink.Config{}
config.Volatile.Log = zaptest.NewLogger(t)
config.Volatile.TLS.SkipPeerCAWhitelist = true
config.Volatile.UserAgent = "Temporal"
up, err := uplink.NewUplink(ctx, &config)
require.NoError(t, err)
defer ctx.Check(up.Close)
project, err := up.OpenProject(ctx, satellite.Addr(), apikey)
require.NoError(t, err)
defer ctx.Check(project.Close)
bucket, err := project.OpenBucket(ctx, bucketName, access)
require.NoError(t, err)
defer ctx.Check(bucket.Close)
bucketInfo, _, err := project.GetBucketInfo(ctx, bucketName)
require.NoError(t, err)
partnerID, err := uuid.Parse("8cd605fa-ad00-45b6-823e-550eddc611d6")
require.NoError(t, err)
assert.Equal(t, *partnerID, bucketInfo.PartnerID)
})
})
}
// check that bucket attributes are stored and retrieved correctly.
func TestBucketAttrs(t *testing.T) {
var (

View File

@ -100,7 +100,17 @@ func (p *Project) CreateBucket(ctx context.Context, name string, cfg *BucketConf
cfg = cfg.clone()
cfg.setDefaults()
var partnerID uuid.UUID
if p.uplinkCfg.Volatile.PartnerID != "" {
id, err := uuid.Parse(p.uplinkCfg.Volatile.PartnerID)
if err != nil {
return storj.Bucket{}, Error.Wrap(err)
}
partnerID = *id
}
bucket = storj.Bucket{
PartnerID: partnerID,
PathCipher: cfg.PathCipher,
DefaultEncryptionParameters: cfg.EncryptionParameters,
DefaultRedundancyScheme: cfg.Volatile.RedundancyScheme,
@ -157,21 +167,8 @@ func (p *Project) OpenBucket(ctx context.Context, bucketName string, access *Enc
}
// partnerID set and bucket's attribution is not set
if p.uplinkCfg.Volatile.PartnerID != "" && bucketInfo.PartnerID.IsZero() {
// make an entry into the attribution table
err = p.checkBucketAttribution(ctx, bucketName)
if err != nil {
return nil, err
}
partnerID, err := uuid.Parse(p.uplinkCfg.Volatile.PartnerID)
if err != nil {
return nil, Error.Wrap(err)
}
// update the bucket metainfo table with corresponding partner info
bucketInfo.PartnerID = *partnerID
bucketInfo, err = p.updateBucket(ctx, bucketInfo)
if bucketInfo.PartnerID.IsZero() {
err = p.trySetBucketAttribution(ctx, bucketName)
if err != nil {
return nil, err
}
@ -237,36 +234,26 @@ func (p *Project) SaltedKeyFromPassphrase(ctx context.Context, passphrase string
return key, nil
}
// checkBucketAttribution Checks the bucket attribution
func (p *Project) checkBucketAttribution(ctx context.Context, bucketName string) (err error) {
// trySetBucketAttribution sets the bucket attribution if PartnerID or UserAgent is available.
func (p *Project) trySetBucketAttribution(ctx context.Context, bucketName string) (err error) {
defer mon.Task()(&ctx)(&err)
if p.uplinkCfg.Volatile.PartnerID == "" {
if p.uplinkCfg.Volatile.PartnerID == "" && p.uplinkCfg.Volatile.UserAgent == "" {
return nil
}
partnerID, err := uuid.Parse(p.uplinkCfg.Volatile.PartnerID)
if err != nil {
return Error.Wrap(err)
var partnerID uuid.UUID
if p.uplinkCfg.Volatile.PartnerID != "" {
id, err := uuid.Parse(p.uplinkCfg.Volatile.PartnerID)
if err != nil {
return Error.Wrap(err)
}
partnerID = *id
}
// UserAgent is sent via RequestHeader
return p.metainfo.SetBucketAttribution(ctx, metainfo.SetBucketAttributionParams{
Bucket: bucketName,
PartnerID: *partnerID,
PartnerID: partnerID,
})
}
// updateBucket updates an existing bucket's attribution info.
func (p *Project) updateBucket(ctx context.Context, bucketInfo storj.Bucket) (bucket storj.Bucket, err error) {
defer mon.Task()(&ctx)(&err)
bucket = storj.Bucket{
Name: bucketInfo.Name,
PartnerID: bucketInfo.PartnerID,
PathCipher: bucketInfo.PathCipher,
DefaultEncryptionParameters: bucketInfo.DefaultEncryptionParameters,
DefaultRedundancyScheme: bucketInfo.DefaultRedundancyScheme,
DefaultSegmentsSize: bucketInfo.DefaultSegmentsSize,
}
return p.project.CreateBucket(ctx, bucketInfo.Name, &bucket)
}

View File

@ -64,9 +64,14 @@ type Config struct {
MaxMemory memory.Size
// PartnerID is the identity given to the partner for value
// attribution
// attribution.
//
// Deprecated: prefer UserAgent
PartnerID string
// UserAgent for the product using the library.
UserAgent string
// DialTimeout is the maximum time to wait connecting to another node.
// If not set, the library default (20 seconds) will be used.
DialTimeout time.Duration
@ -179,7 +184,7 @@ func NewUplink(ctx context.Context, cfg *Config) (_ *Uplink, err error) {
func (u *Uplink) OpenProject(ctx context.Context, satelliteAddr string, apiKey APIKey) (p *Project, err error) {
defer mon.Task()(&ctx)(&err)
m, err := metainfo.Dial(ctx, u.dialer, satelliteAddr, apiKey.key)
m, err := metainfo.Dial(ctx, u.dialer, satelliteAddr, apiKey.key, u.cfg.Volatile.UserAgent)
if err != nil {
return nil, err
}

View File

@ -63,6 +63,7 @@ func (Object_Status) EnumDescriptor() ([]byte, []int) {
type RequestHeader struct {
ApiKey []byte `protobuf:"bytes,1,opt,name=api_key,json=apiKey,proto3" json:"api_key,omitempty"`
UserAgent []byte `protobuf:"bytes,2,opt,name=user_agent,json=userAgent,proto3" json:"user_agent,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -99,6 +100,13 @@ func (m *RequestHeader) GetApiKey() []byte {
return nil
}
func (m *RequestHeader) GetUserAgent() []byte {
if m != nil {
return m.UserAgent
}
return nil
}
type Bucket struct {
Name []byte `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
PathCipher CipherSuite `protobuf:"varint,2,opt,name=path_cipher,json=pathCipher,proto3,enum=encryption.CipherSuite" json:"path_cipher,omitempty"`
@ -5134,239 +5142,241 @@ func init() {
func init() { proto.RegisterFile("metainfo.proto", fileDescriptor_631e2f30a93cd64e) }
var fileDescriptor_631e2f30a93cd64e = []byte{
// 3712 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0x5d, 0x6c, 0x1c, 0x57,
0xf5, 0xf7, 0xec, 0xf7, 0x9e, 0x5d, 0x7b, 0xd7, 0xd7, 0x8e, 0xbd, 0x19, 0xc7, 0x71, 0x32, 0x49,
0x5a, 0xff, 0xf5, 0x6f, 0x9d, 0xca, 0x05, 0x54, 0x94, 0x94, 0x62, 0x67, 0xdd, 0x78, 0x9b, 0xd8,
0x71, 0xc7, 0x49, 0x13, 0x42, 0x61, 0x35, 0xde, 0xb9, 0xb6, 0x87, 0xec, 0xee, 0x2c, 0x33, 0xb3,
0xad, 0x53, 0x9e, 0x90, 0x2a, 0x21, 0x84, 0x84, 0x2a, 0x9e, 0x11, 0x4f, 0x7d, 0xe3, 0x09, 0xde,
0x90, 0x80, 0x57, 0x40, 0x42, 0x45, 0xaa, 0x10, 0x0f, 0x3c, 0x14, 0x9e, 0x78, 0x83, 0x17, 0xde,
0x40, 0x48, 0xe8, 0x7e, 0xcd, 0xf7, 0xec, 0x87, 0x3f, 0x12, 0xfa, 0x36, 0x73, 0xee, 0xb9, 0x67,
0xee, 0x3d, 0x1f, 0xbf, 0x73, 0xe6, 0xdc, 0x19, 0x98, 0xea, 0x60, 0x47, 0x33, 0xba, 0xfb, 0xe6,
0x4a, 0xcf, 0x32, 0x1d, 0x13, 0x15, 0xc4, 0xbd, 0x5c, 0xc5, 0xdd, 0x96, 0xf5, 0xb4, 0xe7, 0x18,
0x66, 0x97, 0x8d, 0xc9, 0x70, 0x60, 0x1e, 0x70, 0x3e, 0x79, 0xe9, 0xc0, 0x34, 0x0f, 0xda, 0xf8,
0x3a, 0xbd, 0xdb, 0xeb, 0xef, 0x5f, 0x77, 0x8c, 0x0e, 0xb6, 0x1d, 0xad, 0xd3, 0x13, 0xcc, 0x5d,
0x53, 0xc7, 0xfc, 0xba, 0xd2, 0x33, 0x8d, 0xae, 0x83, 0x2d, 0x7d, 0x8f, 0x13, 0xca, 0xa6, 0xa5,
0x63, 0xcb, 0x66, 0x77, 0xca, 0x32, 0x4c, 0xaa, 0xf8, 0xdb, 0x7d, 0x6c, 0x3b, 0x9b, 0x58, 0xd3,
0xb1, 0x85, 0xe6, 0x21, 0xaf, 0xf5, 0x8c, 0xe6, 0x13, 0xfc, 0xb4, 0x26, 0x5d, 0x92, 0x96, 0xcb,
0x6a, 0x4e, 0xeb, 0x19, 0x77, 0xf0, 0x53, 0xe5, 0xa7, 0x69, 0xc8, 0xad, 0xf7, 0x5b, 0x4f, 0xb0,
0x83, 0x10, 0x64, 0xba, 0x5a, 0x07, 0x73, 0x06, 0x7a, 0x8d, 0x5e, 0x83, 0x52, 0x4f, 0x73, 0x0e,
0x9b, 0x2d, 0xa3, 0x77, 0x88, 0xad, 0x5a, 0xea, 0x92, 0xb4, 0x3c, 0xb5, 0x3a, 0xbf, 0xe2, 0xdb,
0xc8, 0x2d, 0x3a, 0xb2, 0xdb, 0x37, 0x1c, 0xac, 0x02, 0xe1, 0x65, 0x04, 0x74, 0x0b, 0xa0, 0x65,
0x61, 0xcd, 0xc1, 0x7a, 0x53, 0x73, 0x6a, 0xe9, 0x4b, 0xd2, 0x72, 0x69, 0x55, 0x5e, 0x61, 0x7b,
0x5c, 0x11, 0x7b, 0x5c, 0xb9, 0x2f, 0xf6, 0xb8, 0x5e, 0xf8, 0xed, 0x67, 0x4b, 0x13, 0x1f, 0xfd,
0x65, 0x49, 0x52, 0x8b, 0x7c, 0xde, 0x9a, 0x83, 0x5e, 0x81, 0x59, 0x1d, 0xef, 0x6b, 0xfd, 0xb6,
0xd3, 0xb4, 0xf1, 0x41, 0x07, 0x77, 0x9d, 0xa6, 0x6d, 0x7c, 0x80, 0x6b, 0x99, 0x4b, 0xd2, 0x72,
0x5a, 0x45, 0x7c, 0x6c, 0x97, 0x0d, 0xed, 0x1a, 0x1f, 0x60, 0xf4, 0x10, 0xce, 0x8b, 0x19, 0x16,
0xd6, 0xfb, 0x5d, 0x5d, 0xeb, 0xb6, 0x9e, 0x36, 0xed, 0xd6, 0x21, 0xee, 0xe0, 0x5a, 0x96, 0xae,
0x62, 0x61, 0xc5, 0x53, 0x9e, 0xea, 0xf2, 0xec, 0x52, 0x16, 0x75, 0x9e, 0xcf, 0x0e, 0x0f, 0x20,
0x1d, 0x16, 0x85, 0x60, 0x6f, 0xf7, 0xcd, 0x9e, 0x66, 0x69, 0x1d, 0xec, 0x60, 0xcb, 0xae, 0xe5,
0xa8, 0xf0, 0x4b, 0x7e, 0xdd, 0x6c, 0xb8, 0x97, 0x3b, 0x2e, 0x9f, 0xba, 0xc0, 0xc5, 0xc4, 0x0d,
0xa2, 0x45, 0x80, 0x9e, 0x66, 0x39, 0x5d, 0x6c, 0x35, 0x0d, 0xbd, 0x96, 0xa7, 0x96, 0x28, 0x72,
0x4a, 0x43, 0x57, 0x0c, 0x98, 0x62, 0xc6, 0xba, 0x6b, 0xd8, 0x4e, 0xc3, 0xc1, 0x9d, 0x58, 0xa3,
0x05, 0x55, 0x9f, 0x3a, 0x96, 0xea, 0x95, 0x8f, 0xd3, 0x30, 0xc3, 0x9e, 0x75, 0x8b, 0xd2, 0xb8,
0x3f, 0xa1, 0xeb, 0x90, 0x3b, 0xa4, 0x3e, 0x55, 0xab, 0x50, 0xc1, 0xf3, 0x2b, 0xae, 0xbf, 0x07,
0x5c, 0x4e, 0xe5, 0x6c, 0xa7, 0xec, 0x56, 0x49, 0x1e, 0x91, 0x3e, 0x9e, 0x47, 0x64, 0xce, 0xd2,
0x23, 0xb2, 0xa7, 0xef, 0x11, 0xb9, 0xb0, 0x47, 0x7c, 0x15, 0x66, 0x83, 0x56, 0xb2, 0x7b, 0x66,
0xd7, 0xc6, 0x68, 0x19, 0x72, 0x7b, 0x94, 0x4e, 0xf5, 0x5e, 0x5a, 0xad, 0x7a, 0x66, 0x62, 0xfc,
0x2a, 0x1f, 0x57, 0x1e, 0x42, 0x95, 0x51, 0x6e, 0x63, 0xe7, 0x34, 0x8d, 0xac, 0xbc, 0x0e, 0xd3,
0x3e, 0xc1, 0x63, 0xaf, 0xeb, 0xb1, 0xf0, 0xbf, 0x3a, 0x6e, 0xe3, 0xd3, 0xf5, 0x3f, 0x65, 0x4e,
0x68, 0x4d, 0xc8, 0x66, 0xab, 0x53, 0x3e, 0x92, 0xc4, 0x9a, 0x49, 0x80, 0x1d, 0xfb, 0x91, 0x73,
0x90, 0x6b, 0xf5, 0x2d, 0xdb, 0xb4, 0x04, 0xd8, 0xb2, 0x3b, 0x34, 0x0b, 0xd9, 0xb6, 0xd1, 0x31,
0x58, 0x4c, 0x66, 0x55, 0x76, 0x83, 0x2e, 0x40, 0x51, 0x37, 0x2c, 0xdc, 0x22, 0x86, 0xa7, 0x7e,
0x9c, 0x55, 0x3d, 0x82, 0xf2, 0x08, 0x90, 0x7f, 0x45, 0x5c, 0x8d, 0x2b, 0x90, 0x35, 0x1c, 0xdc,
0xb1, 0x6b, 0xd2, 0xa5, 0xf4, 0x72, 0x69, 0xb5, 0x16, 0xd6, 0xa2, 0xc0, 0x07, 0x95, 0xb1, 0x11,
0x25, 0x74, 0x4c, 0x0b, 0xd3, 0x07, 0x17, 0x54, 0x7a, 0xad, 0x7c, 0x57, 0x82, 0x05, 0xc6, 0xbd,
0x8b, 0x9d, 0x35, 0xc7, 0xb1, 0x8c, 0xbd, 0x3e, 0x79, 0xe4, 0xa9, 0x46, 0x7a, 0xd0, 0x7d, 0x53,
0x61, 0xf7, 0xbd, 0x08, 0x17, 0xe2, 0x97, 0xc0, 0x0d, 0xf2, 0xa1, 0x04, 0x33, 0x6b, 0xba, 0x6e,
0x61, 0xdb, 0xc6, 0xfa, 0x3d, 0x92, 0xe2, 0xee, 0x52, 0x9d, 0x2d, 0x0b, 0x4d, 0x32, 0x2f, 0x42,
0x2b, 0x3c, 0xfd, 0x79, 0x2c, 0x42, 0xbb, 0xb7, 0x60, 0xd6, 0x76, 0x4c, 0x4b, 0x3b, 0xc0, 0x4d,
0x92, 0x3f, 0x9b, 0x1a, 0x93, 0xc6, 0x61, 0x71, 0x7a, 0x85, 0x26, 0xd5, 0x6d, 0x53, 0xc7, 0xfc,
0x31, 0x2a, 0xe2, 0xec, 0x3e, 0x9a, 0xf2, 0x87, 0x14, 0xcc, 0x71, 0x4c, 0x79, 0x68, 0x19, 0xae,
0x33, 0xde, 0x6b, 0xeb, 0xc7, 0x72, 0x0e, 0x5f, 0x04, 0x94, 0x85, 0xbf, 0x13, 0xed, 0x11, 0x9c,
0xe3, 0x3a, 0xa2, 0xd7, 0xa8, 0x06, 0x79, 0x8e, 0x72, 0x1c, 0xe0, 0xc4, 0x2d, 0xba, 0x01, 0xe0,
0xa1, 0xd9, 0x28, 0x30, 0xe6, 0x63, 0x47, 0x37, 0x40, 0xee, 0x68, 0x47, 0x02, 0xb5, 0xb0, 0x1e,
0x84, 0xd2, 0x2c, 0x7d, 0xd2, 0x7c, 0x47, 0x3b, 0xda, 0x10, 0x0c, 0x7e, 0x3c, 0xad, 0x03, 0xe0,
0xa3, 0x9e, 0x61, 0x69, 0xd4, 0x5f, 0x73, 0x63, 0x64, 0x17, 0xdf, 0x3c, 0xe5, 0x53, 0x09, 0xe6,
0x83, 0x1a, 0x65, 0x16, 0x27, 0x2a, 0xdd, 0x84, 0xaa, 0x26, 0x6c, 0xde, 0xa4, 0x56, 0x14, 0x7e,
0xbe, 0xe8, 0x29, 0x37, 0xc6, 0x2b, 0xd4, 0x8a, 0x3b, 0x8d, 0xde, 0xdb, 0xe8, 0x55, 0x98, 0xb4,
0x4c, 0xd3, 0x69, 0xf6, 0x0c, 0xdc, 0xc2, 0xae, 0x03, 0xae, 0x57, 0xc8, 0x92, 0xfe, 0xfc, 0xd9,
0x52, 0x7e, 0x87, 0xd0, 0x1b, 0x75, 0xb5, 0x44, 0xb8, 0xd8, 0x8d, 0x4e, 0x93, 0x93, 0x65, 0xbc,
0xa7, 0x39, 0x98, 0xd6, 0x4b, 0x69, 0x3a, 0x65, 0x9e, 0x4f, 0xa9, 0x50, 0xae, 0x1d, 0x36, 0x7e,
0x07, 0x3f, 0x55, 0xa1, 0xe7, 0x5e, 0x2b, 0xff, 0xf6, 0x36, 0x75, 0xcb, 0xec, 0x90, 0x15, 0x3d,
0x77, 0x3f, 0x79, 0x09, 0xf2, 0xdc, 0x29, 0xb8, 0x93, 0x20, 0x9f, 0x93, 0xec, 0xb0, 0x2b, 0x55,
0xb0, 0xa0, 0x1b, 0x50, 0x31, 0x2d, 0xe3, 0xc0, 0xe8, 0x6a, 0x6d, 0xa1, 0xf8, 0x2c, 0x55, 0x7c,
0x5c, 0x80, 0x4d, 0x09, 0x56, 0xa6, 0x6c, 0x65, 0x13, 0x6a, 0xa1, 0xcd, 0x7b, 0x26, 0xf5, 0x2d,
0x43, 0x1a, 0xba, 0x0c, 0xe5, 0x47, 0x12, 0x9c, 0xe7, 0xa2, 0xea, 0xe6, 0xfb, 0xdd, 0xb6, 0xa9,
0xe9, 0xcf, 0x5d, 0x93, 0xca, 0x27, 0x12, 0xc8, 0x91, 0x45, 0x9d, 0x85, 0xd3, 0xfa, 0x74, 0x95,
0x1a, 0x6e, 0xb2, 0xe3, 0x7b, 0xeb, 0x0f, 0x25, 0x38, 0xc7, 0x37, 0xd4, 0xe8, 0xee, 0x9b, 0xcf,
0x5f, 0xc3, 0x6f, 0xba, 0x20, 0xcb, 0xd6, 0x13, 0xeb, 0x3e, 0xc3, 0x55, 0x42, 0xb2, 0xb8, 0x08,
0xc3, 0x40, 0xed, 0xf0, 0x1c, 0xb7, 0xf6, 0x13, 0xc9, 0x0d, 0x8e, 0x60, 0xc9, 0x71, 0xba, 0xae,
0x13, 0x72, 0x86, 0xd4, 0xe8, 0xce, 0xf0, 0x51, 0x0a, 0xe6, 0x48, 0xd1, 0xc0, 0x17, 0x69, 0x9f,
0x85, 0xca, 0xe6, 0x20, 0xd7, 0xb3, 0xf0, 0xbe, 0x71, 0xc4, 0x95, 0xc6, 0xef, 0xd0, 0x12, 0x94,
0x6c, 0x47, 0xb3, 0x9c, 0xa6, 0xb6, 0x4f, 0x2c, 0x4c, 0x5d, 0x58, 0x05, 0x4a, 0x5a, 0x23, 0x14,
0x74, 0x19, 0x00, 0x77, 0xf5, 0xe6, 0x1e, 0xde, 0x27, 0x35, 0x4c, 0x86, 0xee, 0x2a, 0x55, 0x93,
0xd4, 0x22, 0xee, 0xea, 0xeb, 0x94, 0x48, 0x8a, 0x28, 0x0b, 0x93, 0x32, 0xcb, 0x78, 0x8f, 0x65,
0xb0, 0x82, 0xea, 0x11, 0xbc, 0xc2, 0x2b, 0xe7, 0x2f, 0xbc, 0x16, 0x01, 0xc8, 0x4e, 0x9a, 0xfb,
0x6d, 0xed, 0xc0, 0xa6, 0x2f, 0x5b, 0x79, 0xb5, 0x48, 0x28, 0x6f, 0x12, 0x02, 0x4d, 0x51, 0x41,
0x95, 0x78, 0x26, 0xbb, 0x19, 0xac, 0xbf, 0x5e, 0xf0, 0x54, 0x92, 0x30, 0x63, 0x65, 0x48, 0x35,
0x26, 0x63, 0xc8, 0x88, 0x17, 0x3a, 0xea, 0x57, 0x92, 0xcf, 0xaf, 0xc6, 0x43, 0x84, 0x05, 0x28,
0x1a, 0x76, 0x93, 0x6b, 0x3a, 0x4d, 0x1f, 0x51, 0x30, 0xec, 0x1d, 0x7a, 0xaf, 0xfc, 0x80, 0x3a,
0x62, 0x4c, 0xb9, 0x77, 0x2c, 0x4b, 0x2f, 0x41, 0x89, 0xd9, 0xb6, 0xe9, 0x2b, 0xfc, 0x80, 0x91,
0xb6, 0x47, 0x28, 0xff, 0x16, 0x08, 0xce, 0xc7, 0x15, 0x7e, 0xf7, 0xda, 0xba, 0xb2, 0x01, 0x68,
0xc7, 0x32, 0xbf, 0x85, 0x5b, 0x7e, 0x78, 0x1a, 0x7b, 0x8d, 0xca, 0x6b, 0x30, 0x13, 0x10, 0xc3,
0x2b, 0xe8, 0xcb, 0x50, 0xee, 0x31, 0x72, 0xd3, 0xd6, 0xda, 0xc2, 0x55, 0x4b, 0x9c, 0xb6, 0xab,
0xb5, 0x1d, 0xe5, 0xfb, 0x79, 0xc8, 0xdd, 0xdb, 0x23, 0xb7, 0x89, 0x2e, 0x7d, 0x0d, 0xa6, 0xbc,
0x2a, 0xca, 0x87, 0x07, 0x93, 0x2e, 0x75, 0x87, 0x03, 0xc3, 0x7b, 0xd8, 0xb2, 0xbd, 0x02, 0x5f,
0xdc, 0x92, 0xed, 0xd8, 0x8e, 0xe6, 0xf4, 0x6d, 0xea, 0xd6, 0x53, 0xfe, 0xed, 0xb0, 0x47, 0xaf,
0xec, 0xd2, 0x61, 0x95, 0xb3, 0xa1, 0x97, 0xa1, 0x68, 0x3b, 0x16, 0xd6, 0x3a, 0x44, 0xa1, 0x59,
0x1a, 0x0a, 0x55, 0x1e, 0xe0, 0x85, 0x5d, 0x3a, 0xd0, 0xa8, 0xab, 0x05, 0xc6, 0xd2, 0xd0, 0x43,
0xbd, 0x80, 0xdc, 0xf1, 0xda, 0x30, 0x6b, 0xe4, 0x99, 0xe4, 0xe9, 0x44, 0x46, 0x7e, 0x0c, 0x19,
0x05, 0x36, 0x6d, 0x8d, 0x94, 0xe1, 0xac, 0xfa, 0xc3, 0x54, 0x46, 0x61, 0x9c, 0x75, 0xf0, 0x79,
0x6b, 0x0e, 0xba, 0x0d, 0x35, 0x4f, 0xdb, 0x44, 0x4f, 0xba, 0xe6, 0x68, 0xcd, 0xae, 0xd9, 0x6d,
0xe1, 0x5a, 0x91, 0xaa, 0x62, 0x92, 0xab, 0x22, 0xbb, 0x4d, 0x88, 0xea, 0x9c, 0xcb, 0xbe, 0xc5,
0xb9, 0x29, 0x1d, 0xbd, 0x0c, 0x28, 0x2a, 0xa8, 0x06, 0xd4, 0x74, 0xd3, 0x91, 0x39, 0xe8, 0x25,
0x40, 0xfb, 0xc6, 0x51, 0xb8, 0x4e, 0x2e, 0x51, 0x88, 0xaf, 0xd2, 0x11, 0x7f, 0x81, 0xbc, 0x09,
0xd3, 0xd1, 0x46, 0x43, 0x79, 0x78, 0x85, 0x5e, 0xb5, 0xc2, 0x1d, 0x86, 0x07, 0x70, 0x2e, 0xbe,
0xb3, 0x30, 0x39, 0x62, 0x67, 0x61, 0x16, 0x27, 0xb4, 0x14, 0x1c, 0xd3, 0xd1, 0xda, 0x6c, 0x1b,
0x53, 0x74, 0x1b, 0x45, 0x4a, 0xa1, 0xeb, 0x5f, 0x82, 0x92, 0xd1, 0x6d, 0x1b, 0x5d, 0xcc, 0xc6,
0x2b, 0x74, 0x1c, 0x18, 0x49, 0x30, 0x58, 0xb8, 0x63, 0x3a, 0x9c, 0xa1, 0xca, 0x18, 0x18, 0x89,
0x30, 0x28, 0x6f, 0x43, 0x8e, 0x79, 0x2d, 0x2a, 0x41, 0xbe, 0xb1, 0xfd, 0xce, 0xda, 0xdd, 0x46,
0xbd, 0x3a, 0x81, 0x26, 0xa1, 0xf8, 0x60, 0xe7, 0xee, 0xbd, 0xb5, 0x7a, 0x63, 0xfb, 0x76, 0x55,
0x42, 0x53, 0x00, 0xb7, 0xee, 0x6d, 0x6d, 0x35, 0xee, 0xdf, 0x27, 0xf7, 0x29, 0x32, 0xcc, 0xef,
0x37, 0xea, 0xd5, 0x34, 0x2a, 0x43, 0xa1, 0xbe, 0x71, 0x77, 0x83, 0x0e, 0x66, 0x94, 0x0f, 0xd3,
0x80, 0x58, 0x40, 0xac, 0xe3, 0x03, 0xa3, 0x7b, 0x92, 0x57, 0xf3, 0xb3, 0x09, 0xe4, 0xa0, 0x83,
0x67, 0x8e, 0xe7, 0xe0, 0xb1, 0xae, 0x93, 0x3f, 0x55, 0xd7, 0x29, 0x9c, 0xc4, 0x75, 0x94, 0x5f,
0xa7, 0x60, 0x26, 0x60, 0x06, 0x8e, 0xa6, 0x67, 0xa6, 0xd6, 0x00, 0xdc, 0x65, 0x86, 0xc2, 0x5d,
0xac, 0x02, 0xb3, 0xa7, 0xaa, 0xc0, 0xdc, 0x89, 0x14, 0xf8, 0x77, 0x49, 0x28, 0x30, 0xf0, 0x86,
0x38, 0xbe, 0x23, 0x07, 0x14, 0x23, 0x0d, 0x55, 0xcc, 0x20, 0xe8, 0x4c, 0x9d, 0x1c, 0x3a, 0xd3,
0x09, 0xd0, 0xa9, 0xcc, 0xc1, 0x6c, 0x70, 0xbb, 0xbc, 0xb1, 0xf3, 0x63, 0x09, 0xaa, 0x6c, 0xe0,
0x24, 0x6d, 0xc7, 0xb3, 0x72, 0x3b, 0xe5, 0x75, 0x98, 0xf6, 0xad, 0xce, 0xeb, 0x5d, 0x9a, 0x94,
0x18, 0xed, 0x5d, 0x32, 0x66, 0x95, 0x8f, 0x2b, 0x3f, 0x4b, 0x89, 0xf9, 0x27, 0xed, 0x23, 0xc6,
0x6e, 0xef, 0xff, 0xa0, 0xea, 0xdb, 0x9e, 0xbf, 0xa4, 0xae, 0x78, 0x1b, 0x64, 0xb5, 0x75, 0x80,
0x95, 0x37, 0x25, 0xd3, 0x21, 0xd6, 0x5b, 0xac, 0x3b, 0x19, 0x28, 0xa1, 0x33, 0x89, 0x25, 0x74,
0xd6, 0x5f, 0x42, 0x37, 0xa0, 0xc2, 0xb6, 0xdc, 0x34, 0xba, 0xad, 0x76, 0x5f, 0xc7, 0x5e, 0x7c,
0x84, 0x74, 0x23, 0x3a, 0x92, 0x0d, 0xce, 0xa7, 0x4e, 0xb1, 0x89, 0xe2, 0x5e, 0x79, 0x24, 0x00,
0x7e, 0xc4, 0x46, 0x67, 0x50, 0xec, 0xa0, 0x46, 0xe7, 0x6f, 0xd2, 0x30, 0x15, 0xe4, 0x8e, 0x71,
0x10, 0x69, 0x88, 0x83, 0xa4, 0x92, 0xea, 0xb6, 0xf4, 0x68, 0x75, 0x5b, 0xb0, 0x10, 0xcb, 0x9c,
0x42, 0x21, 0x96, 0x3d, 0x85, 0x42, 0x2c, 0x77, 0xfa, 0x85, 0x58, 0xfe, 0xe4, 0x68, 0x52, 0x48,
0x42, 0x93, 0x2f, 0xc0, 0x5c, 0xbc, 0x37, 0x21, 0x19, 0x0a, 0xee, 0x74, 0x89, 0xbd, 0xf3, 0x88,
0x7b, 0xe5, 0x63, 0x09, 0x6a, 0xbe, 0xa4, 0x75, 0xc2, 0xf3, 0x84, 0x33, 0xc3, 0x9c, 0xb7, 0xe0,
0x7c, 0xcc, 0x2a, 0x79, 0x1c, 0x8c, 0x07, 0xf7, 0xca, 0x77, 0x84, 0xac, 0x37, 0x8d, 0xae, 0x61,
0x1f, 0x9e, 0x70, 0xcb, 0x63, 0x3e, 0xfc, 0x02, 0xc8, 0x71, 0x0f, 0xe7, 0xc8, 0xff, 0x8f, 0x14,
0x94, 0x76, 0x35, 0x47, 0xcc, 0x3b, 0xbb, 0xd2, 0xe1, 0x44, 0x2d, 0xf2, 0x06, 0x4c, 0xd2, 0xb0,
0x23, 0xc9, 0x5f, 0xd7, 0x1c, 0x3c, 0x56, 0xb4, 0x95, 0xc5, 0xd4, 0xba, 0xe6, 0x60, 0xb4, 0x05,
0x15, 0xaf, 0xf1, 0xcd, 0x84, 0x8d, 0x13, 0x76, 0x53, 0xde, 0x64, 0x2a, 0xee, 0x3a, 0xcc, 0xd8,
0x9a, 0x83, 0xdb, 0x6d, 0x83, 0x16, 0xe0, 0x07, 0x5d, 0xcd, 0xe9, 0x5b, 0xfc, 0xfd, 0x47, 0x45,
0xee, 0xd0, 0xae, 0x18, 0x51, 0xfe, 0x9a, 0x82, 0x3c, 0x7f, 0x3f, 0x19, 0xb7, 0x6a, 0xf8, 0x22,
0x14, 0x7a, 0xa6, 0x6d, 0x38, 0x02, 0x00, 0x4b, 0xab, 0xe7, 0x3d, 0x5f, 0xe1, 0x32, 0x77, 0x38,
0x83, 0xea, 0xb2, 0xa2, 0xd7, 0x61, 0xc6, 0x33, 0xdd, 0x13, 0xfc, 0x94, 0x23, 0x43, 0x3a, 0x0e,
0x19, 0xbc, 0x28, 0xbf, 0x83, 0x9f, 0x32, 0x50, 0xb8, 0x02, 0x93, 0x81, 0xe9, 0xac, 0xee, 0x53,
0xcb, 0x7e, 0x4e, 0xb4, 0x02, 0x33, 0xe4, 0xed, 0xc3, 0x77, 0x88, 0x41, 0x63, 0x9f, 0x1d, 0x5e,
0x4c, 0x93, 0x21, 0xf7, 0xf4, 0xa2, 0x4e, 0xde, 0xe1, 0x56, 0xdd, 0x7a, 0x0e, 0xeb, 0x4d, 0xfe,
0x7e, 0x43, 0x67, 0xb0, 0x23, 0x55, 0x6f, 0xc1, 0x0d, 0x3a, 0x46, 0xe7, 0xbc, 0x08, 0x39, 0x7a,
0x72, 0x60, 0xd7, 0xf2, 0x34, 0xfb, 0x54, 0xbc, 0xcd, 0xd3, 0x5e, 0x9a, 0xca, 0x87, 0x95, 0x4d,
0xc8, 0x52, 0x02, 0x5a, 0x80, 0x22, 0x3b, 0x6b, 0xe8, 0xf6, 0x3b, 0x54, 0xbf, 0x59, 0xb5, 0x40,
0x09, 0xdb, 0xfd, 0x0e, 0x52, 0x20, 0xd3, 0x35, 0x75, 0x51, 0x6f, 0x4d, 0x71, 0x3d, 0xe4, 0xb6,
0x4d, 0x1d, 0x37, 0xea, 0x2a, 0x1d, 0x53, 0x36, 0xa1, 0x12, 0xd2, 0x2b, 0x79, 0xdd, 0xea, 0x69,
0x96, 0x43, 0x44, 0xee, 0xf1, 0xfe, 0x79, 0x56, 0xa5, 0x6d, 0x95, 0x6d, 0x4a, 0x21, 0xa9, 0xd9,
0xe8, 0xea, 0xf8, 0x48, 0x1c, 0x2b, 0xd2, 0x1b, 0xe5, 0x8f, 0x12, 0xcc, 0x70, 0x51, 0x27, 0x7b,
0x65, 0x7a, 0x36, 0x3e, 0xf3, 0x02, 0x54, 0x3a, 0xda, 0x51, 0x93, 0x1e, 0x33, 0xb0, 0x26, 0x28,
0xef, 0xa1, 0x4e, 0x76, 0xb4, 0x23, 0xaf, 0xe7, 0xa9, 0xfc, 0x5e, 0x82, 0xd9, 0xe0, 0xb6, 0x38,
0x42, 0xbe, 0x02, 0x20, 0x5e, 0xcf, 0xdd, 0x75, 0x4e, 0xf3, 0x75, 0x16, 0x45, 0x5f, 0xb9, 0xae,
0x16, 0x39, 0x53, 0x23, 0xbe, 0xef, 0x9a, 0x3a, 0x8d, 0xbe, 0xeb, 0x18, 0x4d, 0xf8, 0x3f, 0xa5,
0xdc, 0xed, 0x9c, 0xf0, 0x85, 0x60, 0xfc, 0xfd, 0x27, 0x84, 0x69, 0xea, 0xb8, 0x61, 0x9a, 0x1e,
0x3d, 0x4c, 0x33, 0x49, 0x61, 0x7a, 0x1b, 0x26, 0xfb, 0xbd, 0xb6, 0xa9, 0xe9, 0x4d, 0x0b, 0xdb,
0xfd, 0xb6, 0xc3, 0xcf, 0x9f, 0x94, 0xa8, 0x0b, 0x11, 0xa5, 0x3e, 0xe8, 0xf1, 0x63, 0x98, 0x7e,
0xdb, 0x51, 0xcb, 0x7d, 0xdf, 0x9d, 0xf2, 0x3d, 0xaf, 0xe3, 0x1e, 0x61, 0x1d, 0x1c, 0xa6, 0x2f,
0x42, 0x9e, 0x9e, 0x14, 0xbb, 0xc7, 0x85, 0xe1, 0x48, 0xcd, 0x91, 0xe1, 0x86, 0x8e, 0xae, 0x41,
0xe6, 0x50, 0xb3, 0x0f, 0xf9, 0xc7, 0x4d, 0xd3, 0xe2, 0x88, 0x8c, 0x3e, 0x6e, 0x53, 0xb3, 0x0f,
0x55, 0x3a, 0xac, 0xfc, 0x27, 0x05, 0x65, 0x92, 0xf0, 0x84, 0x09, 0xd0, 0x6a, 0x38, 0xa0, 0x4a,
0xab, 0xe7, 0x7c, 0xfb, 0xf3, 0x72, 0xa3, 0x2f, 0xaa, 0x42, 0x20, 0x90, 0x4a, 0x06, 0x81, 0xb4,
0x0f, 0x04, 0xa2, 0x07, 0xa0, 0xd9, 0x11, 0x0e, 0x40, 0xdf, 0x86, 0x73, 0xee, 0x29, 0xa0, 0x2f,
0x1e, 0x49, 0x69, 0x3f, 0x42, 0x70, 0xcc, 0x88, 0xb9, 0x1e, 0xcd, 0x8e, 0xa6, 0xd3, 0xfc, 0xb1,
0xd3, 0x69, 0x42, 0xfe, 0x2b, 0x24, 0xe6, 0xbf, 0xba, 0x7b, 0xcc, 0x15, 0x7c, 0x07, 0x45, 0xff,
0x0f, 0xd3, 0x76, 0xbf, 0xd5, 0xc2, 0xb6, 0xbd, 0xdf, 0x6f, 0x37, 0x39, 0xd2, 0x33, 0x6f, 0xa8,
0x7a, 0x03, 0x3b, 0x0c, 0xe2, 0x7f, 0x97, 0x72, 0xfd, 0x69, 0x4b, 0x7b, 0x82, 0x59, 0x96, 0xf8,
0x1f, 0xc7, 0xd4, 0x67, 0x91, 0x87, 0x13, 0xf3, 0x6a, 0x36, 0x31, 0xaf, 0xb2, 0xb6, 0x7f, 0x44,
0x95, 0xbc, 0x3e, 0xfc, 0xb9, 0x77, 0xf8, 0x7b, 0x1a, 0xe5, 0xfa, 0x33, 0xd1, 0xb4, 0xf2, 0xa9,
0x77, 0x38, 0x1c, 0x57, 0xbd, 0x7f, 0x3e, 0x73, 0xd3, 0xaf, 0xbc, 0x4d, 0x9d, 0xca, 0x6b, 0xc4,
0xf8, 0x5a, 0xb8, 0x09, 0x79, 0x96, 0x06, 0xc4, 0xe6, 0x13, 0xf2, 0x80, 0xab, 0x6e, 0x92, 0x07,
0xc4, 0x94, 0x48, 0x0a, 0xf0, 0x73, 0x3d, 0xdb, 0x14, 0xb0, 0x08, 0x0b, 0xb1, 0x8a, 0xe4, 0x2e,
0xff, 0x89, 0x04, 0x88, 0x8f, 0x9f, 0xa8, 0x5f, 0x34, 0xa6, 0xaf, 0xaf, 0x43, 0x85, 0x75, 0x84,
0x9a, 0xa3, 0xbb, 0xfc, 0x14, 0x9b, 0xe1, 0x16, 0xa7, 0x6e, 0x5b, 0x28, 0xed, 0x6b, 0x0b, 0x29,
0x8f, 0xdd, 0xd2, 0x33, 0xd0, 0xcc, 0xb9, 0x1e, 0x6c, 0xe6, 0x44, 0x1f, 0x33, 0x4a, 0x37, 0xc7,
0xab, 0x90, 0xdd, 0x6e, 0x8e, 0x3f, 0x68, 0xa5, 0xd1, 0x83, 0xf6, 0x97, 0x92, 0xfb, 0xc1, 0x41,
0xe8, 0x33, 0x93, 0xcf, 0x83, 0xea, 0x95, 0x5f, 0xa4, 0xbd, 0xcf, 0x1c, 0x42, 0x1f, 0xa4, 0x7c,
0x3e, 0x01, 0x27, 0x39, 0x97, 0x64, 0x92, 0xdf, 0xd1, 0x2e, 0x43, 0x39, 0xe6, 0xeb, 0xb5, 0x92,
0xed, 0x3b, 0x90, 0x4b, 0x48, 0x83, 0xb9, 0xe3, 0xa6, 0xc1, 0x7c, 0x4c, 0x1a, 0x7c, 0x19, 0x32,
0x5d, 0x7c, 0x24, 0x4e, 0x36, 0x07, 0x58, 0x91, 0xb2, 0x29, 0xef, 0x43, 0x79, 0x5d, 0x73, 0x5a,
0x87, 0xc7, 0xf6, 0xb7, 0x2f, 0x41, 0xc1, 0x62, 0x03, 0x22, 0x9a, 0x64, 0xdf, 0x37, 0xa0, 0x3e,
0xd1, 0x34, 0x9c, 0x5c, 0x5e, 0xe5, 0x6f, 0x00, 0xd5, 0xf0, 0x30, 0xaa, 0xc3, 0x24, 0x3f, 0xc6,
0x67, 0xad, 0x46, 0x1e, 0x44, 0x8b, 0xe1, 0xaf, 0x4a, 0x03, 0x5f, 0x82, 0x6f, 0x4e, 0xa8, 0xe5,
0x3d, 0x1f, 0x19, 0xdd, 0x00, 0x7e, 0xf2, 0xdf, 0x3c, 0xc0, 0xde, 0x67, 0xe7, 0x21, 0x11, 0x5e,
0xb7, 0x7f, 0x73, 0x42, 0x2d, 0xee, 0x09, 0x9a, 0x6f, 0x09, 0x3a, 0xc5, 0x46, 0x8e, 0xa8, 0x91,
0x25, 0x04, 0x52, 0x90, 0xb7, 0x04, 0x46, 0x46, 0x5f, 0x71, 0xbf, 0x47, 0x68, 0x1b, 0xb6, 0xe3,
0xf6, 0x7c, 0x62, 0x3e, 0x8e, 0xf5, 0x24, 0xf0, 0x45, 0x13, 0x22, 0xfa, 0x06, 0xcc, 0xf1, 0xf9,
0x36, 0x76, 0x9a, 0x9a, 0xf7, 0x5d, 0x02, 0x6f, 0xff, 0x5c, 0x0b, 0x8b, 0x8a, 0xfd, 0x94, 0x62,
0x73, 0x42, 0x9d, 0xdd, 0x8b, 0x19, 0x46, 0x6b, 0x50, 0xe6, 0xdd, 0xf2, 0x3d, 0x52, 0x24, 0xf0,
0x36, 0xd0, 0x85, 0x70, 0xeb, 0xd8, 0xff, 0xba, 0xbe, 0x39, 0xa1, 0x96, 0x4c, 0x8f, 0x4a, 0xf4,
0xc4, 0x45, 0xb4, 0x68, 0x31, 0xcb, 0x0b, 0xe9, 0xc5, 0xb0, 0x8c, 0xc0, 0xcb, 0x24, 0xd1, 0x93,
0xe9, 0x23, 0x13, 0x53, 0x71, 0x29, 0xc4, 0x54, 0x85, 0xb0, 0xa9, 0xc2, 0x07, 0x33, 0xc4, 0x54,
0xa6, 0xa0, 0x11, 0x25, 0xf3, 0xc9, 0x54, 0xc9, 0xc5, 0xb0, 0x92, 0x23, 0x07, 0x1f, 0x44, 0xc9,
0xa6, 0x4b, 0x44, 0xf7, 0x61, 0xc6, 0xaf, 0x05, 0x61, 0x70, 0xa0, 0x72, 0x94, 0x58, 0x65, 0x84,
0xad, 0x3e, 0x6d, 0x86, 0xc7, 0xd0, 0x43, 0x98, 0xe5, 0x52, 0xf7, 0x69, 0x8a, 0x15, 0x62, 0x4b,
0x54, 0xec, 0x95, 0xb0, 0xd8, 0x98, 0x82, 0x66, 0x73, 0x42, 0x45, 0x66, 0x64, 0x90, 0x68, 0x5c,
0x00, 0x0c, 0xb3, 0x5a, 0x39, 0xac, 0xf1, 0x98, 0x2e, 0x0b, 0xd1, 0xb8, 0xed, 0x23, 0xa3, 0xdb,
0x30, 0x25, 0xa4, 0x70, 0xc3, 0xb1, 0x33, 0xfc, 0x8b, 0x11, 0x31, 0x61, 0xcb, 0x89, 0xa7, 0x73,
0xd3, 0xdd, 0x87, 0x19, 0x21, 0xa8, 0xa3, 0x3d, 0xc1, 0x1c, 0x26, 0xe9, 0x29, 0x7e, 0x5c, 0x79,
0x14, 0x79, 0x57, 0x21, 0xda, 0xb3, 0xc3, 0x63, 0x44, 0x7b, 0x81, 0x4d, 0x0a, 0xed, 0x55, 0xc2,
0xda, 0x4b, 0xac, 0xcc, 0x89, 0xf6, 0xec, 0xc8, 0x20, 0x7a, 0x0c, 0xe7, 0x84, 0xe0, 0xa0, 0x5d,
0xaa, 0x54, 0xf2, 0xd5, 0x88, 0xe4, 0x78, 0xc3, 0x88, 0x3d, 0x07, 0x2c, 0xb3, 0xe6, 0x41, 0x3f,
0xf5, 0xc4, 0xe9, 0x70, 0x38, 0x45, 0x6b, 0x2a, 0x12, 0x4e, 0xb6, 0x47, 0x45, 0x5b, 0x50, 0x15,
0x22, 0x74, 0x9e, 0x43, 0x6b, 0x28, 0x7c, 0x80, 0x15, 0x5f, 0x23, 0x6c, 0x4e, 0xa8, 0x15, 0x3b,
0x38, 0xb2, 0x5e, 0x84, 0x3c, 0x1f, 0x55, 0xde, 0x82, 0x49, 0x8e, 0xb3, 0x3c, 0x25, 0x7f, 0x19,
0x8a, 0x16, 0xbf, 0x16, 0x90, 0xbd, 0x10, 0x81, 0x6c, 0x36, 0x4e, 0x31, 0xdb, 0xe3, 0x56, 0xfe,
0x05, 0x30, 0x1d, 0x61, 0x40, 0x1b, 0xf1, 0xa8, 0x7d, 0x31, 0x09, 0xb5, 0xd9, 0xd4, 0x08, 0x6c,
0xdf, 0x8c, 0x81, 0xed, 0x85, 0x58, 0xd8, 0x76, 0x05, 0xf8, 0x70, 0x7b, 0x23, 0x1e, 0xb7, 0x2f,
0x26, 0xe1, 0x76, 0x78, 0x11, 0xdc, 0x94, 0x6f, 0xc4, 0x01, 0xf7, 0x85, 0x78, 0xe0, 0x76, 0x45,
0xf8, 0x91, 0xfb, 0x9b, 0x43, 0x90, 0xfb, 0x85, 0x61, 0xc8, 0xed, 0x4a, 0x8d, 0x87, 0xee, 0xf5,
0x58, 0xe8, 0x5e, 0x4c, 0x80, 0x6e, 0x57, 0x58, 0x00, 0xbb, 0x37, 0xe2, 0xb1, 0xfb, 0x62, 0x12,
0x76, 0x7b, 0xba, 0x0a, 0x80, 0xf7, 0xcd, 0x18, 0xf0, 0x5e, 0x88, 0x05, 0x6f, 0xcf, 0x60, 0x1e,
0x7a, 0xbf, 0x11, 0x87, 0xde, 0x17, 0xe2, 0xd1, 0xdb, 0xd3, 0xb4, 0x0f, 0xbe, 0x1f, 0x0c, 0x82,
0xef, 0x2b, 0x03, 0xe1, 0xdb, 0x95, 0x17, 0x83, 0xdf, 0x8f, 0x06, 0xe2, 0xf7, 0xd5, 0xc1, 0xf8,
0xed, 0x0a, 0x8e, 0x03, 0xf0, 0x8d, 0x78, 0x00, 0xbf, 0x98, 0x04, 0xe0, 0x9e, 0xda, 0x03, 0x08,
0xbe, 0x99, 0x80, 0xe0, 0x4b, 0x89, 0x08, 0xee, 0x0a, 0x0a, 0x41, 0xf8, 0x83, 0x41, 0x10, 0x7e,
0x65, 0x20, 0x84, 0x7b, 0x1a, 0x8c, 0x62, 0xf8, 0xa3, 0x81, 0x18, 0x7e, 0x75, 0x30, 0x86, 0x7b,
0x1a, 0x8c, 0x01, 0xf1, 0xaf, 0x0f, 0x06, 0xf1, 0x6b, 0x43, 0x40, 0xdc, 0x95, 0x1d, 0x8b, 0xe2,
0xeb, 0xb1, 0x28, 0xbe, 0x98, 0x80, 0xe2, 0x5e, 0x64, 0xf9, 0x61, 0x7c, 0x3b, 0x11, 0xc6, 0x2f,
0x0f, 0x80, 0x71, 0x57, 0x56, 0x04, 0xc7, 0x01, 0x0a, 0x62, 0x78, 0xf5, 0x9f, 0xd3, 0x50, 0xd8,
0xe2, 0x32, 0xd0, 0x16, 0x94, 0x19, 0x6c, 0xf2, 0x7f, 0x66, 0x07, 0x97, 0xc8, 0xf2, 0x10, 0x2c,
0x46, 0x75, 0x28, 0xde, 0xc6, 0x0e, 0x97, 0x35, 0xa0, 0x56, 0x96, 0x07, 0x01, 0x32, 0x59, 0x14,
0xd3, 0x65, 0xd2, 0xa2, 0x02, 0xd9, 0x54, 0x1e, 0x82, 0xcd, 0x68, 0x13, 0x4a, 0x44, 0xa9, 0x6c,
0xcc, 0x46, 0x83, 0xca, 0x67, 0x79, 0x20, 0x44, 0x23, 0x0c, 0xb3, 0xbb, 0x62, 0x7b, 0x7e, 0x30,
0x1d, 0xad, 0x8c, 0x96, 0x47, 0xc4, 0x6c, 0xf4, 0x16, 0x94, 0xa8, 0xb7, 0xf2, 0x6f, 0x75, 0x07,
0xd6, 0xd3, 0xf2, 0x60, 0xc8, 0xa6, 0x06, 0xa6, 0x51, 0xca, 0x85, 0x0d, 0x2e, 0xac, 0xe5, 0x21,
0xd8, 0xcd, 0x0d, 0xcc, 0x65, 0x0d, 0xa8, 0xb0, 0xe5, 0x41, 0x00, 0x2e, 0x2c, 0xc2, 0x06, 0x02,
0x16, 0x89, 0xd4, 0xda, 0xf2, 0x40, 0x28, 0x47, 0xef, 0xc2, 0xb4, 0x2f, 0xb0, 0xf9, 0xba, 0x46,
0xa8, 0xb9, 0xe5, 0x51, 0x80, 0x1d, 0x35, 0x01, 0xf9, 0x43, 0x9b, 0x8b, 0x1f, 0xa5, 0xf6, 0x96,
0x47, 0x02, 0x78, 0x62, 0x1d, 0xfa, 0x5c, 0x71, 0x9c, 0x3d, 0xb8, 0x08, 0x97, 0x87, 0x40, 0x3c,
0xda, 0x81, 0x49, 0x66, 0x2f, 0x21, 0x6f, 0x48, 0x35, 0x2e, 0x0f, 0xc3, 0x7a, 0xa2, 0x5f, 0x0f,
0x91, 0x85, 0xd4, 0x11, 0xaa, 0x72, 0x79, 0x14, 0xd8, 0x27, 0xfa, 0xf5, 0xa9, 0x5d, 0x88, 0x1f,
0xa5, 0x3a, 0x97, 0x47, 0x82, 0x7f, 0xb4, 0x07, 0x33, 0x7e, 0xbd, 0x8b, 0x27, 0x8c, 0x54, 0xa5,
0xcb, 0xa3, 0xa5, 0x01, 0x74, 0x07, 0xca, 0xfe, 0x7f, 0x24, 0xd0, 0xc0, 0x7a, 0x5d, 0x1e, 0x9c,
0x07, 0xd0, 0x3b, 0x50, 0x11, 0xa0, 0x2d, 0x16, 0x3b, 0xb4, 0x70, 0x97, 0x87, 0xe7, 0x04, 0xf4,
0x1a, 0x64, 0x69, 0xc1, 0x8d, 0xe6, 0xe2, 0xbb, 0x2a, 0xf2, 0x7c, 0x42, 0xe9, 0x8e, 0x1e, 0x42,
0x95, 0x81, 0x3c, 0x17, 0x7d, 0xaf, 0xad, 0xc7, 0x2c, 0x29, 0xf4, 0x17, 0x69, 0xcc, 0x92, 0x22,
0x7f, 0x45, 0x7e, 0x0d, 0xaa, 0x01, 0x67, 0x25, 0xb4, 0xcb, 0x83, 0xfd, 0x95, 0x48, 0x56, 0x86,
0xb8, 0x2c, 0x11, 0xb3, 0x0b, 0x53, 0xbe, 0x1f, 0xaf, 0x08, 0x25, 0xea, 0xe8, 0xc1, 0x5f, 0xc4,
0xe4, 0x4b, 0x09, 0x0c, 0x9e, 0xd0, 0x26, 0xa0, 0x90, 0x69, 0x08, 0xf5, 0xca, 0x30, 0xeb, 0x10,
0xe1, 0x57, 0x87, 0x1a, 0x88, 0x2b, 0x24, 0xe0, 0xa6, 0xf1, 0x0a, 0x09, 0xff, 0x01, 0x16, 0xa3,
0x90, 0xe8, 0x1f, 0x59, 0xef, 0x40, 0xc5, 0xef, 0xa3, 0x21, 0x1b, 0xc6, 0xff, 0x27, 0xe5, 0xb7,
0x61, 0xd2, 0x6f, 0x43, 0xef, 0xc2, 0x74, 0x30, 0x87, 0x11, 0x62, 0x60, 0x41, 0xf1, 0x7f, 0xe6,
0x04, 0xe1, 0x21, 0xe1, 0x87, 0x19, 0x92, 0x07, 0x7d, 0x7f, 0xba, 0xf8, 0x03, 0x2b, 0xfa, 0x1f,
0x8d, 0x3f, 0xb0, 0x62, 0x7e, 0x8f, 0x59, 0xcf, 0x3c, 0x4e, 0xf5, 0xf6, 0xf6, 0x72, 0xf4, 0x5c,
0xf6, 0xd5, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x70, 0x7c, 0x53, 0x8c, 0xd4, 0x44, 0x00, 0x00,
// 3730 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0x4d, 0x6c, 0x1c, 0xc7,
0x95, 0xe6, 0xfc, 0xcf, 0xbc, 0x19, 0x72, 0x86, 0x45, 0x8a, 0x1c, 0x35, 0x45, 0x51, 0x6a, 0x49,
0xb6, 0x16, 0x6b, 0x53, 0x06, 0xbd, 0xbb, 0xf0, 0x42, 0xf2, 0x7a, 0x49, 0x0d, 0xad, 0x19, 0x4b,
0xa4, 0xe8, 0xa6, 0x64, 0x69, 0xb5, 0x4e, 0x1a, 0xcd, 0xe9, 0x22, 0xd9, 0xd1, 0xcc, 0xf4, 0xa4,
0xbb, 0xc7, 0xa6, 0x9c, 0x53, 0x00, 0x03, 0x41, 0x10, 0x20, 0x30, 0x72, 0x0e, 0x72, 0xf2, 0x2d,
0xa7, 0xe4, 0x16, 0x20, 0xc9, 0x35, 0x09, 0x10, 0x38, 0x80, 0x11, 0xe4, 0x90, 0x83, 0x93, 0x53,
0x6e, 0xc9, 0x25, 0xb7, 0x04, 0x01, 0x82, 0xfa, 0xeb, 0xff, 0x9e, 0x1f, 0xfe, 0x48, 0xf1, 0xad,
0xfb, 0x55, 0xd5, 0xeb, 0xaa, 0xef, 0xbd, 0xfa, 0xde, 0xeb, 0x57, 0xdd, 0x30, 0xd3, 0xc5, 0x8e,
0x66, 0xf4, 0xf6, 0xcd, 0xd5, 0xbe, 0x65, 0x3a, 0x26, 0x2a, 0x8a, 0x7b, 0xa9, 0x86, 0x7b, 0x6d,
0xeb, 0x59, 0xdf, 0x31, 0xcc, 0x1e, 0x6b, 0x93, 0xe0, 0xc0, 0x3c, 0xe0, 0xfd, 0xa4, 0x95, 0x03,
0xd3, 0x3c, 0xe8, 0xe0, 0x1b, 0xf4, 0x6e, 0x6f, 0xb0, 0x7f, 0xc3, 0x31, 0xba, 0xd8, 0x76, 0xb4,
0x6e, 0x5f, 0x74, 0xee, 0x99, 0x3a, 0xe6, 0xd7, 0xd5, 0xbe, 0x69, 0xf4, 0x1c, 0x6c, 0xe9, 0x7b,
0x5c, 0x50, 0x31, 0x2d, 0x1d, 0x5b, 0x36, 0xbb, 0x93, 0xef, 0xc0, 0xb4, 0x82, 0xbf, 0x3e, 0xc0,
0xb6, 0xd3, 0xc4, 0x9a, 0x8e, 0x2d, 0xb4, 0x08, 0x05, 0xad, 0x6f, 0xa8, 0x4f, 0xf1, 0xb3, 0x7a,
0xea, 0x52, 0xea, 0x7a, 0x45, 0xc9, 0x6b, 0x7d, 0xe3, 0x2e, 0x7e, 0x86, 0x96, 0x01, 0x06, 0x36,
0xb6, 0x54, 0xed, 0x00, 0xf7, 0x9c, 0x7a, 0x9a, 0xb6, 0x95, 0x88, 0x64, 0x9d, 0x08, 0xe4, 0x1f,
0x66, 0x20, 0xbf, 0x31, 0x68, 0x3f, 0xc5, 0x0e, 0x42, 0x90, 0xed, 0x69, 0x5d, 0xcc, 0xc7, 0xd3,
0x6b, 0xf4, 0x06, 0x94, 0xfb, 0x9a, 0x73, 0xa8, 0xb6, 0x8d, 0xfe, 0x21, 0xb6, 0xe8, 0xf0, 0x99,
0xb5, 0xc5, 0x55, 0xdf, 0x3a, 0x6f, 0xd3, 0x96, 0xdd, 0x81, 0xe1, 0x60, 0x05, 0x48, 0x5f, 0x26,
0x40, 0xb7, 0x01, 0xda, 0x16, 0xd6, 0x1c, 0xac, 0xab, 0x9a, 0x53, 0xcf, 0x5c, 0x4a, 0x5d, 0x2f,
0xaf, 0x49, 0xab, 0x0c, 0x82, 0x55, 0x01, 0xc1, 0xea, 0x03, 0x01, 0xc1, 0x46, 0xf1, 0x97, 0x5f,
0xac, 0x4c, 0x7d, 0xf2, 0x87, 0x95, 0x94, 0x52, 0xe2, 0xe3, 0xd6, 0x1d, 0xf4, 0x1a, 0xcc, 0xeb,
0x78, 0x5f, 0x1b, 0x74, 0x1c, 0xd5, 0xc6, 0x07, 0x5d, 0xdc, 0x73, 0x54, 0xdb, 0xf8, 0x08, 0xd7,
0xb3, 0x97, 0x52, 0xd7, 0x33, 0x0a, 0xe2, 0x6d, 0xbb, 0xac, 0x69, 0xd7, 0xf8, 0x08, 0xa3, 0x47,
0x70, 0x5e, 0x8c, 0xb0, 0xb0, 0x3e, 0xe8, 0xe9, 0x5a, 0xaf, 0xfd, 0x4c, 0xb5, 0xdb, 0x87, 0xb8,
0x8b, 0xeb, 0x39, 0x3a, 0x8b, 0xa5, 0x55, 0x0f, 0x5b, 0xc5, 0xed, 0xb3, 0x4b, 0xbb, 0x28, 0x8b,
0x7c, 0x74, 0xb8, 0x01, 0xe9, 0xb0, 0x2c, 0x14, 0x7b, 0xab, 0x57, 0xfb, 0x9a, 0xa5, 0x75, 0xb1,
0x83, 0x2d, 0xbb, 0x9e, 0xa7, 0xca, 0x2f, 0xf9, 0xb1, 0xd9, 0x74, 0x2f, 0x77, 0xdc, 0x7e, 0xca,
0x12, 0x57, 0x13, 0xd7, 0x48, 0xac, 0xd5, 0xd7, 0x2c, 0xa7, 0x87, 0x2d, 0xd5, 0xd0, 0xeb, 0x05,
0x66, 0x2d, 0x2e, 0x69, 0xe9, 0xb2, 0x01, 0x33, 0xcc, 0x58, 0xf7, 0x0c, 0xdb, 0x69, 0x39, 0xb8,
0x1b, 0x6b, 0xb4, 0x20, 0xf4, 0xe9, 0x63, 0x41, 0x2f, 0x7f, 0x9a, 0x81, 0x39, 0xf6, 0xac, 0xdb,
0x54, 0xc6, 0xdd, 0x0d, 0xdd, 0x80, 0xfc, 0x21, 0x75, 0xb9, 0x7a, 0x95, 0x2a, 0x5e, 0x5c, 0x75,
0xb7, 0x43, 0xc0, 0x23, 0x15, 0xde, 0xed, 0x94, 0xdd, 0x2a, 0xc9, 0x23, 0x32, 0xc7, 0xf3, 0x88,
0xec, 0x59, 0x7a, 0x44, 0xee, 0xf4, 0x3d, 0x22, 0x1f, 0xf6, 0x88, 0xff, 0x85, 0xf9, 0xa0, 0x95,
0xec, 0xbe, 0xd9, 0xb3, 0x31, 0xba, 0x0e, 0xf9, 0x3d, 0x2a, 0xa7, 0xb8, 0x97, 0xd7, 0x6a, 0x9e,
0x99, 0x58, 0x7f, 0x85, 0xb7, 0xcb, 0x8f, 0xa0, 0xc6, 0x24, 0x77, 0xb0, 0x73, 0x9a, 0x46, 0x96,
0xdf, 0x84, 0x59, 0x9f, 0xe2, 0x89, 0xe7, 0xf5, 0x44, 0xf8, 0x5f, 0x03, 0x77, 0xf0, 0xe9, 0xfa,
0x9f, 0xbc, 0x20, 0x50, 0x13, 0xba, 0xd9, 0xec, 0xe4, 0x4f, 0x52, 0x62, 0xce, 0x64, 0x83, 0x1d,
0xfb, 0x91, 0x0b, 0x90, 0x6f, 0x0f, 0x2c, 0xdb, 0xb4, 0x04, 0x17, 0xb3, 0x3b, 0x34, 0x0f, 0xb9,
0x8e, 0xd1, 0x35, 0xd8, 0x9e, 0xcc, 0x29, 0xec, 0x06, 0x5d, 0x80, 0x92, 0x6e, 0x58, 0xb8, 0x4d,
0x0c, 0x4f, 0xfd, 0x38, 0xa7, 0x78, 0x02, 0xf9, 0x31, 0x20, 0xff, 0x8c, 0x38, 0x8c, 0xab, 0x90,
0x33, 0x1c, 0xdc, 0xb5, 0xeb, 0xa9, 0x4b, 0x99, 0xeb, 0xe5, 0xb5, 0x7a, 0x18, 0x45, 0xc1, 0x0f,
0x0a, 0xeb, 0x46, 0x40, 0xe8, 0x9a, 0x16, 0xa6, 0x0f, 0x2e, 0x2a, 0xf4, 0x5a, 0xfe, 0x66, 0x0a,
0x96, 0x58, 0xef, 0x5d, 0xec, 0xac, 0x3b, 0x8e, 0x65, 0xec, 0x0d, 0xc8, 0x23, 0x4f, 0x75, 0xa7,
0x07, 0xdd, 0x37, 0x1d, 0x76, 0xdf, 0x8b, 0x70, 0x21, 0x7e, 0x0a, 0xdc, 0x20, 0x1f, 0xa7, 0x60,
0x6e, 0x5d, 0xd7, 0x2d, 0x6c, 0xdb, 0x58, 0xbf, 0x4f, 0x22, 0xe0, 0x3d, 0x8a, 0xd9, 0x75, 0x81,
0x24, 0xf3, 0x22, 0xb4, 0xca, 0xa3, 0xa3, 0xd7, 0x45, 0xa0, 0x7b, 0x1b, 0xe6, 0x6d, 0xc7, 0xb4,
0xb4, 0x03, 0xac, 0x92, 0xf0, 0xaa, 0x6a, 0x4c, 0x1b, 0xa7, 0xc5, 0xd9, 0x55, 0x1a, 0x73, 0xb7,
0x4d, 0x1d, 0xf3, 0xc7, 0x28, 0x88, 0x77, 0xf7, 0xc9, 0xe4, 0xdf, 0xa4, 0x61, 0x81, 0x73, 0xca,
0x23, 0xcb, 0x70, 0x9d, 0xf1, 0x7e, 0x47, 0x3f, 0x96, 0x73, 0xf8, 0x76, 0x40, 0x45, 0xf8, 0x3b,
0x41, 0x8f, 0xf0, 0x1c, 0xc7, 0x88, 0x5e, 0xa3, 0x3a, 0x14, 0x38, 0xcb, 0x71, 0x82, 0x13, 0xb7,
0xe8, 0x26, 0x80, 0xc7, 0x66, 0xe3, 0xd0, 0x98, 0xaf, 0x3b, 0xba, 0x09, 0x52, 0x57, 0x3b, 0x12,
0xac, 0x85, 0xf5, 0x20, 0x95, 0xe6, 0xe8, 0x93, 0x16, 0xbb, 0xda, 0xd1, 0xa6, 0xe8, 0xe0, 0xe7,
0xd3, 0x06, 0x00, 0x3e, 0xea, 0x1b, 0x96, 0x46, 0xfd, 0x35, 0x3f, 0x41, 0x74, 0xf1, 0x8d, 0x93,
0x3f, 0x4f, 0xc1, 0x62, 0x10, 0x51, 0x66, 0x71, 0x02, 0x69, 0x13, 0x6a, 0x9a, 0xb0, 0xb9, 0x4a,
0xad, 0x28, 0xfc, 0x7c, 0xd9, 0x03, 0x37, 0xc6, 0x2b, 0x94, 0xaa, 0x3b, 0x8c, 0xde, 0xdb, 0xe8,
0x75, 0x98, 0xb6, 0x4c, 0xd3, 0x51, 0xfb, 0x06, 0x6e, 0x63, 0xd7, 0x01, 0x37, 0xaa, 0x64, 0x4a,
0xbf, 0xff, 0x62, 0xa5, 0xb0, 0x43, 0xe4, 0xad, 0x86, 0x52, 0x26, 0xbd, 0xd8, 0x8d, 0x4e, 0x83,
0x93, 0x65, 0x7c, 0xa0, 0x39, 0x98, 0xa6, 0x53, 0x19, 0x3a, 0x64, 0x91, 0x0f, 0xa9, 0xd2, 0x5e,
0x3b, 0xac, 0xfd, 0x2e, 0x7e, 0xa6, 0x40, 0xdf, 0xbd, 0x96, 0xff, 0xee, 0x2d, 0xea, 0xb6, 0xd9,
0x25, 0x33, 0x7a, 0xe1, 0x7e, 0xf2, 0x0a, 0x14, 0xb8, 0x53, 0x70, 0x27, 0x41, 0x3e, 0x27, 0xd9,
0x61, 0x57, 0x8a, 0xe8, 0x82, 0x6e, 0x42, 0xd5, 0xb4, 0x8c, 0x03, 0xa3, 0xa7, 0x75, 0x04, 0xf0,
0x39, 0x0a, 0x7c, 0xdc, 0x06, 0x9b, 0x11, 0x5d, 0x19, 0xd8, 0x72, 0x13, 0xea, 0xa1, 0xc5, 0x7b,
0x26, 0xf5, 0x4d, 0x23, 0x35, 0x72, 0x1a, 0xf2, 0xf7, 0x52, 0x70, 0x9e, 0xab, 0x6a, 0x98, 0x1f,
0xf6, 0x3a, 0xa6, 0xa6, 0xbf, 0x70, 0x24, 0xe5, 0xcf, 0x52, 0x20, 0x45, 0x26, 0x75, 0x16, 0x4e,
0xeb, 0xc3, 0x2a, 0x3d, 0xda, 0x64, 0xc7, 0xf7, 0xd6, 0xef, 0xa6, 0xe0, 0x1c, 0x5f, 0x50, 0xab,
0xb7, 0x6f, 0xbe, 0x78, 0x84, 0xdf, 0x76, 0x49, 0x96, 0xcd, 0x27, 0xd6, 0x7d, 0x46, 0x43, 0x42,
0xa2, 0xb8, 0xd8, 0x86, 0x81, 0xdc, 0xe1, 0x05, 0x2e, 0xed, 0x07, 0x29, 0x77, 0x73, 0x04, 0x53,
0x8e, 0xd3, 0x75, 0x9d, 0x90, 0x33, 0xa4, 0xc7, 0x77, 0x86, 0x4f, 0xd2, 0xb0, 0x40, 0x92, 0x06,
0x3e, 0x49, 0xfb, 0x2c, 0x20, 0x5b, 0x80, 0x7c, 0xdf, 0xc2, 0xfb, 0xc6, 0x11, 0x07, 0x8d, 0xdf,
0xa1, 0x15, 0x28, 0xdb, 0x8e, 0x66, 0x39, 0xaa, 0xb6, 0x4f, 0x2c, 0x4c, 0x5d, 0x58, 0x01, 0x2a,
0x5a, 0x27, 0x12, 0x74, 0x19, 0x00, 0xf7, 0x74, 0x75, 0x0f, 0xef, 0x93, 0x1c, 0x26, 0x4b, 0x57,
0x95, 0xae, 0xa7, 0x94, 0x12, 0xee, 0xe9, 0x1b, 0x54, 0x48, 0x92, 0x28, 0x0b, 0x93, 0x34, 0xcb,
0xf8, 0x80, 0x45, 0xb0, 0xa2, 0xe2, 0x09, 0xbc, 0xc4, 0x2b, 0xef, 0x4f, 0xbc, 0x96, 0x01, 0xc8,
0x4a, 0xd4, 0xfd, 0x8e, 0x76, 0x60, 0xd3, 0x97, 0xad, 0x82, 0x52, 0x22, 0x92, 0xb7, 0x89, 0x80,
0x86, 0xa8, 0x20, 0x24, 0x9e, 0xc9, 0x6e, 0x05, 0xf3, 0xaf, 0x97, 0x3c, 0x48, 0x12, 0x46, 0xac,
0x8e, 0xc8, 0xc6, 0x24, 0x0c, 0x59, 0xf1, 0x42, 0x47, 0xfd, 0x2a, 0xe5, 0xf3, 0xab, 0xc9, 0x18,
0x61, 0x09, 0x4a, 0x86, 0xad, 0x72, 0xa4, 0x33, 0xf4, 0x11, 0x45, 0xc3, 0xde, 0xa1, 0xf7, 0xf2,
0x77, 0xa8, 0x23, 0xc6, 0xa4, 0x7b, 0xc7, 0xb2, 0xf4, 0x0a, 0x94, 0x99, 0x6d, 0x55, 0x5f, 0xe2,
0x07, 0x4c, 0xb4, 0x3d, 0x46, 0xfa, 0xb7, 0x44, 0x78, 0x3e, 0x2e, 0xf1, 0xbb, 0xdf, 0xd1, 0xe5,
0x4d, 0x40, 0x3b, 0x96, 0xf9, 0x35, 0xdc, 0xf6, 0xd3, 0xd3, 0xc4, 0x73, 0x94, 0xdf, 0x80, 0xb9,
0x80, 0x1a, 0x9e, 0x41, 0x5f, 0x86, 0x4a, 0x9f, 0x89, 0x55, 0x5b, 0xeb, 0x08, 0x57, 0x2d, 0x73,
0xd9, 0xae, 0xd6, 0x71, 0xe4, 0x6f, 0x17, 0x20, 0x7f, 0x7f, 0x8f, 0xdc, 0x26, 0xba, 0xf4, 0x35,
0x98, 0xf1, 0xb2, 0x28, 0x1f, 0x1f, 0x4c, 0xbb, 0xd2, 0x1d, 0x4e, 0x0c, 0x1f, 0x60, 0xcb, 0xf6,
0x12, 0x7c, 0x71, 0x4b, 0x96, 0x63, 0x3b, 0x9a, 0x33, 0xb0, 0xa9, 0x5b, 0xcf, 0xf8, 0x97, 0xc3,
0x1e, 0xbd, 0xba, 0x4b, 0x9b, 0x15, 0xde, 0x0d, 0xbd, 0x0a, 0x25, 0xdb, 0xb1, 0xb0, 0xd6, 0x25,
0x80, 0xe6, 0xe8, 0x56, 0xa8, 0xf1, 0x0d, 0x5e, 0xdc, 0xa5, 0x0d, 0xad, 0x86, 0x52, 0x64, 0x5d,
0x5a, 0x7a, 0xa8, 0x16, 0x90, 0x3f, 0x5e, 0x19, 0x66, 0x9d, 0x3c, 0x93, 0x3c, 0x9d, 0xe8, 0x28,
0x4c, 0xa0, 0xa3, 0xc8, 0x86, 0xad, 0x93, 0x34, 0x9c, 0x65, 0x7f, 0x98, 0xea, 0x28, 0x4e, 0x32,
0x0f, 0x3e, 0x6e, 0xdd, 0x41, 0x77, 0xa0, 0xee, 0xa1, 0x4d, 0x70, 0xd2, 0x35, 0x47, 0x53, 0x7b,
0x66, 0xaf, 0x8d, 0xeb, 0x25, 0x0a, 0xc5, 0x34, 0x87, 0x22, 0xb7, 0x4d, 0x84, 0xca, 0x82, 0xdb,
0x7d, 0x8b, 0xf7, 0xa6, 0x72, 0xf4, 0x2a, 0xa0, 0xa8, 0xa2, 0x3a, 0x50, 0xd3, 0xcd, 0x46, 0xc6,
0xa0, 0x57, 0x00, 0xed, 0x1b, 0x47, 0xe1, 0x3c, 0xb9, 0x4c, 0x29, 0xbe, 0x46, 0x5b, 0xfc, 0x09,
0x72, 0x13, 0x66, 0xa3, 0x85, 0x86, 0xca, 0xe8, 0x0c, 0xbd, 0x66, 0x85, 0x2b, 0x0c, 0x0f, 0xe1,
0x5c, 0x7c, 0x65, 0x61, 0x7a, 0xcc, 0xca, 0xc2, 0x3c, 0x4e, 0x28, 0x29, 0x38, 0xa6, 0xa3, 0x75,
0xd8, 0x32, 0x66, 0xe8, 0x32, 0x4a, 0x54, 0x42, 0xe7, 0xbf, 0x02, 0x65, 0xa3, 0xd7, 0x31, 0x7a,
0x98, 0xb5, 0x57, 0x69, 0x3b, 0x30, 0x91, 0xe8, 0x60, 0xe1, 0xae, 0xe9, 0xf0, 0x0e, 0x35, 0xd6,
0x81, 0x89, 0x48, 0x07, 0xf9, 0x5d, 0xc8, 0x33, 0xaf, 0x45, 0x65, 0x28, 0xb4, 0xb6, 0xdf, 0x5b,
0xbf, 0xd7, 0x6a, 0xd4, 0xa6, 0xd0, 0x34, 0x94, 0x1e, 0xee, 0xdc, 0xbb, 0xbf, 0xde, 0x68, 0x6d,
0xdf, 0xa9, 0xa5, 0xd0, 0x0c, 0xc0, 0xed, 0xfb, 0x5b, 0x5b, 0xad, 0x07, 0x0f, 0xc8, 0x7d, 0x9a,
0x34, 0xf3, 0xfb, 0xcd, 0x46, 0x2d, 0x83, 0x2a, 0x50, 0x6c, 0x6c, 0xde, 0xdb, 0xa4, 0x8d, 0x59,
0xf9, 0xe3, 0x0c, 0x20, 0xb6, 0x21, 0x36, 0xf0, 0x81, 0xd1, 0x3b, 0xc9, 0xab, 0xf9, 0xd9, 0x6c,
0xe4, 0xa0, 0x83, 0x67, 0x8f, 0xe7, 0xe0, 0xb1, 0xae, 0x53, 0x38, 0x55, 0xd7, 0x29, 0x9e, 0xc4,
0x75, 0xe4, 0x9f, 0xa7, 0x61, 0x2e, 0x60, 0x06, 0xce, 0xa6, 0x67, 0x06, 0x6b, 0x80, 0xee, 0xb2,
0x23, 0xe9, 0x2e, 0x16, 0xc0, 0xdc, 0xa9, 0x02, 0x98, 0x3f, 0x11, 0x80, 0x7f, 0x4e, 0x09, 0x00,
0x03, 0x6f, 0x88, 0x93, 0x3b, 0x72, 0x00, 0x98, 0xd4, 0x48, 0x60, 0x86, 0x51, 0x67, 0xfa, 0xe4,
0xd4, 0x99, 0x49, 0xa0, 0x4e, 0x79, 0x01, 0xe6, 0x83, 0xcb, 0xe5, 0x85, 0x9d, 0xef, 0xa7, 0xa0,
0xc6, 0x1a, 0x4e, 0x52, 0x76, 0x3c, 0x2b, 0xb7, 0x93, 0xdf, 0x84, 0x59, 0xdf, 0xec, 0xbc, 0xda,
0xa5, 0x49, 0x85, 0xd1, 0xda, 0x25, 0xeb, 0xac, 0xf0, 0x76, 0xf9, 0x47, 0x69, 0x31, 0xfe, 0xa4,
0x75, 0xc4, 0xd8, 0xe5, 0xfd, 0x1b, 0xd4, 0x7c, 0xcb, 0xf3, 0xa7, 0xd4, 0x55, 0x6f, 0x81, 0x2c,
0xb7, 0x0e, 0x74, 0xe5, 0x45, 0xc9, 0x4c, 0xa8, 0xeb, 0x6d, 0x56, 0x9d, 0x0c, 0xa4, 0xd0, 0xd9,
0xc4, 0x14, 0x3a, 0xe7, 0x4f, 0xa1, 0x5b, 0x50, 0x65, 0x4b, 0x56, 0x8d, 0x5e, 0xbb, 0x33, 0xd0,
0xb1, 0xb7, 0x3f, 0x42, 0xd8, 0x88, 0x8a, 0x64, 0x8b, 0xf7, 0x53, 0x66, 0xd8, 0x40, 0x71, 0x2f,
0x3f, 0x16, 0x04, 0x3f, 0x66, 0xa1, 0x33, 0xa8, 0x76, 0x58, 0xa1, 0xf3, 0x17, 0x19, 0x98, 0x09,
0xf6, 0x8e, 0x71, 0x90, 0xd4, 0x08, 0x07, 0x49, 0x27, 0xe5, 0x6d, 0x99, 0xf1, 0xf2, 0xb6, 0x60,
0x22, 0x96, 0x3d, 0x85, 0x44, 0x2c, 0x77, 0x0a, 0x89, 0x58, 0xfe, 0xf4, 0x13, 0xb1, 0xc2, 0xc9,
0xd9, 0xa4, 0x98, 0xc4, 0x26, 0xff, 0x01, 0x0b, 0xf1, 0xde, 0x84, 0x24, 0x28, 0xba, 0xc3, 0x53,
0xec, 0x9d, 0x47, 0xdc, 0xcb, 0x9f, 0xa6, 0xa0, 0xee, 0x0b, 0x5a, 0x27, 0x3c, 0x4f, 0x38, 0x33,
0xce, 0x79, 0x07, 0xce, 0xc7, 0xcc, 0x92, 0xef, 0x83, 0xc9, 0xe8, 0x5e, 0xfe, 0x86, 0xd0, 0xf5,
0xb6, 0xd1, 0x33, 0xec, 0xc3, 0x13, 0x2e, 0x79, 0xc2, 0x87, 0x5f, 0x00, 0x29, 0xee, 0xe1, 0x9c,
0xf9, 0xff, 0x92, 0x86, 0xf2, 0xae, 0xe6, 0x88, 0x71, 0x67, 0x97, 0x3a, 0x9c, 0xa8, 0x44, 0xde,
0x82, 0x69, 0xba, 0xed, 0x48, 0xf0, 0xd7, 0x35, 0x07, 0x4f, 0xb4, 0xdb, 0x2a, 0x62, 0x68, 0x43,
0x73, 0x30, 0xda, 0x82, 0xaa, 0x57, 0xf8, 0x66, 0xca, 0x26, 0xd9, 0x76, 0x33, 0xde, 0x60, 0xaa,
0xee, 0x06, 0xcc, 0xd9, 0x9a, 0x83, 0x3b, 0x1d, 0x83, 0x26, 0xe0, 0x07, 0x3d, 0xcd, 0x19, 0x58,
0xfc, 0xfd, 0x47, 0x41, 0x6e, 0xd3, 0xae, 0x68, 0x91, 0xff, 0x98, 0x86, 0x02, 0x7f, 0x3f, 0x99,
0x34, 0x6b, 0xf8, 0x4f, 0x28, 0xf6, 0x4d, 0xdb, 0x70, 0x04, 0x01, 0x96, 0xd7, 0xce, 0x7b, 0xbe,
0xc2, 0x75, 0xee, 0xf0, 0x0e, 0x8a, 0xdb, 0x15, 0xbd, 0x09, 0x73, 0x9e, 0xe9, 0x9e, 0xe2, 0x67,
0x9c, 0x19, 0x32, 0x71, 0xcc, 0xe0, 0xed, 0xf2, 0xbb, 0xf8, 0x19, 0x23, 0x85, 0x2b, 0x30, 0x1d,
0x18, 0xce, 0xf2, 0x3e, 0xa5, 0xe2, 0xef, 0x89, 0x56, 0x61, 0x8e, 0xbc, 0x7d, 0xf8, 0x0e, 0x31,
0xe8, 0xde, 0x67, 0x87, 0x17, 0xb3, 0xa4, 0xc9, 0x3d, 0xbd, 0x68, 0x90, 0x77, 0xb8, 0x35, 0x37,
0x9f, 0xc3, 0xba, 0xca, 0xdf, 0x6f, 0xe8, 0x08, 0x76, 0xa4, 0xea, 0x4d, 0xb8, 0x45, 0xdb, 0xe8,
0x98, 0x97, 0x21, 0x4f, 0x4f, 0x0e, 0xec, 0x7a, 0x81, 0x46, 0x9f, 0xaa, 0xb7, 0x78, 0x5a, 0x4b,
0x53, 0x78, 0xb3, 0xdc, 0x84, 0x1c, 0x15, 0xa0, 0x25, 0x28, 0xb1, 0xb3, 0x86, 0xde, 0xa0, 0x4b,
0xf1, 0xcd, 0x29, 0x45, 0x2a, 0xd8, 0x1e, 0x74, 0x91, 0x0c, 0xd9, 0x9e, 0xa9, 0x8b, 0x7c, 0x6b,
0x86, 0xe3, 0x90, 0xdf, 0x36, 0x75, 0xdc, 0x6a, 0x28, 0xb4, 0x4d, 0x6e, 0x42, 0x35, 0x84, 0x2b,
0x79, 0xdd, 0xea, 0x6b, 0x96, 0x43, 0x54, 0xee, 0xf1, 0xfa, 0x79, 0x4e, 0xa1, 0x65, 0x95, 0x6d,
0x2a, 0x21, 0xa1, 0xd9, 0xe8, 0xe9, 0xf8, 0x48, 0x1c, 0x2b, 0xd2, 0x1b, 0xf9, 0xb7, 0x29, 0x98,
0xe3, 0xaa, 0x4e, 0xf6, 0xca, 0xf4, 0x7c, 0x7c, 0xe6, 0x25, 0xa8, 0x76, 0xb5, 0x23, 0x95, 0x1e,
0x33, 0xb0, 0x22, 0x28, 0xaf, 0xa1, 0x4e, 0x77, 0xb5, 0x23, 0xaf, 0xe6, 0x29, 0xff, 0x3a, 0x05,
0xf3, 0xc1, 0x65, 0x71, 0x86, 0x7c, 0x0d, 0x40, 0xbc, 0x9e, 0xbb, 0xf3, 0x9c, 0xe5, 0xf3, 0x2c,
0x89, 0xba, 0x72, 0x43, 0x29, 0xf1, 0x4e, 0xad, 0xf8, 0xba, 0x6b, 0xfa, 0x34, 0xea, 0xae, 0x13,
0x14, 0xe1, 0x7f, 0x97, 0x76, 0x97, 0x73, 0xc2, 0x17, 0x82, 0xc9, 0xd7, 0x9f, 0xb0, 0x4d, 0xd3,
0xc7, 0xdd, 0xa6, 0x99, 0xf1, 0xb7, 0x69, 0x36, 0x69, 0x9b, 0xde, 0x81, 0xe9, 0x41, 0xbf, 0x63,
0x6a, 0xba, 0x6a, 0x61, 0x7b, 0xd0, 0x71, 0xf8, 0xf9, 0x93, 0x1c, 0x75, 0x21, 0x02, 0xea, 0xc3,
0x3e, 0x3f, 0x86, 0x19, 0x74, 0x1c, 0xa5, 0x32, 0xf0, 0xdd, 0xc9, 0xdf, 0xf2, 0x2a, 0xee, 0x91,
0xae, 0xc3, 0xb7, 0xe9, 0xcb, 0x50, 0xa0, 0x27, 0xc5, 0xee, 0x71, 0x61, 0x78, 0xa7, 0xe6, 0x49,
0x73, 0x4b, 0x47, 0xd7, 0x20, 0x7b, 0xa8, 0xd9, 0x87, 0xfc, 0xe3, 0xa6, 0x59, 0x71, 0x44, 0x46,
0x1f, 0xd7, 0xd4, 0xec, 0x43, 0x85, 0x36, 0xcb, 0xff, 0x48, 0x43, 0x85, 0x04, 0x3c, 0x61, 0x02,
0xb4, 0x16, 0xde, 0x50, 0xe5, 0xb5, 0x73, 0xbe, 0xf5, 0x79, 0xb1, 0xd1, 0xb7, 0xab, 0x42, 0x24,
0x90, 0x4e, 0x26, 0x81, 0x8c, 0x8f, 0x04, 0xa2, 0x07, 0xa0, 0xb9, 0x31, 0x0e, 0x40, 0xdf, 0x85,
0x73, 0xee, 0x29, 0xa0, 0x6f, 0x3f, 0x92, 0xd4, 0x7e, 0x8c, 0xcd, 0x31, 0x27, 0xc6, 0x7a, 0x32,
0x3b, 0x1a, 0x4e, 0x0b, 0xc7, 0x0e, 0xa7, 0x09, 0xf1, 0xaf, 0x98, 0x18, 0xff, 0x1a, 0xee, 0x31,
0x57, 0xf0, 0x1d, 0x14, 0xfd, 0x3b, 0xcc, 0xda, 0x83, 0x76, 0x1b, 0xdb, 0xf6, 0xfe, 0xa0, 0xa3,
0x72, 0xa6, 0x67, 0xde, 0x50, 0xf3, 0x1a, 0x76, 0x18, 0xc5, 0xff, 0x2a, 0xed, 0xfa, 0xd3, 0x96,
0xf6, 0x14, 0xb3, 0x28, 0xf1, 0x2f, 0xce, 0xa9, 0xcf, 0x23, 0x0e, 0x27, 0xc6, 0xd5, 0x5c, 0x62,
0x5c, 0x65, 0x65, 0xff, 0x08, 0x94, 0x3c, 0x3f, 0xfc, 0xb1, 0x77, 0xf8, 0x7b, 0x1a, 0xe9, 0xfa,
0x73, 0x41, 0x5a, 0xfe, 0xdc, 0x3b, 0x1c, 0x8e, 0xcb, 0xde, 0xbf, 0x9c, 0xb1, 0xe9, 0x67, 0xde,
0xa2, 0x4e, 0xe5, 0x35, 0x62, 0x72, 0x14, 0x6e, 0x41, 0x81, 0x85, 0x01, 0xb1, 0xf8, 0x84, 0x38,
0xe0, 0xc2, 0x4d, 0xe2, 0x80, 0x18, 0x12, 0x09, 0x01, 0xfe, 0x5e, 0xcf, 0x37, 0x04, 0x2c, 0xc3,
0x52, 0x2c, 0x90, 0xdc, 0xe5, 0x3f, 0x4b, 0x01, 0xe2, 0xed, 0x27, 0xaa, 0x17, 0x4d, 0xe8, 0xeb,
0x1b, 0x50, 0x65, 0x15, 0x21, 0x75, 0x7c, 0x97, 0x9f, 0x61, 0x23, 0xdc, 0xe4, 0xd4, 0x2d, 0x0b,
0x65, 0x7c, 0x65, 0x21, 0xf9, 0x89, 0x9b, 0x7a, 0x06, 0x8a, 0x39, 0x37, 0x82, 0xc5, 0x9c, 0xe8,
0x63, 0xc6, 0xa9, 0xe6, 0x78, 0x19, 0xb2, 0x5b, 0xcd, 0xf1, 0x6f, 0xda, 0xd4, 0xf8, 0x9b, 0xf6,
0xa7, 0x29, 0xf7, 0x83, 0x83, 0xd0, 0x67, 0x26, 0x5f, 0x06, 0xe8, 0xe5, 0x9f, 0x64, 0xbc, 0xcf,
0x1c, 0x42, 0x1f, 0xa4, 0x7c, 0x39, 0x09, 0x27, 0x39, 0x96, 0x64, 0x93, 0xdf, 0xd1, 0x2e, 0x43,
0x25, 0xe6, 0xeb, 0xb5, 0xb2, 0xed, 0x3b, 0x90, 0x4b, 0x08, 0x83, 0xf9, 0xe3, 0x86, 0xc1, 0x42,
0x4c, 0x18, 0x7c, 0x15, 0xb2, 0x3d, 0x7c, 0x24, 0x4e, 0x36, 0x87, 0x58, 0x91, 0x76, 0x93, 0x3f,
0x84, 0xca, 0x86, 0xe6, 0xb4, 0x0f, 0x8f, 0xed, 0x6f, 0xff, 0x05, 0x45, 0x8b, 0x35, 0x88, 0xdd,
0x24, 0xf9, 0xbe, 0x01, 0xf5, 0xa9, 0xa6, 0xdb, 0xc9, 0xed, 0x2b, 0xff, 0x09, 0xa0, 0x16, 0x6e,
0x46, 0x0d, 0x98, 0xe6, 0xc7, 0xf8, 0xac, 0xd4, 0xc8, 0x37, 0xd1, 0x72, 0xf8, 0xab, 0xd2, 0xc0,
0x97, 0xe0, 0xcd, 0x29, 0xa5, 0xb2, 0xe7, 0x13, 0xa3, 0x9b, 0xc0, 0x4f, 0xfe, 0xd5, 0x03, 0xec,
0x7d, 0x76, 0x1e, 0x52, 0xe1, 0x55, 0xfb, 0x9b, 0x53, 0x4a, 0x69, 0x4f, 0xc8, 0x7c, 0x53, 0xd0,
0x29, 0x37, 0x72, 0x46, 0x8d, 0x4c, 0x21, 0x10, 0x82, 0xbc, 0x29, 0x30, 0x31, 0xfa, 0x1f, 0xf7,
0x7b, 0x84, 0x8e, 0x61, 0x3b, 0x6e, 0xcd, 0x27, 0xe6, 0xe3, 0x58, 0x4f, 0x03, 0x9f, 0x34, 0x11,
0xa2, 0xaf, 0xc0, 0x02, 0x1f, 0x6f, 0x63, 0x47, 0xd5, 0xbc, 0xef, 0x12, 0x78, 0xf9, 0xe7, 0x5a,
0x58, 0x55, 0xec, 0xa7, 0x14, 0xcd, 0x29, 0x65, 0x7e, 0x2f, 0xa6, 0x19, 0xad, 0x43, 0x85, 0x57,
0xcb, 0xf7, 0x48, 0x92, 0xc0, 0xcb, 0x40, 0x17, 0xc2, 0xa5, 0x63, 0xff, 0xeb, 0x7a, 0x73, 0x4a,
0x29, 0x9b, 0x9e, 0x94, 0xe0, 0xc4, 0x55, 0xb4, 0x69, 0x32, 0xcb, 0x13, 0xe9, 0xe5, 0xb0, 0x8e,
0xc0, 0xcb, 0x24, 0xc1, 0xc9, 0xf4, 0x89, 0x89, 0xa9, 0xb8, 0x16, 0x62, 0xaa, 0x62, 0xd8, 0x54,
0xe1, 0x83, 0x19, 0x62, 0x2a, 0x53, 0xc8, 0x08, 0xc8, 0x7c, 0x30, 0x05, 0xb9, 0x14, 0x06, 0x39,
0x72, 0xf0, 0x41, 0x40, 0x36, 0x5d, 0x21, 0x7a, 0x00, 0x73, 0x7e, 0x14, 0x84, 0xc1, 0x81, 0xea,
0x91, 0x63, 0xc1, 0x08, 0x5b, 0x7d, 0xd6, 0x0c, 0xb7, 0xa1, 0x47, 0x30, 0xcf, 0xb5, 0xee, 0xd3,
0x10, 0x2b, 0xd4, 0x96, 0xa9, 0xda, 0x2b, 0x61, 0xb5, 0x31, 0x09, 0x4d, 0x73, 0x4a, 0x41, 0x66,
0xa4, 0x91, 0x20, 0x2e, 0x08, 0x86, 0x59, 0xad, 0x12, 0x46, 0x3c, 0xa6, 0xca, 0x42, 0x10, 0xb7,
0x7d, 0x62, 0x74, 0x07, 0x66, 0x84, 0x16, 0x6e, 0x38, 0x76, 0x86, 0x7f, 0x31, 0xa2, 0x26, 0x6c,
0x39, 0xf1, 0x74, 0x6e, 0xba, 0x07, 0x30, 0x27, 0x14, 0x75, 0xb5, 0xa7, 0x98, 0xd3, 0x24, 0x3d,
0xc5, 0x8f, 0x4b, 0x8f, 0x22, 0xef, 0x2a, 0x04, 0x3d, 0x3b, 0xdc, 0x46, 0xd0, 0x0b, 0x2c, 0x52,
0xa0, 0x57, 0x0d, 0xa3, 0x97, 0x98, 0x99, 0x13, 0xf4, 0xec, 0x48, 0x23, 0x7a, 0x02, 0xe7, 0x84,
0xe2, 0xa0, 0x5d, 0x6a, 0x54, 0xf3, 0xd5, 0x88, 0xe6, 0x78, 0xc3, 0x88, 0x35, 0x07, 0x2c, 0xb3,
0xee, 0x51, 0x3f, 0xf5, 0xc4, 0xd9, 0xf0, 0x76, 0x8a, 0xe6, 0x54, 0x64, 0x3b, 0xd9, 0x9e, 0x14,
0x6d, 0x41, 0x4d, 0xa8, 0xd0, 0x79, 0x0c, 0xad, 0xa3, 0xf0, 0x01, 0x56, 0x7c, 0x8e, 0xd0, 0x9c,
0x52, 0xaa, 0x76, 0xb0, 0x65, 0xa3, 0x04, 0x05, 0xde, 0x2a, 0xbf, 0x03, 0xd3, 0x9c, 0x67, 0x79,
0x48, 0xfe, 0x6f, 0x28, 0x59, 0xfc, 0x5a, 0x50, 0xf6, 0x52, 0x84, 0xb2, 0x59, 0x3b, 0xe5, 0x6c,
0xaf, 0xb7, 0xfc, 0x37, 0x80, 0xd9, 0x48, 0x07, 0xb4, 0x19, 0xcf, 0xda, 0x17, 0x93, 0x58, 0x9b,
0x0d, 0x8d, 0xd0, 0xf6, 0xad, 0x18, 0xda, 0x5e, 0x8a, 0xa5, 0x6d, 0x57, 0x81, 0x8f, 0xb7, 0x37,
0xe3, 0x79, 0xfb, 0x62, 0x12, 0x6f, 0x87, 0x27, 0xc1, 0x4d, 0xf9, 0x56, 0x1c, 0x71, 0x5f, 0x88,
0x27, 0x6e, 0x57, 0x85, 0x9f, 0xb9, 0xbf, 0x3a, 0x82, 0xb9, 0x5f, 0x1a, 0xc5, 0xdc, 0xae, 0xd6,
0x78, 0xea, 0xde, 0x88, 0xa5, 0xee, 0xe5, 0x04, 0xea, 0x76, 0x95, 0x05, 0xb8, 0x7b, 0x33, 0x9e,
0xbb, 0x2f, 0x26, 0x71, 0xb7, 0x87, 0x55, 0x80, 0xbc, 0x6f, 0xc5, 0x90, 0xf7, 0x52, 0x2c, 0x79,
0x7b, 0x06, 0xf3, 0xd8, 0xfb, 0xad, 0x38, 0xf6, 0xbe, 0x10, 0xcf, 0xde, 0x1e, 0xd2, 0x3e, 0xfa,
0x7e, 0x38, 0x8c, 0xbe, 0xaf, 0x0c, 0xa5, 0x6f, 0x57, 0x5f, 0x0c, 0x7f, 0x3f, 0x1e, 0xca, 0xdf,
0x57, 0x87, 0xf3, 0xb7, 0xab, 0x38, 0x8e, 0xc0, 0x37, 0xe3, 0x09, 0xfc, 0x62, 0x12, 0x81, 0x7b,
0xb0, 0x07, 0x18, 0xbc, 0x99, 0xc0, 0xe0, 0x2b, 0x89, 0x0c, 0xee, 0x2a, 0x0a, 0x51, 0xf8, 0xc3,
0x61, 0x14, 0x7e, 0x65, 0x28, 0x85, 0x7b, 0x08, 0x46, 0x39, 0xfc, 0xf1, 0x50, 0x0e, 0xbf, 0x3a,
0x9c, 0xc3, 0x3d, 0x04, 0x63, 0x48, 0xfc, 0xff, 0x87, 0x93, 0xf8, 0xb5, 0x11, 0x24, 0xee, 0xea,
0x8e, 0x65, 0xf1, 0x8d, 0x58, 0x16, 0x5f, 0x4e, 0x60, 0x71, 0x6f, 0x67, 0xf9, 0x69, 0x7c, 0x3b,
0x91, 0xc6, 0x2f, 0x0f, 0xa1, 0x71, 0x57, 0x57, 0x84, 0xc7, 0x01, 0x8a, 0xa2, 0x79, 0xed, 0xaf,
0xb3, 0x50, 0xdc, 0xe2, 0x3a, 0xd0, 0x16, 0x54, 0x18, 0x6d, 0xf2, 0x7f, 0x66, 0x87, 0xa7, 0xc8,
0xd2, 0x08, 0x2e, 0x46, 0x0d, 0x28, 0xdd, 0xc1, 0x0e, 0xd7, 0x35, 0x24, 0x57, 0x96, 0x86, 0x11,
0x32, 0x99, 0x14, 0xc3, 0x32, 0x69, 0x52, 0x81, 0x68, 0x2a, 0x8d, 0xe0, 0x66, 0xd4, 0x84, 0x32,
0x01, 0x95, 0xb5, 0xd9, 0x68, 0x58, 0xfa, 0x2c, 0x0d, 0xa5, 0x68, 0x84, 0x61, 0x7e, 0x57, 0x2c,
0xcf, 0x4f, 0xa6, 0xe3, 0xa5, 0xd1, 0xd2, 0x98, 0x9c, 0x8d, 0xde, 0x81, 0x32, 0xf5, 0x56, 0xfe,
0xad, 0xee, 0xd0, 0x7c, 0x5a, 0x1a, 0x4e, 0xd9, 0xd4, 0xc0, 0x74, 0x97, 0x72, 0x65, 0xc3, 0x13,
0x6b, 0x69, 0x04, 0x77, 0x73, 0x03, 0x73, 0x5d, 0x43, 0x32, 0x6c, 0x69, 0x18, 0x81, 0x0b, 0x8b,
0xb0, 0x86, 0x80, 0x45, 0x22, 0xb9, 0xb6, 0x34, 0x94, 0xca, 0xd1, 0xfb, 0x30, 0xeb, 0xdb, 0xd8,
0x7c, 0x5e, 0x63, 0xe4, 0xdc, 0xd2, 0x38, 0xc4, 0x8e, 0x54, 0x40, 0xfe, 0xad, 0xcd, 0xd5, 0x8f,
0x93, 0x7b, 0x4b, 0x63, 0x11, 0x3c, 0xb1, 0x0e, 0x7d, 0xae, 0x38, 0xce, 0x1e, 0x9e, 0x84, 0x4b,
0x23, 0x28, 0x1e, 0xed, 0xc0, 0x34, 0xb3, 0x97, 0xd0, 0x37, 0x22, 0x1b, 0x97, 0x46, 0x71, 0x3d,
0xc1, 0xd7, 0x63, 0x64, 0xa1, 0x75, 0x8c, 0xac, 0x5c, 0x1a, 0x87, 0xf6, 0x09, 0xbe, 0x3e, 0xd8,
0x85, 0xfa, 0x71, 0xb2, 0x73, 0x69, 0x2c, 0xfa, 0x47, 0x7b, 0x30, 0xe7, 0xc7, 0x5d, 0x3c, 0x61,
0xac, 0x2c, 0x5d, 0x1a, 0x2f, 0x0c, 0xa0, 0xbb, 0x50, 0xf1, 0xff, 0x23, 0x81, 0x86, 0xe6, 0xeb,
0xd2, 0xf0, 0x38, 0x80, 0xde, 0x83, 0xaa, 0x20, 0x6d, 0x31, 0xd9, 0x91, 0x89, 0xbb, 0x34, 0x3a,
0x26, 0xa0, 0x37, 0x20, 0x47, 0x13, 0x6e, 0xb4, 0x10, 0x5f, 0x55, 0x91, 0x16, 0x13, 0x52, 0x77,
0xf4, 0x08, 0x6a, 0x8c, 0xe4, 0xb9, 0xea, 0xfb, 0x1d, 0x3d, 0x66, 0x4a, 0xa1, 0xbf, 0x48, 0x63,
0xa6, 0x14, 0xf9, 0x2b, 0xf2, 0xff, 0xa0, 0x16, 0x70, 0x56, 0x22, 0xbb, 0x3c, 0xdc, 0x5f, 0x89,
0x66, 0x79, 0x84, 0xcb, 0x12, 0x35, 0xbb, 0x30, 0xe3, 0xfb, 0xf1, 0x8a, 0x48, 0xa2, 0x8e, 0x1e,
0xfc, 0x45, 0x4c, 0xba, 0x94, 0xd0, 0xc1, 0x53, 0xaa, 0x02, 0x0a, 0x99, 0x86, 0x48, 0xaf, 0x8c,
0xb2, 0x0e, 0x51, 0x7e, 0x75, 0xa4, 0x81, 0x38, 0x20, 0x01, 0x37, 0x8d, 0x07, 0x24, 0xfc, 0x07,
0x58, 0x0c, 0x20, 0xd1, 0x3f, 0xb2, 0xde, 0x83, 0xaa, 0xdf, 0x47, 0x43, 0x36, 0x8c, 0xff, 0x4f,
0xca, 0x6f, 0xc3, 0xa4, 0xdf, 0x86, 0xde, 0x87, 0xd9, 0x60, 0x0c, 0x23, 0xc2, 0xc0, 0x84, 0xe2,
0xff, 0xcc, 0x09, 0xd2, 0x43, 0xc2, 0x0f, 0x33, 0x24, 0x0e, 0xfa, 0xfe, 0x74, 0xf1, 0x6f, 0xac,
0xe8, 0x7f, 0x34, 0xfe, 0x8d, 0x15, 0xf3, 0x7b, 0xcc, 0x46, 0xf6, 0x49, 0xba, 0xbf, 0xb7, 0x97,
0xa7, 0xe7, 0xb2, 0xaf, 0xff, 0x33, 0x00, 0x00, 0xff, 0xff, 0xef, 0x28, 0x67, 0x84, 0xf3, 0x44,
0x00, 0x00,
}
type DRPCMetainfoClient interface {

View File

@ -56,6 +56,7 @@ service Metainfo {
message RequestHeader {
bytes api_key = 1;
bytes user_agent = 2;
}
message Bucket {

View File

@ -149,7 +149,7 @@ func (client *Uplink) Shutdown() error { return nil }
// DialMetainfo dials destination with apikey and returns metainfo Client
func (client *Uplink) DialMetainfo(ctx context.Context, destination Peer, apikey *macaroon.APIKey) (*metainfo.Client, error) {
return metainfo.Dial(ctx, client.Dialer, destination.Addr(), apikey)
return metainfo.Dial(ctx, client.Dialer, destination.Addr(), apikey, "Test/1.0")
}
// DialPiecestore dials destination storagenode and returns a piecestore client.

51
private/useragent/info.go Normal file
View File

@ -0,0 +1,51 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
// Package useragent implements parts of https://tools.ietf.org/html/rfc7231#section-5.5.3 and
// https://tools.ietf.org/html/rfc2616#section-14.43
package useragent
import (
"strings"
"github.com/zeebo/errs"
)
// Error is the default error class.
var Error = errs.Class("useragent")
// Info contains parsed user agent.
type Info struct {
Product Product
Full string
}
// Product is an user agent product.
type Product struct {
Name string
Version string
}
// Parse parses user agent string to information.
func Parse(s string) (Info, error) {
if s == "" {
return Info{}, nil
}
s = strings.TrimSpace(s)
info := Info{}
info.Full = s
parts := strings.SplitN(s, " ", 2)
productTokens := strings.SplitN(parts[0], "/", 2)
if len(productTokens) >= 1 {
info.Product.Name = productTokens[0]
}
if len(productTokens) >= 2 {
info.Product.Version = productTokens[1]
}
return info, nil
}

View File

@ -0,0 +1,31 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package useragent_test
import (
"testing"
"github.com/stretchr/testify/require"
"storj.io/storj/private/useragent"
)
func TestUserAgent(t *testing.T) {
type testcase struct {
in string
info useragent.Info
}
var tests = []testcase{
{"Hello", useragent.Info{useragent.Product{"Hello", ""}, "Hello"}},
{"Hello/1.0", useragent.Info{useragent.Product{"Hello", "1.0"}, "Hello/1.0"}},
{"Hello/1.0+version#123", useragent.Info{useragent.Product{"Hello", "1.0+version#123"}, "Hello/1.0+version#123"}},
}
for _, test := range tests {
info, err := useragent.Parse(test.in)
require.NoError(t, err)
require.Equal(t, test.info, info)
}
}

View File

@ -1866,6 +1866,11 @@
"id": 1,
"name": "api_key",
"type": "bytes"
},
{
"id": 2,
"name": "user_agent",
"type": "bytes"
}
]
},

View File

@ -261,6 +261,36 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB, pointerDB metai
pb.DRPCRegisterOrders(peer.Server.DRPC(), peer.Orders.Endpoint.DRPC())
}
{ // setup marketing portal
log.Debug("Satellite API Process setting up marketing server")
peer.Marketing.PartnersService = rewards.NewPartnersService(
peer.Log.Named("partners"),
rewards.DefaultPartnersDB,
[]string{
"https://us-central-1.tardigrade.io/",
"https://asia-east-1.tardigrade.io/",
"https://europe-west-1.tardigrade.io/",
},
)
peer.Marketing.Listener, err = net.Listen("tcp", config.Marketing.Address)
if err != nil {
return nil, errs.Combine(err, peer.Close())
}
peer.Marketing.Endpoint, err = marketingweb.NewServer(
peer.Log.Named("marketing:endpoint"),
config.Marketing,
peer.DB.Rewards(),
peer.Marketing.PartnersService,
peer.Marketing.Listener,
)
if err != nil {
return nil, errs.Combine(err, peer.Close())
}
}
{ // setup metainfo
log.Debug("Satellite API Process setting up metainfo")
peer.Metainfo.Database = pointerDB
@ -274,6 +304,7 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB, pointerDB metai
peer.Orders.Service,
peer.Overlay.Service,
peer.DB.Attribution(),
peer.Marketing.PartnersService,
peer.DB.PeerIdentities(),
peer.DB.Console().APIKeys(),
peer.Accounting.ProjectUsage,
@ -401,36 +432,6 @@ func NewAPI(log *zap.Logger, full *identity.FullIdentity, db DB, pointerDB metai
}
}
{ // setup marketing portal
log.Debug("Satellite API Process setting up marketing server")
peer.Marketing.PartnersService = rewards.NewPartnersService(
peer.Log.Named("partners"),
rewards.DefaultPartnersDB,
[]string{
"https://us-central-1.tardigrade.io/",
"https://asia-east-1.tardigrade.io/",
"https://europe-west-1.tardigrade.io/",
},
)
peer.Marketing.Listener, err = net.Listen("tcp", config.Marketing.Address)
if err != nil {
return nil, errs.Combine(err, peer.Close())
}
peer.Marketing.Endpoint, err = marketingweb.NewServer(
peer.Log.Named("marketing:endpoint"),
config.Marketing,
peer.DB.Rewards(),
peer.Marketing.PartnersService,
peer.Marketing.Listener,
)
if err != nil {
return nil, errs.Combine(err, peer.Close())
}
}
{ // setup console
log.Debug("Satellite API Process setting up console")
consoleConfig := config.Console

View File

@ -28,6 +28,7 @@ import (
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/orders"
"storj.io/storj/satellite/overlay"
"storj.io/storj/satellite/rewards"
"storj.io/storj/storage"
"storj.io/storj/uplink/eestream"
"storj.io/storj/uplink/storage/meta"
@ -70,7 +71,8 @@ type Endpoint struct {
metainfo *Service
orders *orders.Service
overlay *overlay.Service
partnerinfo attribution.DB
attributions attribution.DB
partners *rewards.PartnersService
peerIdentities overlay.PeerIdentities
projectUsage *accounting.Service
apiKeys APIKeys
@ -81,7 +83,8 @@ type Endpoint struct {
}
// NewEndpoint creates new metainfo endpoint instance
func NewEndpoint(log *zap.Logger, metainfo *Service, orders *orders.Service, cache *overlay.Service, partnerinfo attribution.DB, peerIdentities overlay.PeerIdentities,
func NewEndpoint(log *zap.Logger, metainfo *Service, orders *orders.Service, cache *overlay.Service,
attributions attribution.DB, partners *rewards.PartnersService, peerIdentities overlay.PeerIdentities,
apiKeys APIKeys, projectUsage *accounting.Service, rsConfig RSConfig, satellite signing.Signer, maxCommitInterval time.Duration) *Endpoint {
// TODO do something with too many params
return &Endpoint{
@ -89,7 +92,8 @@ func NewEndpoint(log *zap.Logger, metainfo *Service, orders *orders.Service, cac
metainfo: metainfo,
orders: orders,
overlay: cache,
partnerinfo: partnerinfo,
attributions: attributions,
partners: partners,
peerIdentities: peerIdentities,
apiKeys: apiKeys,
projectUsage: projectUsage,
@ -746,62 +750,40 @@ func (endpoint *Endpoint) CreateBucket(ctx context.Context, req *pb.BucketCreate
}
// TODO set default Redundancy if not set
err = endpoint.validateRedundancy(ctx, req.GetDefaultRedundancyScheme())
if err != nil {
return nil, rpcstatus.Error(rpcstatus.InvalidArgument, err.Error())
}
// checks if bucket exists before updates it or makes a new entry
bucket, err := endpoint.metainfo.GetBucket(ctx, req.GetName(), keyInfo.ProjectID)
_, err = endpoint.metainfo.GetBucket(ctx, req.GetName(), keyInfo.ProjectID)
if err == nil {
var partnerID uuid.UUID
err = partnerID.UnmarshalJSON(req.GetPartnerId())
if err != nil {
return nil, rpcstatus.Error(rpcstatus.InvalidArgument, err.Error())
}
// partnerID not set
if partnerID.IsZero() {
return resp, rpcstatus.Error(rpcstatus.AlreadyExists, "Bucket already exists")
}
//update the bucket
bucket.PartnerID = partnerID
bucket, err = endpoint.metainfo.UpdateBucket(ctx, bucket)
pbBucket, err := convertBucketToProto(ctx, bucket)
if err != nil {
return resp, rpcstatus.Error(rpcstatus.Internal, err.Error())
}
return &pb.BucketCreateResponse{
Bucket: pbBucket,
}, nil
return nil, rpcstatus.Error(rpcstatus.AlreadyExists, "bucket already exists")
}
if !storj.ErrBucketNotFound.Has(err) {
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
}
// create the bucket
if storj.ErrBucketNotFound.Has(err) {
bucket, err := convertProtoToBucket(req, keyInfo.ProjectID)
if err != nil {
return nil, rpcstatus.Error(rpcstatus.InvalidArgument, err.Error())
}
bucket, err = endpoint.metainfo.CreateBucket(ctx, bucket)
if err != nil {
return nil, Error.Wrap(err)
}
convBucket, err := convertBucketToProto(ctx, bucket)
if err != nil {
return resp, err
}
return &pb.BucketCreateResponse{
Bucket: convBucket,
}, nil
bucket, err := convertProtoToBucket(req, keyInfo.ProjectID)
if err != nil {
return nil, rpcstatus.Error(rpcstatus.InvalidArgument, err.Error())
}
return nil, Error.Wrap(err)
bucket, err = endpoint.metainfo.CreateBucket(ctx, bucket)
if err != nil {
endpoint.log.Error("error while creating bucket", zap.String("bucketName", bucket.Name), zap.Error(err))
return nil, rpcstatus.Error(rpcstatus.Internal, "unable to create bucket")
}
convBucket, err := convertBucketToProto(ctx, bucket)
if err != nil {
endpoint.log.Error("error while converting bucket to proto", zap.String("bucketName", bucket.Name), zap.Error(err))
return nil, rpcstatus.Error(rpcstatus.Internal, "unable to create bucket")
}
return &pb.BucketCreateResponse{
Bucket: convBucket,
}, nil
}
// DeleteBucket deletes a bucket
@ -892,7 +874,30 @@ func (endpoint *Endpoint) SetBucketAttribution(ctx context.Context, req *pb.Buck
return &pb.BucketSetAttributionResponse{}, err
}
func (endpoint *Endpoint) setBucketAttribution(ctx context.Context, header *pb.RequestHeader, bucketName []byte, parterID []byte) error {
// resolvePartnerID returns partnerIDBytes as parsed or UUID corresponding to header.UserAgent.
// returns empty uuid when neither is defined.
func (endpoint *Endpoint) resolvePartnerID(ctx context.Context, header *pb.RequestHeader, partnerIDBytes []byte) (uuid.UUID, error) {
if len(partnerIDBytes) > 0 {
partnerID, err := bytesToUUID(partnerIDBytes)
if err != nil {
return uuid.UUID{}, rpcstatus.Errorf(rpcstatus.InvalidArgument, "unable to parse partner ID: %v", err)
}
return partnerID, nil
}
if len(header.UserAgent) == 0 {
return uuid.UUID{}, nil
}
partner, err := endpoint.partners.ByUserAgent(ctx, string(header.UserAgent))
if err != nil || partner.UUID == nil {
return uuid.UUID{}, rpcstatus.Errorf(rpcstatus.InvalidArgument, "unable to resolve user agent %q: %v", string(header.UserAgent), err)
}
return *partner.UUID, nil
}
func (endpoint *Endpoint) setBucketAttribution(ctx context.Context, header *pb.RequestHeader, bucketName []byte, partnerIDBytes []byte) error {
keyInfo, err := endpoint.validateAuth(ctx, header, macaroon.Action{
Op: macaroon.ActionList,
Bucket: bucketName,
@ -903,15 +908,18 @@ func (endpoint *Endpoint) setBucketAttribution(ctx context.Context, header *pb.R
return rpcstatus.Error(rpcstatus.Unauthenticated, err.Error())
}
partnerID, err := bytesToUUID(parterID)
partnerID, err := endpoint.resolvePartnerID(ctx, header, partnerIDBytes)
if err != nil {
return rpcstatus.Errorf(rpcstatus.InvalidArgument, "unable to parse partner ID: %v", err)
return rpcstatus.Error(rpcstatus.InvalidArgument, err.Error())
}
if partnerID.IsZero() {
return rpcstatus.Error(rpcstatus.InvalidArgument, "unknown user agent or partner id")
}
// check if attribution is set for given bucket
_, err = endpoint.partnerinfo.Get(ctx, keyInfo.ProjectID, bucketName)
_, err = endpoint.attributions.Get(ctx, keyInfo.ProjectID, bucketName)
if err == nil {
endpoint.log.Info("Bucket already attributed", zap.ByteString("bucketName", bucketName), zap.Stringer("Partner ID", partnerID))
endpoint.log.Info("bucket already attributed", zap.ByteString("bucketName", bucketName), zap.Stringer("Partner ID", partnerID))
return nil
}
@ -933,10 +941,33 @@ func (endpoint *Endpoint) setBucketAttribution(ctx context.Context, header *pb.R
}
if len(items) > 0 {
return rpcstatus.Errorf(rpcstatus.AlreadyExists, "Bucket %q is not empty, PartnerID %q cannot be attributed", bucketName, partnerID)
return rpcstatus.Errorf(rpcstatus.AlreadyExists, "bucket %q is not empty, PartnerID %q cannot be attributed", bucketName, partnerID)
}
_, err = endpoint.partnerinfo.Insert(ctx, &attribution.Info{
// checks if bucket exists before updates it or makes a new entry
bucket, err := endpoint.metainfo.GetBucket(ctx, bucketName, keyInfo.ProjectID)
if err != nil {
if storj.ErrBucketNotFound.Has(err) {
return rpcstatus.Errorf(rpcstatus.NotFound, "bucket %q does not exist", bucketName)
}
endpoint.log.Error("error while getting bucket", zap.ByteString("bucketName", bucketName), zap.Error(err))
return rpcstatus.Error(rpcstatus.Internal, "unable to set bucket attribution")
}
if !bucket.PartnerID.IsZero() {
endpoint.log.Info("bucket already attributed", zap.ByteString("bucketName", bucketName), zap.Stringer("Partner ID", partnerID))
return nil
}
// update bucket information
bucket.PartnerID = partnerID
_, err = endpoint.metainfo.UpdateBucket(ctx, bucket)
if err != nil {
endpoint.log.Error("error while updating bucket", zap.ByteString("bucketName", bucketName), zap.Error(err))
return rpcstatus.Error(rpcstatus.Internal, "unable to set bucket attribution")
}
// update attribution table
_, err = endpoint.attributions.Insert(ctx, &attribution.Info{
ProjectID: keyInfo.ProjectID,
BucketName: bucketName,
PartnerID: partnerID,
@ -945,6 +976,7 @@ func (endpoint *Endpoint) setBucketAttribution(ctx context.Context, header *pb.R
endpoint.log.Error("error while inserting attribution to DB", zap.Error(err))
return rpcstatus.Error(rpcstatus.Internal, err.Error())
}
return nil
}
@ -957,6 +989,7 @@ func convertProtoToBucket(req *pb.BucketCreateRequest, projectID uuid.UUID) (buc
defaultRS := req.GetDefaultRedundancyScheme()
defaultEP := req.GetDefaultEncryptionParameters()
// TODO: resolve partner id
var partnerID uuid.UUID
err = partnerID.UnmarshalJSON(req.GetPartnerId())

View File

@ -802,40 +802,43 @@ func TestSetBucketAttribution(t *testing.T) {
err := uplink.CreateBucket(ctx, planet.Satellites[0], "alpha")
require.NoError(t, err)
err = uplink.CreateBucket(ctx, planet.Satellites[0], "alpha-new")
require.NoError(t, err)
metainfoClient, err := planet.Uplinks[0].DialMetainfo(ctx, planet.Satellites[0], apiKey)
require.NoError(t, err)
defer ctx.Check(metainfoClient.Close)
partnerID := testrand.UUID()
{
// bucket with no items
{ // bucket with no items
err = metainfoClient.SetBucketAttribution(ctx, metainfo.SetBucketAttributionParams{
Bucket: "alpha",
PartnerID: partnerID,
})
require.NoError(t, err)
}
// no bucket exists
{ // setting attribution on a bucket that doesn't exist should fail
err = metainfoClient.SetBucketAttribution(ctx, metainfo.SetBucketAttributionParams{
Bucket: "beta",
PartnerID: partnerID,
})
require.NoError(t, err)
require.Error(t, err)
}
{
// already attributed bucket, adding files
{ // add data to an attributed bucket
err = planet.Uplinks[0].Upload(ctx, planet.Satellites[0], "alpha", "path", []byte{1, 2, 3})
assert.NoError(t, err)
// bucket with items
// trying to set attribution should be ignored
err = metainfoClient.SetBucketAttribution(ctx, metainfo.SetBucketAttributionParams{
Bucket: "beta",
Bucket: "alpha",
PartnerID: partnerID,
})
require.NoError(t, err)
}
{
//non attributed bucket, and adding files
{ // non attributed bucket, and adding files
err = planet.Uplinks[0].Upload(ctx, planet.Satellites[0], "alpha-new", "path", []byte{1, 2, 3})
assert.NoError(t, err)

View File

@ -8,6 +8,7 @@ import (
"os"
"strings"
"github.com/skyrings/skyring-common/tools/uuid"
"github.com/zeebo/errs"
)
@ -20,6 +21,7 @@ type PartnerList struct {
type PartnerInfo struct {
Name string
ID string
UUID *uuid.UUID
}
// UserAgent returns canonical user agent.

View File

@ -3,6 +3,8 @@
package rewards
import "github.com/skyrings/skyring-common/tools/uuid"
// DefaultPartnersDB is current default settings.
var DefaultPartnersDB = func() PartnersDB {
list := DefaultPartners()
@ -13,105 +15,145 @@ var DefaultPartnersDB = func() PartnersDB {
return db
}()
// parseUUID parse string to UUID, should be used ONLY with hardcoded partner UUID's.
func parseUUID(s string) *uuid.UUID {
u, err := uuid.Parse(s)
if err != nil {
panic(err)
}
return u
}
// DefaultPartners lists Storj default open-source partners.
func DefaultPartners() PartnerList {
return PartnerList{
Partners: []PartnerInfo{{
Name: "Blocknify",
ID: "120bf202-8252-437e-ac12-0e364bee852e",
UUID: parseUUID("120bf202-8252-437e-ac12-0e364bee852e"),
}, {
Name: "Breaker",
ID: "53688ea5-8695-4060-a2c6-b56969217909",
UUID: parseUUID("53688ea5-8695-4060-a2c6-b56969217909"),
}, {
Name: "Confluent",
ID: "2fb801c6-a6d7-4d82-a838-32fef98cc398",
UUID: parseUUID("2fb801c6-a6d7-4d82-a838-32fef98cc398"),
}, {
Name: "Consensys",
ID: "e28c8847-b323-4a7d-8111-25a0578a58bb",
UUID: parseUUID("e28c8847-b323-4a7d-8111-25a0578a58bb"),
}, {
Name: "Couchbase",
ID: "0af89ac1-0189-42c6-a47c-e169780b3818",
UUID: parseUUID("0af89ac1-0189-42c6-a47c-e169780b3818"),
}, {
Name: "Digital Ocean",
ID: "881b92f6-77aa-42ee-961a-b80009d45dd8",
UUID: parseUUID("881b92f6-77aa-42ee-961a-b80009d45dd8"),
}, {
Name: "Deloitte",
ID: "cadac3fb-6a3f-4d17-9748-cc66d0617d55",
UUID: parseUUID("cadac3fb-6a3f-4d17-9748-cc66d0617d55"),
}, {
Name: "DVLabs",
ID: "53fb82d7-73ff-4a1a-ab0c-6968cffc850e",
UUID: parseUUID("53fb82d7-73ff-4a1a-ab0c-6968cffc850e"),
}, {
Name: "Fluree",
ID: "86c33256-cded-434c-aaac-405343974394",
UUID: parseUUID("86c33256-cded-434c-aaac-405343974394"),
}, {
Name: "Flexential",
ID: "3e1b911a-c778-47ea-878c-9f3f264f8bc1",
UUID: parseUUID("3e1b911a-c778-47ea-878c-9f3f264f8bc1"),
}, {
Name: "Heroku",
ID: "706011f3-400e-45eb-a796-90cce2a7d67e",
UUID: parseUUID("706011f3-400e-45eb-a796-90cce2a7d67e"),
}, {
Name: "Infura",
ID: "1519bdee-ed18-45fe-86c6-4c7fa9668a14",
UUID: parseUUID("1519bdee-ed18-45fe-86c6-4c7fa9668a14"),
}, {
Name: "GroundX",
ID: "e56c6a65-d5bf-457a-a414-e55c36624f73",
UUID: parseUUID("e56c6a65-d5bf-457a-a414-e55c36624f73"),
}, {
Name: "MariaDB",
ID: "8ee019ef-2aae-4867-9c18-41c65ea318c4",
UUID: parseUUID("8ee019ef-2aae-4867-9c18-41c65ea318c4"),
}, {
Name: "MongoDB",
ID: "bbd340b2-0ae4-4254-af90-eaba6c273abb",
UUID: parseUUID("bbd340b2-0ae4-4254-af90-eaba6c273abb"),
}, {
Name: "Netki",
ID: "3405a882-0cb2-4f91-a6e0-21be193b80e5",
UUID: parseUUID("3405a882-0cb2-4f91-a6e0-21be193b80e5"),
}, {
Name: "FileZilla",
ID: "a1ba07a4-e095-4a43-914c-1d56c9ff5afd",
UUID: parseUUID("a1ba07a4-e095-4a43-914c-1d56c9ff5afd"),
}, {
Name: "InfluxDB",
ID: "e50a17b3-4d82-4da7-8719-09312a83685d",
UUID: parseUUID("e50a17b3-4d82-4da7-8719-09312a83685d"),
}, {
Name: "Mysterium Network",
ID: "c10228c2-af70-4e4d-be49-e8bfbe9ca8ef",
UUID: parseUUID("c10228c2-af70-4e4d-be49-e8bfbe9ca8ef"),
}, {
Name: "Kafka",
ID: "OSPP005",
}, {
Name: "Minio",
ID: "5bffe844-5da7-4aa9-bf37-7d695cf819f2",
UUID: parseUUID("5bffe844-5da7-4aa9-bf37-7d695cf819f2"),
}, {
Name: "Nextcloud",
ID: "42f588fb-f39d-4886-81af-b614ca16ce37",
UUID: parseUUID("42f588fb-f39d-4886-81af-b614ca16ce37"),
}, {
Name: "Node Haven",
ID: "3b53a9b3-2005-476c-9ffd-894ed832abe4",
UUID: parseUUID("3b53a9b3-2005-476c-9ffd-894ed832abe4"),
}, {
Name: "Plesk",
ID: "dc01ed96-2990-4819-9cb3-45d4846b9ad1",
UUID: parseUUID("dc01ed96-2990-4819-9cb3-45d4846b9ad1"),
}, {
Name: "Pydio",
ID: "b02b9f0d-fac7-439c-8ba2-0c4634d5826f",
UUID: parseUUID("b02b9f0d-fac7-439c-8ba2-0c4634d5826f"),
}, {
Name: "Raiden Network",
ID: "57855387-5a58-4a2b-97d2-15b1d76eea3c",
UUID: parseUUID("57855387-5a58-4a2b-97d2-15b1d76eea3c"),
}, {
Name: "Satoshi Soup",
ID: "4400d796-3777-4964-8536-22a4ae439ed3",
UUID: parseUUID("4400d796-3777-4964-8536-22a4ae439ed3"),
}, {
Name: "Sirin Labs",
ID: "6e40f882-ef77-4a5d-b5ad-18525d3df023",
UUID: parseUUID("6e40f882-ef77-4a5d-b5ad-18525d3df023"),
}, {
Name: "Status Messenger",
ID: "b6114126-c06d-49f9-8d23-3e0dd2e350ab",
UUID: parseUUID("b6114126-c06d-49f9-8d23-3e0dd2e350ab"),
}, {
Name: "Temporal",
ID: "aeedbe32-1519-4320-b2f4-33725c65af54",
UUID: parseUUID("aeedbe32-1519-4320-b2f4-33725c65af54"),
}, {
Name: "Terminal.co",
ID: "7bf23e53-6393-4bd0-8bf9-53ecf0de742f",
UUID: parseUUID("7bf23e53-6393-4bd0-8bf9-53ecf0de742f"),
}, {
Name: "Zenko",
ID: "8cd605fa-ad00-45b6-823e-550eddc611d6",
UUID: parseUUID("8cd605fa-ad00-45b6-823e-550eddc611d6"),
}},
}
}

View File

@ -10,6 +10,8 @@ import (
"github.com/zeebo/errs"
"go.uber.org/zap"
"storj.io/storj/private/useragent"
)
var (
@ -100,11 +102,21 @@ func (service *PartnersService) GetActiveOffer(ctx context.Context, offers Offer
return offer, nil
}
// PartnerByName looks up partner by name.
func (service *PartnersService) PartnerByName(ctx context.Context, name string) (PartnerInfo, error) {
// ByName looks up partner by name.
func (service *PartnersService) ByName(ctx context.Context, name string) (PartnerInfo, error) {
return service.db.ByName(ctx, name)
}
// ByUserAgent looks up partner by user agent.
func (service *PartnersService) ByUserAgent(ctx context.Context, userAgentString string) (PartnerInfo, error) {
info, err := useragent.Parse(userAgentString)
if err != nil {
return PartnerInfo{}, ErrPartners.Wrap(err)
}
return service.db.ByName(ctx, info.Product.Name)
}
// All returns all partners.
func (service *PartnersService) All(ctx context.Context) ([]PartnerInfo, error) {
return service.db.All(ctx)

View File

@ -71,7 +71,7 @@ func TestOffer_Database(t *testing.T) {
require.NoError(t, err)
var pID string
if new.Type == rewards.Partner {
partner, err := planet.Satellites[0].API.Marketing.PartnersService.PartnerByName(ctx, new.Name)
partner, err := planet.Satellites[0].API.Marketing.PartnersService.ByName(ctx, new.Name)
require.NoError(t, err)
pID = partner.ID
}

View File

@ -32,6 +32,8 @@ type Client struct {
conn *rpc.Conn
client rpc.MetainfoClient
apiKeyRaw []byte
userAgent string
}
// ListItem is a single item in a listing
@ -42,15 +44,17 @@ type ListItem struct {
}
// New used as a public function
func New(client rpc.MetainfoClient, apiKey *macaroon.APIKey) *Client {
func New(client rpc.MetainfoClient, apiKey *macaroon.APIKey, userAgent string) *Client {
return &Client{
client: client,
apiKeyRaw: apiKey.SerializeRaw(),
userAgent: userAgent,
}
}
// Dial dials to metainfo endpoint with the specified api key.
func Dial(ctx context.Context, dialer rpc.Dialer, address string, apiKey *macaroon.APIKey) (*Client, error) {
func Dial(ctx context.Context, dialer rpc.Dialer, address string, apiKey *macaroon.APIKey, userAgent string) (*Client, error) {
conn, err := dialer.DialAddressInsecureBestEffort(ctx, address)
if err != nil {
return nil, Error.Wrap(err)
@ -60,6 +64,7 @@ func Dial(ctx context.Context, dialer rpc.Dialer, address string, apiKey *macaro
conn: conn,
client: conn.MetainfoClient(),
apiKeyRaw: apiKey.SerializeRaw(),
userAgent: userAgent,
}, nil
}
@ -73,7 +78,8 @@ func (client *Client) Close() error {
func (client *Client) header() *pb.RequestHeader {
return &pb.RequestHeader{
ApiKey: client.apiKeyRaw,
ApiKey: client.apiKeyRaw,
UserAgent: []byte(client.userAgent),
}
}
@ -353,10 +359,15 @@ type SetBucketAttributionParams struct {
}
func (params *SetBucketAttributionParams) toRequest(header *pb.RequestHeader) *pb.BucketSetAttributionRequest {
var bytes []byte
if !params.PartnerID.IsZero() {
bytes = params.PartnerID[:]
}
return &pb.BucketSetAttributionRequest{
Header: header,
Name: []byte(params.Bucket),
PartnerId: params.PartnerID[:],
PartnerId: bytes,
}
}