Added log_streamer for log pubsub

pull/2342/head
John Welsh 9 years ago
parent 0d16a01db7
commit 5a33d1f338

@ -31,7 +31,7 @@ message Log {
} }
// Syslog log levels // Syslog log levels
enum LogLevel { enum Level {
EMERG = 0; EMERG = 0;
ALERT = 1; ALERT = 1;
CRIT = 2; CRIT = 2;
@ -43,7 +43,8 @@ message Log {
} }
Source source = 1; Source source = 1;
string release = 2; Level level = 2;
string log = 3; string release = 3;
google.protobuf.Timestamp timestamp = 4; string log = 4;
google.protobuf.Timestamp timestamp = 5;
} }

@ -19,6 +19,7 @@ package hapi.services.tiller;
import "hapi/chart/chart.proto"; import "hapi/chart/chart.proto";
import "hapi/chart/config.proto"; import "hapi/chart/config.proto";
import "hapi/release/release.proto"; import "hapi/release/release.proto";
import "hapi/release/log.proto";
import "hapi/release/info.proto"; import "hapi/release/info.proto";
import "hapi/release/status.proto"; import "hapi/release/status.proto";
import "hapi/version/version.proto"; import "hapi/version/version.proto";

@ -8,6 +8,7 @@ Package release is a generated protocol buffer package.
It is generated from these files: It is generated from these files:
hapi/release/hook.proto hapi/release/hook.proto
hapi/release/info.proto hapi/release/info.proto
hapi/release/log.proto
hapi/release/release.proto hapi/release/release.proto
hapi/release/status.proto hapi/release/status.proto
hapi/release/test_run.proto hapi/release/test_run.proto
@ -16,6 +17,7 @@ It is generated from these files:
It has these top-level messages: It has these top-level messages:
Hook Hook
Info Info
Log
Release Release
Status Status
TestRun TestRun

@ -0,0 +1,135 @@
// Code generated by protoc-gen-go.
// source: hapi/release/log.proto
// DO NOT EDIT!
package release
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/timestamp"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Allows filtering by log event source
type Log_Source int32
const (
Log_HOOK Log_Source = 0
Log_TEST Log_Source = 1
Log_POD Log_Source = 2
Log_SYSTEM Log_Source = 3
)
var Log_Source_name = map[int32]string{
0: "HOOK",
1: "TEST",
2: "POD",
3: "SYSTEM",
}
var Log_Source_value = map[string]int32{
"HOOK": 0,
"TEST": 1,
"POD": 2,
"SYSTEM": 3,
}
func (x Log_Source) String() string {
return proto.EnumName(Log_Source_name, int32(x))
}
func (Log_Source) EnumDescriptor() ([]byte, []int) { return fileDescriptor2, []int{0, 0} }
// Syslog log levels
type Log_Level int32
const (
Log_EMERG Log_Level = 0
Log_ALERT Log_Level = 1
Log_CRIT Log_Level = 2
Log_ERR Log_Level = 3
Log_WARNING Log_Level = 4
Log_NOTICE Log_Level = 5
Log_INFO Log_Level = 6
Log_DEBUG Log_Level = 7
)
var Log_Level_name = map[int32]string{
0: "EMERG",
1: "ALERT",
2: "CRIT",
3: "ERR",
4: "WARNING",
5: "NOTICE",
6: "INFO",
7: "DEBUG",
}
var Log_Level_value = map[string]int32{
"EMERG": 0,
"ALERT": 1,
"CRIT": 2,
"ERR": 3,
"WARNING": 4,
"NOTICE": 5,
"INFO": 6,
"DEBUG": 7,
}
func (x Log_Level) String() string {
return proto.EnumName(Log_Level_name, int32(x))
}
func (Log_Level) EnumDescriptor() ([]byte, []int) { return fileDescriptor2, []int{0, 1} }
type Log struct {
Source Log_Source `protobuf:"varint,1,opt,name=source,enum=hapi.release.Log_Source" json:"source,omitempty"`
Level Log_Level `protobuf:"varint,2,opt,name=level,enum=hapi.release.Log_Level" json:"level,omitempty"`
Release string `protobuf:"bytes,3,opt,name=release" json:"release,omitempty"`
Log string `protobuf:"bytes,4,opt,name=log" json:"log,omitempty"`
Timestamp *google_protobuf.Timestamp `protobuf:"bytes,5,opt,name=timestamp" json:"timestamp,omitempty"`
}
func (m *Log) Reset() { *m = Log{} }
func (m *Log) String() string { return proto.CompactTextString(m) }
func (*Log) ProtoMessage() {}
func (*Log) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} }
func (m *Log) GetTimestamp() *google_protobuf.Timestamp {
if m != nil {
return m.Timestamp
}
return nil
}
func init() {
proto.RegisterType((*Log)(nil), "hapi.release.Log")
proto.RegisterEnum("hapi.release.Log_Source", Log_Source_name, Log_Source_value)
proto.RegisterEnum("hapi.release.Log_Level", Log_Level_name, Log_Level_value)
}
func init() { proto.RegisterFile("hapi/release/log.proto", fileDescriptor2) }
var fileDescriptor2 = []byte{
// 317 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x8f, 0x4b, 0x4b, 0xfb, 0x40,
0x14, 0xc5, 0x9b, 0x77, 0x73, 0xfb, 0xe7, 0xcf, 0x65, 0x16, 0x3a, 0x74, 0x63, 0xe9, 0xaa, 0x1b,
0x27, 0x5a, 0x37, 0x6e, 0xfb, 0x18, 0x6b, 0x30, 0x4d, 0x64, 0x12, 0x11, 0x5d, 0x08, 0xad, 0x8c,
0xb1, 0x90, 0x32, 0xa5, 0x0f, 0xbf, 0xae, 0x5f, 0x45, 0x66, 0xd2, 0xa8, 0xe0, 0xee, 0xde, 0x7b,
0x7e, 0xe7, 0x72, 0x0e, 0x9c, 0xbc, 0x2f, 0x36, 0xab, 0x68, 0x2b, 0x2b, 0xb9, 0xd8, 0xc9, 0xa8,
0x52, 0x25, 0xdb, 0x6c, 0xd5, 0x5e, 0x91, 0x7f, 0xfa, 0xce, 0x8e, 0xf7, 0xee, 0x59, 0xa9, 0x54,
0x59, 0xc9, 0xc8, 0x68, 0xcb, 0xc3, 0x5b, 0xb4, 0x5f, 0xad, 0xe5, 0x6e, 0xbf, 0x58, 0x6f, 0x6a,
0xbc, 0xff, 0x69, 0x83, 0x93, 0xa8, 0x92, 0x5c, 0x80, 0xbf, 0x53, 0x87, 0xed, 0xab, 0xa4, 0x56,
0xcf, 0x1a, 0xfc, 0x1f, 0x52, 0xf6, 0xfb, 0x0f, 0x4b, 0x54, 0xc9, 0x72, 0xa3, 0x8b, 0x23, 0x47,
0xce, 0xc1, 0xab, 0xe4, 0x87, 0xac, 0xa8, 0x6d, 0x0c, 0xa7, 0x7f, 0x0d, 0x89, 0x96, 0x45, 0x4d,
0x11, 0x0a, 0xc1, 0x51, 0xa3, 0x4e, 0xcf, 0x1a, 0x84, 0xa2, 0x59, 0x09, 0x82, 0x53, 0xa9, 0x92,
0xba, 0xe6, 0xaa, 0x47, 0x72, 0x0d, 0xe1, 0x77, 0x4e, 0xea, 0xf5, 0xac, 0x41, 0x67, 0xd8, 0x65,
0x75, 0x13, 0xd6, 0x34, 0x61, 0x45, 0x43, 0x88, 0x1f, 0xb8, 0x7f, 0x09, 0x7e, 0x1d, 0x93, 0xb4,
0xc1, 0xbd, 0xcd, 0xb2, 0x3b, 0x6c, 0xe9, 0xa9, 0xe0, 0x79, 0x81, 0x16, 0x09, 0xc0, 0xb9, 0xcf,
0xa6, 0x68, 0x13, 0x00, 0x3f, 0x7f, 0xca, 0x0b, 0x3e, 0x47, 0xa7, 0xff, 0x02, 0x9e, 0x09, 0x4a,
0x42, 0xf0, 0xf8, 0x9c, 0x8b, 0x19, 0xb6, 0xf4, 0x38, 0x4a, 0xb8, 0xd0, 0x9e, 0x36, 0xb8, 0x13,
0x11, 0x17, 0x68, 0x6b, 0x37, 0x17, 0x02, 0x1d, 0xd2, 0x81, 0xe0, 0x71, 0x24, 0xd2, 0x38, 0x9d,
0xa1, 0xab, 0x5f, 0xa5, 0x59, 0x11, 0x4f, 0x38, 0x7a, 0x9a, 0x8d, 0xd3, 0x9b, 0x0c, 0x7d, 0xfd,
0x60, 0xca, 0xc7, 0x0f, 0x33, 0x0c, 0xc6, 0xe1, 0x73, 0xd3, 0x74, 0xe9, 0x9b, 0xf0, 0x57, 0x5f,
0x01, 0x00, 0x00, 0xff, 0xff, 0xe3, 0x7b, 0x56, 0xb1, 0xbc, 0x01, 0x00, 0x00,
}

