broker: append message logs

This commit is contained in:
Chris Lu 2020-04-17 02:29:38 -07:00
parent 2a45897237
commit 3f3dba5a68
4 changed files with 230 additions and 79 deletions

View file

@ -0,0 +1,116 @@
package messaging
import (
"context"
"fmt"
"time"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/operation"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"github.com/chrislusf/seaweedfs/weed/pb/messaging_pb"
"github.com/chrislusf/seaweedfs/weed/security"
"github.com/chrislusf/seaweedfs/weed/util"
)
func (broker *MessageBroker) appendToFile(targetFile string, topicConfig *messaging_pb.TopicConfiguration, data []byte) error {
assignResult, uploadResult, err2 := broker.assignAndUpload(topicConfig, data)
if err2 != nil {
return err2
}
dir, name := util.FullPath(targetFile).DirAndName()
chunk := &filer_pb.FileChunk{
FileId: assignResult.Fid,
Offset: 0, // needs to be fixed during appending
Size: uint64(uploadResult.Size),
Mtime: time.Now().UnixNano(),
ETag: uploadResult.ETag,
IsGzipped: uploadResult.Gzip > 0,
}
// append the chunk
if err := broker.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.AppendToEntryRequest{
Directory: dir,
EntryName: name,
Chunks: []*filer_pb.FileChunk{chunk},
}
_, err := client.AppendToEntry(context.Background(), request)
if err != nil {
glog.V(0).Infof("append to file %v: %v", request, err)
return err
}
return nil
}); err != nil {
return fmt.Errorf("append to file %v: %v", targetFile, err)
}
return nil
}
func (broker *MessageBroker) assignAndUpload(topicConfig *messaging_pb.TopicConfiguration, data []byte) (*operation.AssignResult, *operation.UploadResult, error) {
var assignResult = &operation.AssignResult{}
var collection, replication string
// assign a volume location
if err := broker.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.AssignVolumeRequest{
Count: 1,
Replication: topicConfig.Replication,
Collection: topicConfig.Collection,
}
resp, err := client.AssignVolume(context.Background(), request)
if err != nil {
glog.V(0).Infof("assign volume failure %v: %v", request, err)
return err
}
if resp.Error != "" {
return fmt.Errorf("assign volume failure %v: %v", request, resp.Error)
}
assignResult.Auth = security.EncodedJwt(resp.Auth)
assignResult.Fid = resp.FileId
assignResult.Url = resp.Url
assignResult.PublicUrl = resp.PublicUrl
assignResult.Count = uint64(resp.Count)
collection, replication = resp.Collection, resp.Replication
return nil
}); err != nil {
return nil, nil, err
}
// upload data
targetUrl := fmt.Sprintf("http://%s/%s", assignResult.Url, assignResult.Fid)
uploadResult, err := operation.UploadData(targetUrl, "", broker.option.Cipher, data, false, "", nil, assignResult.Auth)
if err != nil {
return nil, nil, fmt.Errorf("upload data %s: %v", targetUrl, err)
}
// println("uploaded to", targetUrl)
return assignResult, uploadResult, nil
}
func (broker *MessageBroker) WithFilerClient(fn func(filer_pb.SeaweedFilerClient) error) (err error) {
for _, filer := range broker.option.Filers {
if err = pb.WithFilerClient(filer, broker.grpcDialOption, fn); err != nil {
glog.V(0).Infof("fail to connect to %s: %v", filer, err)
} else {
break
}
}
return
}

View file

@ -32,6 +32,11 @@ func (broker *MessageBroker) Publish(stream messaging_pb.SeaweedMessaging_Publis
updatesChan := make(chan int32) updatesChan := make(chan int32)
// TODO look it up
topicConfig := &messaging_pb.TopicConfiguration{
}
go func() { go func() {
for update := range updatesChan { for update := range updatesChan {
if err := stream.Send(&messaging_pb.PublishResponse{ if err := stream.Send(&messaging_pb.PublishResponse{
@ -47,18 +52,16 @@ func (broker *MessageBroker) Publish(stream messaging_pb.SeaweedMessaging_Publis
logBuffer := log_buffer.NewLogBuffer(time.Minute, func(startTime, stopTime time.Time, buf []byte) { logBuffer := log_buffer.NewLogBuffer(time.Minute, func(startTime, stopTime time.Time, buf []byte) {
//targetFile := targetFile := fmt.Sprintf(
fmt.Sprintf("%s/%s/%s/%04d-%02d-%02d/%02d-%02d.part%02d", "%s/%s/%s/%04d-%02d-%02d/%02d-%02d.part%02d",
filer2.TopicsDir, namespace, topic, filer2.TopicsDir, namespace, topic,
startTime.Year(), startTime.Month(), startTime.Day(), startTime.Hour(), startTime.Minute(), startTime.Year(), startTime.Month(), startTime.Day(), startTime.Hour(), startTime.Minute(),
partition, partition,
) )
/* if err := broker.appendToFile(targetFile, topicConfig, buf); err != nil {
if err := f.appendToFile(targetFile, buf); err != nil { glog.V(0).Infof("log write failed %s: %v", targetFile, err)
glog.V(0).Infof("log write failed %s: %v", targetFile, err) }
}
*/
}, func() { }, func() {
// notify subscribers // notify subscribers

View file

@ -90,8 +90,7 @@ message PublishResponse {
message ConfigureTopicRequest { message ConfigureTopicRequest {
string namespace = 1; string namespace = 1;
string topic = 2; string topic = 2;
int32 partition_count = 3; TopicConfiguration configuration = 3;
string collection = 4;
} }
message ConfigureTopicResponse { message ConfigureTopicResponse {
} }
@ -101,5 +100,11 @@ message GetTopicConfigurationRequest {
string topic = 2; string topic = 2;
} }
message GetTopicConfigurationResponse { message GetTopicConfigurationResponse {
int32 partitions = 3; TopicConfiguration configuration = 1;
}
message TopicConfiguration {
int32 partition_count = 1;
string collection = 2;
string replication = 3;
} }

View file

@ -18,6 +18,7 @@ It has these top-level messages:
ConfigureTopicResponse ConfigureTopicResponse
GetTopicConfigurationRequest GetTopicConfigurationRequest
GetTopicConfigurationResponse GetTopicConfigurationResponse
TopicConfiguration
*/ */
package messaging_pb package messaging_pb
@ -396,10 +397,9 @@ func (m *PublishResponse_RedirectMessage) GetNewBroker() string {
} }
type ConfigureTopicRequest struct { type ConfigureTopicRequest struct {
Namespace string `protobuf:"bytes,1,opt,name=namespace" json:"namespace,omitempty"` Namespace string `protobuf:"bytes,1,opt,name=namespace" json:"namespace,omitempty"`
Topic string `protobuf:"bytes,2,opt,name=topic" json:"topic,omitempty"` Topic string `protobuf:"bytes,2,opt,name=topic" json:"topic,omitempty"`
PartitionCount int32 `protobuf:"varint,3,opt,name=partition_count,json=partitionCount" json:"partition_count,omitempty"` Configuration *TopicConfiguration `protobuf:"bytes,3,opt,name=configuration" json:"configuration,omitempty"`
Collection string `protobuf:"bytes,4,opt,name=collection" json:"collection,omitempty"`
} }
func (m *ConfigureTopicRequest) Reset() { *m = ConfigureTopicRequest{} } func (m *ConfigureTopicRequest) Reset() { *m = ConfigureTopicRequest{} }
@ -421,18 +421,11 @@ func (m *ConfigureTopicRequest) GetTopic() string {
return "" return ""
} }
func (m *ConfigureTopicRequest) GetPartitionCount() int32 { func (m *ConfigureTopicRequest) GetConfiguration() *TopicConfiguration {
if m != nil { if m != nil {
return m.PartitionCount return m.Configuration
} }
return 0 return nil
}
func (m *ConfigureTopicRequest) GetCollection() string {
if m != nil {
return m.Collection
}
return ""
} }
type ConfigureTopicResponse struct { type ConfigureTopicResponse struct {
@ -468,7 +461,7 @@ func (m *GetTopicConfigurationRequest) GetTopic() string {
} }
type GetTopicConfigurationResponse struct { type GetTopicConfigurationResponse struct {
Partitions int32 `protobuf:"varint,3,opt,name=partitions" json:"partitions,omitempty"` Configuration *TopicConfiguration `protobuf:"bytes,1,opt,name=configuration" json:"configuration,omitempty"`
} }
func (m *GetTopicConfigurationResponse) Reset() { *m = GetTopicConfigurationResponse{} } func (m *GetTopicConfigurationResponse) Reset() { *m = GetTopicConfigurationResponse{} }
@ -476,13 +469,45 @@ func (m *GetTopicConfigurationResponse) String() string { return prot
func (*GetTopicConfigurationResponse) ProtoMessage() {} func (*GetTopicConfigurationResponse) ProtoMessage() {}
func (*GetTopicConfigurationResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } func (*GetTopicConfigurationResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *GetTopicConfigurationResponse) GetPartitions() int32 { func (m *GetTopicConfigurationResponse) GetConfiguration() *TopicConfiguration {
if m != nil { if m != nil {
return m.Partitions return m.Configuration
}
return nil
}
type TopicConfiguration struct {
PartitionCount int32 `protobuf:"varint,1,opt,name=partition_count,json=partitionCount" json:"partition_count,omitempty"`
Collection string `protobuf:"bytes,2,opt,name=collection" json:"collection,omitempty"`
Replication string `protobuf:"bytes,3,opt,name=replication" json:"replication,omitempty"`
}
func (m *TopicConfiguration) Reset() { *m = TopicConfiguration{} }
func (m *TopicConfiguration) String() string { return proto.CompactTextString(m) }
func (*TopicConfiguration) ProtoMessage() {}
func (*TopicConfiguration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
func (m *TopicConfiguration) GetPartitionCount() int32 {
if m != nil {
return m.PartitionCount
} }
return 0 return 0
} }
func (m *TopicConfiguration) GetCollection() string {
if m != nil {
return m.Collection
}
return ""
}
func (m *TopicConfiguration) GetReplication() string {
if m != nil {
return m.Replication
}
return ""
}
func init() { func init() {
proto.RegisterType((*SubscriberMessage)(nil), "messaging_pb.SubscriberMessage") proto.RegisterType((*SubscriberMessage)(nil), "messaging_pb.SubscriberMessage")
proto.RegisterType((*SubscriberMessage_InitMessage)(nil), "messaging_pb.SubscriberMessage.InitMessage") proto.RegisterType((*SubscriberMessage_InitMessage)(nil), "messaging_pb.SubscriberMessage.InitMessage")
@ -500,6 +525,7 @@ func init() {
proto.RegisterType((*ConfigureTopicResponse)(nil), "messaging_pb.ConfigureTopicResponse") proto.RegisterType((*ConfigureTopicResponse)(nil), "messaging_pb.ConfigureTopicResponse")
proto.RegisterType((*GetTopicConfigurationRequest)(nil), "messaging_pb.GetTopicConfigurationRequest") proto.RegisterType((*GetTopicConfigurationRequest)(nil), "messaging_pb.GetTopicConfigurationRequest")
proto.RegisterType((*GetTopicConfigurationResponse)(nil), "messaging_pb.GetTopicConfigurationResponse") proto.RegisterType((*GetTopicConfigurationResponse)(nil), "messaging_pb.GetTopicConfigurationResponse")
proto.RegisterType((*TopicConfiguration)(nil), "messaging_pb.TopicConfiguration")
proto.RegisterEnum("messaging_pb.SubscriberMessage_InitMessage_StartPosition", SubscriberMessage_InitMessage_StartPosition_name, SubscriberMessage_InitMessage_StartPosition_value) proto.RegisterEnum("messaging_pb.SubscriberMessage_InitMessage_StartPosition", SubscriberMessage_InitMessage_StartPosition_name, SubscriberMessage_InitMessage_StartPosition_value)
} }
@ -742,56 +768,57 @@ var _SeaweedMessaging_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("messaging.proto", fileDescriptor0) } func init() { proto.RegisterFile("messaging.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 802 bytes of a gzipped FileDescriptorProto // 829 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x56, 0x5d, 0x4f, 0xdb, 0x48, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x56, 0x4d, 0x8f, 0xe3, 0x44,
0x14, 0xc5, 0x76, 0x12, 0xf0, 0xcd, 0xe7, 0x8e, 0x96, 0x55, 0xe4, 0x05, 0x36, 0x32, 0x2b, 0x6d, 0x10, 0xdd, 0xb6, 0x93, 0xcc, 0xba, 0xf2, 0x49, 0x8b, 0x41, 0x91, 0x99, 0x01, 0xcb, 0x8b, 0x44,
0xb6, 0xa8, 0x16, 0x4a, 0x55, 0x89, 0x22, 0x24, 0x94, 0xd0, 0x88, 0x46, 0x22, 0x25, 0x9a, 0xe4, 0x60, 0x84, 0x35, 0x0a, 0x42, 0x1a, 0x56, 0x2b, 0xa1, 0x24, 0x84, 0x25, 0xd2, 0x84, 0x8d, 0x3a,
0xb5, 0x8a, 0x26, 0xce, 0x00, 0x56, 0x12, 0x3b, 0xf5, 0x4c, 0x8a, 0x78, 0x6e, 0x5f, 0xfb, 0xd6, 0xb9, 0xa2, 0xc8, 0x71, 0x7a, 0xb3, 0x56, 0x12, 0xdb, 0xb8, 0x3b, 0x8c, 0xe6, 0xc4, 0x01, 0xae,
0x5f, 0x52, 0xa9, 0x3f, 0xa0, 0x7d, 0xef, 0x7f, 0xaa, 0x3c, 0xfe, 0x88, 0x1d, 0x42, 0xa0, 0x48, 0x9c, 0xf8, 0x27, 0x48, 0xfc, 0x00, 0xb8, 0xf3, 0x9f, 0x90, 0xdb, 0xdf, 0x49, 0x26, 0x13, 0x22,
0xbc, 0xd9, 0xd7, 0xe7, 0xdc, 0x73, 0xe7, 0xde, 0x33, 0xe3, 0x81, 0xe2, 0x84, 0x32, 0x46, 0x2e, 0xcd, 0xcd, 0x2e, 0xbf, 0x7a, 0xaf, 0xba, 0xea, 0x95, 0x6d, 0xa8, 0xaf, 0x29, 0x63, 0xe6, 0xc2,
0x2d, 0xfb, 0xd2, 0x98, 0xba, 0x0e, 0x77, 0x50, 0x2e, 0x0a, 0xf4, 0xa7, 0x03, 0xfd, 0x63, 0x0a, 0x76, 0x16, 0x86, 0xe7, 0xbb, 0xdc, 0xc5, 0x95, 0x24, 0x30, 0xf5, 0x66, 0xfa, 0xaf, 0x05, 0x78,
0xfe, 0xe8, 0xce, 0x06, 0xcc, 0x74, 0xad, 0x01, 0x75, 0xdb, 0xe2, 0x13, 0x45, 0xc7, 0x90, 0xb2, 0x6f, 0xbc, 0x99, 0x31, 0xcb, 0xb7, 0x67, 0xd4, 0x1f, 0x8a, 0x47, 0x14, 0x7f, 0x03, 0x05, 0xdb,
0x6c, 0x8b, 0x97, 0xa5, 0x8a, 0x54, 0xcd, 0xd6, 0xf6, 0x8c, 0x38, 0xc5, 0xb8, 0x05, 0x37, 0x5a, 0xb1, 0x79, 0x13, 0x69, 0xa8, 0x55, 0x6e, 0x5f, 0x19, 0xd9, 0x14, 0x63, 0x07, 0x6e, 0x0c, 0x1c,
0xb6, 0xc5, 0x83, 0x67, 0x2c, 0x88, 0xe8, 0x08, 0x14, 0x62, 0x8e, 0xca, 0xb2, 0xe0, 0x3f, 0xbb, 0x9b, 0x47, 0xd7, 0x44, 0x24, 0xe2, 0x57, 0x20, 0x9b, 0xd6, 0xb2, 0x29, 0x89, 0xfc, 0xcf, 0x1f,
0x8f, 0x5f, 0x37, 0x47, 0x21, 0xdd, 0xa3, 0x69, 0xdf, 0x65, 0xc8, 0xc6, 0x72, 0xa2, 0x2d, 0x50, 0xcb, 0xef, 0x58, 0xcb, 0x38, 0x3d, 0x48, 0x53, 0xff, 0x96, 0xa0, 0x9c, 0xe1, 0xc4, 0x17, 0xa0,
0x6d, 0x32, 0xa1, 0x6c, 0x4a, 0x4c, 0x2a, 0x6a, 0x52, 0xf1, 0x3c, 0x80, 0xfe, 0x84, 0x34, 0x77, 0x38, 0xe6, 0x9a, 0x32, 0xcf, 0xb4, 0xa8, 0xa8, 0x49, 0x21, 0x69, 0x00, 0xbf, 0x0f, 0x45, 0xee,
0xa6, 0x96, 0x29, 0xd4, 0x54, 0xec, 0xbf, 0x78, 0x9c, 0x29, 0x71, 0xb9, 0xc5, 0x2d, 0xc7, 0x2e, 0x7a, 0xb6, 0x25, 0xd4, 0x14, 0x12, 0xde, 0x04, 0x39, 0x9e, 0xe9, 0x73, 0x9b, 0xdb, 0xae, 0xd3,
0x2b, 0x15, 0xa9, 0x9a, 0xc6, 0xf3, 0x00, 0xea, 0x43, 0x9e, 0x71, 0xe2, 0xf2, 0x8e, 0xc3, 0x7c, 0x94, 0x35, 0xd4, 0x2a, 0x92, 0x34, 0x80, 0xa7, 0x50, 0x65, 0xdc, 0xf4, 0xf9, 0xc8, 0x65, 0x21,
0x44, 0xaa, 0x22, 0x55, 0x0b, 0xb5, 0x57, 0xbf, 0xb1, 0x52, 0xa3, 0x1b, 0x4f, 0x80, 0x93, 0xf9, 0xa2, 0xa0, 0xa1, 0x56, 0xad, 0xfd, 0xf5, 0xff, 0x38, 0xa9, 0x31, 0xce, 0x12, 0x90, 0x3c, 0x1f,
0x50, 0x05, 0xb2, 0xdc, 0x9a, 0x50, 0xc6, 0xc9, 0x64, 0xfa, 0x96, 0x95, 0xd3, 0x15, 0xa9, 0xaa, 0xd6, 0xa0, 0xcc, 0xed, 0x35, 0x65, 0xdc, 0x5c, 0x7b, 0x3f, 0xb0, 0x66, 0x51, 0x43, 0x2d, 0x99,
0xe0, 0x78, 0x08, 0xed, 0x42, 0x9e, 0x45, 0xf9, 0xfb, 0xd6, 0xb0, 0x9c, 0x11, 0xe5, 0xe7, 0xe6, 0x64, 0x43, 0xf8, 0x05, 0x54, 0x59, 0xc2, 0x3f, 0xb5, 0xe7, 0xcd, 0x92, 0x28, 0xbf, 0x92, 0x06,
0xc1, 0xd6, 0x50, 0x3f, 0x80, 0x7c, 0x42, 0x06, 0x01, 0x64, 0xce, 0xea, 0xbd, 0x66, 0xb7, 0x57, 0x07, 0x73, 0xfd, 0x06, 0xaa, 0x39, 0x19, 0x0c, 0x50, 0xba, 0xed, 0x4c, 0xfa, 0xe3, 0x49, 0xe3,
0x5a, 0x43, 0x39, 0xd8, 0x68, 0xd6, 0xf1, 0x59, 0xcb, 0x7b, 0x93, 0x50, 0x1e, 0xd4, 0x5e, 0xab, 0x19, 0xae, 0xc0, 0xf3, 0x7e, 0x87, 0xdc, 0x0e, 0x82, 0x3b, 0x84, 0xab, 0xa0, 0x4c, 0x06, 0xc3,
0xdd, 0xec, 0xf6, 0xea, 0xed, 0x4e, 0x49, 0xd6, 0xf6, 0x00, 0xe6, 0x6d, 0x45, 0xdb, 0x00, 0xfe, 0xfe, 0x78, 0xd2, 0x19, 0x8e, 0x1a, 0x92, 0x7a, 0x05, 0x90, 0xb6, 0x15, 0x5f, 0x02, 0x84, 0x27,
0xca, 0xa8, 0xa7, 0x24, 0x89, 0x6a, 0xd4, 0x20, 0xd2, 0x1a, 0xea, 0x3f, 0x25, 0x58, 0x0f, 0xa1, 0xa3, 0x81, 0x12, 0x12, 0xd5, 0x28, 0x51, 0x64, 0x30, 0xd7, 0xff, 0x45, 0x70, 0x16, 0x43, 0x35,
0x15, 0x50, 0xa3, 0x32, 0x7d, 0x64, 0x43, 0xde, 0x97, 0xf0, 0x3c, 0x88, 0x4a, 0xa0, 0x8c, 0xe8, 0x50, 0x92, 0x32, 0x43, 0x64, 0x57, 0xba, 0x46, 0x24, 0x0d, 0xe2, 0x06, 0xc8, 0x4b, 0x7a, 0x2f,
0x8d, 0x68, 0x77, 0x0e, 0x7b, 0x8f, 0xde, 0x08, 0x3e, 0x90, 0xf1, 0x8c, 0x8a, 0x46, 0xe7, 0xb0, 0xda, 0x5d, 0x21, 0xc1, 0x65, 0x30, 0x82, 0x9f, 0xcd, 0xd5, 0x86, 0x8a, 0x46, 0x57, 0x48, 0x78,
0xff, 0x82, 0x8e, 0x60, 0xfd, 0x8a, 0x92, 0x21, 0x75, 0x59, 0x39, 0x55, 0x51, 0xaa, 0xd9, 0x9a, 0x83, 0x5f, 0xc1, 0xd9, 0x3b, 0x6a, 0xce, 0xa9, 0xcf, 0x9a, 0x05, 0x4d, 0x6e, 0x95, 0xdb, 0x7a,
0x9e, 0x6c, 0x6f, 0xd8, 0xc8, 0x37, 0x3e, 0xa8, 0x69, 0x73, 0xf7, 0x06, 0x87, 0x14, 0xed, 0x10, 0xbe, 0xbd, 0x71, 0x23, 0xbf, 0x0f, 0x41, 0x7d, 0x87, 0xfb, 0xf7, 0x24, 0x4e, 0x51, 0x5f, 0x42,
0x72, 0xf1, 0x0f, 0xa1, 0xaa, 0x3f, 0xfe, 0xa4, 0xaa, 0x1c, 0x53, 0x3d, 0x94, 0x0f, 0x24, 0xfd, 0x25, 0xfb, 0x20, 0x56, 0x0d, 0xc7, 0x9f, 0x57, 0x95, 0x32, 0xaa, 0x2f, 0xa5, 0x1b, 0xa4, 0xff,
0x9b, 0x04, 0xf9, 0x86, 0xeb, 0x8c, 0xe6, 0x8e, 0xfe, 0x1f, 0x52, 0x43, 0xc2, 0x49, 0xe0, 0xe8, 0x85, 0xa0, 0xda, 0xf5, 0xdd, 0x65, 0xea, 0xe8, 0xcf, 0xa0, 0x30, 0x37, 0xb9, 0x19, 0x39, 0xfa,
0xcd, 0xa5, 0x85, 0x60, 0x01, 0x41, 0xa7, 0xb0, 0xe1, 0xd2, 0xa1, 0xe5, 0x52, 0x93, 0x07, 0x06, 0x7c, 0x6f, 0x21, 0x44, 0x40, 0xf0, 0x6b, 0x78, 0xee, 0xd3, 0xb9, 0xed, 0x53, 0x8b, 0x47, 0x06,
0x5e, 0xd8, 0x00, 0x89, 0xcc, 0x06, 0x0e, 0xb0, 0x61, 0x92, 0x88, 0xac, 0xed, 0x43, 0x71, 0xe1, 0xde, 0x5a, 0x80, 0x1c, 0xb3, 0x41, 0x22, 0x6c, 0x4c, 0x92, 0x24, 0xab, 0xd7, 0x50, 0xdf, 0x7a,
0xa3, 0x37, 0x07, 0x9b, 0x5e, 0xf7, 0x07, 0x22, 0x43, 0x64, 0x65, 0x7a, 0xed, 0xa7, 0xd4, 0xbf, 0x18, 0xcc, 0xc1, 0xa1, 0x77, 0xd3, 0x99, 0x60, 0x48, 0xac, 0x4c, 0xef, 0x42, 0x4a, 0xfd, 0x4f,
0x2a, 0x50, 0xe8, 0xcc, 0x06, 0x63, 0x8b, 0x5d, 0x61, 0xfa, 0x7e, 0x46, 0x99, 0xb7, 0x93, 0xe2, 0x19, 0x6a, 0xa3, 0xcd, 0x6c, 0x65, 0xb3, 0x77, 0x84, 0xfe, 0xb4, 0xa1, 0x2c, 0xd8, 0xa4, 0xec,
0x5b, 0xb1, 0x9a, 0xac, 0x24, 0x89, 0x5d, 0xba, 0x0f, 0xfd, 0x65, 0xcb, 0x0f, 0x60, 0xbf, 0x26, 0x2a, 0xb6, 0xf2, 0x95, 0xe4, 0xb1, 0x7b, 0xf7, 0x30, 0x3c, 0xb6, 0x74, 0x44, 0xf6, 0xb7, 0x26,
0x9c, 0x24, 0x3a, 0xa1, 0xf5, 0x9f, 0x78, 0x1b, 0x6a, 0x3f, 0x24, 0xc8, 0xc6, 0x64, 0xe3, 0x33, 0x37, 0x73, 0x9d, 0x50, 0xa7, 0x4f, 0xbc, 0x86, 0xea, 0x3f, 0x08, 0xca, 0x19, 0xd9, 0xec, 0x8c,
0xce, 0xad, 0x98, 0x31, 0x3a, 0x9f, 0x3b, 0x4b, 0x11, 0xce, 0x7a, 0xf9, 0xd0, 0x95, 0x3d, 0x81, 0x2b, 0x07, 0x66, 0x8c, 0xdf, 0xa4, 0xce, 0x92, 0x85, 0xb3, 0xbe, 0x3a, 0xf6, 0x64, 0x4f, 0x60,
0xd9, 0x3e, 0xcb, 0x50, 0x8c, 0x04, 0xd9, 0xd4, 0xb1, 0x19, 0x45, 0x27, 0x90, 0x31, 0x1d, 0xfb, 0xb6, 0xdf, 0x25, 0xa8, 0x27, 0x82, 0xcc, 0x73, 0x1d, 0x46, 0x71, 0x0f, 0x4a, 0x96, 0xeb, 0xbc,
0xc2, 0xba, 0x5c, 0x7e, 0x84, 0x2e, 0xc0, 0x8d, 0x13, 0x81, 0x0d, 0x9b, 0x1f, 0x50, 0x51, 0xeb, 0xb5, 0x17, 0xfb, 0x5f, 0xa1, 0x5b, 0x70, 0xa3, 0x27, 0xb0, 0x71, 0xf3, 0xa3, 0x54, 0x3c, 0xd8,
0x96, 0x11, 0x9f, 0xaf, 0x4e, 0x73, 0xb7, 0x15, 0x0f, 0x20, 0x9f, 0xd0, 0x40, 0xff, 0x41, 0x31, 0x31, 0xe2, 0x17, 0x87, 0x69, 0x1e, 0xb6, 0xe2, 0x0d, 0x54, 0x73, 0x1a, 0xf8, 0x53, 0xa8, 0x27,
0x1a, 0x43, 0xdf, 0x74, 0x66, 0xb6, 0xef, 0xb0, 0x34, 0x2e, 0x44, 0xe1, 0x13, 0x2f, 0xfa, 0x08, 0x63, 0x98, 0x5a, 0xee, 0xc6, 0x09, 0x1d, 0x56, 0x24, 0xb5, 0x24, 0xdc, 0x0b, 0xa2, 0x27, 0x98,
0x13, 0x7f, 0x91, 0x60, 0xd3, 0x17, 0x9b, 0xb9, 0xb4, 0xe7, 0xb9, 0x20, 0xf4, 0xf2, 0x63, 0x0c, 0xf8, 0x0f, 0x04, 0xe7, 0xa1, 0xd8, 0xc6, 0xa7, 0x93, 0xc0, 0x05, 0xb1, 0x97, 0x4f, 0x31, 0xd0,
0xb4, 0xa4, 0x50, 0x65, 0x59, 0xa1, 0x68, 0x07, 0xc0, 0x74, 0xc6, 0x63, 0x6a, 0x46, 0xe7, 0xb9, 0x77, 0x50, 0xb5, 0x22, 0x32, 0x33, 0x31, 0x51, 0xb9, 0xad, 0xe5, 0x3b, 0x21, 0x64, 0x7a, 0x59,
0x8a, 0x63, 0x11, 0xbd, 0x0c, 0x7f, 0x2d, 0x56, 0xe5, 0xb7, 0x4d, 0xc7, 0xb0, 0x75, 0x4a, 0xb9, 0x1c, 0xc9, 0xa7, 0xe9, 0x4d, 0xf8, 0x60, 0xbb, 0xa8, 0xb0, 0x6b, 0x3a, 0x81, 0x8b, 0xd7, 0x94,
0x88, 0x85, 0x08, 0x22, 0xce, 0xf4, 0xc7, 0x97, 0xad, 0x1f, 0xc3, 0xf6, 0x1d, 0x39, 0x03, 0x87, 0xef, 0x61, 0x38, 0xbd, 0x6a, 0x7d, 0x01, 0x97, 0x0f, 0x70, 0x46, 0x06, 0xd9, 0x39, 0x16, 0x3a,
0xec, 0x00, 0x44, 0x0b, 0x60, 0xc1, 0x92, 0x62, 0x91, 0xda, 0x27, 0x05, 0x4a, 0x5d, 0x4a, 0xae, 0xed, 0x58, 0xbf, 0x00, 0xde, 0x05, 0x1d, 0x3d, 0x5d, 0xfc, 0x11, 0x80, 0xe5, 0xae, 0x56, 0xd4,
0x29, 0x1d, 0xb6, 0xc3, 0x99, 0xa3, 0x73, 0x50, 0xa3, 0x7f, 0x12, 0xfa, 0xe7, 0x9e, 0x9f, 0x95, 0x12, 0x35, 0x84, 0x47, 0xc8, 0x44, 0x82, 0xcf, 0x98, 0x4f, 0xbd, 0x95, 0x6d, 0xa5, 0xbd, 0x57,
0xf6, 0xf7, 0x8a, 0x63, 0x4b, 0x5f, 0xab, 0x4a, 0xfb, 0x12, 0x3a, 0x83, 0xf5, 0xc0, 0x44, 0x68, 0x48, 0x36, 0xd4, 0xfe, 0x4d, 0x86, 0xc6, 0x98, 0x9a, 0x77, 0x94, 0xce, 0x87, 0x71, 0xe9, 0xf8,
0x6b, 0xd5, 0x16, 0xd2, 0xb6, 0x57, 0x3a, 0x2f, 0xc8, 0xf6, 0x0e, 0x0a, 0xc9, 0x16, 0xa3, 0xdd, 0x0d, 0x28, 0xc9, 0xb7, 0x13, 0x7f, 0xfc, 0xc8, 0x47, 0x55, 0xfd, 0xf0, 0xc0, 0xeb, 0x55, 0x7f,
0x24, 0x6d, 0xa9, 0x2d, 0xb4, 0x7f, 0x57, 0x83, 0x42, 0x09, 0xe4, 0xc2, 0xe6, 0xd2, 0x9e, 0xa2, 0xd6, 0x42, 0xd7, 0x08, 0xdf, 0xc2, 0x59, 0x64, 0x76, 0x7c, 0x71, 0x68, 0xd5, 0xd5, 0xcb, 0x83,
0x85, 0x0b, 0xc6, 0xaa, 0x61, 0x6a, 0x7b, 0x0f, 0xc2, 0x86, 0x9a, 0x0d, 0x1d, 0x4a, 0xcc, 0x9f, 0x1b, 0x12, 0xb1, 0xfd, 0x08, 0xb5, 0xbc, 0x17, 0xf0, 0x8b, 0x7c, 0xda, 0x5e, 0xfb, 0xaa, 0x9f,
0xc2, 0x05, 0x33, 0xcc, 0xb1, 0x45, 0x6d, 0xde, 0x28, 0x44, 0x03, 0xe9, 0x78, 0x37, 0xaa, 0x41, 0x1c, 0x06, 0xc5, 0x12, 0xd8, 0x87, 0xf3, 0xbd, 0xc3, 0xc7, 0x5b, 0x3f, 0x42, 0x87, 0x5c, 0xa7,
0x46, 0x5c, 0xac, 0x5e, 0xfc, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x31, 0x28, 0xa2, 0x6b, 0x09, 0x5e, 0x1d, 0x85, 0x8d, 0x35, 0xbb, 0x3a, 0x34, 0x58, 0x38, 0x85, 0xb7, 0xcc, 0xb0, 0x56, 0x36,
0x00, 0x00, 0x75, 0x78, 0xb7, 0x96, 0x0c, 0x64, 0x14, 0xfc, 0xf9, 0xcd, 0x4a, 0xe2, 0x07, 0xf0, 0xcb, 0xff,
0x02, 0x00, 0x00, 0xff, 0xff, 0xed, 0x8d, 0x77, 0xac, 0x13, 0x0a, 0x00, 0x00,
} }