@ -40,7 +40,7 @@ type Release struct {
func (m *Release) Reset() { *m = Release{} } func (m *Release) Reset() { *m = Release{} }
func (m *Release) String() string { return proto.CompactTextString(m) } func (m *Release) String() string { return proto.CompactTextString(m) }
func (*Release) ProtoMessage() {} func (*Release) ProtoMessage() {}
func (*Release) Descriptor() ([]byte, []int) { return fileDescriptor2, []int{0} } func (*Release) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} }
func (m *Release) GetInfo() *Info { func (m *Release) GetInfo() *Info {
if m != nil { if m != nil {
@ -74,9 +74,9 @@ func init() {
proto.RegisterType((*Release)(nil), "hapi.release.Release") proto.RegisterType((*Release)(nil), "hapi.release.Release")
} }
func init() { proto.RegisterFile("hapi/release/release.proto", fileDescriptor2) } func init() { proto.RegisterFile("hapi/release/release.proto", fileDescriptor3) }
var fileDescriptor2 = []byte{ var fileDescriptor3 = []byte{
// 256 bytes of a gzipped FileDescriptorProto // 256 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbf, 0x4e, 0xc3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xbf, 0x4e, 0xc3, 0x40,
0x0c, 0xc6, 0x95, 0x36, 0x7f, 0x1a, 0xc3, 0x82, 0x07, 0xb0, 0x22, 0x86, 0x88, 0x01, 0x22, 0x86, 0x0c, 0xc6, 0x95, 0x36, 0x7f, 0x1a, 0xc3, 0x82, 0x07, 0xb0, 0x22, 0x86, 0x88, 0x01, 0x22, 0x86,

@ -51,7 +51,7 @@ var Status_Code_value = map[string]int32{
func (x Status_Code) String() string { func (x Status_Code) String() string {
return proto.EnumName(Status_Code_name, int32(x)) return proto.EnumName(Status_Code_name, int32(x))
} }
func (Status_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor3, []int{0, 0} } func (Status_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor4, []int{0, 0} }
// Status defines the status of a release. // Status defines the status of a release.
type Status struct { type Status struct {
@ -67,7 +67,7 @@ type Status struct {
func (m *Status) Reset() { *m = Status{} } func (m *Status) Reset() { *m = Status{} }
func (m *Status) String() string { return proto.CompactTextString(m) } func (m *Status) String() string { return proto.CompactTextString(m) }
func (*Status) ProtoMessage() {} func (*Status) ProtoMessage() {}
func (*Status) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } func (*Status) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} }
func (m *Status) GetLastTestSuiteRun() *TestSuite { func (m *Status) GetLastTestSuiteRun() *TestSuite {
if m != nil { if m != nil {
@ -81,9 +81,9 @@ func init() {
proto.RegisterEnum("hapi.release.Status_Code", Status_Code_name, Status_Code_value) proto.RegisterEnum("hapi.release.Status_Code", Status_Code_name, Status_Code_value)
} }
func init() { proto.RegisterFile("hapi/release/status.proto", fileDescriptor3) } func init() { proto.RegisterFile("hapi/release/status.proto", fileDescriptor4) }
var fileDescriptor3 = []byte{ var fileDescriptor4 = []byte{
// 291 bytes of a gzipped FileDescriptorProto // 291 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xdf, 0x6a, 0xc2, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0xdf, 0x6a, 0xc2, 0x30,
0x14, 0xc6, 0x57, 0xad, 0x3a, 0x8f, 0x22, 0x21, 0x1b, 0xac, 0xca, 0x06, 0xc5, 0xab, 0xde, 0xac, 0x14, 0xc6, 0x57, 0xad, 0x3a, 0x8f, 0x22, 0x21, 0x1b, 0xac, 0xca, 0x06, 0xc5, 0xab, 0xde, 0xac,

@ -36,7 +36,7 @@ var TestRun_Status_value = map[string]int32{
func (x TestRun_Status) String() string { func (x TestRun_Status) String() string {
return proto.EnumName(TestRun_Status_name, int32(x)) return proto.EnumName(TestRun_Status_name, int32(x))
} }
func (TestRun_Status) EnumDescriptor() ([]byte, []int) { return fileDescriptor4, []int{0, 0} } func (TestRun_Status) EnumDescriptor() ([]byte, []int) { return fileDescriptor5, []int{0, 0} }
type TestRun struct { type TestRun struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
@ -49,7 +49,7 @@ type TestRun struct {
func (m *TestRun) Reset() { *m = TestRun{} } func (m *TestRun) Reset() { *m = TestRun{} }
func (m *TestRun) String() string { return proto.CompactTextString(m) } func (m *TestRun) String() string { return proto.CompactTextString(m) }
func (*TestRun) ProtoMessage() {} func (*TestRun) ProtoMessage() {}
func (*TestRun) Descriptor() ([]byte, []int) { return fileDescriptor4, []int{0} } func (*TestRun) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} }
func (m *TestRun) GetStartedAt() *google_protobuf.Timestamp { func (m *TestRun) GetStartedAt() *google_protobuf.Timestamp {
if m != nil { if m != nil {
@ -70,9 +70,9 @@ func init() {
proto.RegisterEnum("hapi.release.TestRun_Status", TestRun_Status_name, TestRun_Status_value) proto.RegisterEnum("hapi.release.TestRun_Status", TestRun_Status_name, TestRun_Status_value)
} }
func init() { proto.RegisterFile("hapi/release/test_run.proto", fileDescriptor4) } func init() { proto.RegisterFile("hapi/release/test_run.proto", fileDescriptor5) }
var fileDescriptor4 = []byte{ var fileDescriptor5 = []byte{
// 265 bytes of a gzipped FileDescriptorProto // 265 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0x41, 0x4b, 0xfb, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0x41, 0x4b, 0xfb, 0x40,
0x14, 0xc4, 0xff, 0xc9, 0xbf, 0x26, 0x64, 0x53, 0x24, 0xec, 0x29, 0x54, 0xc1, 0xd0, 0x53, 0x4e, 0x14, 0xc4, 0xff, 0xc9, 0xbf, 0x26, 0x64, 0x53, 0x24, 0xec, 0x29, 0x54, 0xc1, 0xd0, 0x53, 0x4e,

@ -27,7 +27,7 @@ type TestSuite struct {
func (m *TestSuite) Reset() { *m = TestSuite{} } func (m *TestSuite) Reset() { *m = TestSuite{} }
func (m *TestSuite) String() string { return proto.CompactTextString(m) } func (m *TestSuite) String() string { return proto.CompactTextString(m) }
func (*TestSuite) ProtoMessage() {} func (*TestSuite) ProtoMessage() {}
func (*TestSuite) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} } func (*TestSuite) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{0} }
func (m *TestSuite) GetStartedAt() *google_protobuf.Timestamp { func (m *TestSuite) GetStartedAt() *google_protobuf.Timestamp {
if m != nil { if m != nil {
@ -54,9 +54,9 @@ func init() {
proto.RegisterType((*TestSuite)(nil), "hapi.release.TestSuite") proto.RegisterType((*TestSuite)(nil), "hapi.release.TestSuite")
} }
func init() { proto.RegisterFile("hapi/release/test_suite.proto", fileDescriptor5) } func init() { proto.RegisterFile("hapi/release/test_suite.proto", fileDescriptor6) }
var fileDescriptor5 = []byte{ var fileDescriptor6 = []byte{
// 207 bytes of a gzipped FileDescriptorProto // 207 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0xc1, 0x4a, 0x86, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x8f, 0xc1, 0x4a, 0x86, 0x40,
0x14, 0x85, 0x31, 0x21, 0x71, 0x74, 0x35, 0x10, 0x88, 0x11, 0x49, 0x2b, 0x57, 0x33, 0x60, 0xab, 0x14, 0x85, 0x31, 0x21, 0x71, 0x74, 0x35, 0x10, 0x88, 0x11, 0x49, 0x2b, 0x57, 0x33, 0x60, 0xab,

@ -41,6 +41,7 @@ import math "math"
import hapi_chart3 "k8s.io/helm/pkg/proto/hapi/chart" import hapi_chart3 "k8s.io/helm/pkg/proto/hapi/chart"
import hapi_chart "k8s.io/helm/pkg/proto/hapi/chart" import hapi_chart "k8s.io/helm/pkg/proto/hapi/chart"
import hapi_release5 "k8s.io/helm/pkg/proto/hapi/release" import hapi_release5 "k8s.io/helm/pkg/proto/hapi/release"
import hapi_release6 "k8s.io/helm/pkg/proto/hapi/release"
import hapi_release4 "k8s.io/helm/pkg/proto/hapi/release" import hapi_release4 "k8s.io/helm/pkg/proto/hapi/release"
import hapi_release3 "k8s.io/helm/pkg/proto/hapi/release" import hapi_release3 "k8s.io/helm/pkg/proto/hapi/release"
import hapi_version "k8s.io/helm/pkg/proto/hapi/version" import hapi_version "k8s.io/helm/pkg/proto/hapi/version"
@ -253,10 +254,7 @@ func (*GetReleaseLogsRequest) ProtoMessage() {}
func (*GetReleaseLogsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } func (*GetReleaseLogsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
type GetReleaseLogsResponse struct { type GetReleaseLogsResponse struct {
// Source is the name of the release that generated the log Log *hapi_release6.Log `protobuf:"bytes,1,opt,name=log" json:"log,omitempty"`
Source string `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"`
// Log is a single log line
Log string `protobuf:"bytes,2,opt,name=log" json:"log,omitempty"`
} }
func (m *GetReleaseLogsResponse) Reset() { *m = GetReleaseLogsResponse{} } func (m *GetReleaseLogsResponse) Reset() { *m = GetReleaseLogsResponse{} }
@ -264,6 +262,13 @@ func (m *GetReleaseLogsResponse) String() string { return proto.Compa
func (*GetReleaseLogsResponse) ProtoMessage() {} func (*GetReleaseLogsResponse) ProtoMessage() {}
func (*GetReleaseLogsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } func (*GetReleaseLogsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *GetReleaseLogsResponse) GetLog() *hapi_release6.Log {
if m != nil {
return m.Log
}
return nil
}
// UpdateReleaseRequest updates a release. // UpdateReleaseRequest updates a release.
type UpdateReleaseRequest struct { type UpdateReleaseRequest struct {
// The name of the release // The name of the release
@ -1089,82 +1094,82 @@ var _ReleaseService_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) } func init() { proto.RegisterFile("hapi/services/tiller.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 1226 bytes of a gzipped FileDescriptorProto // 1229 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xdd, 0x6e, 0xe3, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xdd, 0x72, 0xdb, 0x44,
0x14, 0xae, 0xe3, 0xfc, 0x9e, 0x76, 0x43, 0x76, 0xb6, 0x4d, 0x5d, 0x0b, 0x50, 0x31, 0x82, 0x66, 0x14, 0x8e, 0x2c, 0xc7, 0x3f, 0x27, 0x69, 0x48, 0xb7, 0xf9, 0x51, 0x35, 0xc0, 0x04, 0x75, 0xa0,
0x77, 0xd9, 0x14, 0xc2, 0x15, 0x12, 0x42, 0x6a, 0xbb, 0x51, 0x5b, 0x28, 0x5d, 0xc9, 0xd9, 0x2e, 0x6e, 0x4b, 0x1d, 0x30, 0x57, 0xcc, 0x00, 0x33, 0x69, 0xea, 0x49, 0x0a, 0x26, 0x9d, 0x91, 0xdb,
0x12, 0x42, 0x44, 0x6e, 0x32, 0x69, 0xcd, 0x3a, 0x9e, 0xe0, 0x19, 0x97, 0xed, 0x2d, 0x77, 0x3c, 0x32, 0xc3, 0x30, 0x78, 0x14, 0x7b, 0xed, 0x88, 0xca, 0x5a, 0xa3, 0x5d, 0x85, 0xe6, 0x96, 0x3b,
0x0a, 0x6f, 0xc1, 0x03, 0x00, 0xcf, 0x84, 0x3c, 0x3f, 0x8e, 0xed, 0xda, 0xad, 0xc9, 0x4d, 0x3c, 0x1e, 0x85, 0xb7, 0xe0, 0x01, 0x80, 0x67, 0x62, 0xb4, 0x3f, 0xb2, 0x56, 0x91, 0x12, 0xe1, 0x1b,
0x33, 0xe7, 0xcc, 0xf9, 0xf9, 0xce, 0xe9, 0x37, 0xa7, 0x60, 0x5e, 0x3b, 0x0b, 0x77, 0x9f, 0xe2, 0x6b, 0x77, 0xcf, 0xd9, 0xf3, 0xf3, 0x9d, 0x93, 0x6f, 0x4f, 0xc0, 0xbe, 0xf0, 0x16, 0xfe, 0x21,
0xe0, 0xc6, 0x9d, 0x60, 0xba, 0xcf, 0x5c, 0xcf, 0xc3, 0x41, 0x7f, 0x11, 0x10, 0x46, 0xd0, 0x66, 0xc5, 0xd1, 0xa5, 0x3f, 0xc6, 0xf4, 0x90, 0xf9, 0x41, 0x80, 0xa3, 0xee, 0x22, 0x22, 0x8c, 0xa0,
0x24, 0xeb, 0x2b, 0x59, 0x5f, 0xc8, 0xcc, 0x2e, 0xbf, 0x31, 0xb9, 0x76, 0x02, 0x26, 0x7e, 0x85, 0x9d, 0x44, 0xd6, 0x55, 0xb2, 0xae, 0x90, 0xd9, 0x7b, 0xfc, 0xc6, 0xf8, 0xc2, 0x8b, 0x98, 0xf8,
0xb6, 0xb9, 0x9d, 0x3c, 0x27, 0xfe, 0xcc, 0xbd, 0x92, 0x02, 0xe1, 0x22, 0xc0, 0x1e, 0x76, 0x28, 0x15, 0xda, 0xf6, 0x7e, 0xf6, 0x9c, 0x84, 0x53, 0x7f, 0x26, 0x05, 0xc2, 0x45, 0x84, 0x03, 0xec,
0x56, 0xdf, 0xd4, 0x25, 0x25, 0x73, 0xfd, 0x19, 0x91, 0x82, 0x9d, 0x94, 0x80, 0x32, 0x87, 0x85, 0x51, 0xac, 0xbe, 0x52, 0xb6, 0xa7, 0xc9, 0x02, 0x32, 0xd3, 0x8c, 0xa9, 0x73, 0x3f, 0x9c, 0x12,
0x34, 0x65, 0xef, 0x06, 0x07, 0xd4, 0x25, 0xbe, 0xfa, 0x0a, 0x99, 0xf5, 0x57, 0x05, 0x9e, 0x9c, 0x29, 0xb8, 0xaf, 0x09, 0x28, 0xf3, 0x58, 0x4c, 0x35, 0x3f, 0x97, 0x38, 0xa2, 0x3e, 0x09, 0xd5,
0xb9, 0x94, 0xd9, 0xe2, 0x22, 0xb5, 0xf1, 0xaf, 0x21, 0xa6, 0x0c, 0x6d, 0x42, 0xcd, 0x73, 0xe7, 0x57, 0xc8, 0x9c, 0xbf, 0x6a, 0x70, 0x6f, 0xe0, 0x53, 0xe6, 0x8a, 0x8b, 0xd4, 0xc5, 0xbf, 0xc6,
0x2e, 0x33, 0xb4, 0x5d, 0xad, 0xa7, 0xdb, 0x62, 0x83, 0xba, 0x50, 0x27, 0xb3, 0x19, 0xc5, 0xcc, 0x98, 0x32, 0xb4, 0x03, 0xeb, 0x81, 0x3f, 0xf7, 0x99, 0x65, 0x1c, 0x18, 0x1d, 0xd3, 0x15, 0x1b,
0xa8, 0xec, 0x6a, 0xbd, 0x96, 0x2d, 0x77, 0xe8, 0x1b, 0x68, 0x50, 0x12, 0xb0, 0xf1, 0xe5, 0xad, 0xb4, 0x07, 0x0d, 0x32, 0x9d, 0x52, 0xcc, 0xac, 0xda, 0x81, 0xd1, 0x69, 0xbb, 0x72, 0x87, 0xbe,
0xa1, 0xef, 0x6a, 0xbd, 0xf6, 0xe0, 0x93, 0x7e, 0x1e, 0x14, 0xfd, 0xc8, 0xd3, 0x88, 0x04, 0xac, 0x81, 0x26, 0x25, 0x11, 0x1b, 0x9d, 0x5f, 0x59, 0xe6, 0x81, 0xd1, 0xd9, 0xea, 0x7d, 0xdc, 0x2d,
0x1f, 0xfd, 0x1c, 0xde, 0xda, 0x75, 0xca, 0xbf, 0x91, 0xdd, 0x99, 0xeb, 0x31, 0x1c, 0x18, 0x55, 0x82, 0xa8, 0x9b, 0x78, 0x1a, 0x92, 0x88, 0x75, 0x93, 0x9f, 0x67, 0x57, 0x6e, 0x83, 0xf2, 0x6f,
0x61, 0x57, 0xec, 0xd0, 0x31, 0x00, 0xb7, 0x4b, 0x82, 0x29, 0x0e, 0x8c, 0x1a, 0x37, 0xdd, 0x2b, 0x62, 0x77, 0xea, 0x07, 0x0c, 0x47, 0x56, 0x5d, 0xd8, 0x15, 0x3b, 0x74, 0x02, 0xc0, 0xed, 0x92,
0x61, 0xfa, 0x55, 0xa4, 0x6f, 0xb7, 0xa8, 0x5a, 0xa2, 0xaf, 0x61, 0x43, 0x40, 0x32, 0x9e, 0x90, 0x68, 0x82, 0x23, 0x6b, 0x9d, 0x9b, 0xee, 0x54, 0x30, 0xfd, 0x32, 0xd1, 0x77, 0xdb, 0x54, 0x2d,
0x29, 0xa6, 0x46, 0x7d, 0x57, 0xef, 0xb5, 0x07, 0x3b, 0xc2, 0x94, 0x42, 0x78, 0x24, 0x40, 0x3b, 0xd1, 0x57, 0xb0, 0x29, 0x20, 0x19, 0x8d, 0xc9, 0x04, 0x53, 0xab, 0x71, 0x60, 0x76, 0xb6, 0x7a,
0x22, 0x53, 0x6c, 0xaf, 0x0b, 0xf5, 0x68, 0x4d, 0xd1, 0xfb, 0xd0, 0xf2, 0x9d, 0x39, 0xa6, 0x0b, 0xf7, 0x85, 0x29, 0x85, 0xfc, 0x50, 0x80, 0x76, 0x4c, 0x26, 0xd8, 0xdd, 0x10, 0xea, 0xc9, 0x9a,
0x67, 0x82, 0x8d, 0x06, 0x8f, 0x70, 0x79, 0x60, 0xfd, 0x0c, 0x4d, 0xe5, 0xdc, 0x1a, 0x40, 0x5d, 0xa2, 0xf7, 0xa1, 0x1d, 0x7a, 0x73, 0x4c, 0x17, 0xde, 0x18, 0x5b, 0x4d, 0x1e, 0xe1, 0xf2, 0xc0,
0xa4, 0x86, 0xd6, 0xa1, 0x71, 0x71, 0xfe, 0xdd, 0xf9, 0xab, 0x1f, 0xce, 0x3b, 0x6b, 0xa8, 0x09, 0xf9, 0x19, 0x5a, 0xca, 0xb9, 0xd3, 0x83, 0x86, 0x48, 0x0d, 0x6d, 0x40, 0xf3, 0xf5, 0xd9, 0x77,
0xd5, 0xf3, 0x83, 0xef, 0x87, 0x1d, 0x0d, 0x3d, 0x86, 0x47, 0x67, 0x07, 0xa3, 0xd7, 0x63, 0x7b, 0x67, 0x2f, 0x7f, 0x38, 0xdb, 0x5e, 0x43, 0x2d, 0xa8, 0x9f, 0x1d, 0x7d, 0xdf, 0xdf, 0x36, 0xd0,
0x78, 0x36, 0x3c, 0x18, 0x0d, 0x5f, 0x76, 0x2a, 0xd6, 0x87, 0xd0, 0x8a, 0x63, 0x46, 0x0d, 0xd0, 0x5d, 0xb8, 0x33, 0x38, 0x1a, 0xbe, 0x1a, 0xb9, 0xfd, 0x41, 0xff, 0x68, 0xd8, 0x7f, 0xbe, 0x5d,
0x0f, 0x46, 0x47, 0xe2, 0xca, 0xcb, 0xe1, 0xe8, 0xa8, 0xa3, 0x59, 0x7f, 0x68, 0xb0, 0x99, 0x2e, 0x73, 0x3e, 0x84, 0x76, 0x1a, 0x33, 0x6a, 0x82, 0x79, 0x34, 0x3c, 0x16, 0x57, 0x9e, 0xf7, 0x87,
0x11, 0x5d, 0x10, 0x9f, 0xe2, 0xa8, 0x46, 0x13, 0x12, 0xfa, 0x71, 0x8d, 0xf8, 0x06, 0x21, 0xa8, 0xc7, 0xdb, 0x86, 0xf3, 0x87, 0x01, 0x3b, 0x7a, 0x89, 0xe8, 0x82, 0x84, 0x14, 0x27, 0x35, 0x1a,
0xfa, 0xf8, 0x9d, 0xaa, 0x10, 0x5f, 0x47, 0x9a, 0x8c, 0x30, 0xc7, 0xe3, 0xd5, 0xd1, 0x6d, 0xb1, 0x93, 0x38, 0x4c, 0x6b, 0xc4, 0x37, 0x08, 0x41, 0x3d, 0xc4, 0xef, 0x54, 0x85, 0xf8, 0x3a, 0xd1,
0x41, 0x5f, 0x40, 0x53, 0xa6, 0x4e, 0x8d, 0xea, 0xae, 0xde, 0x5b, 0x1f, 0x6c, 0xa5, 0x01, 0x91, 0x64, 0x84, 0x79, 0x01, 0xaf, 0x8e, 0xe9, 0x8a, 0x0d, 0xfa, 0x1c, 0x5a, 0x32, 0x75, 0x6a, 0xd5,
0x1e, 0xed, 0x58, 0xcd, 0x3a, 0x86, 0xed, 0x63, 0xac, 0x22, 0x11, 0x78, 0xa9, 0x8e, 0x89, 0xfc, 0x0f, 0xcc, 0xce, 0x46, 0x6f, 0x57, 0x07, 0x44, 0x7a, 0x74, 0x53, 0x35, 0xe7, 0x04, 0xf6, 0x4f,
0x3a, 0x73, 0xcc, 0x83, 0x89, 0xfc, 0x3a, 0x73, 0x8c, 0x0c, 0x68, 0xc8, 0x76, 0xe3, 0xe1, 0xd4, 0xb0, 0x8a, 0x44, 0xe0, 0xa5, 0x3a, 0x26, 0xf1, 0xeb, 0xcd, 0x31, 0x0f, 0x26, 0xf1, 0xeb, 0xcd,
0x6c, 0xb5, 0xb5, 0x18, 0x18, 0x77, 0x0d, 0xc9, 0xbc, 0xf2, 0x2c, 0x7d, 0x0a, 0xd5, 0xa8, 0xd9, 0x31, 0xb2, 0xa0, 0x29, 0xdb, 0x8d, 0x87, 0xb3, 0xee, 0xaa, 0xad, 0xc3, 0xc0, 0xba, 0x6e, 0x48,
0xb9, 0x99, 0xf5, 0x01, 0x4a, 0xc7, 0x79, 0xea, 0xcf, 0x88, 0xcd, 0xe5, 0xe9, 0x52, 0xe9, 0xd9, 0xe6, 0x55, 0x64, 0xe9, 0x13, 0xa8, 0x27, 0xcd, 0xce, 0xcd, 0x6c, 0xf4, 0x90, 0x1e, 0xe7, 0x8b,
0x52, 0x9d, 0x24, 0xbd, 0x1e, 0x11, 0x9f, 0x61, 0x9f, 0xad, 0x16, 0xff, 0x19, 0xec, 0xe4, 0x58, 0x70, 0x4a, 0x5c, 0x2e, 0xd7, 0x4b, 0x65, 0xe6, 0x4b, 0x75, 0x9a, 0xf5, 0x7a, 0x4c, 0x42, 0x86,
0x92, 0x09, 0xec, 0x43, 0x43, 0x86, 0xc6, 0xad, 0x15, 0xe2, 0xaa, 0xb4, 0xac, 0x21, 0x6c, 0x2d, 0x43, 0xb6, 0x5a, 0xfc, 0x03, 0xb8, 0x5f, 0x60, 0x49, 0x26, 0x70, 0x08, 0x4d, 0x19, 0x1a, 0xb7,
0xad, 0x9d, 0x91, 0xab, 0x15, 0x41, 0x3d, 0x84, 0x6e, 0xd6, 0x8c, 0x8c, 0xa8, 0x0b, 0x75, 0x4a, 0x56, 0x8a, 0xab, 0xd2, 0x72, 0xfa, 0xb0, 0xbb, 0xb4, 0x36, 0x20, 0xb3, 0x15, 0x41, 0xfd, 0x1a,
0xc2, 0x60, 0xa2, 0x2c, 0xc9, 0x1d, 0xea, 0x80, 0xee, 0x91, 0x2b, 0xd9, 0x2b, 0xd1, 0xd2, 0xfa, 0xf6, 0xf2, 0x66, 0x64, 0x44, 0x0f, 0xc0, 0x0c, 0xc8, 0x4c, 0x46, 0x73, 0x57, 0x8f, 0x66, 0x40,
0xa7, 0x02, 0x9b, 0x17, 0x8b, 0xa9, 0xc3, 0xb0, 0x8a, 0xf2, 0x9e, 0x50, 0xf6, 0xa0, 0xc6, 0xf9, 0x66, 0x6e, 0x22, 0x75, 0xfe, 0xa9, 0xc1, 0xce, 0xeb, 0xc5, 0xc4, 0x63, 0x58, 0x05, 0x78, 0x43,
0x4b, 0x96, 0xe5, 0xb1, 0x48, 0x53, 0x90, 0xdc, 0x51, 0xf4, 0x6b, 0x0b, 0x39, 0x7a, 0x06, 0xf5, 0x14, 0x0f, 0x61, 0x9d, 0x53, 0x9a, 0xac, 0x88, 0xb4, 0x29, 0x78, 0xef, 0x38, 0xf9, 0x75, 0x85,
0x1b, 0xc7, 0x0b, 0x31, 0xe5, 0x35, 0x89, 0x0b, 0x28, 0x35, 0x39, 0xf9, 0xd9, 0x52, 0x03, 0x6d, 0x1c, 0x3d, 0x86, 0xc6, 0xa5, 0x17, 0xc4, 0x98, 0xf2, 0x72, 0xa4, 0xb5, 0x93, 0x9a, 0x9c, 0x0f,
0x43, 0x63, 0x1a, 0xdc, 0x8e, 0x83, 0xd0, 0xe7, 0x6c, 0xd0, 0xb4, 0xeb, 0xd3, 0xe0, 0xd6, 0x0e, 0x5d, 0xa9, 0x81, 0xf6, 0xa1, 0x39, 0x89, 0xae, 0x46, 0x51, 0x1c, 0x72, 0x22, 0x68, 0xb9, 0x8d,
0x7d, 0xf4, 0x31, 0x3c, 0x9a, 0xba, 0xd4, 0xb9, 0xf4, 0xf0, 0xf8, 0x9a, 0x90, 0xb7, 0x94, 0x13, 0x49, 0x74, 0xe5, 0xc6, 0x21, 0x7a, 0x00, 0x77, 0x26, 0x3e, 0xf5, 0xce, 0x03, 0x3c, 0xba, 0x20,
0x42, 0xd3, 0xde, 0x90, 0x87, 0x27, 0xd1, 0x19, 0x32, 0xa3, 0xa6, 0x9e, 0x04, 0xd8, 0x61, 0xd8, 0xe4, 0x2d, 0xe5, 0x5c, 0xd0, 0x72, 0x37, 0xe5, 0xe1, 0x69, 0x72, 0x86, 0xec, 0xa4, 0x9f, 0xc7,
0xa8, 0x73, 0x79, 0xbc, 0x8f, 0x90, 0x63, 0xee, 0x1c, 0x93, 0x90, 0xf1, 0xbf, 0x62, 0xdd, 0x56, 0x11, 0xf6, 0x18, 0xb6, 0x1a, 0x5c, 0x9e, 0xee, 0x13, 0xd0, 0x98, 0x3f, 0xc7, 0x24, 0x66, 0xfc,
0x5b, 0xf4, 0x11, 0x6c, 0x04, 0x98, 0x62, 0x36, 0x96, 0x51, 0x36, 0xf9, 0xcd, 0x75, 0x7e, 0xf6, 0x0f, 0xd8, 0x74, 0xd5, 0x16, 0x7d, 0x04, 0x9b, 0x11, 0xa6, 0x98, 0x8d, 0x64, 0x94, 0x2d, 0x7e,
0x46, 0x84, 0x85, 0xa0, 0xfa, 0x9b, 0xe3, 0x32, 0xa3, 0xc5, 0x45, 0x7c, 0x2d, 0xae, 0x85, 0x14, 0x73, 0x83, 0x9f, 0xbd, 0x11, 0x61, 0x21, 0xa8, 0xff, 0xe6, 0xf9, 0xcc, 0x6a, 0x73, 0x11, 0x5f,
0xab, 0x6b, 0xa0, 0xae, 0x85, 0x14, 0x8b, 0x6b, 0xd6, 0x09, 0x6c, 0x65, 0xe0, 0x5c, 0xb5, 0x49, 0x8b, 0x6b, 0x31, 0xc5, 0xea, 0x1a, 0xa8, 0x6b, 0x31, 0xc5, 0xe2, 0x9a, 0x73, 0x0a, 0xbb, 0x39,
0xfe, 0xd5, 0xa0, 0x6b, 0x13, 0xcf, 0xbb, 0x74, 0x26, 0x6f, 0x4b, 0xd4, 0x26, 0x01, 0x63, 0xe5, 0x38, 0x57, 0xed, 0x8f, 0x7f, 0x0d, 0xd8, 0x73, 0x49, 0x10, 0x9c, 0x7b, 0xe3, 0xb7, 0x15, 0x6a,
0x7e, 0x18, 0xf5, 0x1c, 0x18, 0x13, 0x4d, 0x56, 0x4d, 0x35, 0x59, 0x0a, 0xe0, 0x5a, 0x31, 0xc0, 0x93, 0x81, 0xb1, 0x76, 0x33, 0x8c, 0x66, 0x01, 0x8c, 0x99, 0xfe, 0xaa, 0x6b, 0xfd, 0xa5, 0x01,
0xf5, 0x34, 0xc0, 0x0a, 0xbd, 0xc6, 0x12, 0x3d, 0xeb, 0x5b, 0xd8, 0xbe, 0x93, 0xcf, 0xaa, 0xe0, 0xbc, 0x5e, 0x0e, 0x70, 0x43, 0x07, 0x58, 0xa1, 0xd7, 0x5c, 0xa2, 0xe7, 0x7c, 0x0b, 0xfb, 0xd7,
0xfc, 0x59, 0x81, 0xad, 0x53, 0x9f, 0x32, 0xc7, 0xf3, 0x32, 0xd8, 0xc4, 0x3d, 0xaa, 0x95, 0xee, 0xf2, 0x59, 0x15, 0x9c, 0x3f, 0x6b, 0xb0, 0xfb, 0x22, 0xa4, 0xcc, 0x0b, 0x82, 0x1c, 0x36, 0x69,
0xd1, 0xca, 0xff, 0xe9, 0x51, 0x3d, 0x05, 0xae, 0xaa, 0x44, 0x35, 0x51, 0x89, 0x52, 0x7d, 0x9b, 0x8f, 0x1a, 0x95, 0x7b, 0xb4, 0xf6, 0x7f, 0x7a, 0xd4, 0xd4, 0xc0, 0x55, 0x95, 0xa8, 0x67, 0x2a,
0x22, 0xae, 0x7a, 0x86, 0xb8, 0xd0, 0x07, 0x00, 0xa2, 0xd1, 0xb8, 0x71, 0x01, 0x62, 0x8b, 0x9f, 0x51, 0xa9, 0x6f, 0x35, 0xce, 0x6a, 0xe4, 0x38, 0x0b, 0x7d, 0x00, 0x20, 0x1a, 0x8d, 0x1b, 0x17,
0x9c, 0x4b, 0x4a, 0x50, 0xb8, 0x37, 0xf3, 0x71, 0x4f, 0x74, 0xad, 0x75, 0x0a, 0xdd, 0x2c, 0x54, 0x20, 0xb6, 0xf9, 0xc9, 0x99, 0x64, 0x03, 0x85, 0x7b, 0xab, 0x18, 0xf7, 0x4c, 0xd7, 0x3a, 0x2f,
0xab, 0xc2, 0xfe, 0xbb, 0x06, 0xdb, 0x17, 0xbe, 0x9b, 0x0b, 0x7c, 0x5e, 0x53, 0xde, 0x81, 0xa2, 0x60, 0x2f, 0x0f, 0xd5, 0xaa, 0xb0, 0xff, 0x6e, 0xc0, 0xfe, 0xeb, 0xd0, 0x2f, 0x04, 0xbe, 0xa8,
0x92, 0x03, 0xc5, 0x26, 0xd4, 0x16, 0x61, 0x70, 0x85, 0x25, 0xb4, 0x62, 0x93, 0xcc, 0xb1, 0x9a, 0x29, 0xaf, 0x41, 0x51, 0x2b, 0x80, 0x62, 0x07, 0xd6, 0x17, 0x71, 0x34, 0xc3, 0x12, 0x5a, 0xb1,
0xca, 0xd1, 0x1a, 0x83, 0x71, 0x37, 0x86, 0x15, 0x33, 0x8a, 0xa2, 0x8e, 0x1f, 0x9a, 0x96, 0x78, 0xc9, 0xe6, 0x58, 0xd7, 0x72, 0x74, 0x46, 0x60, 0x5d, 0x8f, 0x61, 0xc5, 0x8c, 0x92, 0xa8, 0xd3,
0x54, 0xac, 0x27, 0xf0, 0xf8, 0x18, 0xb3, 0x37, 0xe2, 0x0f, 0x40, 0xa6, 0x67, 0x0d, 0x01, 0x25, 0x37, 0xa6, 0x2d, 0xde, 0x13, 0xe7, 0x1e, 0xdc, 0x3d, 0xc1, 0xec, 0x8d, 0xf8, 0x03, 0x90, 0xe9,
0x0f, 0x97, 0xfe, 0xe4, 0x51, 0xda, 0x9f, 0x9a, 0xba, 0x94, 0x7e, 0xcc, 0xd9, 0x5f, 0x71, 0xdb, 0x39, 0x7d, 0x40, 0xd9, 0xc3, 0xa5, 0x3f, 0x79, 0xa4, 0xfb, 0x53, 0x03, 0x97, 0xd2, 0x4f, 0xe9,
0x27, 0x2e, 0x65, 0x24, 0xb8, 0xbd, 0x0f, 0xba, 0x0e, 0xe8, 0x73, 0xe7, 0x9d, 0xa4, 0xfc, 0x68, 0xfa, 0x4b, 0x6e, 0xfb, 0xd4, 0xa7, 0x8c, 0x44, 0x57, 0x37, 0x41, 0xb7, 0x0d, 0xe6, 0xdc, 0x7b,
0x69, 0x1d, 0xf3, 0x08, 0xe2, 0xab, 0x32, 0x82, 0xe4, 0xab, 0xae, 0x95, 0x7b, 0xd5, 0x7f, 0x02, 0x27, 0xd9, 0x3e, 0x59, 0x3a, 0x27, 0x3c, 0x82, 0xf4, 0xaa, 0x8c, 0x20, 0xfb, 0xa0, 0x1b, 0xd5,
0xf4, 0x1a, 0xc7, 0x03, 0xc6, 0x03, 0x6f, 0x8f, 0x2a, 0x42, 0x25, 0xdd, 0x68, 0x06, 0x34, 0x26, 0x1e, 0xf4, 0x9f, 0x00, 0xbd, 0xc2, 0xe9, 0x6c, 0x71, 0xcb, 0xb3, 0xa3, 0x8a, 0x50, 0xd3, 0x1b,
0x1e, 0x76, 0xfc, 0x70, 0x21, 0xcb, 0xa6, 0xb6, 0xd6, 0x1e, 0x3c, 0x49, 0x59, 0x97, 0x71, 0x46, 0xcd, 0x82, 0xe6, 0x38, 0xc0, 0x5e, 0x18, 0x2f, 0x64, 0xd9, 0xd4, 0xd6, 0x79, 0x08, 0xf7, 0x34,
0xf9, 0xd0, 0x2b, 0x69, 0x3d, 0x5a, 0x0e, 0xfe, 0x6e, 0x41, 0x5b, 0x4d, 0x04, 0x62, 0xba, 0x43, 0xeb, 0x32, 0xce, 0x24, 0x1f, 0x3a, 0x93, 0xd6, 0x93, 0x65, 0xef, 0xef, 0x36, 0x6c, 0xa9, 0x61,
0x2e, 0x6c, 0x24, 0x47, 0x1f, 0xf4, 0xb4, 0x78, 0xf8, 0xcb, 0x4c, 0xb0, 0xe6, 0xb3, 0x32, 0xaa, 0x40, 0x0c, 0x76, 0xc8, 0x87, 0xcd, 0xec, 0xd4, 0x83, 0x1e, 0x95, 0xcf, 0x7d, 0xb9, 0xe1, 0xd5,
0x22, 0x16, 0x6b, 0xed, 0x73, 0x0d, 0x51, 0xe8, 0x64, 0x27, 0x12, 0xf4, 0x22, 0xdf, 0x46, 0xc1, 0x7e, 0x5c, 0x45, 0x55, 0xc4, 0xe2, 0xac, 0x7d, 0x66, 0x20, 0x0a, 0xdb, 0xf9, 0x61, 0x04, 0x3d,
0x08, 0x64, 0xf6, 0xcb, 0xaa, 0x2b, 0xb7, 0xe8, 0x86, 0x57, 0x3f, 0x3d, 0x46, 0xa0, 0x07, 0xcd, 0x2d, 0xb6, 0x51, 0x32, 0xfd, 0xd8, 0xdd, 0xaa, 0xea, 0xca, 0x2d, 0xba, 0xe4, 0xd5, 0xd7, 0x27,
0xa4, 0x27, 0x17, 0x73, 0xbf, 0xb4, 0x7e, 0xec, 0x97, 0x40, 0x3b, 0x3d, 0x29, 0xa0, 0xe7, 0x0f, 0x08, 0x74, 0xab, 0x19, 0x7d, 0x68, 0xb1, 0x0f, 0x2b, 0xeb, 0xa7, 0x7e, 0x09, 0x6c, 0xe9, 0x43,
0x19, 0x49, 0x8c, 0x25, 0xe6, 0x67, 0xe5, 0x94, 0x13, 0xe8, 0xfe, 0x02, 0x8f, 0x52, 0xcf, 0x20, 0x02, 0x7a, 0x72, 0x9b, 0x91, 0xcc, 0x44, 0x62, 0x7f, 0x5a, 0x4d, 0x39, 0x83, 0xee, 0x2f, 0x70,
0x2a, 0x28, 0x4f, 0xde, 0xe8, 0x61, 0x3e, 0x2f, 0xa5, 0x1b, 0x27, 0x37, 0x87, 0x76, 0x9a, 0xdf, 0x47, 0x7b, 0x06, 0x51, 0x49, 0x79, 0x8a, 0x46, 0x0f, 0xfb, 0x49, 0x25, 0xdd, 0x34, 0xb9, 0x39,
0x8a, 0x92, 0xcb, 0x7d, 0x30, 0x8a, 0x92, 0xcb, 0xa7, 0x4c, 0x6b, 0x2d, 0x6a, 0x9c, 0x2c, 0xfd, 0x6c, 0xe9, 0xfc, 0x56, 0x96, 0x5c, 0xe1, 0x83, 0x51, 0x96, 0x5c, 0x31, 0x65, 0x3a, 0x6b, 0x49,
0x14, 0x35, 0x4e, 0x01, 0x55, 0x16, 0x35, 0x4e, 0x11, 0xab, 0x59, 0x6b, 0xc8, 0x01, 0x58, 0xb2, 0xe3, 0xe4, 0xe9, 0xa7, 0xac, 0x71, 0x4a, 0xa8, 0xb2, 0xac, 0x71, 0xca, 0x58, 0xcd, 0x59, 0x43,
0x0f, 0xda, 0x2b, 0xac, 0x47, 0x9a, 0xb4, 0xcc, 0xde, 0xc3, 0x8a, 0xb1, 0x8b, 0x05, 0xbc, 0x97, 0x1e, 0xc0, 0x92, 0x7d, 0xd0, 0xc3, 0xd2, 0x7a, 0xe8, 0xa4, 0x65, 0x77, 0x6e, 0x57, 0x4c, 0x5d,
0x79, 0x9e, 0x51, 0x01, 0x34, 0xf9, 0x53, 0x89, 0xf9, 0xa2, 0xa4, 0x76, 0x26, 0x29, 0x49, 0x68, 0x2c, 0xe0, 0xbd, 0xdc, 0xf3, 0x8c, 0x4a, 0xa0, 0x29, 0x9e, 0x4a, 0xec, 0xa7, 0x15, 0xb5, 0x73,
0xf7, 0x24, 0x95, 0x66, 0xcb, 0x7b, 0x92, 0xca, 0x70, 0xa3, 0xb5, 0x86, 0x5c, 0x68, 0xdb, 0xa1, 0x49, 0x49, 0x42, 0xbb, 0x21, 0x29, 0x9d, 0x2d, 0x6f, 0x48, 0x2a, 0xc7, 0x8d, 0xce, 0x1a, 0xf2,
0x2f, 0x5d, 0x47, 0xb4, 0x84, 0x0a, 0x6e, 0xdf, 0x25, 0x44, 0xf3, 0x69, 0x09, 0xcd, 0x65, 0xcb, 0x61, 0xcb, 0x8d, 0x43, 0xe9, 0x3a, 0xa1, 0x25, 0x54, 0x72, 0xfb, 0x3a, 0x21, 0xda, 0x8f, 0x2a,
0x1f, 0xc2, 0x8f, 0x4d, 0xa5, 0x7a, 0x59, 0xe7, 0xff, 0x6d, 0x7f, 0xf9, 0x5f, 0x00, 0x00, 0x00, 0x68, 0x2e, 0x5b, 0xfe, 0x19, 0xfc, 0xd8, 0x52, 0xaa, 0xe7, 0x0d, 0xfe, 0x8f, 0xf6, 0x17, 0xff,
0xff, 0xff, 0x33, 0x5c, 0xa4, 0xea, 0x3e, 0x10, 0x00, 0x00, 0x05, 0x00, 0x00, 0xff, 0xff, 0x60, 0x54, 0x63, 0x84, 0x51, 0x10, 0x00, 0x00,
} }

@ -1,48 +1,87 @@
package logdistributor package logdistributor
import "fmt" import (
rspb "k8s.io/helm/pkg/proto/hapi/release"
)
type Log struct { type Logsub struct {
Log string C chan *rspb.Log
release string
sources []rspb.Log_Source
level rspb.Log_Level
} }
type Subscription struct { type release struct {
c chan<- *Log name string
sourceMappings map[rspb.Log_Source]map[*Logsub]bool
} }
type Listener struct { type Pubsub struct {
subs map[*Subscription]bool releases map[string]*release
} }
type Distributor struct { func New() *Pubsub {
listeners map[string]*Listener rls := make(map[string]*release)
return &Pubsub{releases: rls}
} }
func (l *Listener) subscribe(c chan<- *Log) *Subscription { func newRelease(name string) *release {
sub := &Subscription{c} rs := &release{name: name}
l.subs[sub] = true rs.sourceMappings = make(map[rspb.Log_Source]map[*Logsub]bool, len(rspb.Log_Source_name))
return sub return rs
} }
func (d *Distributor) Subscribe() { func (rs *release) subscribe(sub *Logsub) {
for _, source := range sub.sources {
log_source := rspb.Log_Source(source)
if _, ok := rs.sourceMappings[log_source]; !ok {
subs := make(map[*Logsub]bool, 1)
rs.sourceMappings[log_source] = subs
}
rs.sourceMappings[log_source][sub] = true
}
}
func (ps *Pubsub) subscribe(sub *Logsub) {
if _, ok := ps.releases[sub.release]; !ok {
rs := newRelease(sub.release)
rs.subscribe(sub)
ps.releases[sub.release] = rs
}
ps.releases[sub.release].subscribe(sub)
} }
func (l *Listener) unsubscribe(sub *Subscription) { func (ps *Pubsub) Subscribe(release string, level rspb.Log_Level, sources ...rspb.Log_Source) *Logsub {
delete(l.subs, sub) ch := make(chan *rspb.Log)
ls := &Logsub{C: ch, release: release, level: level, sources: sources}
ps.subscribe(ls)
return ls
} }
func (l *Listener) writeLog(log *Log) error { func (ps *Pubsub) Unsubscribe(sub *Logsub) {
for _, s := range l.subs { if rs, ok := ps.releases[sub.release]; ok {
s.c <- log for source, subMap := range rs.sourceMappings {
delete(subMap, sub)
if len(subMap) == 0 {
delete(rs.sourceMappings, source)
}
}
if len(rs.sourceMappings) == 0 {
delete(ps.releases, sub.release)
}
} }
return nil
} }
func (d *Distributor) WriteLog(log *Log, release string) error { func (ps *Pubsub) PubLog(rls string, source rspb.Log_Source, level rspb.Log_Level, message string) {
l := d.listeners[release] log := &rspb.Log{Release: rls, Source: source, Level: level, Log: message}
if l == nil { if rls, ok := ps.releases[log.Release]; ok {
return fmt.Errorf("No listeners configured for %s", release) if subs, ok := rls.sourceMappings[log.Source]; ok {
for sub := range subs {
if sub.level >= log.Level {
sub.C <- log
}
}
}
} }
return l.writeLog(log)
} }

@ -3,40 +3,87 @@ package logdistributor
import ( import (
"testing" "testing"
"fmt" "fmt"
rspb "k8s.io/helm/pkg/proto/hapi/release"
) )
func TestDistributor_WriteLog(t *testing.T) { func TestPubsub_Subscribe(t *testing.T) {
d := &Distributor{} ps := New()
l := &Log{Log: "Test log"} rlsName := "testrls"
d.WriteLog(l, "testrelease")
if len(d.listeners) != 1 { ps.Subscribe(rlsName, rspb.Log_WARNING, rspb.Log_HOOK)
t.Errorf("Invalid number of listeners present: %d (expecting 1)", len(d.listeners)) if len(ps.releases[rlsName].sourceMappings) != 1 {
t.Error("testrls should have one log source entry")
}
ps.Subscribe(rlsName, rspb.Log_WARNING, rspb.Log_POD)
if len(ps.releases[rlsName].sourceMappings) != 2 {
t.Error("testrls should have two log source entries")
}
if len(ps.releases[rlsName].sourceMappings[rspb.Log_HOOK]) != 1 {
t.Error("testrls should have one subscription to the Log_HOOK event stream")
}
if len(ps.releases[rlsName].sourceMappings[rspb.Log_POD]) != 1 {
t.Error("testrls should have one subscription to the Log_POD event stream")
}
if len(ps.releases[rlsName].sourceMappings[rspb.Log_SYSTEM]) != 0 {
t.Error("testrls should have no subscriptions to the Log_SYSTEM event stream")
} }
} }
func BenchmarkDistributor_WriteLog(b *testing.B) { func TestPubsub_Unsubscribe(t *testing.T) {
ps := New()
rlsName := "testrls"
sub := ps.Subscribe(rlsName, rspb.Log_WARNING, rspb.Log_HOOK)
if len(ps.releases[rlsName].sourceMappings) != 1 {
t.Error("testrls should have one log source entry")
}
ps.Unsubscribe(sub)
if _, ok := ps.releases[rlsName]; ok {
t.Error("pubsub should have no entry for testrls")
}
sub2 := ps.Subscribe(rlsName, rspb.Log_WARNING, rspb.Log_HOOK)
sub3 := ps.Subscribe(rlsName, rspb.Log_WARNING, rspb.Log_POD)
if len(ps.releases[rlsName].sourceMappings) != 2 {
t.Error("testrls should have two log source entries")
}
ps.Unsubscribe(sub3)
if len(ps.releases[rlsName].sourceMappings) != 1 {
t.Error("testrls should have one log source entry")
}
ps.Unsubscribe(sub2)
if _, ok := ps.releases[rlsName]; ok {
t.Error("pubsub should have no entry for testrls")
}
} }
func ExampleDistributor_WriteLog() { func TestPubsub_PubLog(t *testing.T) {
sub := &Subscription{}
c := make(chan *Log)
sub.c = c
go func(){ }
for l := range c {
fmt.Println(l.Log)
}
func Example() {
ps := New()
sub := ps.Subscribe("testrls", rspb.Log_WARNING, rspb.Log_HOOK, rspb.Log_POD)
go func() {
for { for {
select { select {
case l := <-c: case l := <-sub.C:
fmt.Println(l.Log) fmt.Println(l.Log)
} }
} }
}() }()
sub.c <- &Log{Log: "Test log!"} // No output as log level is too low for the configured subscription
ps.PubLog("testrls", rspb.Log_POD, rspb.Log_DEBUG, "Test log!")
// Picked up by the subscription
ps.PubLog("testrls", rspb.Log_POD, rspb.Log_ERR, "Test log!")
// Output: Test log! // Output: Test log!
} }

Loading…
Cancel
Save