From 5592bb1b453bf00be2c756487614700820a6c95f Mon Sep 17 00:00:00 2001
From: Derek Wang
Date: Wed, 29 Jun 2022 11:34:38 -0700
Subject: [PATCH] feat: expose pending messages and processing rate (#79)
* feat: expose pending messages and processing rate
Signed-off-by: Derek Wang
---
cmd/commands/processor.go | 23 +-
.../crds/numaflow.numaproj.io_pipelines.yaml | 8 +-
.../crds/numaflow.numaproj.io_vertices.yaml | 8 +-
config/install.yaml | 16 +-
docs/APIs.md | 62 ++
pkg/apis/numaflow/v1alpha1/generated.pb.go | 839 ++++++++++++------
pkg/apis/numaflow/v1alpha1/generated.proto | 16 +-
pkg/apis/numaflow/v1alpha1/vertex_instance.go | 8 +
pkg/apis/numaflow/v1alpha1/vertex_types.go | 6 +-
.../v1alpha1/zz_generated.deepcopy.go | 26 +
pkg/isb/interfaces.go | 13 +-
pkg/isb/jetstream/options.go | 13 +-
pkg/isb/jetstream/reader.go | 2 +-
pkg/isb/jetstream/writer.go | 6 +-
pkg/isb/redis/read.go | 1 -
pkg/metrics/metrics.go | 134 ++-
pkg/metrics/metrics_test.go | 3 +-
pkg/sinks/sink.go | 41 +-
pkg/sources/generator/tickgen.go | 17 +-
pkg/sources/generator/tickgen_test.go | 5 +-
pkg/sources/generator/watermark.go | 14 +-
pkg/sources/generator/watermark_test.go | 3 +-
pkg/sources/http/http.go | 4 -
pkg/sources/source.go | 54 +-
pkg/sources/types/metadata.go | 9 -
pkg/udf/udf.go | 57 +-
test/fixtures/expect.go | 2 +-
test/fixtures/util.go | 9 +-
28 files changed, 986 insertions(+), 413 deletions(-)
create mode 100644 pkg/apis/numaflow/v1alpha1/vertex_instance.go
delete mode 100644 pkg/sources/types/metadata.go
diff --git a/cmd/commands/processor.go b/cmd/commands/processor.go
index d10d10027..57efde689 100644
--- a/cmd/commands/processor.go
+++ b/cmd/commands/processor.go
@@ -52,30 +52,29 @@ func NewProcessorCommand() *cobra.Command {
return fmt.Errorf("invalid replica %q", replicaStr)
}
log = log.With("vertex", vertex.Name)
+ vertexInstance := &dfv1.VertexInstance{
+ Vertex: vertex,
+ Hostname: hostname,
+ Replica: int32(replica),
+ }
ctx := logging.WithLogger(signals.SetupSignalHandler(), log)
switch processorType {
case "source":
p := &sources.SourceProcessor{
- ISBSvcType: dfv1.ISBSvcType(isbSvcType),
- Vertex: vertex,
- Hostname: hostname,
- Replica: replica,
+ ISBSvcType: dfv1.ISBSvcType(isbSvcType),
+ VertexInstance: vertexInstance,
}
return p.Start(ctx)
case "sink":
p := &sinks.SinkProcessor{
- ISBSvcType: dfv1.ISBSvcType(isbSvcType),
- Vertex: vertex,
- Hostname: hostname,
- Replica: replica,
+ ISBSvcType: dfv1.ISBSvcType(isbSvcType),
+ VertexInstance: vertexInstance,
}
return p.Start(ctx)
case "udf":
p := &udf.UDFProcessor{
- ISBSvcType: dfv1.ISBSvcType(isbSvcType),
- Vertex: vertex,
- Hostname: hostname,
- Replica: replica,
+ ISBSvcType: dfv1.ISBSvcType(isbSvcType),
+ VertexInstance: vertexInstance,
}
return p.Start(ctx)
default:
diff --git a/config/base/crds/numaflow.numaproj.io_pipelines.yaml b/config/base/crds/numaflow.numaproj.io_pipelines.yaml
index e5b90fe0e..d7b75fb36 100644
--- a/config/base/crds/numaflow.numaproj.io_pipelines.yaml
+++ b/config/base/crds/numaflow.numaproj.io_pipelines.yaml
@@ -1444,8 +1444,14 @@ spec:
type: string
scale:
properties:
+ lookbackSeconds:
+ default: 180
+ description: Lookback seconds to calculate the average pending
+ messages and processing rate
+ format: int32
+ type: integer
max:
- default: 1
+ default: 100
description: Maximum replicas
format: int32
type: integer
diff --git a/config/base/crds/numaflow.numaproj.io_vertices.yaml b/config/base/crds/numaflow.numaproj.io_vertices.yaml
index e70a6727f..8d7f27145 100644
--- a/config/base/crds/numaflow.numaproj.io_vertices.yaml
+++ b/config/base/crds/numaflow.numaproj.io_vertices.yaml
@@ -1316,8 +1316,14 @@ spec:
type: integer
scale:
properties:
+ lookbackSeconds:
+ default: 180
+ description: Lookback seconds to calculate the average pending
+ messages and processing rate
+ format: int32
+ type: integer
max:
- default: 1
+ default: 100
description: Maximum replicas
format: int32
type: integer
diff --git a/config/install.yaml b/config/install.yaml
index b45c607c2..391742a15 100644
--- a/config/install.yaml
+++ b/config/install.yaml
@@ -6170,8 +6170,14 @@ spec:
type: string
scale:
properties:
+ lookbackSeconds:
+ default: 180
+ description: Lookback seconds to calculate the average pending
+ messages and processing rate
+ format: int32
+ type: integer
max:
- default: 1
+ default: 100
description: Maximum replicas
format: int32
type: integer
@@ -10057,8 +10063,14 @@ spec:
type: integer
scale:
properties:
+ lookbackSeconds:
+ default: 180
+ description: Lookback seconds to calculate the average pending
+ messages and processing rate
+ format: int32
+ type: integer
max:
- default: 1
+ default: 100
description: Maximum replicas
format: int32
type: integer
diff --git a/docs/APIs.md b/docs/APIs.md
index 822d7f993..70d9a2f77 100644
--- a/docs/APIs.md
+++ b/docs/APIs.md
@@ -2983,6 +2983,18 @@ Maximum replicas
+
+
+lookbackSeconds int32
+ |
+
+(Optional)
+
+Lookback seconds to calculate the average pending messages and
+processing rate
+
+ |
+
@@ -3273,6 +3285,10 @@ Description
Vertex
+(Appears on:
+VertexInstance)
+
+
@@ -3374,6 +3390,52 @@ Refer to the Kubernetes API documentation for the fields of the
+
+VertexInstance
+
+
+
+VertexInstance is a wrapper of a vertex instance, which contains the
+vertex spec and the instance information such as hostname and replica
+index.
+
+
+
+
+
+
+Field
+ |
+
+Description
+ |
+
+
+
+
+
+vertex
+ Vertex
+ |
+
+ |
+
+
+
+hostname string
+ |
+
+ |
+
+
+
+replica int32
+ |
+
+ |
+
+
+
VertexLimits
diff --git a/pkg/apis/numaflow/v1alpha1/generated.pb.go b/pkg/apis/numaflow/v1alpha1/generated.pb.go
index f815666fd..9c954d295 100644
--- a/pkg/apis/numaflow/v1alpha1/generated.pb.go
+++ b/pkg/apis/numaflow/v1alpha1/generated.pb.go
@@ -1392,10 +1392,38 @@ func (m *Vertex) XXX_DiscardUnknown() {
var xxx_messageInfo_Vertex proto.InternalMessageInfo
+func (m *VertexInstance) Reset() { *m = VertexInstance{} }
+func (*VertexInstance) ProtoMessage() {}
+func (*VertexInstance) Descriptor() ([]byte, []int) {
+ return fileDescriptor_9d0d1b17d3865563, []int{48}
+}
+func (m *VertexInstance) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *VertexInstance) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ b = b[:cap(b)]
+ n, err := m.MarshalToSizedBuffer(b)
+ if err != nil {
+ return nil, err
+ }
+ return b[:n], nil
+}
+func (m *VertexInstance) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_VertexInstance.Merge(m, src)
+}
+func (m *VertexInstance) XXX_Size() int {
+ return m.Size()
+}
+func (m *VertexInstance) XXX_DiscardUnknown() {
+ xxx_messageInfo_VertexInstance.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_VertexInstance proto.InternalMessageInfo
+
func (m *VertexLimits) Reset() { *m = VertexLimits{} }
func (*VertexLimits) ProtoMessage() {}
func (*VertexLimits) Descriptor() ([]byte, []int) {
- return fileDescriptor_9d0d1b17d3865563, []int{48}
+ return fileDescriptor_9d0d1b17d3865563, []int{49}
}
func (m *VertexLimits) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1423,7 +1451,7 @@ var xxx_messageInfo_VertexLimits proto.InternalMessageInfo
func (m *VertexList) Reset() { *m = VertexList{} }
func (*VertexList) ProtoMessage() {}
func (*VertexList) Descriptor() ([]byte, []int) {
- return fileDescriptor_9d0d1b17d3865563, []int{49}
+ return fileDescriptor_9d0d1b17d3865563, []int{50}
}
func (m *VertexList) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1451,7 +1479,7 @@ var xxx_messageInfo_VertexList proto.InternalMessageInfo
func (m *VertexSpec) Reset() { *m = VertexSpec{} }
func (*VertexSpec) ProtoMessage() {}
func (*VertexSpec) Descriptor() ([]byte, []int) {
- return fileDescriptor_9d0d1b17d3865563, []int{50}
+ return fileDescriptor_9d0d1b17d3865563, []int{51}
}
func (m *VertexSpec) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1479,7 +1507,7 @@ var xxx_messageInfo_VertexSpec proto.InternalMessageInfo
func (m *VertexStatus) Reset() { *m = VertexStatus{} }
func (*VertexStatus) ProtoMessage() {}
func (*VertexStatus) Descriptor() ([]byte, []int) {
- return fileDescriptor_9d0d1b17d3865563, []int{51}
+ return fileDescriptor_9d0d1b17d3865563, []int{52}
}
func (m *VertexStatus) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1507,7 +1535,7 @@ var xxx_messageInfo_VertexStatus proto.InternalMessageInfo
func (m *Watermark) Reset() { *m = Watermark{} }
func (*Watermark) ProtoMessage() {}
func (*Watermark) Descriptor() ([]byte, []int) {
- return fileDescriptor_9d0d1b17d3865563, []int{52}
+ return fileDescriptor_9d0d1b17d3865563, []int{53}
}
func (m *Watermark) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -1591,6 +1619,7 @@ func init() {
proto.RegisterType((*UDF)(nil), "github.com.numaproj.numaflow.pkg.apis.numaflow.v1alpha1.UDF")
proto.RegisterType((*UDSink)(nil), "github.com.numaproj.numaflow.pkg.apis.numaflow.v1alpha1.UDSink")
proto.RegisterType((*Vertex)(nil), "github.com.numaproj.numaflow.pkg.apis.numaflow.v1alpha1.Vertex")
+ proto.RegisterType((*VertexInstance)(nil), "github.com.numaproj.numaflow.pkg.apis.numaflow.v1alpha1.VertexInstance")
proto.RegisterType((*VertexLimits)(nil), "github.com.numaproj.numaflow.pkg.apis.numaflow.v1alpha1.VertexLimits")
proto.RegisterType((*VertexList)(nil), "github.com.numaproj.numaflow.pkg.apis.numaflow.v1alpha1.VertexList")
proto.RegisterType((*VertexSpec)(nil), "github.com.numaproj.numaflow.pkg.apis.numaflow.v1alpha1.VertexSpec")
@@ -1603,286 +1632,291 @@ func init() {
}
var fileDescriptor_9d0d1b17d3865563 = []byte{
- // 4453 bytes of a gzipped FileDescriptorProto
+ // 4529 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5c, 0x4f, 0x6c, 0x1c, 0x59,
- 0x5a, 0x4f, 0xf5, 0x1f, 0xbb, 0xfb, 0x6b, 0x3b, 0xb6, 0x5f, 0x32, 0xa1, 0x63, 0x32, 0xee, 0x50,
- 0xa3, 0x19, 0x05, 0xd8, 0x6d, 0x33, 0x66, 0x96, 0xcd, 0xc2, 0xce, 0x66, 0xdc, 0x76, 0xec, 0x71,
- 0x62, 0x67, 0xcc, 0x6b, 0x3b, 0x61, 0x76, 0x56, 0x84, 0xe7, 0xea, 0xd7, 0xed, 0x9a, 0xae, 0xae,
- 0xea, 0xad, 0x7a, 0xe5, 0xc4, 0x23, 0x56, 0x20, 0x71, 0x18, 0x10, 0xa0, 0x5d, 0x89, 0x0b, 0xd2,
- 0x0a, 0xc4, 0x61, 0x25, 0xc4, 0x81, 0x0b, 0x02, 0x09, 0x81, 0x56, 0xe2, 0x84, 0x86, 0xdb, 0x1c,
- 0x90, 0x18, 0xa4, 0x95, 0xb5, 0x63, 0x24, 0x6e, 0x88, 0x45, 0x73, 0x8b, 0x90, 0x40, 0xef, 0x4f,
- 0xfd, 0xed, 0x6a, 0xc7, 0xee, 0xb6, 0xc3, 0x81, 0xdc, 0xba, 0xde, 0xf7, 0xbd, 0xdf, 0xf7, 0xfe,
- 0x7e, 0xef, 0xfb, 0xf3, 0x5e, 0xc3, 0x7a, 0xc7, 0x64, 0xfb, 0xfe, 0x5e, 0xdd, 0x70, 0x7a, 0x8b,
- 0xb6, 0xdf, 0x23, 0x7d, 0xd7, 0xf9, 0x50, 0xfc, 0x68, 0x5b, 0xce, 0x93, 0xc5, 0x7e, 0xb7, 0xb3,
- 0x48, 0xfa, 0xa6, 0x17, 0x95, 0x1c, 0xbc, 0x49, 0xac, 0xfe, 0x3e, 0x79, 0x73, 0xb1, 0x43, 0x6d,
- 0xea, 0x12, 0x46, 0x5b, 0xf5, 0xbe, 0xeb, 0x30, 0x07, 0x7d, 0x35, 0x02, 0xaa, 0x07, 0x40, 0xf5,
- 0xa0, 0x5a, 0xbd, 0xdf, 0xed, 0xd4, 0x39, 0x50, 0x54, 0x12, 0x00, 0xcd, 0x7f, 0x39, 0xd6, 0x82,
- 0x8e, 0xd3, 0x71, 0x16, 0x05, 0xde, 0x9e, 0xdf, 0x16, 0x5f, 0xe2, 0x43, 0xfc, 0x92, 0x72, 0xe6,
- 0xf5, 0xee, 0x6d, 0xaf, 0x6e, 0x3a, 0xbc, 0x59, 0x8b, 0x86, 0xe3, 0xd2, 0xc5, 0x83, 0x81, 0xb6,
- 0xcc, 0xbf, 0x15, 0xf1, 0xf4, 0x88, 0xb1, 0x6f, 0xda, 0xd4, 0x3d, 0x0c, 0xfa, 0xb2, 0xe8, 0x52,
- 0xcf, 0xf1, 0x5d, 0x83, 0x9e, 0xa9, 0x96, 0xb7, 0xd8, 0xa3, 0x8c, 0x64, 0xc9, 0x5a, 0x1c, 0x56,
- 0xcb, 0xf5, 0x6d, 0x66, 0xf6, 0x06, 0xc5, 0xfc, 0xd2, 0xf3, 0x2a, 0x78, 0xc6, 0x3e, 0xed, 0x91,
- 0x74, 0x3d, 0xfd, 0x3f, 0xa7, 0xe0, 0xf2, 0xf2, 0x9e, 0xc7, 0x5c, 0x62, 0xb0, 0x87, 0xd4, 0x65,
- 0xf4, 0x29, 0xba, 0x09, 0x05, 0x9b, 0xf4, 0x68, 0x55, 0xbb, 0xa9, 0xdd, 0x2a, 0x37, 0xa6, 0x3e,
- 0x39, 0xaa, 0x5d, 0x3a, 0x3e, 0xaa, 0x15, 0x1e, 0x90, 0x1e, 0xc5, 0x82, 0x82, 0x0c, 0x98, 0x90,
- 0xbd, 0xad, 0xe6, 0x6f, 0x6a, 0xb7, 0x2a, 0x4b, 0x77, 0xea, 0x23, 0x4e, 0x53, 0xbd, 0x29, 0x60,
- 0x1a, 0x70, 0x7c, 0x54, 0x9b, 0x90, 0xbf, 0xb1, 0x82, 0x46, 0x1f, 0x40, 0xc1, 0x33, 0xed, 0x6e,
- 0xb5, 0x20, 0x44, 0xbc, 0x3d, 0xba, 0x08, 0xd3, 0xee, 0x36, 0x4a, 0xbc, 0x07, 0xfc, 0x17, 0x16,
- 0xa0, 0xe8, 0xbb, 0x1a, 0xcc, 0x19, 0x8e, 0xcd, 0x08, 0x1f, 0xa8, 0x1d, 0xda, 0xeb, 0x5b, 0x84,
- 0xd1, 0x6a, 0x51, 0x88, 0xba, 0x37, 0xb2, 0xa8, 0x95, 0x34, 0x62, 0xe3, 0x95, 0xe3, 0xa3, 0xda,
- 0xdc, 0x40, 0x31, 0x1e, 0x94, 0x8d, 0x1e, 0x41, 0xde, 0x6f, 0xb5, 0xab, 0x13, 0xa2, 0x09, 0x5f,
- 0x1f, 0xb9, 0x09, 0xbb, 0xab, 0x6b, 0x8d, 0xc9, 0xe3, 0xa3, 0x5a, 0x7e, 0x77, 0x75, 0x0d, 0x73,
- 0x44, 0xd4, 0x85, 0x12, 0x5f, 0x65, 0x2d, 0xc2, 0x48, 0x75, 0x52, 0xa0, 0x2f, 0x8f, 0x8c, 0xbe,
- 0xa5, 0x80, 0x1a, 0x53, 0xc7, 0x47, 0xb5, 0x52, 0xf0, 0x85, 0x43, 0x01, 0xe8, 0x8f, 0x34, 0x98,
- 0xb2, 0x9d, 0x16, 0x6d, 0x52, 0x8b, 0x1a, 0xcc, 0x71, 0xab, 0xa5, 0x9b, 0xf9, 0x5b, 0x95, 0xa5,
- 0xf7, 0x47, 0x96, 0x98, 0x5c, 0x9b, 0xf5, 0x07, 0x31, 0xec, 0xbb, 0x36, 0x73, 0x0f, 0x1b, 0x57,
- 0xd5, 0xfa, 0x9c, 0x8a, 0x93, 0x70, 0xa2, 0x11, 0x68, 0x17, 0x2a, 0xcc, 0xb1, 0xf8, 0xba, 0x37,
- 0x1d, 0xdb, 0xab, 0x96, 0x45, 0x9b, 0x16, 0xea, 0x72, 0xcb, 0x70, 0xc9, 0x75, 0xbe, 0xe7, 0xeb,
- 0x07, 0x6f, 0xd6, 0x77, 0x42, 0xb6, 0xc6, 0x15, 0x05, 0x5c, 0x89, 0xca, 0x3c, 0x1c, 0xc7, 0x41,
- 0x14, 0x66, 0x3c, 0x6a, 0xf8, 0xae, 0xc9, 0x0e, 0xf9, 0x14, 0xd3, 0xa7, 0xac, 0x0a, 0x62, 0x80,
- 0xdf, 0xc8, 0x82, 0xde, 0x76, 0x5a, 0xcd, 0x24, 0x77, 0xe3, 0xca, 0xf1, 0x51, 0x6d, 0x26, 0x55,
- 0x88, 0xd3, 0x98, 0xc8, 0x86, 0x59, 0xb3, 0x47, 0x3a, 0x74, 0xdb, 0xb7, 0xac, 0x26, 0x35, 0x5c,
- 0xca, 0xbc, 0x6a, 0x45, 0x74, 0xe1, 0x56, 0x96, 0x9c, 0x4d, 0xc7, 0x20, 0xd6, 0x7b, 0x7b, 0x1f,
- 0x52, 0x83, 0x61, 0xda, 0xa6, 0x2e, 0xb5, 0x0d, 0xda, 0xa8, 0xaa, 0xce, 0xcc, 0x6e, 0xa4, 0x90,
- 0xf0, 0x00, 0x36, 0x5a, 0x87, 0xb9, 0xbe, 0x6b, 0x3a, 0xa2, 0x09, 0x16, 0xf1, 0x3c, 0xbe, 0xf1,
- 0xab, 0x53, 0x42, 0x19, 0x5c, 0x57, 0x30, 0x73, 0xdb, 0x69, 0x06, 0x3c, 0x58, 0x07, 0xdd, 0x82,
- 0x52, 0x50, 0x58, 0x9d, 0xbe, 0xa9, 0xdd, 0x2a, 0xca, 0x65, 0x13, 0xd4, 0xc5, 0x21, 0x15, 0xad,
- 0x41, 0x89, 0xb4, 0xdb, 0xa6, 0xcd, 0x39, 0x2f, 0x8b, 0x21, 0xbc, 0x91, 0xd5, 0xb5, 0x65, 0xc5,
- 0x23, 0x71, 0x82, 0x2f, 0x1c, 0xd6, 0x45, 0xf7, 0x00, 0x79, 0xd4, 0x3d, 0x30, 0x0d, 0xba, 0x6c,
- 0x18, 0x8e, 0x6f, 0x33, 0xd1, 0xf6, 0x19, 0xd1, 0xf6, 0x79, 0xd5, 0x76, 0xd4, 0x1c, 0xe0, 0xc0,
- 0x19, 0xb5, 0xd0, 0x5d, 0x98, 0x3c, 0x70, 0x2c, 0xbf, 0x47, 0xbd, 0xea, 0xac, 0x18, 0xed, 0xf9,
- 0xac, 0x26, 0x3d, 0x14, 0x2c, 0x8d, 0x19, 0x05, 0x3e, 0x29, 0xbf, 0x3d, 0x1c, 0xd4, 0x45, 0x26,
- 0x4c, 0x58, 0x66, 0xcf, 0x64, 0x5e, 0x75, 0x4e, 0x74, 0xec, 0xee, 0xc8, 0x5b, 0x41, 0x6e, 0x81,
- 0x4d, 0x01, 0x26, 0x35, 0xa6, 0xfc, 0x8d, 0x95, 0x00, 0x64, 0x40, 0xd1, 0x33, 0x88, 0x45, 0xab,
- 0x48, 0x48, 0xfa, 0xc6, 0xe8, 0x2a, 0x93, 0xa3, 0x34, 0xa6, 0x55, 0x9f, 0x8a, 0xe2, 0x13, 0x4b,
- 0xec, 0xf9, 0x3b, 0x30, 0x37, 0xb0, 0x09, 0xd1, 0x2c, 0xe4, 0xbb, 0xf4, 0x50, 0x9e, 0x18, 0x98,
- 0xff, 0x44, 0x57, 0xa1, 0x78, 0x40, 0x2c, 0x9f, 0x56, 0x73, 0xa2, 0x4c, 0x7e, 0xfc, 0x72, 0xee,
- 0xb6, 0xa6, 0x3f, 0x82, 0xe9, 0x65, 0x9f, 0xed, 0x3b, 0xae, 0xf9, 0x91, 0xd8, 0x47, 0x68, 0x0d,
- 0x8a, 0xcc, 0xe9, 0x52, 0x5b, 0x54, 0xaf, 0x2c, 0xbd, 0x9e, 0x35, 0xcc, 0x72, 0x6d, 0xde, 0xa7,
- 0x87, 0x81, 0xdc, 0x46, 0x99, 0xb7, 0x6c, 0x87, 0xd7, 0xc3, 0xb2, 0xba, 0xfe, 0x4d, 0x98, 0x68,
- 0xf8, 0xed, 0x36, 0x75, 0x4f, 0x71, 0x82, 0xd5, 0xa1, 0xc0, 0x0e, 0xfb, 0xaa, 0x75, 0xe1, 0xd2,
- 0x28, 0xec, 0x1c, 0xf6, 0xe9, 0xb3, 0xa3, 0x1a, 0x48, 0x1c, 0xfe, 0x85, 0x05, 0x9f, 0xfe, 0x85,
- 0x06, 0x57, 0x64, 0xa1, 0x5a, 0x3d, 0x2b, 0x8e, 0xdd, 0x36, 0x3b, 0x88, 0x42, 0xd1, 0xa5, 0x2d,
- 0xd3, 0x53, 0x6d, 0x5f, 0x1d, 0x79, 0xc8, 0x31, 0x47, 0x91, 0xa0, 0xb2, 0x6b, 0xa2, 0x00, 0x4b,
- 0x74, 0xe4, 0x43, 0xf9, 0x43, 0xca, 0x3c, 0xe6, 0x52, 0xd2, 0x13, 0x6d, 0xae, 0x2c, 0xbd, 0x3b,
- 0xb2, 0xa8, 0x7b, 0x94, 0x35, 0x05, 0x92, 0x12, 0x37, 0x7d, 0x7c, 0x54, 0x2b, 0x87, 0x85, 0x38,
- 0x92, 0xa4, 0xff, 0x7b, 0x0e, 0xca, 0xe1, 0xe1, 0x85, 0x5e, 0x83, 0xa2, 0xd0, 0x15, 0x6a, 0x58,
- 0xc3, 0xe5, 0x21, 0x54, 0x0a, 0x96, 0x34, 0xf4, 0x3a, 0x4c, 0x1a, 0x4e, 0xaf, 0x47, 0xec, 0x56,
- 0x35, 0x77, 0x33, 0x7f, 0xab, 0xdc, 0xa8, 0xf0, 0x5d, 0xb1, 0x22, 0x8b, 0x70, 0x40, 0x43, 0x37,
- 0xa0, 0x40, 0xdc, 0x8e, 0x57, 0xcd, 0x0b, 0x1e, 0x71, 0x3a, 0x2f, 0xbb, 0x1d, 0x0f, 0x8b, 0x52,
- 0xf4, 0x35, 0xc8, 0x53, 0xfb, 0xa0, 0x5a, 0x18, 0xbe, 0xed, 0xee, 0xda, 0x07, 0x0f, 0x89, 0xdb,
- 0xa8, 0xa8, 0x36, 0xe4, 0xef, 0xda, 0x07, 0x98, 0xd7, 0x41, 0xef, 0xc3, 0x94, 0xdc, 0x79, 0x5b,
- 0x7c, 0x23, 0x7b, 0xd5, 0xa2, 0xc0, 0xa8, 0x0d, 0xdf, 0xba, 0x82, 0x2f, 0x3a, 0x45, 0x62, 0x85,
- 0x1e, 0x4e, 0x40, 0xa1, 0xf7, 0xa1, 0x1c, 0x58, 0x79, 0x9e, 0x3a, 0xa7, 0x33, 0x15, 0x30, 0x56,
- 0x4c, 0x98, 0x7e, 0xdb, 0x37, 0x5d, 0xda, 0xa3, 0x36, 0xf3, 0x1a, 0x73, 0x4a, 0x40, 0x39, 0xa0,
- 0x7a, 0x38, 0x42, 0xd3, 0xff, 0x2b, 0x07, 0x83, 0x56, 0x42, 0x52, 0xa0, 0x76, 0x9e, 0x02, 0xd1,
- 0x1e, 0xcc, 0x84, 0x7a, 0x7f, 0xdb, 0xb1, 0x4c, 0xe3, 0x50, 0x6d, 0x85, 0xdb, 0xaa, 0xda, 0xcc,
- 0x46, 0x92, 0xfc, 0xec, 0xa8, 0xf6, 0xea, 0xa0, 0x8d, 0x5c, 0x8f, 0x18, 0x70, 0x1a, 0x90, 0xcb,
- 0x48, 0x1f, 0x8f, 0xd2, 0x5c, 0x7c, 0x6d, 0xc8, 0x0e, 0x1f, 0xe1, 0x6c, 0x1c, 0x7d, 0xa5, 0xe8,
- 0x7f, 0x91, 0x83, 0xc2, 0xdd, 0x56, 0x87, 0x72, 0x6d, 0xd1, 0x76, 0x9d, 0x5e, 0x5a, 0x5b, 0xac,
- 0xb9, 0x4e, 0x0f, 0x0b, 0x0a, 0x9a, 0x87, 0x1c, 0x73, 0xd4, 0x00, 0x81, 0xa2, 0xe7, 0x76, 0x1c,
- 0x9c, 0x63, 0x0e, 0xfa, 0x08, 0xc0, 0x70, 0xec, 0x96, 0x29, 0x4d, 0x8b, 0xfc, 0x98, 0x16, 0xe4,
- 0x9a, 0xe3, 0x3e, 0x21, 0x6e, 0x6b, 0x25, 0x44, 0x6c, 0x5c, 0x3e, 0x3e, 0xaa, 0x41, 0xf4, 0x8d,
- 0x63, 0xd2, 0x50, 0x27, 0x3c, 0x5b, 0xa4, 0x91, 0xbc, 0x32, 0xb2, 0x5c, 0x3e, 0x10, 0xc3, 0x4f,
- 0x16, 0xfd, 0x0f, 0x35, 0x80, 0x88, 0x05, 0xbd, 0x0d, 0x33, 0x7b, 0x42, 0x19, 0x6e, 0x91, 0xa7,
- 0x9b, 0xd4, 0xee, 0xb0, 0x7d, 0x31, 0x78, 0x05, 0x39, 0x69, 0x8d, 0x24, 0x09, 0xa7, 0x79, 0xd1,
- 0x3b, 0x30, 0x2b, 0x8b, 0x76, 0x3d, 0xa2, 0x30, 0xc5, 0xe0, 0x4e, 0x37, 0xae, 0x72, 0x13, 0xa5,
- 0x91, 0xa2, 0xe1, 0x01, 0x6e, 0xfd, 0x2d, 0x98, 0x1b, 0x18, 0x29, 0x54, 0x83, 0x62, 0x97, 0x1e,
- 0x6e, 0xf0, 0x73, 0x84, 0x2b, 0x15, 0xa1, 0x45, 0xef, 0xf3, 0x02, 0x2c, 0xcb, 0xf5, 0xff, 0xd6,
- 0xa0, 0xb4, 0xe6, 0xdb, 0x86, 0x38, 0x75, 0x9e, 0x7f, 0x46, 0x04, 0x3a, 0x2a, 0x97, 0xa9, 0xa3,
- 0x7c, 0x98, 0xe8, 0x3e, 0x09, 0x75, 0x58, 0x65, 0x69, 0x6b, 0xf4, 0x39, 0x57, 0x4d, 0xaa, 0xdf,
- 0x17, 0x78, 0xd2, 0xac, 0xbd, 0xac, 0x1a, 0x34, 0x71, 0xff, 0x91, 0x10, 0xaa, 0x84, 0xcd, 0x7f,
- 0x0d, 0x2a, 0x31, 0xb6, 0x33, 0x1d, 0xbc, 0x7f, 0xa9, 0xc1, 0xcc, 0xba, 0x74, 0xff, 0x1c, 0x57,
- 0x3a, 0x5b, 0xe8, 0x3a, 0xe4, 0xdd, 0xbe, 0x2f, 0xea, 0xe7, 0xa5, 0xdf, 0x80, 0xb7, 0x77, 0x31,
- 0x2f, 0x43, 0xbf, 0x06, 0xa5, 0x96, 0x2f, 0x4d, 0x5d, 0x75, 0xe4, 0xd4, 0x63, 0xfb, 0x2b, 0x74,
- 0x32, 0xa3, 0x9e, 0x71, 0x27, 0x80, 0xef, 0xb8, 0x55, 0x55, 0x4b, 0x5a, 0x69, 0xc1, 0x17, 0x0e,
- 0xd1, 0xf8, 0x19, 0xd1, 0xf3, 0x3a, 0x4d, 0xf3, 0x23, 0xe9, 0x3f, 0x16, 0xe5, 0x19, 0xb1, 0x25,
- 0x8b, 0x70, 0x40, 0xd3, 0xbf, 0x9b, 0x83, 0x6b, 0xeb, 0x94, 0xad, 0x12, 0xda, 0x73, 0xec, 0x55,
- 0xda, 0xb7, 0x9c, 0x43, 0xae, 0xda, 0x30, 0xfd, 0x36, 0x7a, 0x07, 0xc0, 0xf4, 0xf6, 0x9a, 0x07,
- 0x06, 0x3f, 0xa2, 0xd5, 0x14, 0xde, 0x54, 0x23, 0x06, 0x1b, 0xcd, 0x86, 0xa2, 0x3c, 0x4b, 0x7c,
- 0xe1, 0x58, 0x9d, 0xe8, 0x30, 0xcb, 0x9d, 0x70, 0x98, 0x35, 0x01, 0xfa, 0x91, 0x82, 0xcc, 0x0b,
- 0xce, 0x5f, 0x0c, 0xc4, 0x9c, 0x45, 0x37, 0xc6, 0x60, 0xc6, 0x51, 0x59, 0x7f, 0x97, 0x87, 0xf9,
- 0x75, 0xca, 0xc2, 0xb3, 0x5a, 0xd9, 0x22, 0xcd, 0x3e, 0x35, 0xf8, 0xa8, 0x7c, 0xac, 0xc1, 0x84,
- 0x45, 0xf6, 0xa8, 0xe5, 0x89, 0x2d, 0x50, 0x59, 0x7a, 0x3c, 0xf2, 0x9a, 0x1c, 0x2e, 0xa5, 0xbe,
- 0x29, 0x24, 0xa4, 0x56, 0xa9, 0x2c, 0xc4, 0x4a, 0x3c, 0xfa, 0x0a, 0x54, 0x0c, 0xcb, 0xf7, 0x18,
- 0x75, 0xb7, 0x1d, 0x57, 0x6e, 0xee, 0x62, 0xe4, 0x50, 0xad, 0x44, 0x24, 0x1c, 0xe7, 0x43, 0x4b,
- 0x00, 0x86, 0x65, 0x52, 0x9b, 0x89, 0x5a, 0x72, 0x6d, 0xa0, 0x60, 0xbc, 0x57, 0x42, 0x0a, 0x8e,
- 0x71, 0x71, 0x51, 0x3d, 0xc7, 0x36, 0x99, 0x23, 0x45, 0x15, 0x92, 0xa2, 0xb6, 0x22, 0x12, 0x8e,
- 0xf3, 0x89, 0x6a, 0x94, 0xb9, 0xa6, 0xe1, 0x89, 0x6a, 0xc5, 0x54, 0xb5, 0x88, 0x84, 0xe3, 0x7c,
- 0x7c, 0xfb, 0xc5, 0xfa, 0x7f, 0xa6, 0xed, 0xf7, 0xf7, 0x25, 0x58, 0x48, 0x0c, 0x2b, 0x23, 0x8c,
- 0xb6, 0x7d, 0xab, 0x49, 0x59, 0x30, 0x81, 0x5f, 0x81, 0x8a, 0x72, 0x44, 0x1e, 0x44, 0xaa, 0x29,
- 0x6c, 0x54, 0x33, 0x22, 0xe1, 0x38, 0x1f, 0xfa, 0xfd, 0x68, 0xde, 0x73, 0x62, 0xde, 0x8d, 0xf3,
- 0x99, 0xf7, 0x81, 0x06, 0x9e, 0x6a, 0xee, 0x17, 0xa1, 0x6c, 0x13, 0xe6, 0x89, 0x8d, 0xa4, 0xf6,
- 0x4c, 0x68, 0x8b, 0x3c, 0x08, 0x08, 0x38, 0xe2, 0x41, 0xdb, 0x70, 0x55, 0x0d, 0xf1, 0xdd, 0xa7,
- 0x7d, 0xc7, 0x65, 0xd4, 0x95, 0x75, 0x0b, 0xa2, 0xee, 0x0d, 0x55, 0xf7, 0xea, 0x56, 0x06, 0x0f,
- 0xce, 0xac, 0x89, 0xb6, 0xe0, 0x8a, 0x21, 0x6c, 0x5b, 0x4c, 0x2d, 0x87, 0xb4, 0x02, 0xc0, 0xa2,
- 0x00, 0xfc, 0x69, 0x05, 0x78, 0x65, 0x65, 0x90, 0x05, 0x67, 0xd5, 0x4b, 0xaf, 0xe6, 0x89, 0x91,
- 0x56, 0xf3, 0xe4, 0x28, 0xab, 0xb9, 0x34, 0xda, 0x6a, 0x2e, 0x9f, 0x6e, 0x35, 0xf3, 0x91, 0xe7,
- 0xeb, 0x88, 0xba, 0xdc, 0x21, 0x93, 0x2e, 0x96, 0x58, 0x78, 0x90, 0x1c, 0xf9, 0x66, 0x06, 0x0f,
- 0xce, 0xac, 0x89, 0xf6, 0x60, 0x5e, 0x96, 0xdf, 0xb5, 0x0d, 0xf7, 0xb0, 0xcf, 0xd5, 0x7d, 0x0c,
- 0xb7, 0x22, 0x70, 0x75, 0x85, 0x3b, 0xdf, 0x1c, 0xca, 0x89, 0x4f, 0x40, 0x41, 0xbf, 0x02, 0xd3,
- 0x72, 0x96, 0xb6, 0x48, 0x3f, 0x16, 0x9b, 0x78, 0x45, 0xc1, 0x4e, 0xaf, 0xc4, 0x89, 0x38, 0xc9,
- 0x8b, 0x96, 0x61, 0xa6, 0x7f, 0x60, 0xf0, 0x9f, 0x1b, 0xed, 0x07, 0x94, 0xb6, 0x68, 0x4b, 0x84,
- 0x26, 0xca, 0x8d, 0x9f, 0x0a, 0x0c, 0xdf, 0xed, 0x24, 0x19, 0xa7, 0xf9, 0xd1, 0x6d, 0x98, 0xf2,
- 0x18, 0x71, 0x99, 0x72, 0x6a, 0x44, 0xc0, 0xa2, 0x1c, 0x79, 0x10, 0xcd, 0x18, 0x0d, 0x27, 0x38,
- 0xc7, 0xd1, 0x1e, 0xcf, 0xe4, 0x61, 0x28, 0xbc, 0xc2, 0x94, 0xda, 0xff, 0x9d, 0xb4, 0xda, 0xff,
- 0x60, 0x9c, 0xed, 0x9f, 0x21, 0xe1, 0x54, 0xdb, 0xfe, 0x1e, 0x20, 0x57, 0xf9, 0xb0, 0xd2, 0x8d,
- 0x89, 0x69, 0xfe, 0x30, 0xf4, 0x82, 0x07, 0x38, 0x70, 0x46, 0x2d, 0xd4, 0x84, 0x57, 0x3c, 0x6a,
- 0x33, 0xd3, 0xa6, 0x56, 0x12, 0x4e, 0x1e, 0x09, 0xaf, 0x2a, 0xb8, 0x57, 0x9a, 0x59, 0x4c, 0x38,
- 0xbb, 0xee, 0x38, 0x83, 0xff, 0xa3, 0xb2, 0x38, 0x77, 0xe5, 0xd0, 0x9c, 0x9b, 0xda, 0xfe, 0x38,
- 0xad, 0xb6, 0x1f, 0x8f, 0x3f, 0x6f, 0xa3, 0xa9, 0xec, 0x25, 0x00, 0x31, 0x0b, 0x71, 0x9d, 0x1d,
- 0x6a, 0x2a, 0x1c, 0x52, 0x70, 0x8c, 0x8b, 0xef, 0xc2, 0x60, 0x9c, 0xe3, 0xea, 0x3a, 0xdc, 0x85,
- 0xcd, 0x38, 0x11, 0x27, 0x79, 0x87, 0xaa, 0xfc, 0xe2, 0xc8, 0x2a, 0xff, 0x1e, 0x20, 0xd3, 0x36,
- 0x59, 0x38, 0xe5, 0x12, 0x6f, 0x22, 0x19, 0xf9, 0xdb, 0x18, 0xe0, 0xc0, 0x19, 0xb5, 0x86, 0x2c,
- 0xe5, 0xc9, 0xf3, 0x5d, 0xca, 0xa5, 0xd1, 0x97, 0x32, 0x7a, 0x0c, 0xd7, 0x85, 0x28, 0x35, 0x3e,
- 0x49, 0x60, 0xa9, 0xfc, 0x7f, 0x46, 0x01, 0x5f, 0xc7, 0xc3, 0x18, 0xf1, 0x70, 0x0c, 0x3e, 0x3f,
- 0x86, 0x4b, 0x5b, 0x5c, 0x38, 0xb1, 0x86, 0x1f, 0x0c, 0x2b, 0x19, 0x3c, 0x38, 0xb3, 0x26, 0x5f,
- 0x62, 0x8c, 0x2f, 0x43, 0xb2, 0x67, 0xd1, 0x96, 0x38, 0x08, 0x4a, 0xd1, 0x12, 0xdb, 0xd9, 0x6c,
- 0x2a, 0x0a, 0x8e, 0x71, 0x65, 0xe9, 0xea, 0xa9, 0x33, 0xea, 0xea, 0x75, 0x91, 0xe6, 0x69, 0x27,
- 0x8e, 0x04, 0xa5, 0xf0, 0xc3, 0x58, 0xf6, 0x4a, 0x9a, 0x01, 0x0f, 0xd6, 0x11, 0x47, 0xa5, 0xe1,
- 0x9a, 0x7d, 0xe6, 0x25, 0xb1, 0x2e, 0xa7, 0x8e, 0xca, 0x0c, 0x1e, 0x9c, 0x59, 0x93, 0x1b, 0x29,
- 0xfb, 0x94, 0x58, 0x6c, 0x3f, 0x09, 0x38, 0x93, 0x34, 0x52, 0xde, 0x1d, 0x64, 0xc1, 0x59, 0xf5,
- 0xc6, 0x51, 0x6f, 0x7f, 0x90, 0x83, 0x2b, 0xeb, 0x54, 0xa5, 0x58, 0xb6, 0x9d, 0x56, 0xa0, 0xd7,
- 0xfe, 0x9f, 0x7a, 0x59, 0x7f, 0xa2, 0x01, 0xbc, 0xbb, 0xb3, 0xb3, 0xad, 0x5c, 0xe4, 0x16, 0x14,
- 0x88, 0xaf, 0x22, 0x1c, 0x95, 0xa5, 0xb5, 0xd1, 0x33, 0x59, 0xf1, 0xa0, 0xb7, 0x0a, 0x27, 0xf8,
- 0x6c, 0x1f, 0x0b, 0x74, 0xf4, 0xb3, 0x30, 0xa9, 0xce, 0x06, 0x31, 0x56, 0xa5, 0x28, 0xa3, 0xa0,
- 0xce, 0x0f, 0x1c, 0xd0, 0xf5, 0x9f, 0xe4, 0xe0, 0xda, 0x86, 0xcd, 0xa8, 0xdb, 0x64, 0xb4, 0x9f,
- 0x08, 0x4a, 0xa3, 0xdf, 0x88, 0xe5, 0xfa, 0x64, 0x7b, 0x7f, 0xe1, 0x74, 0x3e, 0xbb, 0xcc, 0x17,
- 0x6d, 0x51, 0x46, 0xa2, 0x5d, 0x19, 0x95, 0xc5, 0x12, 0x7c, 0x3e, 0x14, 0xbc, 0x3e, 0x35, 0x54,
- 0x44, 0xa0, 0x39, 0xf2, 0x68, 0x64, 0x77, 0x80, 0xaf, 0xbc, 0x28, 0x16, 0x23, 0xd6, 0xa1, 0x10,
- 0x87, 0xbe, 0x03, 0x13, 0x1e, 0x23, 0xcc, 0x0f, 0x22, 0x6c, 0xbb, 0xe7, 0x2d, 0x58, 0x80, 0x47,
- 0x07, 0xa4, 0xfc, 0xc6, 0x4a, 0xa8, 0xfe, 0x13, 0x0d, 0xe6, 0xb3, 0x2b, 0x6e, 0x9a, 0x1e, 0x43,
- 0xdf, 0x1a, 0x18, 0xf6, 0x53, 0x86, 0x4a, 0x78, 0x6d, 0x31, 0xe8, 0xb3, 0x4a, 0x70, 0x29, 0x28,
- 0x89, 0x0d, 0x39, 0x83, 0xa2, 0xc9, 0x68, 0x2f, 0xb0, 0x12, 0xde, 0x3b, 0xe7, 0xae, 0xc7, 0x76,
- 0x25, 0x97, 0x82, 0xa5, 0x30, 0xfd, 0xe3, 0xdc, 0xb0, 0x2e, 0xf3, 0x69, 0x41, 0xdd, 0x64, 0xe2,
- 0xe3, 0xde, 0x78, 0x89, 0x8f, 0x86, 0x1f, 0x6b, 0xcf, 0x60, 0xfa, 0xe3, 0x37, 0x07, 0xd3, 0x1f,
- 0xef, 0x8d, 0x9f, 0xfe, 0x48, 0x8d, 0xc2, 0xd0, 0x2c, 0xc8, 0x8f, 0x72, 0x70, 0xe3, 0xa4, 0x55,
- 0x83, 0x3a, 0xe1, 0xe2, 0xd4, 0xc6, 0xbd, 0x0e, 0x71, 0xe2, 0x32, 0x44, 0x4b, 0x50, 0xec, 0xef,
- 0x13, 0x2f, 0x50, 0xa7, 0xc1, 0xa9, 0x53, 0xdc, 0xe6, 0x85, 0xcf, 0x8e, 0x6a, 0x15, 0xa9, 0x86,
- 0xc5, 0x27, 0x96, 0xac, 0x5c, 0xb1, 0xf4, 0xa8, 0xe7, 0x45, 0x86, 0x5d, 0xa8, 0x58, 0xb6, 0x64,
- 0x31, 0x0e, 0xe8, 0x88, 0xc1, 0x84, 0x74, 0x96, 0x54, 0x38, 0x79, 0x73, 0xe4, 0x7e, 0x64, 0xa4,
- 0xca, 0xa2, 0x4e, 0x29, 0xbf, 0x5b, 0xc9, 0xd2, 0xff, 0xea, 0x32, 0x5c, 0xcb, 0x9e, 0x13, 0xde,
- 0xf6, 0x03, 0xea, 0x7a, 0xa6, 0x63, 0xab, 0xd3, 0x27, 0x4a, 0xb3, 0xca, 0x62, 0x1c, 0xd0, 0xd1,
- 0x2d, 0x28, 0xb9, 0xb4, 0x6f, 0x99, 0x06, 0xf1, 0x94, 0xd3, 0x21, 0xa2, 0x8f, 0x58, 0x95, 0xe1,
- 0x90, 0x3a, 0xe4, 0xea, 0x47, 0xfe, 0xff, 0xf0, 0xea, 0xc7, 0x9f, 0x6b, 0xdc, 0x9e, 0x93, 0x11,
- 0x87, 0x81, 0x0a, 0x6a, 0x2e, 0xce, 0xb3, 0x65, 0xaf, 0x4a, 0xbb, 0x70, 0x88, 0x40, 0x3c, 0xbc,
- 0x2d, 0xe8, 0x07, 0x1a, 0x54, 0x7b, 0x29, 0x83, 0xf1, 0x02, 0x6f, 0xcf, 0xdc, 0x38, 0x3e, 0xaa,
- 0x55, 0xb7, 0x86, 0xc8, 0xc3, 0x43, 0x5b, 0x82, 0x7e, 0x0b, 0x2a, 0x7d, 0xbe, 0x2e, 0x3c, 0x46,
- 0x6d, 0x83, 0xaa, 0x5c, 0xdd, 0xe8, 0xab, 0x79, 0x3b, 0xc2, 0x6a, 0x32, 0x97, 0x30, 0xda, 0x39,
- 0x6c, 0xcc, 0x70, 0xd7, 0x2e, 0x46, 0xc0, 0x71, 0x89, 0x89, 0x3b, 0x37, 0x5b, 0x17, 0x7d, 0xe7,
- 0xe6, 0xfb, 0xd9, 0x77, 0x6e, 0xc8, 0x39, 0x6b, 0xc8, 0x97, 0x77, 0x6f, 0x5e, 0xde, 0xbd, 0x79,
- 0x51, 0x77, 0x6f, 0x6e, 0x41, 0xc9, 0xa3, 0x8c, 0x99, 0x76, 0xc7, 0xab, 0xce, 0xca, 0x04, 0x1d,
- 0x97, 0xda, 0x54, 0x65, 0x38, 0xa4, 0xa2, 0x9f, 0x87, 0xb2, 0x08, 0xb1, 0x2d, 0xbb, 0x1d, 0xaf,
- 0x3a, 0x27, 0x32, 0x75, 0xe2, 0x24, 0x6f, 0x06, 0x85, 0x38, 0xa2, 0xa3, 0xb7, 0x60, 0x4a, 0xa6,
- 0x12, 0xe5, 0x11, 0x24, 0xee, 0xc9, 0x94, 0x1b, 0xb3, 0x7c, 0x05, 0x37, 0x62, 0xe5, 0x38, 0xc1,
- 0xc5, 0x5d, 0x57, 0x1a, 0xc6, 0x21, 0xab, 0x57, 0x92, 0xae, 0x6b, 0x14, 0xa1, 0xc4, 0x31, 0x2e,
- 0xf4, 0x2a, 0xe4, 0x99, 0xe5, 0x55, 0xaf, 0x0a, 0xe6, 0xd0, 0xc5, 0xd8, 0xd9, 0x6c, 0x62, 0x5e,
- 0x3e, 0xfe, 0x25, 0x9a, 0xff, 0xd1, 0x60, 0x26, 0x75, 0x8f, 0x83, 0xcb, 0xf4, 0x5d, 0x4b, 0x9d,
- 0x94, 0xa1, 0xcc, 0x5d, 0xbc, 0x89, 0x79, 0x39, 0x7a, 0xac, 0xfc, 0x98, 0xdc, 0x98, 0xfa, 0xe8,
- 0xc1, 0xf2, 0x4e, 0x93, 0x3b, 0x2e, 0x03, 0x2e, 0xcc, 0xed, 0xd4, 0xe8, 0xe6, 0x93, 0x71, 0xd1,
- 0x93, 0x47, 0x38, 0x16, 0x1c, 0x28, 0x9c, 0x26, 0x38, 0xa0, 0x7f, 0xa6, 0x41, 0xf9, 0x3e, 0x69,
- 0x77, 0x49, 0xd3, 0xb4, 0xbb, 0xe8, 0x75, 0x98, 0xdc, 0x73, 0x9d, 0x2e, 0x75, 0x3d, 0x95, 0xfd,
- 0x15, 0x29, 0xc5, 0x86, 0x2c, 0xc2, 0x01, 0x8d, 0xfb, 0xa3, 0xcc, 0xe9, 0x9b, 0x46, 0xda, 0x1f,
- 0xdd, 0xe1, 0x85, 0x58, 0xd2, 0xd0, 0x23, 0x39, 0x77, 0xf9, 0x31, 0x6f, 0x62, 0xee, 0x6c, 0x36,
- 0x65, 0x46, 0x35, 0x98, 0x75, 0xf4, 0x46, 0xc2, 0xbe, 0x2a, 0x0f, 0xb5, 0x88, 0xbe, 0x9f, 0x83,
- 0x8a, 0xec, 0x9a, 0xf4, 0x40, 0xcf, 0xb3, 0x73, 0x77, 0x44, 0xf0, 0xdc, 0xf3, 0x7b, 0xd4, 0x5d,
- 0x77, 0x1d, 0xbf, 0xaf, 0x66, 0x29, 0x1e, 0x0c, 0x89, 0x88, 0x61, 0x00, 0x3d, 0x2a, 0x0a, 0x46,
- 0xa7, 0x70, 0x81, 0xa3, 0x53, 0x3c, 0x71, 0x74, 0xfe, 0x5a, 0x83, 0xf2, 0xa6, 0xd9, 0xa6, 0xc6,
- 0xa1, 0x61, 0x51, 0xf4, 0x2d, 0xa8, 0xb6, 0xa8, 0x45, 0x19, 0x5d, 0x77, 0x89, 0x41, 0xb7, 0xa9,
- 0x6b, 0x0a, 0x55, 0xef, 0xd8, 0x2d, 0x69, 0x8d, 0x17, 0xc3, 0x88, 0x45, 0x75, 0x75, 0x08, 0x1f,
- 0x1e, 0x8a, 0x80, 0x36, 0x60, 0xaa, 0x45, 0x3d, 0xd3, 0xa5, 0xad, 0xed, 0x98, 0xdd, 0xfd, 0x7a,
- 0xb0, 0xa4, 0x57, 0x63, 0xb4, 0x67, 0x47, 0xb5, 0xe9, 0x6d, 0xb3, 0x4f, 0x2d, 0xd3, 0xa6, 0xd2,
- 0x00, 0x4f, 0x54, 0xd5, 0x8b, 0x90, 0xdf, 0x74, 0x3a, 0xfa, 0xef, 0xe6, 0x21, 0x3c, 0xc3, 0xd1,
- 0xef, 0x69, 0x50, 0x21, 0xb6, 0xed, 0x30, 0x75, 0x38, 0xca, 0xf0, 0x3d, 0x1e, 0xdb, 0x54, 0xa8,
- 0x2f, 0x47, 0xa0, 0xf2, 0xa4, 0x0e, 0x0f, 0xd4, 0x18, 0x05, 0xc7, 0x65, 0x23, 0x3f, 0x15, 0x8c,
- 0xde, 0x1a, 0xbf, 0x15, 0xa7, 0x08, 0x3d, 0xcf, 0x7f, 0x03, 0x66, 0xd3, 0x8d, 0x3d, 0x8b, 0x22,
- 0x1c, 0x27, 0xec, 0xf5, 0x67, 0x1a, 0x94, 0x02, 0x65, 0x86, 0x56, 0xa0, 0xe0, 0x7b, 0xd4, 0x3d,
- 0xdb, 0x1d, 0x44, 0xa1, 0x01, 0x77, 0x3d, 0xea, 0x62, 0x51, 0x19, 0xbd, 0x07, 0xa5, 0x3e, 0xf1,
- 0xbc, 0x27, 0x8e, 0xdb, 0x52, 0x6a, 0xf6, 0x94, 0x40, 0xf2, 0x6c, 0x56, 0x55, 0x71, 0x08, 0xa2,
- 0xff, 0x70, 0x1a, 0x2a, 0x0f, 0x08, 0x33, 0x0f, 0xa8, 0xf0, 0x87, 0x2f, 0xc6, 0x21, 0xfa, 0x53,
- 0x0d, 0xae, 0x25, 0x23, 0xd7, 0x17, 0xe8, 0x15, 0xcd, 0x1f, 0x1f, 0xd5, 0xae, 0xe1, 0x4c, 0x69,
- 0x78, 0x48, 0x2b, 0x84, 0x7f, 0x34, 0x10, 0x08, 0xbf, 0x68, 0xff, 0xa8, 0x39, 0x4c, 0x20, 0x1e,
- 0xde, 0x96, 0x97, 0xfe, 0xd1, 0x08, 0xfe, 0xd1, 0x85, 0xbf, 0x49, 0xf8, 0x5e, 0xb6, 0x7f, 0xf4,
- 0x70, 0x74, 0x0b, 0x28, 0xda, 0x91, 0x2f, 0x9d, 0xa2, 0x97, 0x4e, 0xd1, 0x8b, 0x72, 0x8a, 0xfa,
- 0x29, 0xa7, 0x68, 0x9c, 0x64, 0x84, 0xca, 0xf2, 0x4b, 0xb4, 0x61, 0xce, 0xd5, 0xf8, 0x6e, 0xca,
- 0x1f, 0xe7, 0xe0, 0x4a, 0x86, 0x76, 0x40, 0xef, 0xc0, 0xac, 0xc7, 0x1c, 0x97, 0x74, 0x68, 0x34,
- 0xa1, 0xf2, 0x40, 0x13, 0x37, 0x40, 0x9b, 0x29, 0x1a, 0x1e, 0xe0, 0x46, 0x8f, 0x01, 0x88, 0x61,
- 0x50, 0xcf, 0xdb, 0x72, 0x5a, 0x81, 0x5d, 0x76, 0x87, 0xbb, 0x0b, 0xcb, 0x61, 0xe9, 0xb3, 0xa3,
- 0xda, 0x97, 0xb3, 0x12, 0x46, 0x41, 0x7b, 0x98, 0xbc, 0xeb, 0x1d, 0x55, 0xc0, 0x31, 0x48, 0xf4,
- 0xeb, 0x00, 0xf2, 0xf6, 0x77, 0x78, 0x4f, 0xf1, 0x39, 0x51, 0xfd, 0x7a, 0x70, 0xbb, 0xba, 0xfe,
- 0xab, 0x3e, 0xb1, 0x19, 0x5f, 0x15, 0xe2, 0xee, 0xee, 0xc3, 0x10, 0x05, 0xc7, 0x10, 0xf5, 0x7f,
- 0xcc, 0x41, 0x29, 0xb0, 0x17, 0x5f, 0x40, 0xde, 0xa6, 0x93, 0xc8, 0xdb, 0x8c, 0xfe, 0x08, 0x25,
- 0x68, 0xf2, 0xd0, 0x4c, 0x8d, 0x93, 0xca, 0xd4, 0xac, 0x8f, 0x2f, 0xea, 0xe4, 0xdc, 0xcc, 0x33,
- 0x0d, 0x2e, 0x07, 0xac, 0xea, 0x7e, 0xf2, 0x57, 0x61, 0xda, 0xa5, 0xa4, 0xd5, 0x20, 0xcc, 0xd8,
- 0x17, 0xd3, 0x27, 0x6f, 0x27, 0xcf, 0x1d, 0x1f, 0xd5, 0xa6, 0x71, 0x9c, 0x80, 0x93, 0x7c, 0xa8,
- 0x0e, 0xe0, 0xb7, 0xda, 0x8f, 0x1c, 0x57, 0x38, 0x5b, 0xf2, 0x4e, 0xb2, 0x98, 0xc4, 0xdd, 0xd5,
- 0x35, 0x55, 0x8a, 0x63, 0x1c, 0x59, 0x17, 0xa1, 0xf3, 0x63, 0x5e, 0x84, 0x2e, 0x9c, 0xe9, 0x22,
- 0xf4, 0x3f, 0x6b, 0x30, 0x15, 0x75, 0xfe, 0xc2, 0x53, 0x51, 0xed, 0x64, 0x2a, 0x6a, 0x79, 0xec,
- 0xb9, 0x1d, 0x92, 0x7c, 0xfa, 0x41, 0x31, 0xea, 0x96, 0x48, 0x37, 0xed, 0xc1, 0xbc, 0x99, 0x99,
- 0x82, 0x89, 0xa9, 0x8e, 0xf0, 0x5e, 0xd9, 0xc6, 0x50, 0x4e, 0x7c, 0x02, 0x0a, 0xf2, 0xa1, 0x74,
- 0x40, 0x5d, 0x66, 0x1a, 0x34, 0xe8, 0xdf, 0xfa, 0x39, 0x3d, 0x5b, 0x8c, 0xc6, 0xf4, 0xa1, 0x12,
- 0x80, 0x43, 0x51, 0x68, 0x0f, 0x8a, 0xb4, 0xd5, 0xa1, 0xc1, 0x3d, 0xf2, 0xb7, 0xc7, 0xba, 0xc3,
- 0x1f, 0x8d, 0x27, 0xff, 0xf2, 0xb0, 0x84, 0x46, 0x1e, 0x94, 0xad, 0xc0, 0x65, 0x56, 0x06, 0x73,
- 0x63, 0x64, 0x39, 0xa1, 0xf3, 0x1d, 0xdd, 0xeb, 0x0c, 0x8b, 0x70, 0x24, 0x07, 0x75, 0xc3, 0xd7,
- 0x09, 0xc5, 0x73, 0xd2, 0x04, 0x27, 0xbc, 0x7d, 0xf3, 0xa0, 0xfc, 0x84, 0x30, 0xea, 0xf6, 0x88,
- 0xdb, 0x55, 0x06, 0xed, 0xe8, 0x3d, 0x7c, 0x14, 0x20, 0x45, 0x3d, 0x0c, 0x8b, 0x70, 0x24, 0x47,
- 0xff, 0x61, 0x2e, 0x52, 0x3d, 0x2f, 0x3a, 0x17, 0xf8, 0x56, 0x32, 0x17, 0xb8, 0x90, 0xce, 0x05,
- 0xa6, 0x82, 0x11, 0x67, 0xcf, 0x06, 0x12, 0xa8, 0x58, 0xc4, 0x63, 0xbb, 0xfd, 0x16, 0x61, 0x2a,
- 0x2a, 0x57, 0x59, 0xfa, 0xb9, 0xd3, 0x29, 0x93, 0x1d, 0xb3, 0x47, 0x23, 0x7b, 0x75, 0x33, 0x82,
- 0xc1, 0x71, 0x4c, 0xfd, 0x3f, 0x34, 0x98, 0x1b, 0xc8, 0xff, 0xa2, 0x7d, 0x98, 0xb0, 0x85, 0x85,
- 0x3d, 0xf6, 0xa3, 0xba, 0x98, 0xa1, 0x2e, 0x17, 0x8d, 0x2a, 0x50, 0xf8, 0xc8, 0x86, 0x12, 0x7d,
- 0xca, 0xa8, 0x6b, 0x13, 0x4b, 0x1d, 0x8c, 0xe7, 0xf3, 0x80, 0x4f, 0xd8, 0x53, 0x77, 0x15, 0x32,
- 0x0e, 0x65, 0xe8, 0x5f, 0xe4, 0xa0, 0x12, 0xe3, 0x7b, 0x5e, 0xc4, 0x56, 0xdc, 0x2b, 0x94, 0xae,
- 0xe6, 0xae, 0x6b, 0xa9, 0x89, 0x8e, 0xdd, 0x2b, 0x54, 0x24, 0xbc, 0x89, 0xe3, 0x7c, 0x68, 0x09,
- 0xa0, 0x47, 0x3c, 0x46, 0x5d, 0xa1, 0x1b, 0x53, 0xb7, 0xf9, 0xb6, 0x42, 0x0a, 0x8e, 0x71, 0xa1,
- 0x9b, 0x2a, 0xfc, 0x51, 0x48, 0xbe, 0x86, 0x19, 0x12, 0xdb, 0x28, 0x9e, 0x43, 0x6c, 0x03, 0x75,
- 0x60, 0x36, 0x68, 0x75, 0x40, 0x55, 0x1b, 0xf7, 0x94, 0xc0, 0xd2, 0x54, 0x4c, 0x41, 0xe0, 0x01,
- 0x50, 0xfd, 0x6f, 0x34, 0x98, 0x4e, 0xd8, 0xbb, 0xe8, 0xb5, 0xf8, 0xe5, 0x85, 0x58, 0xa4, 0x34,
- 0x71, 0xe9, 0xe0, 0x0d, 0x98, 0x90, 0x03, 0xa4, 0x06, 0x3e, 0xdc, 0x88, 0x72, 0x08, 0xb1, 0xa2,
- 0xf2, 0x2d, 0xa5, 0x42, 0x29, 0xe9, 0x2d, 0xa5, 0x62, 0x2d, 0x38, 0xa0, 0xa3, 0x2f, 0x71, 0x0b,
- 0x5e, 0xb6, 0x4e, 0x8d, 0x74, 0x78, 0x30, 0x04, 0xfd, 0xc0, 0x21, 0x87, 0xfe, 0x36, 0xc8, 0x97,
- 0xb7, 0xe8, 0x3a, 0xe4, 0x7b, 0xa6, 0xad, 0xc2, 0x99, 0x22, 0x68, 0xba, 0x65, 0xda, 0x98, 0x97,
- 0x09, 0x12, 0x79, 0xaa, 0x02, 0x3c, 0x92, 0x44, 0x9e, 0x62, 0x5e, 0x26, 0xde, 0xb7, 0x89, 0xd8,
- 0xf8, 0x23, 0xc8, 0x5b, 0x4e, 0x47, 0x6d, 0xa6, 0xd1, 0x23, 0xb6, 0x9b, 0x4e, 0x47, 0x4a, 0xd8,
- 0x74, 0x3a, 0x98, 0x23, 0x22, 0x03, 0x8a, 0x5d, 0xd2, 0xee, 0x12, 0xb5, 0x77, 0x46, 0xd7, 0xb7,
- 0x61, 0x1c, 0x5f, 0x3d, 0xda, 0xe2, 0x9f, 0x58, 0x62, 0x23, 0x03, 0x26, 0xfc, 0x96, 0xf8, 0x23,
- 0x88, 0x71, 0xff, 0x6b, 0x62, 0x77, 0x55, 0x88, 0x10, 0x8a, 0x40, 0xfe, 0xc6, 0x0a, 0x5a, 0xff,
- 0xa7, 0x1c, 0xa8, 0xbf, 0x9f, 0x40, 0x3e, 0x94, 0x3b, 0xc1, 0x23, 0x29, 0x35, 0x66, 0xef, 0x8e,
- 0x71, 0x2f, 0x37, 0xf1, 0xdc, 0x4a, 0xa6, 0xa6, 0xc2, 0x42, 0x1c, 0x49, 0x42, 0x34, 0x39, 0x96,
- 0xab, 0x63, 0x8e, 0xa5, 0x14, 0x37, 0x38, 0x9a, 0x04, 0x0a, 0xfb, 0x8c, 0xf5, 0xd5, 0x58, 0x8e,
- 0xfe, 0x5e, 0x30, 0xba, 0x1f, 0x27, 0x83, 0xa0, 0xfc, 0x1b, 0x0b, 0x68, 0xbd, 0x07, 0xea, 0xa8,
- 0x42, 0x46, 0xe2, 0x69, 0xa4, 0x0c, 0x6e, 0x2f, 0x9e, 0xee, 0x00, 0x09, 0x9f, 0xf5, 0xc5, 0x5e,
- 0x4c, 0x64, 0xbe, 0x81, 0xd4, 0xff, 0x35, 0x07, 0xf9, 0x9d, 0xcd, 0xa6, 0xbc, 0x00, 0x2c, 0x22,
- 0x15, 0xb4, 0xd9, 0x35, 0xfb, 0x0f, 0xa9, 0x6b, 0xb6, 0xa5, 0x97, 0x5a, 0x8a, 0x5f, 0x00, 0x4e,
- 0x73, 0xe0, 0x8c, 0x5a, 0xe8, 0x03, 0x98, 0x32, 0xc8, 0x0a, 0x75, 0x99, 0x54, 0x3a, 0x67, 0x8b,
- 0xe5, 0x8a, 0x74, 0xe2, 0xca, 0x72, 0x54, 0x1d, 0x27, 0xc0, 0xd0, 0x2e, 0x80, 0x11, 0x41, 0xe7,
- 0xcf, 0x02, 0x2d, 0xdf, 0x82, 0x46, 0xc0, 0x31, 0x20, 0x84, 0xa1, 0xdc, 0xe5, 0xac, 0x02, 0xb5,
- 0x70, 0x16, 0x54, 0xb1, 0x28, 0xef, 0x07, 0x75, 0x71, 0x04, 0xa3, 0xff, 0x58, 0x83, 0xfc, 0xee,
- 0xea, 0x1a, 0x72, 0xa0, 0x1c, 0xde, 0x5a, 0x51, 0x7b, 0xa2, 0x31, 0x7e, 0x18, 0x53, 0x0a, 0x0e,
- 0x3f, 0x71, 0x24, 0x03, 0xed, 0xc3, 0xe4, 0x9e, 0x6f, 0x5a, 0xcc, 0xb4, 0x45, 0x9c, 0x67, 0x1c,
- 0x4f, 0x23, 0x78, 0x5d, 0xa9, 0x92, 0x66, 0x12, 0x15, 0x07, 0xf0, 0xfa, 0x77, 0x40, 0xe9, 0x02,
- 0x6e, 0x41, 0x5e, 0x44, 0x27, 0x43, 0x0b, 0x32, 0xab, 0xa3, 0xfa, 0x3f, 0xe4, 0x60, 0x42, 0xfd,
- 0xed, 0xce, 0xc5, 0xc7, 0x00, 0x68, 0x22, 0x06, 0xb0, 0x32, 0xe6, 0x1f, 0x51, 0x0c, 0x8d, 0x00,
- 0xf4, 0x52, 0x11, 0x80, 0x71, 0xff, 0xf1, 0xe2, 0x39, 0xfe, 0xff, 0x13, 0x98, 0x8a, 0xff, 0x33,
- 0xc6, 0x0b, 0x73, 0xfe, 0xf5, 0x4f, 0x35, 0x80, 0x40, 0xf2, 0x85, 0x7b, 0xde, 0xad, 0xa4, 0xe7,
- 0x7d, 0x67, 0xcc, 0x31, 0x1d, 0xe2, 0x77, 0xff, 0x6d, 0x21, 0xe8, 0x92, 0xf0, 0xba, 0x3f, 0xd6,
- 0xe0, 0x32, 0x49, 0x78, 0xb2, 0xaa, 0x67, 0xe7, 0xe6, 0x18, 0x5f, 0x53, 0xcd, 0x48, 0xfd, 0x07,
- 0x15, 0x4e, 0x89, 0x45, 0xb7, 0x61, 0xaa, 0xaf, 0xfc, 0x19, 0x61, 0xd5, 0xe6, 0x92, 0x77, 0x0b,
- 0xb6, 0x63, 0x34, 0x9c, 0xe0, 0x7c, 0x4e, 0xe4, 0x20, 0x7f, 0x2e, 0x91, 0x83, 0x78, 0xae, 0xad,
- 0x70, 0x62, 0xae, 0xcd, 0x86, 0x72, 0xdb, 0x75, 0x7a, 0xc2, 0x39, 0x57, 0xff, 0x4d, 0x31, 0xa6,
- 0xc3, 0x1f, 0xea, 0x97, 0xb5, 0x00, 0x17, 0x47, 0x22, 0xb8, 0x22, 0x65, 0x8e, 0x94, 0x36, 0x71,
- 0x1e, 0xd2, 0x42, 0xdb, 0x76, 0x47, 0xa2, 0xe2, 0x00, 0x5e, 0xff, 0x97, 0x5c, 0xb0, 0x0f, 0x9b,
- 0xa9, 0xcb, 0xaa, 0xda, 0x90, 0xcb, 0xaa, 0xea, 0xbd, 0x41, 0xdc, 0x3d, 0x7d, 0x03, 0x26, 0x5c,
- 0x4a, 0x3c, 0xc7, 0x56, 0x2f, 0x77, 0xc2, 0x3d, 0x8f, 0x45, 0x29, 0x56, 0xd4, 0xb8, 0x1b, 0x9b,
- 0x7b, 0x8e, 0x1b, 0xfb, 0xa5, 0xd8, 0xdc, 0xe4, 0xc5, 0x9e, 0x0e, 0xb7, 0x59, 0xc6, 0xfc, 0x08,
- 0x0b, 0x5d, 0xa5, 0x89, 0x8a, 0x69, 0x0b, 0x5d, 0xa5, 0x72, 0x42, 0x0e, 0xd4, 0x82, 0x29, 0xee,
- 0xce, 0x0a, 0x2b, 0xbd, 0xb5, 0xcc, 0x46, 0xf0, 0x91, 0xc3, 0x15, 0xbc, 0x19, 0xc3, 0xc1, 0x09,
- 0x54, 0xfd, 0xeb, 0x10, 0x45, 0x1f, 0xd0, 0x22, 0x94, 0xfb, 0xae, 0xd3, 0x27, 0x1d, 0xc2, 0xa8,
- 0xb2, 0x6e, 0xc2, 0x15, 0xb0, 0x1d, 0x10, 0x70, 0xc4, 0xd3, 0xa8, 0x7f, 0xf2, 0xf9, 0xc2, 0xa5,
- 0x4f, 0x3f, 0x5f, 0xb8, 0xf4, 0xd9, 0xe7, 0x0b, 0x97, 0x7e, 0xfb, 0x78, 0x41, 0xfb, 0xe4, 0x78,
- 0x41, 0xfb, 0xf4, 0x78, 0x41, 0xfb, 0xec, 0x78, 0x41, 0xfb, 0xf1, 0xf1, 0x82, 0xf6, 0xbd, 0x7f,
- 0x5b, 0xb8, 0xf4, 0xcd, 0x52, 0x30, 0xcd, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x03, 0xe6, 0xe9,
- 0xab, 0xbb, 0x4f, 0x00, 0x00,
+ 0x5a, 0x4f, 0xf5, 0x1f, 0xbb, 0xfb, 0x6b, 0x3b, 0xb6, 0x5f, 0x32, 0xa1, 0x63, 0x32, 0x76, 0xa8,
+ 0xd1, 0x8c, 0x02, 0xec, 0xb6, 0x19, 0x33, 0xcb, 0x66, 0x61, 0x67, 0x67, 0xdc, 0x76, 0xec, 0x38,
+ 0x69, 0x67, 0xcc, 0x6b, 0x3b, 0x61, 0x76, 0x56, 0x84, 0xe7, 0xea, 0xd7, 0xed, 0x9a, 0xae, 0xae,
+ 0xea, 0xad, 0x7a, 0xe5, 0xc4, 0xa3, 0x5d, 0x81, 0xc4, 0x61, 0x40, 0x80, 0x76, 0x25, 0x2e, 0x48,
+ 0x2b, 0x10, 0x87, 0x95, 0x10, 0x07, 0x2e, 0x08, 0x24, 0x04, 0x5a, 0x89, 0x13, 0x1a, 0x2e, 0x68,
+ 0x0e, 0x48, 0x0c, 0xd2, 0xca, 0xda, 0x31, 0x12, 0x37, 0xc4, 0xa2, 0xbd, 0x45, 0x48, 0xa0, 0xf7,
+ 0xa7, 0xfe, 0x76, 0xb5, 0x63, 0x77, 0xdb, 0xe1, 0x40, 0x6e, 0x5d, 0xef, 0xfb, 0xde, 0xef, 0x7b,
+ 0x7f, 0xbf, 0xf7, 0xfd, 0x79, 0xaf, 0x61, 0xa3, 0x63, 0xb2, 0x7d, 0x7f, 0xaf, 0x66, 0x38, 0xbd,
+ 0x25, 0xdb, 0xef, 0x91, 0xbe, 0xeb, 0x7c, 0x28, 0x7e, 0xb4, 0x2d, 0xe7, 0xc9, 0x52, 0xbf, 0xdb,
+ 0x59, 0x22, 0x7d, 0xd3, 0x8b, 0x4a, 0x0e, 0xde, 0x24, 0x56, 0x7f, 0x9f, 0xbc, 0xb9, 0xd4, 0xa1,
+ 0x36, 0x75, 0x09, 0xa3, 0xad, 0x5a, 0xdf, 0x75, 0x98, 0x83, 0xbe, 0x1c, 0x01, 0xd5, 0x02, 0xa0,
+ 0x5a, 0x50, 0xad, 0xd6, 0xef, 0x76, 0x6a, 0x1c, 0x28, 0x2a, 0x09, 0x80, 0xe6, 0xbf, 0x18, 0x6b,
+ 0x41, 0xc7, 0xe9, 0x38, 0x4b, 0x02, 0x6f, 0xcf, 0x6f, 0x8b, 0x2f, 0xf1, 0x21, 0x7e, 0x49, 0x39,
+ 0xf3, 0x7a, 0xf7, 0xb6, 0x57, 0x33, 0x1d, 0xde, 0xac, 0x25, 0xc3, 0x71, 0xe9, 0xd2, 0xc1, 0x40,
+ 0x5b, 0xe6, 0xdf, 0x8a, 0x78, 0x7a, 0xc4, 0xd8, 0x37, 0x6d, 0xea, 0x1e, 0x06, 0x7d, 0x59, 0x72,
+ 0xa9, 0xe7, 0xf8, 0xae, 0x41, 0xcf, 0x54, 0xcb, 0x5b, 0xea, 0x51, 0x46, 0xb2, 0x64, 0x2d, 0x0d,
+ 0xab, 0xe5, 0xfa, 0x36, 0x33, 0x7b, 0x83, 0x62, 0x7e, 0xe9, 0x79, 0x15, 0x3c, 0x63, 0x9f, 0xf6,
+ 0x48, 0xba, 0x9e, 0xfe, 0x9f, 0x53, 0x70, 0x79, 0x65, 0xcf, 0x63, 0x2e, 0x31, 0xd8, 0x43, 0xea,
+ 0x32, 0xfa, 0x14, 0xdd, 0x84, 0x82, 0x4d, 0x7a, 0xb4, 0xaa, 0xdd, 0xd4, 0x6e, 0x95, 0xeb, 0x53,
+ 0x9f, 0x1c, 0x2d, 0x5e, 0x3a, 0x3e, 0x5a, 0x2c, 0x3c, 0x20, 0x3d, 0x8a, 0x05, 0x05, 0x19, 0x30,
+ 0x21, 0x7b, 0x5b, 0xcd, 0xdf, 0xd4, 0x6e, 0x55, 0x96, 0xdf, 0xa9, 0x8d, 0x38, 0x4d, 0xb5, 0xa6,
+ 0x80, 0xa9, 0xc3, 0xf1, 0xd1, 0xe2, 0x84, 0xfc, 0x8d, 0x15, 0x34, 0xfa, 0x00, 0x0a, 0x9e, 0x69,
+ 0x77, 0xab, 0x05, 0x21, 0xe2, 0xed, 0xd1, 0x45, 0x98, 0x76, 0xb7, 0x5e, 0xe2, 0x3d, 0xe0, 0xbf,
+ 0xb0, 0x00, 0x45, 0xdf, 0xd1, 0x60, 0xce, 0x70, 0x6c, 0x46, 0xf8, 0x40, 0xed, 0xd0, 0x5e, 0xdf,
+ 0x22, 0x8c, 0x56, 0x8b, 0x42, 0xd4, 0xbd, 0x91, 0x45, 0xad, 0xa6, 0x11, 0xeb, 0xaf, 0x1c, 0x1f,
+ 0x2d, 0xce, 0x0d, 0x14, 0xe3, 0x41, 0xd9, 0xe8, 0x11, 0xe4, 0xfd, 0x56, 0xbb, 0x3a, 0x21, 0x9a,
+ 0xf0, 0xd5, 0x91, 0x9b, 0xb0, 0xbb, 0xb6, 0x5e, 0x9f, 0x3c, 0x3e, 0x5a, 0xcc, 0xef, 0xae, 0xad,
+ 0x63, 0x8e, 0x88, 0xba, 0x50, 0xe2, 0xab, 0xac, 0x45, 0x18, 0xa9, 0x4e, 0x0a, 0xf4, 0x95, 0x91,
+ 0xd1, 0xb7, 0x14, 0x50, 0x7d, 0xea, 0xf8, 0x68, 0xb1, 0x14, 0x7c, 0xe1, 0x50, 0x00, 0xfa, 0x43,
+ 0x0d, 0xa6, 0x6c, 0xa7, 0x45, 0x9b, 0xd4, 0xa2, 0x06, 0x73, 0xdc, 0x6a, 0xe9, 0x66, 0xfe, 0x56,
+ 0x65, 0xf9, 0xfd, 0x91, 0x25, 0x26, 0xd7, 0x66, 0xed, 0x41, 0x0c, 0xfb, 0x8e, 0xcd, 0xdc, 0xc3,
+ 0xfa, 0x55, 0xb5, 0x3e, 0xa7, 0xe2, 0x24, 0x9c, 0x68, 0x04, 0xda, 0x85, 0x0a, 0x73, 0x2c, 0xbe,
+ 0xee, 0x4d, 0xc7, 0xf6, 0xaa, 0x65, 0xd1, 0xa6, 0x85, 0x9a, 0xdc, 0x32, 0x5c, 0x72, 0x8d, 0xef,
+ 0xf9, 0xda, 0xc1, 0x9b, 0xb5, 0x9d, 0x90, 0xad, 0x7e, 0x45, 0x01, 0x57, 0xa2, 0x32, 0x0f, 0xc7,
+ 0x71, 0x10, 0x85, 0x19, 0x8f, 0x1a, 0xbe, 0x6b, 0xb2, 0x43, 0x3e, 0xc5, 0xf4, 0x29, 0xab, 0x82,
+ 0x18, 0xe0, 0x37, 0xb2, 0xa0, 0xb7, 0x9d, 0x56, 0x33, 0xc9, 0x5d, 0xbf, 0x72, 0x7c, 0xb4, 0x38,
+ 0x93, 0x2a, 0xc4, 0x69, 0x4c, 0x64, 0xc3, 0xac, 0xd9, 0x23, 0x1d, 0xba, 0xed, 0x5b, 0x56, 0x93,
+ 0x1a, 0x2e, 0x65, 0x5e, 0xb5, 0x22, 0xba, 0x70, 0x2b, 0x4b, 0x4e, 0xc3, 0x31, 0x88, 0xf5, 0xde,
+ 0xde, 0x87, 0xd4, 0x60, 0x98, 0xb6, 0xa9, 0x4b, 0x6d, 0x83, 0xd6, 0xab, 0xaa, 0x33, 0xb3, 0x9b,
+ 0x29, 0x24, 0x3c, 0x80, 0x8d, 0x36, 0x60, 0xae, 0xef, 0x9a, 0x8e, 0x68, 0x82, 0x45, 0x3c, 0x8f,
+ 0x6f, 0xfc, 0xea, 0x94, 0x50, 0x06, 0xd7, 0x15, 0xcc, 0xdc, 0x76, 0x9a, 0x01, 0x0f, 0xd6, 0x41,
+ 0xb7, 0xa0, 0x14, 0x14, 0x56, 0xa7, 0x6f, 0x6a, 0xb7, 0x8a, 0x72, 0xd9, 0x04, 0x75, 0x71, 0x48,
+ 0x45, 0xeb, 0x50, 0x22, 0xed, 0xb6, 0x69, 0x73, 0xce, 0xcb, 0x62, 0x08, 0x6f, 0x64, 0x75, 0x6d,
+ 0x45, 0xf1, 0x48, 0x9c, 0xe0, 0x0b, 0x87, 0x75, 0xd1, 0x3d, 0x40, 0x1e, 0x75, 0x0f, 0x4c, 0x83,
+ 0xae, 0x18, 0x86, 0xe3, 0xdb, 0x4c, 0xb4, 0x7d, 0x46, 0xb4, 0x7d, 0x5e, 0xb5, 0x1d, 0x35, 0x07,
+ 0x38, 0x70, 0x46, 0x2d, 0x74, 0x07, 0x26, 0x0f, 0x1c, 0xcb, 0xef, 0x51, 0xaf, 0x3a, 0x2b, 0x46,
+ 0x7b, 0x3e, 0xab, 0x49, 0x0f, 0x05, 0x4b, 0x7d, 0x46, 0x81, 0x4f, 0xca, 0x6f, 0x0f, 0x07, 0x75,
+ 0x91, 0x09, 0x13, 0x96, 0xd9, 0x33, 0x99, 0x57, 0x9d, 0x13, 0x1d, 0xbb, 0x33, 0xf2, 0x56, 0x90,
+ 0x5b, 0xa0, 0x21, 0xc0, 0xa4, 0xc6, 0x94, 0xbf, 0xb1, 0x12, 0x80, 0x0c, 0x28, 0x7a, 0x06, 0xb1,
+ 0x68, 0x15, 0x09, 0x49, 0x5f, 0x1b, 0x5d, 0x65, 0x72, 0x94, 0xfa, 0xb4, 0xea, 0x53, 0x51, 0x7c,
+ 0x62, 0x89, 0x3d, 0xff, 0x0e, 0xcc, 0x0d, 0x6c, 0x42, 0x34, 0x0b, 0xf9, 0x2e, 0x3d, 0x94, 0x27,
+ 0x06, 0xe6, 0x3f, 0xd1, 0x55, 0x28, 0x1e, 0x10, 0xcb, 0xa7, 0xd5, 0x9c, 0x28, 0x93, 0x1f, 0xbf,
+ 0x9c, 0xbb, 0xad, 0xe9, 0x8f, 0x60, 0x7a, 0xc5, 0x67, 0xfb, 0x8e, 0x6b, 0x7e, 0x24, 0xf6, 0x11,
+ 0x5a, 0x87, 0x22, 0x73, 0xba, 0xd4, 0x16, 0xd5, 0x2b, 0xcb, 0xaf, 0x67, 0x0d, 0xb3, 0x5c, 0x9b,
+ 0xf7, 0xe9, 0x61, 0x20, 0xb7, 0x5e, 0xe6, 0x2d, 0xdb, 0xe1, 0xf5, 0xb0, 0xac, 0xae, 0x7f, 0x1d,
+ 0x26, 0xea, 0x7e, 0xbb, 0x4d, 0xdd, 0x53, 0x9c, 0x60, 0x35, 0x28, 0xb0, 0xc3, 0xbe, 0x6a, 0x5d,
+ 0xb8, 0x34, 0x0a, 0x3b, 0x87, 0x7d, 0xfa, 0xec, 0x68, 0x11, 0x24, 0x0e, 0xff, 0xc2, 0x82, 0x4f,
+ 0xff, 0x89, 0x06, 0x57, 0x64, 0xa1, 0x5a, 0x3d, 0xab, 0x8e, 0xdd, 0x36, 0x3b, 0x88, 0x42, 0xd1,
+ 0xa5, 0x2d, 0xd3, 0x53, 0x6d, 0x5f, 0x1b, 0x79, 0xc8, 0x31, 0x47, 0x91, 0xa0, 0xb2, 0x6b, 0xa2,
+ 0x00, 0x4b, 0x74, 0xe4, 0x43, 0xf9, 0x43, 0xca, 0x3c, 0xe6, 0x52, 0xd2, 0x13, 0x6d, 0xae, 0x2c,
+ 0xdf, 0x1d, 0x59, 0xd4, 0x3d, 0xca, 0x9a, 0x02, 0x49, 0x89, 0x9b, 0x3e, 0x3e, 0x5a, 0x2c, 0x87,
+ 0x85, 0x38, 0x92, 0xa4, 0xff, 0x7b, 0x0e, 0xca, 0xe1, 0xe1, 0x85, 0x5e, 0x83, 0xa2, 0xd0, 0x15,
+ 0x6a, 0x58, 0xc3, 0xe5, 0x21, 0x54, 0x0a, 0x96, 0x34, 0xf4, 0x3a, 0x4c, 0x1a, 0x4e, 0xaf, 0x47,
+ 0xec, 0x56, 0x35, 0x77, 0x33, 0x7f, 0xab, 0x5c, 0xaf, 0xf0, 0x5d, 0xb1, 0x2a, 0x8b, 0x70, 0x40,
+ 0x43, 0x37, 0xa0, 0x40, 0xdc, 0x8e, 0x57, 0xcd, 0x0b, 0x1e, 0x71, 0x3a, 0xaf, 0xb8, 0x1d, 0x0f,
+ 0x8b, 0x52, 0xf4, 0x15, 0xc8, 0x53, 0xfb, 0xa0, 0x5a, 0x18, 0xbe, 0xed, 0xee, 0xd8, 0x07, 0x0f,
+ 0x89, 0x5b, 0xaf, 0xa8, 0x36, 0xe4, 0xef, 0xd8, 0x07, 0x98, 0xd7, 0x41, 0xef, 0xc3, 0x94, 0xdc,
+ 0x79, 0x5b, 0x7c, 0x23, 0x7b, 0xd5, 0xa2, 0xc0, 0x58, 0x1c, 0xbe, 0x75, 0x05, 0x5f, 0x74, 0x8a,
+ 0xc4, 0x0a, 0x3d, 0x9c, 0x80, 0x42, 0xef, 0x43, 0x39, 0xb0, 0xf2, 0x3c, 0x75, 0x4e, 0x67, 0x2a,
+ 0x60, 0xac, 0x98, 0x30, 0xfd, 0xa6, 0x6f, 0xba, 0xb4, 0x47, 0x6d, 0xe6, 0xd5, 0xe7, 0x94, 0x80,
+ 0x72, 0x40, 0xf5, 0x70, 0x84, 0xa6, 0xff, 0x57, 0x0e, 0x06, 0xad, 0x84, 0xa4, 0x40, 0xed, 0x3c,
+ 0x05, 0xa2, 0x3d, 0x98, 0x09, 0xf5, 0xfe, 0xb6, 0x63, 0x99, 0xc6, 0xa1, 0xda, 0x0a, 0xb7, 0x55,
+ 0xb5, 0x99, 0xcd, 0x24, 0xf9, 0xd9, 0xd1, 0xe2, 0xab, 0x83, 0x36, 0x72, 0x2d, 0x62, 0xc0, 0x69,
+ 0x40, 0x2e, 0x23, 0x7d, 0x3c, 0x4a, 0x73, 0xf1, 0xb5, 0x21, 0x3b, 0x7c, 0x84, 0xb3, 0x71, 0xf4,
+ 0x95, 0xa2, 0xff, 0x79, 0x0e, 0x0a, 0x77, 0x5a, 0x1d, 0xca, 0xb5, 0x45, 0xdb, 0x75, 0x7a, 0x69,
+ 0x6d, 0xb1, 0xee, 0x3a, 0x3d, 0x2c, 0x28, 0x68, 0x1e, 0x72, 0xcc, 0x51, 0x03, 0x04, 0x8a, 0x9e,
+ 0xdb, 0x71, 0x70, 0x8e, 0x39, 0xe8, 0x23, 0x00, 0xc3, 0xb1, 0x5b, 0xa6, 0x34, 0x2d, 0xf2, 0x63,
+ 0x5a, 0x90, 0xeb, 0x8e, 0xfb, 0x84, 0xb8, 0xad, 0xd5, 0x10, 0xb1, 0x7e, 0xf9, 0xf8, 0x68, 0x11,
+ 0xa2, 0x6f, 0x1c, 0x93, 0x86, 0x3a, 0xe1, 0xd9, 0x22, 0x8d, 0xe4, 0xd5, 0x91, 0xe5, 0xf2, 0x81,
+ 0x18, 0x7e, 0xb2, 0xe8, 0x7f, 0xa0, 0x01, 0x44, 0x2c, 0xe8, 0x6d, 0x98, 0xd9, 0x13, 0xca, 0x70,
+ 0x8b, 0x3c, 0x6d, 0x50, 0xbb, 0xc3, 0xf6, 0xc5, 0xe0, 0x15, 0xe4, 0xa4, 0xd5, 0x93, 0x24, 0x9c,
+ 0xe6, 0x45, 0xef, 0xc2, 0xac, 0x2c, 0xda, 0xf5, 0x88, 0xc2, 0x14, 0x83, 0x3b, 0x5d, 0xbf, 0xca,
+ 0x4d, 0x94, 0x7a, 0x8a, 0x86, 0x07, 0xb8, 0xf5, 0xb7, 0x60, 0x6e, 0x60, 0xa4, 0xd0, 0x22, 0x14,
+ 0xbb, 0xf4, 0x70, 0x93, 0x9f, 0x23, 0x5c, 0xa9, 0x08, 0x2d, 0x7a, 0x9f, 0x17, 0x60, 0x59, 0xae,
+ 0xff, 0xb7, 0x06, 0xa5, 0x75, 0xdf, 0x36, 0xc4, 0xa9, 0xf3, 0xfc, 0x33, 0x22, 0xd0, 0x51, 0xb9,
+ 0x4c, 0x1d, 0xe5, 0xc3, 0x44, 0xf7, 0x49, 0xa8, 0xc3, 0x2a, 0xcb, 0x5b, 0xa3, 0xcf, 0xb9, 0x6a,
+ 0x52, 0xed, 0xbe, 0xc0, 0x93, 0x66, 0xed, 0x65, 0xd5, 0xa0, 0x89, 0xfb, 0x8f, 0x84, 0x50, 0x25,
+ 0x6c, 0xfe, 0x2b, 0x50, 0x89, 0xb1, 0x9d, 0xe9, 0xe0, 0xfd, 0x0b, 0x0d, 0x66, 0x36, 0xa4, 0xfb,
+ 0xe7, 0xb8, 0xd2, 0xd9, 0x42, 0xd7, 0x21, 0xef, 0xf6, 0x7d, 0x51, 0x3f, 0x2f, 0xfd, 0x06, 0xbc,
+ 0xbd, 0x8b, 0x79, 0x19, 0xfa, 0x35, 0x28, 0xb5, 0x7c, 0x69, 0xea, 0xaa, 0x23, 0xa7, 0x16, 0xdb,
+ 0x5f, 0xa1, 0x93, 0x19, 0xf5, 0x8c, 0x3b, 0x01, 0x7c, 0xc7, 0xad, 0xa9, 0x5a, 0xd2, 0x4a, 0x0b,
+ 0xbe, 0x70, 0x88, 0xc6, 0xcf, 0x88, 0x9e, 0xd7, 0x69, 0x9a, 0x1f, 0x49, 0xff, 0xb1, 0x28, 0xcf,
+ 0x88, 0x2d, 0x59, 0x84, 0x03, 0x9a, 0xfe, 0x9d, 0x1c, 0x5c, 0xdb, 0xa0, 0x6c, 0x8d, 0xd0, 0x9e,
+ 0x63, 0xaf, 0xd1, 0xbe, 0xe5, 0x1c, 0x72, 0xd5, 0x86, 0xe9, 0x37, 0xd1, 0xbb, 0x00, 0xa6, 0xb7,
+ 0xd7, 0x3c, 0x30, 0xf8, 0x11, 0xad, 0xa6, 0xf0, 0xa6, 0x1a, 0x31, 0xd8, 0x6c, 0xd6, 0x15, 0xe5,
+ 0x59, 0xe2, 0x0b, 0xc7, 0xea, 0x44, 0x87, 0x59, 0xee, 0x84, 0xc3, 0xac, 0x09, 0xd0, 0x8f, 0x14,
+ 0x64, 0x5e, 0x70, 0xfe, 0x62, 0x20, 0xe6, 0x2c, 0xba, 0x31, 0x06, 0x33, 0x8e, 0xca, 0xfa, 0xdb,
+ 0x3c, 0xcc, 0x6f, 0x50, 0x16, 0x9e, 0xd5, 0xca, 0x16, 0x69, 0xf6, 0xa9, 0xc1, 0x47, 0xe5, 0x63,
+ 0x0d, 0x26, 0x2c, 0xb2, 0x47, 0x2d, 0x4f, 0x6c, 0x81, 0xca, 0xf2, 0xe3, 0x91, 0xd7, 0xe4, 0x70,
+ 0x29, 0xb5, 0x86, 0x90, 0x90, 0x5a, 0xa5, 0xb2, 0x10, 0x2b, 0xf1, 0xe8, 0x4b, 0x50, 0x31, 0x2c,
+ 0xdf, 0x63, 0xd4, 0xdd, 0x76, 0x5c, 0xb9, 0xb9, 0x8b, 0x91, 0x43, 0xb5, 0x1a, 0x91, 0x70, 0x9c,
+ 0x0f, 0x2d, 0x03, 0x18, 0x96, 0x49, 0x6d, 0x26, 0x6a, 0xc9, 0xb5, 0x81, 0x82, 0xf1, 0x5e, 0x0d,
+ 0x29, 0x38, 0xc6, 0xc5, 0x45, 0xf5, 0x1c, 0xdb, 0x64, 0x8e, 0x14, 0x55, 0x48, 0x8a, 0xda, 0x8a,
+ 0x48, 0x38, 0xce, 0x27, 0xaa, 0x51, 0xe6, 0x9a, 0x86, 0x27, 0xaa, 0x15, 0x53, 0xd5, 0x22, 0x12,
+ 0x8e, 0xf3, 0xf1, 0xed, 0x17, 0xeb, 0xff, 0x99, 0xb6, 0xdf, 0xdf, 0x95, 0x60, 0x21, 0x31, 0xac,
+ 0x8c, 0x30, 0xda, 0xf6, 0xad, 0x26, 0x65, 0xc1, 0x04, 0x7e, 0x09, 0x2a, 0xca, 0x11, 0x79, 0x10,
+ 0xa9, 0xa6, 0xb0, 0x51, 0xcd, 0x88, 0x84, 0xe3, 0x7c, 0xe8, 0xf7, 0xa2, 0x79, 0xcf, 0x89, 0x79,
+ 0x37, 0xce, 0x67, 0xde, 0x07, 0x1a, 0x78, 0xaa, 0xb9, 0x5f, 0x82, 0xb2, 0x4d, 0x98, 0x27, 0x36,
+ 0x92, 0xda, 0x33, 0xa1, 0x2d, 0xf2, 0x20, 0x20, 0xe0, 0x88, 0x07, 0x6d, 0xc3, 0x55, 0x35, 0xc4,
+ 0x77, 0x9e, 0xf6, 0x1d, 0x97, 0x51, 0x57, 0xd6, 0x2d, 0x88, 0xba, 0x37, 0x54, 0xdd, 0xab, 0x5b,
+ 0x19, 0x3c, 0x38, 0xb3, 0x26, 0xda, 0x82, 0x2b, 0x86, 0xb0, 0x6d, 0x31, 0xb5, 0x1c, 0xd2, 0x0a,
+ 0x00, 0x8b, 0x02, 0xf0, 0xa7, 0x15, 0xe0, 0x95, 0xd5, 0x41, 0x16, 0x9c, 0x55, 0x2f, 0xbd, 0x9a,
+ 0x27, 0x46, 0x5a, 0xcd, 0x93, 0xa3, 0xac, 0xe6, 0xd2, 0x68, 0xab, 0xb9, 0x7c, 0xba, 0xd5, 0xcc,
+ 0x47, 0x9e, 0xaf, 0x23, 0xea, 0x72, 0x87, 0x4c, 0xba, 0x58, 0x62, 0xe1, 0x41, 0x72, 0xe4, 0x9b,
+ 0x19, 0x3c, 0x38, 0xb3, 0x26, 0xda, 0x83, 0x79, 0x59, 0x7e, 0xc7, 0x36, 0xdc, 0xc3, 0x3e, 0x57,
+ 0xf7, 0x31, 0xdc, 0x8a, 0xc0, 0xd5, 0x15, 0xee, 0x7c, 0x73, 0x28, 0x27, 0x3e, 0x01, 0x05, 0xfd,
+ 0x0a, 0x4c, 0xcb, 0x59, 0xda, 0x22, 0xfd, 0x58, 0x6c, 0xe2, 0x15, 0x05, 0x3b, 0xbd, 0x1a, 0x27,
+ 0xe2, 0x24, 0x2f, 0x5a, 0x81, 0x99, 0xfe, 0x81, 0xc1, 0x7f, 0x6e, 0xb6, 0x1f, 0x50, 0xda, 0xa2,
+ 0x2d, 0x11, 0x9a, 0x28, 0xd7, 0x7f, 0x2a, 0x30, 0x7c, 0xb7, 0x93, 0x64, 0x9c, 0xe6, 0x47, 0xb7,
+ 0x61, 0xca, 0x63, 0xc4, 0x65, 0xca, 0xa9, 0x11, 0x01, 0x8b, 0x72, 0xe4, 0x41, 0x34, 0x63, 0x34,
+ 0x9c, 0xe0, 0x1c, 0x47, 0x7b, 0x3c, 0x93, 0x87, 0xa1, 0xf0, 0x0a, 0x53, 0x6a, 0xff, 0xb7, 0xd3,
+ 0x6a, 0xff, 0x83, 0x71, 0xb6, 0x7f, 0x86, 0x84, 0x53, 0x6d, 0xfb, 0x7b, 0x80, 0x5c, 0xe5, 0xc3,
+ 0x4a, 0x37, 0x26, 0xa6, 0xf9, 0xc3, 0xd0, 0x0b, 0x1e, 0xe0, 0xc0, 0x19, 0xb5, 0x50, 0x13, 0x5e,
+ 0xf1, 0xa8, 0xcd, 0x4c, 0x9b, 0x5a, 0x49, 0x38, 0x79, 0x24, 0xbc, 0xaa, 0xe0, 0x5e, 0x69, 0x66,
+ 0x31, 0xe1, 0xec, 0xba, 0xe3, 0x0c, 0xfe, 0x0f, 0xcb, 0xe2, 0xdc, 0x95, 0x43, 0x73, 0x6e, 0x6a,
+ 0xfb, 0xe3, 0xb4, 0xda, 0x7e, 0x3c, 0xfe, 0xbc, 0x8d, 0xa6, 0xb2, 0x97, 0x01, 0xc4, 0x2c, 0xc4,
+ 0x75, 0x76, 0xa8, 0xa9, 0x70, 0x48, 0xc1, 0x31, 0x2e, 0xbe, 0x0b, 0x83, 0x71, 0x8e, 0xab, 0xeb,
+ 0x70, 0x17, 0x36, 0xe3, 0x44, 0x9c, 0xe4, 0x1d, 0xaa, 0xf2, 0x8b, 0x23, 0xab, 0xfc, 0x7b, 0x80,
+ 0x4c, 0xdb, 0x64, 0xe1, 0x94, 0x4b, 0xbc, 0x89, 0x64, 0xe4, 0x6f, 0x73, 0x80, 0x03, 0x67, 0xd4,
+ 0x1a, 0xb2, 0x94, 0x27, 0xcf, 0x77, 0x29, 0x97, 0x46, 0x5f, 0xca, 0xe8, 0x31, 0x5c, 0x17, 0xa2,
+ 0xd4, 0xf8, 0x24, 0x81, 0xa5, 0xf2, 0xff, 0x19, 0x05, 0x7c, 0x1d, 0x0f, 0x63, 0xc4, 0xc3, 0x31,
+ 0xf8, 0xfc, 0x18, 0x2e, 0x6d, 0x71, 0xe1, 0xc4, 0x1a, 0x7e, 0x30, 0xac, 0x66, 0xf0, 0xe0, 0xcc,
+ 0x9a, 0x7c, 0x89, 0x31, 0xbe, 0x0c, 0xc9, 0x9e, 0x45, 0x5b, 0xe2, 0x20, 0x28, 0x45, 0x4b, 0x6c,
+ 0xa7, 0xd1, 0x54, 0x14, 0x1c, 0xe3, 0xca, 0xd2, 0xd5, 0x53, 0x67, 0xd4, 0xd5, 0x1b, 0x22, 0xcd,
+ 0xd3, 0x4e, 0x1c, 0x09, 0x4a, 0xe1, 0x87, 0xb1, 0xec, 0xd5, 0x34, 0x03, 0x1e, 0xac, 0x23, 0x8e,
+ 0x4a, 0xc3, 0x35, 0xfb, 0xcc, 0x4b, 0x62, 0x5d, 0x4e, 0x1d, 0x95, 0x19, 0x3c, 0x38, 0xb3, 0x26,
+ 0x37, 0x52, 0xf6, 0x29, 0xb1, 0xd8, 0x7e, 0x12, 0x70, 0x26, 0x69, 0xa4, 0xdc, 0x1d, 0x64, 0xc1,
+ 0x59, 0xf5, 0xc6, 0x51, 0x6f, 0xbf, 0x9f, 0x83, 0x2b, 0x1b, 0x54, 0xa5, 0x58, 0xb6, 0x9d, 0x56,
+ 0xa0, 0xd7, 0xfe, 0x9f, 0x7a, 0x59, 0x7f, 0xac, 0x01, 0xdc, 0xdd, 0xd9, 0xd9, 0x56, 0x2e, 0x72,
+ 0x0b, 0x0a, 0xc4, 0x57, 0x11, 0x8e, 0xca, 0xf2, 0xfa, 0xe8, 0x99, 0xac, 0x78, 0xd0, 0x5b, 0x85,
+ 0x13, 0x7c, 0xb6, 0x8f, 0x05, 0x3a, 0xfa, 0x59, 0x98, 0x54, 0x67, 0x83, 0x18, 0xab, 0x52, 0x94,
+ 0x51, 0x50, 0xe7, 0x07, 0x0e, 0xe8, 0xfa, 0x8f, 0x73, 0x70, 0x6d, 0xd3, 0x66, 0xd4, 0x6d, 0x32,
+ 0xda, 0x4f, 0x04, 0xa5, 0xd1, 0x6f, 0xc4, 0x72, 0x7d, 0xb2, 0xbd, 0xbf, 0x70, 0x3a, 0x9f, 0x5d,
+ 0xe6, 0x8b, 0xb6, 0x28, 0x23, 0xd1, 0xae, 0x8c, 0xca, 0x62, 0x09, 0x3e, 0x1f, 0x0a, 0x5e, 0x9f,
+ 0x1a, 0x2a, 0x22, 0xd0, 0x1c, 0x79, 0x34, 0xb2, 0x3b, 0xc0, 0x57, 0x5e, 0x14, 0x8b, 0x11, 0xeb,
+ 0x50, 0x88, 0x43, 0xdf, 0x86, 0x09, 0x8f, 0x11, 0xe6, 0x07, 0x11, 0xb6, 0xdd, 0xf3, 0x16, 0x2c,
+ 0xc0, 0xa3, 0x03, 0x52, 0x7e, 0x63, 0x25, 0x54, 0xff, 0xb1, 0x06, 0xf3, 0xd9, 0x15, 0x1b, 0xa6,
+ 0xc7, 0xd0, 0x37, 0x06, 0x86, 0xfd, 0x94, 0xa1, 0x12, 0x5e, 0x5b, 0x0c, 0xfa, 0xac, 0x12, 0x5c,
+ 0x0a, 0x4a, 0x62, 0x43, 0xce, 0xa0, 0x68, 0x32, 0xda, 0x0b, 0xac, 0x84, 0xf7, 0xce, 0xb9, 0xeb,
+ 0xb1, 0x5d, 0xc9, 0xa5, 0x60, 0x29, 0x4c, 0xff, 0x38, 0x37, 0xac, 0xcb, 0x7c, 0x5a, 0x50, 0x37,
+ 0x99, 0xf8, 0xb8, 0x37, 0x5e, 0xe2, 0xa3, 0xee, 0xc7, 0xda, 0x33, 0x98, 0xfe, 0xf8, 0xd6, 0x60,
+ 0xfa, 0xe3, 0xbd, 0xf1, 0xd3, 0x1f, 0xa9, 0x51, 0x18, 0x9a, 0x05, 0xf9, 0x61, 0x0e, 0x6e, 0x9c,
+ 0xb4, 0x6a, 0x50, 0x27, 0x5c, 0x9c, 0xda, 0xb8, 0xd7, 0x21, 0x4e, 0x5c, 0x86, 0x68, 0x19, 0x8a,
+ 0xfd, 0x7d, 0xe2, 0x05, 0xea, 0x34, 0x38, 0x75, 0x8a, 0xdb, 0xbc, 0xf0, 0xd9, 0xd1, 0x62, 0x45,
+ 0xaa, 0x61, 0xf1, 0x89, 0x25, 0x2b, 0x57, 0x2c, 0x3d, 0xea, 0x79, 0x91, 0x61, 0x17, 0x2a, 0x96,
+ 0x2d, 0x59, 0x8c, 0x03, 0x3a, 0x62, 0x30, 0x21, 0x9d, 0x25, 0x15, 0x4e, 0x6e, 0x8c, 0xdc, 0x8f,
+ 0x8c, 0x54, 0x59, 0xd4, 0x29, 0xe5, 0x77, 0x2b, 0x59, 0xfa, 0x5f, 0x5e, 0x86, 0x6b, 0xd9, 0x73,
+ 0xc2, 0xdb, 0x7e, 0x40, 0x5d, 0xcf, 0x74, 0x6c, 0x75, 0xfa, 0x44, 0x69, 0x56, 0x59, 0x8c, 0x03,
+ 0x3a, 0xba, 0x05, 0x25, 0x97, 0xf6, 0x2d, 0xd3, 0x20, 0x9e, 0x72, 0x3a, 0x44, 0xf4, 0x11, 0xab,
+ 0x32, 0x1c, 0x52, 0x87, 0x5c, 0xfd, 0xc8, 0xff, 0x1f, 0x5e, 0xfd, 0xf8, 0x33, 0x8d, 0xdb, 0x73,
+ 0x32, 0xe2, 0x30, 0x50, 0x41, 0xcd, 0xc5, 0x79, 0xb6, 0xec, 0x55, 0x69, 0x17, 0x0e, 0x11, 0x88,
+ 0x87, 0xb7, 0x05, 0x7d, 0x5f, 0x83, 0x6a, 0x2f, 0x65, 0x30, 0x5e, 0xe0, 0xed, 0x99, 0x1b, 0xc7,
+ 0x47, 0x8b, 0xd5, 0xad, 0x21, 0xf2, 0xf0, 0xd0, 0x96, 0xa0, 0xdf, 0x84, 0x4a, 0x9f, 0xaf, 0x0b,
+ 0x8f, 0x51, 0xdb, 0xa0, 0x2a, 0x57, 0x37, 0xfa, 0x6a, 0xde, 0x8e, 0xb0, 0x9a, 0xcc, 0x25, 0x8c,
+ 0x76, 0x0e, 0xeb, 0x33, 0xdc, 0xb5, 0x8b, 0x11, 0x70, 0x5c, 0x62, 0xe2, 0xce, 0xcd, 0xd6, 0x45,
+ 0xdf, 0xb9, 0xf9, 0x5e, 0xf6, 0x9d, 0x1b, 0x72, 0xce, 0x1a, 0xf2, 0xe5, 0xdd, 0x9b, 0x97, 0x77,
+ 0x6f, 0x5e, 0xd4, 0xdd, 0x9b, 0x5b, 0x50, 0xf2, 0x28, 0x63, 0xa6, 0xdd, 0xf1, 0xaa, 0xb3, 0x32,
+ 0x41, 0xc7, 0xa5, 0x36, 0x55, 0x19, 0x0e, 0xa9, 0xe8, 0xe7, 0xa1, 0x2c, 0x42, 0x6c, 0x2b, 0x6e,
+ 0xc7, 0xab, 0xce, 0x89, 0x4c, 0x9d, 0x38, 0xc9, 0x9b, 0x41, 0x21, 0x8e, 0xe8, 0xe8, 0x2d, 0x98,
+ 0x92, 0xa9, 0x44, 0x79, 0x04, 0x89, 0x7b, 0x32, 0xe5, 0xfa, 0x2c, 0x5f, 0xc1, 0xf5, 0x58, 0x39,
+ 0x4e, 0x70, 0x71, 0xd7, 0x95, 0x86, 0x71, 0xc8, 0xea, 0x95, 0xa4, 0xeb, 0x1a, 0x45, 0x28, 0x71,
+ 0x8c, 0x0b, 0xbd, 0x0a, 0x79, 0x66, 0x79, 0xd5, 0xab, 0x82, 0x39, 0x74, 0x31, 0x76, 0x1a, 0x4d,
+ 0xcc, 0xcb, 0xc7, 0xbf, 0x44, 0xf3, 0x3f, 0x1a, 0xcc, 0xa4, 0xee, 0x71, 0x70, 0x99, 0xbe, 0x6b,
+ 0xa9, 0x93, 0x32, 0x94, 0xb9, 0x8b, 0x1b, 0x98, 0x97, 0xa3, 0xc7, 0xca, 0x8f, 0xc9, 0x8d, 0xa9,
+ 0x8f, 0x1e, 0xac, 0xec, 0x34, 0xb9, 0xe3, 0x32, 0xe0, 0xc2, 0xdc, 0x4e, 0x8d, 0x6e, 0x3e, 0x19,
+ 0x17, 0x3d, 0x79, 0x84, 0x63, 0xc1, 0x81, 0xc2, 0x69, 0x82, 0x03, 0xfa, 0x67, 0x1a, 0x94, 0xef,
+ 0x93, 0x76, 0x97, 0x34, 0x4d, 0xbb, 0x8b, 0x5e, 0x87, 0xc9, 0x3d, 0xd7, 0xe9, 0x52, 0xd7, 0x53,
+ 0xd9, 0x5f, 0x91, 0x52, 0xac, 0xcb, 0x22, 0x1c, 0xd0, 0xb8, 0x3f, 0xca, 0x9c, 0xbe, 0x69, 0xa4,
+ 0xfd, 0xd1, 0x1d, 0x5e, 0x88, 0x25, 0x0d, 0x3d, 0x92, 0x73, 0x97, 0x1f, 0xf3, 0x26, 0xe6, 0x4e,
+ 0xa3, 0x29, 0x33, 0xaa, 0xc1, 0xac, 0xa3, 0x37, 0x12, 0xf6, 0x55, 0x79, 0xa8, 0x45, 0xf4, 0xbd,
+ 0x1c, 0x54, 0x64, 0xd7, 0xa4, 0x07, 0x7a, 0x9e, 0x9d, 0x7b, 0x47, 0x04, 0xcf, 0x3d, 0xbf, 0x47,
+ 0xdd, 0x0d, 0xd7, 0xf1, 0xfb, 0x6a, 0x96, 0xe2, 0xc1, 0x90, 0x88, 0x18, 0x06, 0xd0, 0xa3, 0xa2,
+ 0x60, 0x74, 0x0a, 0x17, 0x38, 0x3a, 0xc5, 0x13, 0x47, 0xe7, 0xaf, 0x34, 0x28, 0x37, 0xcc, 0x36,
+ 0x35, 0x0e, 0x0d, 0x8b, 0xa2, 0x6f, 0x40, 0xb5, 0x45, 0x2d, 0xca, 0xe8, 0x86, 0x4b, 0x0c, 0xba,
+ 0x4d, 0x5d, 0x53, 0xa8, 0x7a, 0xc7, 0x6e, 0x49, 0x6b, 0xbc, 0x18, 0x46, 0x2c, 0xaa, 0x6b, 0x43,
+ 0xf8, 0xf0, 0x50, 0x04, 0xb4, 0x09, 0x53, 0x2d, 0xea, 0x99, 0x2e, 0x6d, 0x6d, 0xc7, 0xec, 0xee,
+ 0xd7, 0x83, 0x25, 0xbd, 0x16, 0xa3, 0x3d, 0x3b, 0x5a, 0x9c, 0xde, 0x36, 0xfb, 0xd4, 0x32, 0x6d,
+ 0x2a, 0x0d, 0xf0, 0x44, 0x55, 0xbd, 0x08, 0xf9, 0x86, 0xd3, 0xd1, 0x7f, 0x27, 0x0f, 0xe1, 0x19,
+ 0x8e, 0x7e, 0x57, 0x83, 0x0a, 0xb1, 0x6d, 0x87, 0xa9, 0xc3, 0x51, 0x86, 0xef, 0xf1, 0xd8, 0xa6,
+ 0x42, 0x6d, 0x25, 0x02, 0x95, 0x27, 0x75, 0x78, 0xa0, 0xc6, 0x28, 0x38, 0x2e, 0x1b, 0xf9, 0xa9,
+ 0x60, 0xf4, 0xd6, 0xf8, 0xad, 0x38, 0x45, 0xe8, 0x79, 0xfe, 0x6b, 0x30, 0x9b, 0x6e, 0xec, 0x59,
+ 0x14, 0xe1, 0x38, 0x61, 0xaf, 0x3f, 0xd5, 0xa0, 0x14, 0x28, 0x33, 0xb4, 0x0a, 0x05, 0xdf, 0xa3,
+ 0xee, 0xd9, 0xee, 0x20, 0x0a, 0x0d, 0xb8, 0xeb, 0x51, 0x17, 0x8b, 0xca, 0xe8, 0x3d, 0x28, 0xf5,
+ 0x89, 0xe7, 0x3d, 0x71, 0xdc, 0x96, 0x52, 0xb3, 0xa7, 0x04, 0x92, 0x67, 0xb3, 0xaa, 0x8a, 0x43,
+ 0x10, 0xfd, 0x07, 0xd3, 0x50, 0x79, 0x40, 0x98, 0x79, 0x40, 0x85, 0x3f, 0x7c, 0x31, 0x0e, 0xd1,
+ 0x9f, 0x68, 0x70, 0x2d, 0x19, 0xb9, 0xbe, 0x40, 0xaf, 0x68, 0xfe, 0xf8, 0x68, 0xf1, 0x1a, 0xce,
+ 0x94, 0x86, 0x87, 0xb4, 0x42, 0xf8, 0x47, 0x03, 0x81, 0xf0, 0x8b, 0xf6, 0x8f, 0x9a, 0xc3, 0x04,
+ 0xe2, 0xe1, 0x6d, 0x79, 0xe9, 0x1f, 0x8d, 0xe0, 0x1f, 0x5d, 0xf8, 0x9b, 0x84, 0xef, 0x66, 0xfb,
+ 0x47, 0x0f, 0x47, 0xb7, 0x80, 0xa2, 0x1d, 0xf9, 0xd2, 0x29, 0x7a, 0xe9, 0x14, 0xbd, 0x28, 0xa7,
+ 0xa8, 0x9f, 0x72, 0x8a, 0xc6, 0x49, 0x46, 0xa8, 0x2c, 0xbf, 0x44, 0x1b, 0xe6, 0x5c, 0x8d, 0xef,
+ 0xa6, 0xfc, 0x51, 0x0e, 0xae, 0x64, 0x68, 0x07, 0xf4, 0x2e, 0xcc, 0x7a, 0xcc, 0x71, 0x49, 0x87,
+ 0x46, 0x13, 0x2a, 0x0f, 0x34, 0x71, 0x03, 0xb4, 0x99, 0xa2, 0xe1, 0x01, 0x6e, 0xf4, 0x18, 0x80,
+ 0x18, 0x06, 0xf5, 0xbc, 0x2d, 0xa7, 0x15, 0xd8, 0x65, 0xef, 0x70, 0x77, 0x61, 0x25, 0x2c, 0x7d,
+ 0x76, 0xb4, 0xf8, 0xc5, 0xac, 0x84, 0x51, 0xd0, 0x1e, 0x26, 0xef, 0x7a, 0x47, 0x15, 0x70, 0x0c,
+ 0x12, 0xfd, 0x3a, 0x80, 0xbc, 0xfd, 0x1d, 0xde, 0x53, 0x7c, 0x4e, 0x54, 0xbf, 0x16, 0xdc, 0xae,
+ 0xae, 0xfd, 0xaa, 0x4f, 0x6c, 0xc6, 0x57, 0x85, 0xb8, 0xbb, 0xfb, 0x30, 0x44, 0xc1, 0x31, 0x44,
+ 0xfd, 0x1f, 0x72, 0x50, 0x0a, 0xec, 0xc5, 0x17, 0x90, 0xb7, 0xe9, 0x24, 0xf2, 0x36, 0xa3, 0x3f,
+ 0x42, 0x09, 0x9a, 0x3c, 0x34, 0x53, 0xe3, 0xa4, 0x32, 0x35, 0x1b, 0xe3, 0x8b, 0x3a, 0x39, 0x37,
+ 0xf3, 0x4c, 0x83, 0xcb, 0x01, 0xab, 0xba, 0x9f, 0xfc, 0x65, 0x98, 0x76, 0x29, 0x69, 0xd5, 0x09,
+ 0x33, 0xf6, 0xc5, 0xf4, 0xc9, 0xdb, 0xc9, 0x73, 0xc7, 0x47, 0x8b, 0xd3, 0x38, 0x4e, 0xc0, 0x49,
+ 0x3e, 0x54, 0x03, 0xf0, 0x5b, 0xed, 0x47, 0x8e, 0x2b, 0x9c, 0x2d, 0x79, 0x27, 0x59, 0x4c, 0xe2,
+ 0xee, 0xda, 0xba, 0x2a, 0xc5, 0x31, 0x8e, 0xac, 0x8b, 0xd0, 0xf9, 0x31, 0x2f, 0x42, 0x17, 0xce,
+ 0x74, 0x11, 0xfa, 0x9f, 0x35, 0x98, 0x8a, 0x3a, 0x7f, 0xe1, 0xa9, 0xa8, 0x76, 0x32, 0x15, 0xb5,
+ 0x32, 0xf6, 0xdc, 0x0e, 0x49, 0x3e, 0x7d, 0xbf, 0x18, 0x75, 0x4b, 0xa4, 0x9b, 0xf6, 0x60, 0xde,
+ 0xcc, 0x4c, 0xc1, 0xc4, 0x54, 0x47, 0x78, 0xaf, 0x6c, 0x73, 0x28, 0x27, 0x3e, 0x01, 0x05, 0xf9,
+ 0x50, 0x3a, 0xa0, 0x2e, 0x33, 0x0d, 0x1a, 0xf4, 0x6f, 0xe3, 0x9c, 0x9e, 0x2d, 0x46, 0x63, 0xfa,
+ 0x50, 0x09, 0xc0, 0xa1, 0x28, 0xb4, 0x07, 0x45, 0xda, 0xea, 0xd0, 0xe0, 0x1e, 0xf9, 0xdb, 0x63,
+ 0xdd, 0xe1, 0x8f, 0xc6, 0x93, 0x7f, 0x79, 0x58, 0x42, 0x23, 0x0f, 0xca, 0x56, 0xe0, 0x32, 0x2b,
+ 0x83, 0xb9, 0x3e, 0xb2, 0x9c, 0xd0, 0xf9, 0x8e, 0xee, 0x75, 0x86, 0x45, 0x38, 0x92, 0x83, 0xba,
+ 0xe1, 0xeb, 0x84, 0xe2, 0x39, 0x69, 0x82, 0x13, 0xde, 0xbe, 0x79, 0x50, 0x7e, 0x42, 0x18, 0x75,
+ 0x7b, 0xc4, 0xed, 0x2a, 0x83, 0x76, 0xf4, 0x1e, 0x3e, 0x0a, 0x90, 0xa2, 0x1e, 0x86, 0x45, 0x38,
+ 0x92, 0xa3, 0xff, 0x20, 0x17, 0xa9, 0x9e, 0x17, 0x9d, 0x0b, 0x7c, 0x2b, 0x99, 0x0b, 0x5c, 0x48,
+ 0xe7, 0x02, 0x53, 0xc1, 0x88, 0xb3, 0x67, 0x03, 0x09, 0x54, 0x2c, 0xe2, 0xb1, 0xdd, 0x7e, 0x8b,
+ 0x30, 0x15, 0x95, 0xab, 0x2c, 0xff, 0xdc, 0xe9, 0x94, 0xc9, 0x8e, 0xd9, 0xa3, 0x91, 0xbd, 0xda,
+ 0x88, 0x60, 0x70, 0x1c, 0x53, 0xff, 0x0f, 0x0d, 0xe6, 0x06, 0xf2, 0xbf, 0x68, 0x1f, 0x26, 0x6c,
+ 0x61, 0x61, 0x8f, 0xfd, 0xa8, 0x2e, 0x66, 0xa8, 0xcb, 0x45, 0xa3, 0x0a, 0x14, 0x3e, 0xb2, 0xa1,
+ 0x44, 0x9f, 0x32, 0xea, 0xda, 0xc4, 0x52, 0x07, 0xe3, 0xf9, 0x3c, 0xe0, 0x13, 0xf6, 0xd4, 0x1d,
+ 0x85, 0x8c, 0x43, 0x19, 0xfa, 0x4f, 0x72, 0x50, 0x89, 0xf1, 0x3d, 0x2f, 0x62, 0x2b, 0xee, 0x15,
+ 0x4a, 0x57, 0x73, 0xd7, 0xb5, 0xd4, 0x44, 0xc7, 0xee, 0x15, 0x2a, 0x12, 0x6e, 0xe0, 0x38, 0x1f,
+ 0x5a, 0x06, 0xe8, 0x11, 0x8f, 0x51, 0x57, 0xe8, 0xc6, 0xd4, 0x6d, 0xbe, 0xad, 0x90, 0x82, 0x63,
+ 0x5c, 0xe8, 0xa6, 0x0a, 0x7f, 0x14, 0x92, 0xaf, 0x61, 0x86, 0xc4, 0x36, 0x8a, 0xe7, 0x10, 0xdb,
+ 0x40, 0x1d, 0x98, 0x0d, 0x5a, 0x1d, 0x50, 0xd5, 0xc6, 0x3d, 0x25, 0xb0, 0x34, 0x15, 0x53, 0x10,
+ 0x78, 0x00, 0x54, 0xff, 0x6b, 0x0d, 0xa6, 0x13, 0xf6, 0x2e, 0x7a, 0x2d, 0x7e, 0x79, 0x21, 0x16,
+ 0x29, 0x4d, 0x5c, 0x3a, 0x78, 0x03, 0x26, 0xe4, 0x00, 0xa9, 0x81, 0x0f, 0x37, 0xa2, 0x1c, 0x42,
+ 0xac, 0xa8, 0x7c, 0x4b, 0xa9, 0x50, 0x4a, 0x7a, 0x4b, 0xa9, 0x58, 0x0b, 0x0e, 0xe8, 0xe8, 0x0b,
+ 0xdc, 0x82, 0x97, 0xad, 0x53, 0x23, 0x1d, 0x1e, 0x0c, 0x41, 0x3f, 0x70, 0xc8, 0xa1, 0x7f, 0x0b,
+ 0xe4, 0xcb, 0x5b, 0x74, 0x1d, 0xf2, 0x3d, 0xd3, 0x56, 0xe1, 0x4c, 0x11, 0x34, 0xdd, 0x32, 0x6d,
+ 0xcc, 0xcb, 0x04, 0x89, 0x3c, 0x55, 0x01, 0x1e, 0x49, 0x22, 0x4f, 0x31, 0x2f, 0xe3, 0xb6, 0x89,
+ 0xe5, 0x38, 0xdd, 0x3d, 0x62, 0x74, 0x83, 0x80, 0xa8, 0xbc, 0x3e, 0x2b, 0x6c, 0x93, 0x46, 0x92,
+ 0x84, 0xd3, 0xbc, 0xe2, 0x79, 0x9c, 0x08, 0xad, 0x3f, 0x82, 0xbc, 0xe5, 0x74, 0xd4, 0x5e, 0x1c,
+ 0x3d, 0xe0, 0xdb, 0x70, 0x3a, 0xb2, 0x81, 0x0d, 0xa7, 0x83, 0x39, 0x22, 0x32, 0xa0, 0xd8, 0x25,
+ 0xed, 0x2e, 0x51, 0x5b, 0x6f, 0x74, 0x75, 0x1d, 0xa6, 0x01, 0xd4, 0x9b, 0x2f, 0xfe, 0x89, 0x25,
+ 0x36, 0x32, 0x60, 0xc2, 0x6f, 0x89, 0xff, 0x91, 0x18, 0xf7, 0xaf, 0x2a, 0x76, 0xd7, 0x84, 0x08,
+ 0xa1, 0x47, 0xe4, 0x6f, 0xac, 0xa0, 0xf5, 0x7f, 0xcc, 0x81, 0xfa, 0xf7, 0x0a, 0xe4, 0x43, 0xb9,
+ 0x13, 0xbc, 0xb1, 0x52, 0x63, 0x76, 0x77, 0x8c, 0x6b, 0xbd, 0x89, 0xd7, 0x5a, 0x32, 0xb3, 0x15,
+ 0x16, 0xe2, 0x48, 0x12, 0xa2, 0xc9, 0xb1, 0x5c, 0x1b, 0x73, 0x2c, 0xa5, 0xb8, 0xc1, 0xd1, 0x24,
+ 0x50, 0xd8, 0x67, 0xac, 0xaf, 0xc6, 0x72, 0xf4, 0xe7, 0x86, 0xd1, 0xf5, 0x3a, 0x19, 0x43, 0xe5,
+ 0xdf, 0x58, 0x40, 0xeb, 0x3d, 0x50, 0x27, 0x1d, 0x32, 0x12, 0x2f, 0x2b, 0x65, 0x6c, 0x7c, 0xe9,
+ 0x74, 0xe7, 0x4f, 0xf8, 0x2a, 0x30, 0xf6, 0xe0, 0x22, 0xf3, 0x09, 0xa5, 0xfe, 0xaf, 0x39, 0xc8,
+ 0xef, 0x34, 0x9a, 0xf2, 0xfe, 0xb0, 0x08, 0x74, 0xd0, 0x66, 0xd7, 0xec, 0x3f, 0xa4, 0xae, 0xd9,
+ 0x96, 0x4e, 0x6e, 0x29, 0x7e, 0x7f, 0x38, 0xcd, 0x81, 0x33, 0x6a, 0xa1, 0x0f, 0x60, 0xca, 0x20,
+ 0xab, 0xd4, 0x65, 0x52, 0x67, 0x9d, 0x2d, 0x14, 0x2c, 0xb2, 0x91, 0xab, 0x2b, 0x51, 0x75, 0x9c,
+ 0x00, 0x43, 0xbb, 0x00, 0x46, 0x04, 0x9d, 0x3f, 0x0b, 0xb4, 0x7c, 0x4a, 0x1a, 0x01, 0xc7, 0x80,
+ 0x10, 0x86, 0x72, 0x97, 0xb3, 0x0a, 0xd4, 0xc2, 0x59, 0x50, 0xc5, 0xa2, 0xbc, 0x1f, 0xd4, 0xc5,
+ 0x11, 0x8c, 0xfe, 0x23, 0x0d, 0xf2, 0xbb, 0x6b, 0xeb, 0xc8, 0x81, 0x72, 0x78, 0xe9, 0x45, 0xed,
+ 0x89, 0xfa, 0xf8, 0x51, 0x50, 0x29, 0x38, 0xfc, 0xc4, 0x91, 0x0c, 0xb4, 0x0f, 0x93, 0x7b, 0xbe,
+ 0x69, 0x31, 0xd3, 0x16, 0x61, 0xa2, 0x71, 0x1c, 0x95, 0xe0, 0x71, 0xa6, 0xca, 0xb9, 0x49, 0x54,
+ 0x1c, 0xc0, 0xeb, 0xdf, 0x06, 0xa5, 0x0b, 0xb8, 0x01, 0x7a, 0x11, 0x9d, 0x0c, 0x0d, 0xd0, 0xac,
+ 0x8e, 0xea, 0x7f, 0x9f, 0x83, 0x09, 0xf5, 0xaf, 0x3d, 0x17, 0x1f, 0x42, 0xa0, 0x89, 0x10, 0xc2,
+ 0xea, 0x98, 0xff, 0x63, 0x31, 0x34, 0x80, 0xd0, 0x4b, 0x05, 0x10, 0xc6, 0xfd, 0xc3, 0x8c, 0xe7,
+ 0x84, 0x0f, 0xfe, 0x49, 0x83, 0xcb, 0x92, 0x71, 0xd3, 0xf6, 0x18, 0xb1, 0x0d, 0xf1, 0xf7, 0x46,
+ 0x07, 0xa2, 0x64, 0x6c, 0x1b, 0x5e, 0xb9, 0x7f, 0xe2, 0xcc, 0x90, 0xbf, 0xb1, 0x82, 0xe6, 0xb6,
+ 0xc0, 0xbe, 0xe3, 0x31, 0xf1, 0x06, 0x39, 0x97, 0xb4, 0x05, 0xee, 0xaa, 0x72, 0x1c, 0x72, 0xa4,
+ 0x8d, 0x8c, 0xe2, 0x70, 0x23, 0x43, 0x7f, 0x02, 0x53, 0xf1, 0x7f, 0x0a, 0x79, 0x61, 0xc1, 0x10,
+ 0xfd, 0x53, 0x0d, 0x20, 0x90, 0x7c, 0xe1, 0x91, 0x88, 0x56, 0x32, 0x12, 0x31, 0xf6, 0x14, 0x65,
+ 0xc7, 0x21, 0xfe, 0xa6, 0x10, 0x74, 0x49, 0x44, 0x21, 0x3e, 0xd6, 0xe0, 0x32, 0x49, 0x78, 0xf6,
+ 0xaa, 0x67, 0xe7, 0x16, 0x28, 0xb8, 0xa6, 0x9a, 0x91, 0xfa, 0x4f, 0x2e, 0x9c, 0x12, 0x8b, 0x6e,
+ 0xc3, 0x54, 0x5f, 0xf9, 0x77, 0x0f, 0xa2, 0x15, 0x14, 0xa6, 0x1e, 0xb6, 0x63, 0x34, 0x9c, 0xe0,
+ 0x7c, 0x4e, 0x24, 0x25, 0x7f, 0x2e, 0x91, 0x94, 0x78, 0xee, 0xb1, 0x70, 0x62, 0xee, 0xd1, 0x86,
+ 0x72, 0xdb, 0x75, 0x7a, 0x22, 0x58, 0xa1, 0xfe, 0xab, 0x63, 0xcc, 0x00, 0x48, 0xa8, 0x30, 0xd7,
+ 0x03, 0x5c, 0x1c, 0x89, 0xe0, 0x27, 0x03, 0x73, 0xa4, 0xb4, 0x89, 0xf3, 0x90, 0x16, 0x6e, 0xc3,
+ 0x1d, 0x89, 0x8a, 0x03, 0x78, 0xfd, 0x5f, 0x72, 0xc1, 0x3e, 0x6c, 0xa6, 0x2e, 0xef, 0x6a, 0x43,
+ 0x2e, 0xef, 0xaa, 0xf7, 0x17, 0x71, 0x77, 0xfd, 0x0d, 0x98, 0x70, 0x29, 0xf1, 0x1c, 0x5b, 0xbd,
+ 0x64, 0x0a, 0x95, 0x18, 0x16, 0xa5, 0x58, 0x51, 0xe3, 0x6e, 0x7d, 0xee, 0x39, 0x6e, 0xfd, 0x17,
+ 0x62, 0x73, 0x93, 0x17, 0x7b, 0x3a, 0xdc, 0x66, 0x19, 0xf3, 0x23, 0x3c, 0x16, 0x95, 0x36, 0x2b,
+ 0xa6, 0x3d, 0x16, 0x95, 0xda, 0x0a, 0x39, 0x50, 0x0b, 0xa6, 0xb8, 0x7b, 0x2f, 0xbc, 0x96, 0xd6,
+ 0x0a, 0x1b, 0x21, 0x66, 0x10, 0xae, 0xe0, 0x46, 0x0c, 0x07, 0x27, 0x50, 0xf5, 0xaf, 0x42, 0x14,
+ 0x8d, 0x41, 0x4b, 0x50, 0xee, 0xbb, 0x4e, 0x9f, 0x74, 0x08, 0xa3, 0xca, 0x5c, 0x0b, 0x57, 0xc0,
+ 0x76, 0x40, 0xc0, 0x11, 0x4f, 0xbd, 0xf6, 0xc9, 0xe7, 0x0b, 0x97, 0x3e, 0xfd, 0x7c, 0xe1, 0xd2,
+ 0x67, 0x9f, 0x2f, 0x5c, 0xfa, 0xad, 0xe3, 0x05, 0xed, 0x93, 0xe3, 0x05, 0xed, 0xd3, 0xe3, 0x05,
+ 0xed, 0xb3, 0xe3, 0x05, 0xed, 0x47, 0xc7, 0x0b, 0xda, 0x77, 0xff, 0x6d, 0xe1, 0xd2, 0xd7, 0x4b,
+ 0xc1, 0x34, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x21, 0x4d, 0xa6, 0x88, 0xcb, 0x50, 0x00,
+ 0x00,
}
func (m *AbstractVertex) Marshal() (dAtA []byte, err error) {
@@ -4555,6 +4589,11 @@ func (m *Scale) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
+ if m.LookbackSeconds != nil {
+ i = encodeVarintGenerated(dAtA, i, uint64(*m.LookbackSeconds))
+ i--
+ dAtA[i] = 0x18
+ }
if m.Max != nil {
i = encodeVarintGenerated(dAtA, i, uint64(*m.Max))
i--
@@ -4923,6 +4962,49 @@ func (m *Vertex) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
+func (m *VertexInstance) Marshal() (dAtA []byte, err error) {
+ size := m.Size()
+ dAtA = make([]byte, size)
+ n, err := m.MarshalToSizedBuffer(dAtA[:size])
+ if err != nil {
+ return nil, err
+ }
+ return dAtA[:n], nil
+}
+
+func (m *VertexInstance) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *VertexInstance) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ i = encodeVarintGenerated(dAtA, i, uint64(m.Replica))
+ i--
+ dAtA[i] = 0x18
+ i -= len(m.Hostname)
+ copy(dAtA[i:], m.Hostname)
+ i = encodeVarintGenerated(dAtA, i, uint64(len(m.Hostname)))
+ i--
+ dAtA[i] = 0x12
+ if m.Vertex != nil {
+ {
+ size, err := m.Vertex.MarshalToSizedBuffer(dAtA[:i])
+ if err != nil {
+ return 0, err
+ }
+ i -= size
+ i = encodeVarintGenerated(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
func (m *VertexLimits) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -6175,6 +6257,9 @@ func (m *Scale) Size() (n int) {
if m.Max != nil {
n += 1 + sovGenerated(uint64(*m.Max))
}
+ if m.LookbackSeconds != nil {
+ n += 1 + sovGenerated(uint64(*m.LookbackSeconds))
+ }
return n
}
@@ -6300,6 +6385,22 @@ func (m *Vertex) Size() (n int) {
return n
}
+func (m *VertexInstance) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ if m.Vertex != nil {
+ l = m.Vertex.Size()
+ n += 1 + l + sovGenerated(uint64(l))
+ }
+ l = len(m.Hostname)
+ n += 1 + l + sovGenerated(uint64(l))
+ n += 1 + sovGenerated(uint64(m.Replica))
+ return n
+}
+
func (m *VertexLimits) Size() (n int) {
if m == nil {
return 0
@@ -7137,6 +7238,7 @@ func (this *Scale) String() string {
s := strings.Join([]string{`&Scale{`,
`Min:` + valueToStringGenerated(this.Min) + `,`,
`Max:` + valueToStringGenerated(this.Max) + `,`,
+ `LookbackSeconds:` + valueToStringGenerated(this.LookbackSeconds) + `,`,
`}`,
}, "")
return s
@@ -7226,6 +7328,18 @@ func (this *Vertex) String() string {
}, "")
return s
}
+func (this *VertexInstance) String() string {
+ if this == nil {
+ return "nil"
+ }
+ s := strings.Join([]string{`&VertexInstance{`,
+ `Vertex:` + strings.Replace(this.Vertex.String(), "Vertex", "Vertex", 1) + `,`,
+ `Hostname:` + fmt.Sprintf("%v", this.Hostname) + `,`,
+ `Replica:` + fmt.Sprintf("%v", this.Replica) + `,`,
+ `}`,
+ }, "")
+ return s
+}
func (this *VertexLimits) String() string {
if this == nil {
return "nil"
@@ -16305,6 +16419,26 @@ func (m *Scale) Unmarshal(dAtA []byte) error {
}
}
m.Max = &v
+ case 3:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field LookbackSeconds", wireType)
+ }
+ var v int32
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowGenerated
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ v |= int32(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ m.LookbackSeconds = &v
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@@ -17258,6 +17392,143 @@ func (m *Vertex) Unmarshal(dAtA []byte) error {
}
return nil
}
+func (m *VertexInstance) Unmarshal(dAtA []byte) error {
+ l := len(dAtA)
+ iNdEx := 0
+ for iNdEx < l {
+ preIndex := iNdEx
+ var wire uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowGenerated
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ wire |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ fieldNum := int32(wire >> 3)
+ wireType := int(wire & 0x7)
+ if wireType == 4 {
+ return fmt.Errorf("proto: VertexInstance: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: VertexInstance: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Vertex", wireType)
+ }
+ var msglen int
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowGenerated
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ msglen |= int(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ if msglen < 0 {
+ return ErrInvalidLengthGenerated
+ }
+ postIndex := iNdEx + msglen
+ if postIndex < 0 {
+ return ErrInvalidLengthGenerated
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if m.Vertex == nil {
+ m.Vertex = &Vertex{}
+ }
+ if err := m.Vertex.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Hostname", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowGenerated
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ stringLen |= uint64(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ intStringLen := int(stringLen)
+ if intStringLen < 0 {
+ return ErrInvalidLengthGenerated
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthGenerated
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.Hostname = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 3:
+ if wireType != 0 {
+ return fmt.Errorf("proto: wrong wireType = %d for field Replica", wireType)
+ }
+ m.Replica = 0
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowGenerated
+ }
+ if iNdEx >= l {
+ return io.ErrUnexpectedEOF
+ }
+ b := dAtA[iNdEx]
+ iNdEx++
+ m.Replica |= int32(b&0x7F) << shift
+ if b < 0x80 {
+ break
+ }
+ }
+ default:
+ iNdEx = preIndex
+ skippy, err := skipGenerated(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthGenerated
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
func (m *VertexLimits) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
diff --git a/pkg/apis/numaflow/v1alpha1/generated.proto b/pkg/apis/numaflow/v1alpha1/generated.proto
index f6df41b29..e535a8ad1 100644
--- a/pkg/apis/numaflow/v1alpha1/generated.proto
+++ b/pkg/apis/numaflow/v1alpha1/generated.proto
@@ -807,9 +807,14 @@ message Scale {
optional int32 min = 1;
// Maximum replicas
- // +kubebuilder:default=1
+ // +kubebuilder:default=100
// +optional
optional int32 max = 2;
+
+ // Lookback seconds to calculate the average pending messages and processing rate
+ // +kubebuilder:default=180
+ // +optional
+ optional int32 lookbackSeconds = 3;
}
message Sink {
@@ -890,6 +895,15 @@ message Vertex {
optional VertexStatus status = 3;
}
+// VertexInstance is a wrapper of a vertex instance, which contains the vertex spec and the instance information such as hostname and replica index.
+message VertexInstance {
+ optional Vertex vertex = 1;
+
+ optional string hostname = 2;
+
+ optional int32 replica = 3;
+}
+
message VertexLimits {
// Read batch size
// +optional
diff --git a/pkg/apis/numaflow/v1alpha1/vertex_instance.go b/pkg/apis/numaflow/v1alpha1/vertex_instance.go
new file mode 100644
index 000000000..1ed1f4321
--- /dev/null
+++ b/pkg/apis/numaflow/v1alpha1/vertex_instance.go
@@ -0,0 +1,8 @@
+package v1alpha1
+
+// VertexInstance is a wrapper of a vertex instance, which contains the vertex spec and the instance information such as hostname and replica index.
+type VertexInstance struct {
+ Vertex *Vertex `json:"vertex,omitempty" protobuf:"bytes,1,opt,name=vertex"`
+ Hostname string `json:"hostname,omitempty" protobuf:"bytes,2,opt,name=hostname"`
+ Replica int32 `json:"replica,omitempty" protobuf:"varint,3,opt,name=replica"`
+}
diff --git a/pkg/apis/numaflow/v1alpha1/vertex_types.go b/pkg/apis/numaflow/v1alpha1/vertex_types.go
index 7ef27cb4b..5ceb1bac0 100644
--- a/pkg/apis/numaflow/v1alpha1/vertex_types.go
+++ b/pkg/apis/numaflow/v1alpha1/vertex_types.go
@@ -371,9 +371,13 @@ type Scale struct {
// +optional
Min *int32 `json:"min,omitempty" protobuf:"varint,1,opt,name=min"`
// Maximum replicas
- // +kubebuilder:default=1
+ // +kubebuilder:default=100
// +optional
Max *int32 `json:"max,omitempty" protobuf:"varint,2,opt,name=max"`
+ // Lookback seconds to calculate the average pending messages and processing rate
+ // +kubebuilder:default=180
+ // +optional
+ LookbackSeconds *int32 `json:"lookbackSeconds,omitempty" protobuf:"varint,3,opt,name=lookbackSeconds"`
}
type VertexLimits struct {
diff --git a/pkg/apis/numaflow/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/numaflow/v1alpha1/zz_generated.deepcopy.go
index 6c2677e62..08db1584a 100644
--- a/pkg/apis/numaflow/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/numaflow/v1alpha1/zz_generated.deepcopy.go
@@ -1249,6 +1249,11 @@ func (in *Scale) DeepCopyInto(out *Scale) {
*out = new(int32)
**out = **in
}
+ if in.LookbackSeconds != nil {
+ in, out := &in.LookbackSeconds, &out.LookbackSeconds
+ *out = new(int32)
+ **out = **in
+ }
return
}
@@ -1449,6 +1454,27 @@ func (in *Vertex) DeepCopyObject() runtime.Object {
return nil
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *VertexInstance) DeepCopyInto(out *VertexInstance) {
+ *out = *in
+ if in.Vertex != nil {
+ in, out := &in.Vertex, &out.Vertex
+ *out = new(Vertex)
+ (*in).DeepCopyInto(*out)
+ }
+ return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VertexInstance.
+func (in *VertexInstance) DeepCopy() *VertexInstance {
+ if in == nil {
+ return nil
+ }
+ out := new(VertexInstance)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *VertexLimits) DeepCopyInto(out *VertexLimits) {
*out = *in
diff --git a/pkg/isb/interfaces.go b/pkg/isb/interfaces.go
index 1b2f7dcaf..9d34434ec 100644
--- a/pkg/isb/interfaces.go
+++ b/pkg/isb/interfaces.go
@@ -9,12 +9,13 @@ package isb
import (
"context"
"io"
+ "math"
"strconv"
)
const (
- PendingNotAvailable = int64(-1)
- RateNotAvailable = float64(-1)
+ PendingNotAvailable = int64(math.MinInt64)
+ RateNotAvailable = float64(math.MinInt)
)
// Ratable is the interface that wraps the Rate method.
@@ -23,6 +24,12 @@ type Ratable interface {
Rate(context.Context) (float64, error)
}
+// LagReader is the interface that wraps the Pending method.
+type LagReader interface {
+ // Pending returns the pending messages number.
+ Pending(context.Context) (int64, error)
+}
+
// BufferWriter is the buffer to which we are writing.
type BufferWriter interface {
BufferWriterInformation
@@ -42,8 +49,6 @@ type BufferReader interface {
Read(context.Context, int64) ([]*ReadMessage, error)
// Ack acknowledges an array of offset.
Ack(context.Context, []Offset) []error
- // Pending returns the pending messages number.
- Pending(context.Context) (int64, error)
}
// BufferReaderInformation has information regarding the buffer we are reading from.
diff --git a/pkg/isb/jetstream/options.go b/pkg/isb/jetstream/options.go
index 04c4b6e06..9e975243a 100644
--- a/pkg/isb/jetstream/options.go
+++ b/pkg/isb/jetstream/options.go
@@ -57,9 +57,16 @@ func WithRefreshInterval(refreshInterval time.Duration) WriteOption {
}
// WithUsingWriteInfoAsRate sets whether to check sequence for rate calculation
-func WithUsingWriteInfoAsRate(check bool) WriteOption {
+func WithUsingWriteInfoAsRate(yes bool) WriteOption {
return func(o *writeOptions) error {
- o.useWriteInfoAsRate = check
+ o.useWriteInfoAsRate = yes
+ return nil
+ }
+}
+
+func WithWriteRateLookbackSeconds(seconds int64) WriteOption {
+ return func(o *writeOptions) error {
+ o.rateLookbackSeconds = seconds
return nil
}
}
@@ -102,7 +109,7 @@ func WithAckInfoCheckInterval(t time.Duration) ReadOption {
}
}
-func WithRateLookbackSeconds(seconds int64) ReadOption {
+func WithAckRateLookbackSeconds(seconds int64) ReadOption {
return func(o *readOptions) error {
o.rateLookbackSeconds = seconds
return nil
diff --git a/pkg/isb/jetstream/reader.go b/pkg/isb/jetstream/reader.go
index 8933d7449..2d9507cf5 100644
--- a/pkg/isb/jetstream/reader.go
+++ b/pkg/isb/jetstream/reader.go
@@ -159,8 +159,8 @@ func (jr *jetStreamReader) Rate(_ context.Context) (float64, error) {
endSeqInfo := timestampedSeqs[len(timestampedSeqs)-1]
startSeqInfo := timestampedSeqs[len(timestampedSeqs)-2]
for i := len(timestampedSeqs) - 3; i >= 0; i-- {
+ startSeqInfo = timestampedSeqs[i]
if endSeqInfo.timestamp-timestampedSeqs[i].timestamp > jr.opts.rateLookbackSeconds {
- startSeqInfo = timestampedSeqs[i]
break
}
}
diff --git a/pkg/isb/jetstream/writer.go b/pkg/isb/jetstream/writer.go
index 6f3fed3c2..7ce3c39a1 100644
--- a/pkg/isb/jetstream/writer.go
+++ b/pkg/isb/jetstream/writer.go
@@ -148,7 +148,7 @@ func (jw *jetStreamWriter) Close() error {
// Rate returns the writting rate (tps)
func (jw *jetStreamWriter) Rate(_ context.Context) (float64, error) {
- if jw.opts.useWriteInfoAsRate {
+ if !jw.opts.useWriteInfoAsRate {
return isb.RateNotAvailable, nil
}
timestampedSeqs := jw.writtenInfo.Items()
@@ -156,10 +156,10 @@ func (jw *jetStreamWriter) Rate(_ context.Context) (float64, error) {
return isb.RateNotAvailable, nil
}
endSeqInfo := timestampedSeqs[len(timestampedSeqs)-1]
- startSeqInfo := timestampedSeqs[len(timestampedSeqs)-1]
+ startSeqInfo := timestampedSeqs[len(timestampedSeqs)-2]
for i := len(timestampedSeqs) - 3; i >= 0; i-- {
+ startSeqInfo = timestampedSeqs[i]
if endSeqInfo.timestamp-timestampedSeqs[i].timestamp > jw.opts.rateLookbackSeconds {
- startSeqInfo = timestampedSeqs[i]
break
}
}
diff --git a/pkg/isb/redis/read.go b/pkg/isb/redis/read.go
index cf8ac38a8..b6502785e 100644
--- a/pkg/isb/redis/read.go
+++ b/pkg/isb/redis/read.go
@@ -303,7 +303,6 @@ func (br *BufferRead) convertXStreamToMessages(xstreams []redis.XStream, message
}
messages = append(messages, &readMessage)
}
-
}
}
diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go
index 89e633e31..beee16cfd 100644
--- a/pkg/metrics/metrics.go
+++ b/pkg/metrics/metrics.go
@@ -7,17 +7,146 @@ import (
"net/http"
"net/http/pprof"
"os"
+ "time"
dfv1 "github.com/numaproj/numaflow/pkg/apis/numaflow/v1alpha1"
+ "github.com/numaproj/numaflow/pkg/isb"
"github.com/numaproj/numaflow/pkg/shared/logging"
+ sharedqueue "github.com/numaproj/numaflow/pkg/shared/queue"
sharedtls "github.com/numaproj/numaflow/pkg/shared/tls"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.uber.org/zap"
)
-func StartMetricsServer(ctx context.Context) (func(ctx context.Context) error, error) {
+var (
+ processingRate = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "vertex_processing_rate",
+ Help: "Message processing rate, tps. It represents the rate of a vertex instead of a pod.",
+ }, []string{"vertex", "pipeline"})
+
+ pendingMessages = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "vertex_pending_messages",
+ Help: "Pending messages. It meants the pending messages of a vertex, not a pod.",
+ }, []string{"vertex", "pipeline"})
+)
+
+// timestampedPending is a helper struct to wrap a pending number and timestamp pair
+type timestampedPending struct {
+ pending int64
+ // timestamp in seconds
+ timestamp int64
+}
+
+type metricsServer struct {
+ vertex *dfv1.Vertex
+ rater isb.Ratable
+ lagReader isb.LagReader
+ // pendingLookbackSeconds is the look back seconds for pending calculation
+ pendingLookbackSeconds int64
+ refreshInterval time.Duration
+ // pendingInfo stores a list of pending/timestamp(seconds) information
+ pendingInfo *sharedqueue.OverflowQueue[timestampedPending]
+}
+
+type Option func(*metricsServer)
+
+func WithRater(r isb.Ratable) Option {
+ return func(m *metricsServer) {
+ m.rater = r
+ }
+}
+
+func WithLagReader(r isb.LagReader) Option {
+ return func(m *metricsServer) {
+ m.lagReader = r
+ }
+}
+
+func WithRefreshInterval(d time.Duration) Option {
+ return func(m *metricsServer) {
+ m.refreshInterval = d
+ }
+}
+
+func WithPendingLookbackSeconds(seconds int64) Option {
+ return func(m *metricsServer) {
+ m.pendingLookbackSeconds = seconds
+ }
+}
+
+// NewMetricsServer returns a Prometheus metrics server instance, which can be used to start an HTTPS service to expose Prometheus metrics.
+func NewMetricsServer(vertex *dfv1.Vertex, opts ...Option) *metricsServer {
+ m := new(metricsServer)
+ m.vertex = vertex
+ m.refreshInterval = 5 * time.Second // Default refersh interval
+ m.pendingLookbackSeconds = 180 // Default
+ for _, opt := range opts {
+ if opt != nil {
+ opt(m)
+ }
+ }
+ if m.lagReader != nil {
+ m.pendingInfo = sharedqueue.New[timestampedPending](1800)
+ }
+ return m
+}
+
+func (ms *metricsServer) rateAndPending(ctx context.Context) {
+ if ms.lagReader == nil && ms.rater == nil {
+ return
+ }
+ labels := map[string]string{"vertex": ms.vertex.Spec.Name, "pipeline": ms.vertex.Spec.PipelineName}
+ log := logging.FromContext(ctx)
+ ticker := time.NewTicker(ms.refreshInterval)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ticker.C:
+ if ms.rater != nil {
+ if r, err := ms.rater.Rate(ctx); err != nil {
+ log.Errorw("failed to get processing rate", zap.Error(err))
+ } else {
+ if r != isb.RateNotAvailable {
+ processingRate.With(labels).Set(r)
+ }
+ }
+ }
+ if ms.lagReader != nil {
+ if pending, err := ms.lagReader.Pending(ctx); err != nil {
+ log.Errorw("failed to get pending messages", zap.Error(err))
+ } else {
+ if pending != isb.PendingNotAvailable {
+ now := time.Now().Unix()
+ ts := timestampedPending{pending: pending, timestamp: now}
+ ms.pendingInfo.Append(ts)
+ // Calculate avg pending
+ items := ms.pendingInfo.Items()
+ total := pending
+ num := int64(1)
+ for i := len(items) - 2; i >= 0; i-- {
+ if now-items[i].timestamp < ms.pendingLookbackSeconds {
+ total += items[i].pending
+ num++
+ } else {
+ break
+ }
+ }
+ pendingMessages.With(labels).Set(float64(total / num))
+ }
+ }
+ }
+ case <-ctx.Done():
+ return
+ }
+ }
+}
+
+// Start function starts the HTTPS service to expose metrics, it returns a shutdown function and an error if any
+func (ms *metricsServer) Start(ctx context.Context) (func(ctx context.Context) error, error) {
log := logging.FromContext(ctx)
- log.Info("generating self-signed certificate")
+ log.Info("Generating self-signed certificate")
cer, err := sharedtls.GenerateX509KeyPair()
if err != nil {
return nil, fmt.Errorf("failed to generate cert: %w", err)
@@ -46,6 +175,7 @@ func StartMetricsServer(ctx context.Context) (func(ctx context.Context) error, e
Handler: mux,
TLSConfig: &tls.Config{Certificates: []tls.Certificate{*cer}, MinVersion: tls.VersionTLS12},
}
+ go ms.rateAndPending(ctx)
go func() {
log.Info("Starting metrics HTTPS server")
if err := httpServer.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
diff --git a/pkg/metrics/metrics_test.go b/pkg/metrics/metrics_test.go
index 12f75cea0..e302d5741 100644
--- a/pkg/metrics/metrics_test.go
+++ b/pkg/metrics/metrics_test.go
@@ -15,7 +15,8 @@ import (
func Test_StartMetricsServer(t *testing.T) {
t.SkipNow() // flaky
- s, err := StartMetricsServer(context.TODO())
+ ms := NewMetricsServer(&dfv1.Vertex{})
+ s, err := ms.Start(context.TODO())
assert.NoError(t, err)
assert.NotNil(t, s)
e := httpexpect.WithConfig(httpexpect.Config{
diff --git a/pkg/sinks/sink.go b/pkg/sinks/sink.go
index b0106a199..ae6dfd4e9 100644
--- a/pkg/sinks/sink.go
+++ b/pkg/sinks/sink.go
@@ -21,10 +21,8 @@ import (
)
type SinkProcessor struct {
- ISBSvcType dfv1.ISBSvcType
- Vertex *dfv1.Vertex
- Hostname string
- Replica int
+ ISBSvcType dfv1.ISBSvcType
+ VertexInstance *dfv1.VertexInstance
}
func (u *SinkProcessor) Start(ctx context.Context) error {
@@ -33,17 +31,23 @@ func (u *SinkProcessor) Start(ctx context.Context) error {
defer cancel()
var reader isb.BufferReader
var err error
- fromBufferName := u.Vertex.GetFromBuffers()[0].Name
+ fromBufferName := u.VertexInstance.Vertex.GetFromBuffers()[0].Name
switch u.ISBSvcType {
case dfv1.ISBSvcTypeRedis:
redisClient := clients.NewInClusterRedisClient()
fromGroup := fromBufferName + "-group"
- consumer := fmt.Sprintf("%s-%v", u.Vertex.Name, u.Replica)
+ consumer := fmt.Sprintf("%s-%v", u.VertexInstance.Vertex.Name, u.VertexInstance.Replica)
reader = redisisb.NewBufferRead(ctx, redisClient, fromBufferName, fromGroup, consumer)
case dfv1.ISBSvcTypeJetStream:
- streamName := fmt.Sprintf("%s-%s", u.Vertex.Spec.PipelineName, fromBufferName)
+ streamName := fmt.Sprintf("%s-%s", u.VertexInstance.Vertex.Spec.PipelineName, fromBufferName)
+ readOptions := []jetstreamisb.ReadOption{
+ jetstreamisb.WithUsingAckInfoAsRate(true),
+ }
+ if x := u.VertexInstance.Vertex.Spec.Scale.LookbackSeconds; x != nil {
+ readOptions = append(readOptions, jetstreamisb.WithAckRateLookbackSeconds(int64(*x)))
+ }
jetStreamClient := clients.NewInClusterJetStreamClient()
- reader, err = jetstreamisb.NewJetStreamBufferReader(ctx, jetStreamClient, fromBufferName, streamName, streamName)
+ reader, err = jetstreamisb.NewJetStreamBufferReader(ctx, jetStreamClient, fromBufferName, streamName, streamName, readOptions...)
if err != nil {
return err
}
@@ -69,7 +73,18 @@ func (u *SinkProcessor) Start(ctx context.Context) error {
}
}()
- if shutdown, err := metrics.StartMetricsServer(ctx); err != nil {
+ metricsOpts := []metrics.Option{}
+ if x, ok := reader.(isb.LagReader); ok {
+ metricsOpts = append(metricsOpts, metrics.WithLagReader(x))
+ if s := u.VertexInstance.Vertex.Spec.Scale.LookbackSeconds; s != nil {
+ metricsOpts = append(metricsOpts, metrics.WithPendingLookbackSeconds(int64(*s)))
+ }
+ }
+ if x, ok := reader.(isb.Ratable); ok {
+ metricsOpts = append(metricsOpts, metrics.WithRater(x))
+ }
+ ms := metrics.NewMetricsServer(u.VertexInstance.Vertex, metricsOpts...)
+ if shutdown, err := ms.Start(ctx); err != nil {
return fmt.Errorf("failed to start metrics server, error: %w", err)
} else {
defer func() { _ = shutdown(context.Background()) }()
@@ -85,14 +100,14 @@ func (u *SinkProcessor) Start(ctx context.Context) error {
// getSinker takes in the logger from the parent context
func (u *SinkProcessor) getSinker(reader isb.BufferReader, logger *zap.SugaredLogger) (Sinker, error) {
- sink := u.Vertex.Spec.Sink
+ sink := u.VertexInstance.Vertex.Spec.Sink
// TODO: add watermark
if x := sink.Log; x != nil {
- return logsink.NewToLog(u.Vertex, reader, logsink.WithLogger(logger))
+ return logsink.NewToLog(u.VertexInstance.Vertex, reader, logsink.WithLogger(logger))
} else if x := sink.Kafka; x != nil {
- return kafkasink.NewToKafka(u.Vertex, reader, kafkasink.WithLogger(logger))
+ return kafkasink.NewToKafka(u.VertexInstance.Vertex, reader, kafkasink.WithLogger(logger))
} else if x := sink.UDSink; x != nil {
- return udsink.NewUserDefinedSink(u.Vertex, reader, udsink.WithLogger(logger))
+ return udsink.NewUserDefinedSink(u.VertexInstance.Vertex, reader, udsink.WithLogger(logger))
}
return nil, fmt.Errorf("invalid sink spec")
}
diff --git a/pkg/sources/generator/tickgen.go b/pkg/sources/generator/tickgen.go
index a5e05b847..9ef0b7f3b 100644
--- a/pkg/sources/generator/tickgen.go
+++ b/pkg/sources/generator/tickgen.go
@@ -15,7 +15,6 @@ import (
"github.com/numaproj/numaflow/pkg/isb"
"github.com/numaproj/numaflow/pkg/isb/forward"
"github.com/numaproj/numaflow/pkg/shared/logging"
- "github.com/numaproj/numaflow/pkg/sources/types"
"github.com/numaproj/numaflow/pkg/udf/applier"
"github.com/numaproj/numaflow/pkg/watermark/processor"
"github.com/numaproj/numaflow/pkg/watermark/progress"
@@ -115,13 +114,13 @@ func WithReadTimeOut(timeout time.Duration) Option {
// msgSize - size of each generated message
// timeunit - unit of time per tick. could be any golang time.Duration.
// writers - destinations to write to
-func NewMemGen(metadata *types.SourceMetadata, rpu int, msgSize int32, timeunit time.Duration, writers []isb.BufferWriter, opts ...Option) (*memgen, error) {
+func NewMemGen(vertexInstance *dfv1.VertexInstance, rpu int, msgSize int32, timeunit time.Duration, writers []isb.BufferWriter, opts ...Option) (*memgen, error) {
gensrc := &memgen{
rpu: rpu,
msgSize: msgSize,
timeunit: timeunit,
- name: metadata.Vertex.Spec.Name,
- pipelineName: metadata.Vertex.Spec.PipelineName,
+ name: vertexInstance.Vertex.Spec.Name,
+ pipelineName: vertexInstance.Vertex.Spec.PipelineName,
genfn: recordGenerator,
progressor: &watermark{
sourcePublish: nil,
@@ -152,7 +151,7 @@ func NewMemGen(metadata *types.SourceMetadata, rpu int, msgSize int32, timeunit
}
forwardOpts := []forward.Option{forward.WithLogger(gensrc.logger)}
- if x := metadata.Vertex.Spec.Limits; x != nil {
+ if x := vertexInstance.Vertex.Spec.Limits; x != nil {
if x.ReadBatchSize != nil {
forwardOpts = append(forwardOpts, forward.WithReadBatchSize(int64(*x.ReadBatchSize)))
}
@@ -162,7 +161,7 @@ func NewMemGen(metadata *types.SourceMetadata, rpu int, msgSize int32, timeunit
var err error
// TODO: pass it as option
if val, ok := os.LookupEnv(dfv1.EnvWatermarkOn); ok && val == "true" {
- err = gensrc.buildWMProgressor(metadata)
+ err = gensrc.buildWMProgressor(vertexInstance)
if err != nil {
return nil, err
}
@@ -170,7 +169,7 @@ func NewMemGen(metadata *types.SourceMetadata, rpu int, msgSize int32, timeunit
}
// we pass in the context to forwarder as well so that it can shut down when we cancel the context
- forwarder, err := forward.NewInterStepDataForward(metadata.Vertex, gensrc, destinations, forward.All, applier.Terminal, wmProgressor, forwardOpts...)
+ forwarder, err := forward.NewInterStepDataForward(vertexInstance.Vertex, gensrc, destinations, forward.All, applier.Terminal, wmProgressor, forwardOpts...)
if err != nil {
return nil, err
}
@@ -252,10 +251,6 @@ func (mg *memgen) Start() <-chan struct{} {
return mg.forwarder.Start()
}
-func (mg *memgen) Pending(_ context.Context) (int64, error) {
- return isb.PendingNotAvailable, nil
-}
-
// generator fires once per time unit and generates records and writes them to the channel
func (mg *memgen) generator(ctx context.Context, rate int, timeunit time.Duration) {
go func() {
diff --git a/pkg/sources/generator/tickgen_test.go b/pkg/sources/generator/tickgen_test.go
index 908dd84be..9d89a292e 100644
--- a/pkg/sources/generator/tickgen_test.go
+++ b/pkg/sources/generator/tickgen_test.go
@@ -6,7 +6,6 @@ import (
"time"
dfv1 "github.com/numaproj/numaflow/pkg/apis/numaflow/v1alpha1"
- "github.com/numaproj/numaflow/pkg/sources/types"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/numaproj/numaflow/pkg/isb"
@@ -20,7 +19,7 @@ func TestRead(t *testing.T) {
vertex := &dfv1.Vertex{ObjectMeta: v1.ObjectMeta{
Name: "memgen",
}}
- m := &types.SourceMetadata{
+ m := &dfv1.VertexInstance{
Vertex: vertex,
Hostname: "TestRead",
Replica: 0,
@@ -48,7 +47,7 @@ func TestStop(t *testing.T) {
vertex := &dfv1.Vertex{ObjectMeta: v1.ObjectMeta{
Name: "memgen",
}}
- m := &types.SourceMetadata{
+ m := &dfv1.VertexInstance{
Vertex: vertex,
Hostname: "TestRead",
Replica: 0,
diff --git a/pkg/sources/generator/watermark.go b/pkg/sources/generator/watermark.go
index 1c2c12272..79194d1c1 100644
--- a/pkg/sources/generator/watermark.go
+++ b/pkg/sources/generator/watermark.go
@@ -3,8 +3,8 @@ package generator
import (
"fmt"
+ dfv1 "github.com/numaproj/numaflow/pkg/apis/numaflow/v1alpha1"
"github.com/numaproj/numaflow/pkg/isb"
- "github.com/numaproj/numaflow/pkg/sources/types"
"github.com/numaproj/numaflow/pkg/watermark/processor"
"github.com/numaproj/numaflow/pkg/watermark/progress"
"github.com/numaproj/numaflow/pkg/watermark/publish"
@@ -12,7 +12,7 @@ import (
// buildWMProgressor builds the watermark progressor. It will create a sourcePublisher so it can publish the watermark
// it reads from the source. The sourcePublisher is passed in as the input for generic progressor.
-func (mg *memgen) buildWMProgressor(metadata *types.SourceMetadata) error {
+func (mg *memgen) buildWMProgressor(vertexInstance *dfv1.VertexInstance) error {
ctx := mg.lifecycleCtx
js, err := progress.GetJetStreamConnection(mg.lifecycleCtx)
@@ -21,30 +21,30 @@ func (mg *memgen) buildWMProgressor(metadata *types.SourceMetadata) error {
}
// publish source watermark and this is very much dependent on the source
- sourcePublishKeySpace := fmt.Sprintf("source-%s", progress.GetPublishKeySpace(metadata.Vertex))
+ sourcePublishKeySpace := fmt.Sprintf("source-%s", progress.GetPublishKeySpace(vertexInstance.Vertex))
// TODO: remove this once bucket creation has been moved to controller
err = progress.CreateProcessorBucketIfMissing(fmt.Sprintf("%s_PROCESSORS", sourcePublishKeySpace), js)
if err != nil {
return err
}
- publishEntity := processor.NewProcessorEntity(fmt.Sprintf("source-%s-%d", metadata.Vertex.Name, metadata.Replica), sourcePublishKeySpace, processor.WithSeparateOTBuckets(false))
+ publishEntity := processor.NewProcessorEntity(fmt.Sprintf("source-%s-%d", vertexInstance.Vertex.Name, vertexInstance.Replica), sourcePublishKeySpace, processor.WithSeparateOTBuckets(false))
// for tickgen you need the default heartbeat system because there are no concept of source partitions etc
heartbeatBucket, err := progress.GetHeartbeatBucket(js, sourcePublishKeySpace)
if err != nil {
return err
}
// use this while reading the data from the source.
- mg.progressor.sourcePublish = publish.NewPublish(mg.lifecycleCtx, publishEntity, progress.GetPublishKeySpace(metadata.Vertex), js, heartbeatBucket)
+ mg.progressor.sourcePublish = publish.NewPublish(mg.lifecycleCtx, publishEntity, progress.GetPublishKeySpace(vertexInstance.Vertex), js, heartbeatBucket)
// fall back on the generic progressor and use the source publisher as the input to the generic progressor.
// use the source Publisher as the source
// TODO: remove this once bucket creation has been moved to controller
- err = progress.CreateProcessorBucketIfMissing(fmt.Sprintf("%s_PROCESSORS", progress.GetPublishKeySpace(metadata.Vertex)), js)
+ err = progress.CreateProcessorBucketIfMissing(fmt.Sprintf("%s_PROCESSORS", progress.GetPublishKeySpace(vertexInstance.Vertex)), js)
if err != nil {
return err
}
- var wmProgressor = progress.NewGenericProgress(ctx, fmt.Sprintf("%s-%d", metadata.Vertex.Name, metadata.Replica), sourcePublishKeySpace, progress.GetPublishKeySpace(metadata.Vertex), js)
+ var wmProgressor = progress.NewGenericProgress(ctx, fmt.Sprintf("%s-%d", vertexInstance.Vertex.Name, vertexInstance.Replica), sourcePublishKeySpace, progress.GetPublishKeySpace(vertexInstance.Vertex), js)
mg.progressor.wmProgressor = wmProgressor
mg.logger.Info("Initialized watermark progressor")
diff --git a/pkg/sources/generator/watermark_test.go b/pkg/sources/generator/watermark_test.go
index 4ab819d71..dd3a5c626 100644
--- a/pkg/sources/generator/watermark_test.go
+++ b/pkg/sources/generator/watermark_test.go
@@ -9,7 +9,6 @@ import (
dfv1 "github.com/numaproj/numaflow/pkg/apis/numaflow/v1alpha1"
"github.com/numaproj/numaflow/pkg/isb"
"github.com/numaproj/numaflow/pkg/isb/simplebuffer"
- "github.com/numaproj/numaflow/pkg/sources/types"
"github.com/stretchr/testify/assert"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -27,7 +26,7 @@ func TestWatermark(t *testing.T) {
vertex := &dfv1.Vertex{ObjectMeta: v1.ObjectMeta{
Name: "memgen",
}}
- m := &types.SourceMetadata{
+ m := &dfv1.VertexInstance{
Vertex: vertex,
Hostname: "TestRead",
Replica: 0,
diff --git a/pkg/sources/http/http.go b/pkg/sources/http/http.go
index 59639f12a..e279aeadd 100644
--- a/pkg/sources/http/http.go
+++ b/pkg/sources/http/http.go
@@ -174,10 +174,6 @@ func (h *httpSource) GetName() string {
return h.name
}
-func (h *httpSource) Pending(_ context.Context) (int64, error) {
- return isb.PendingNotAvailable, nil
-}
-
func (h *httpSource) Read(ctx context.Context, count int64) ([]*isb.ReadMessage, error) {
msgs := []*isb.ReadMessage{}
timeout := time.After(h.readTimeout)
diff --git a/pkg/sources/source.go b/pkg/sources/source.go
index 3676e8965..dd207e6f4 100644
--- a/pkg/sources/source.go
+++ b/pkg/sources/source.go
@@ -5,7 +5,6 @@ import (
"fmt"
"sync"
- "github.com/numaproj/numaflow/pkg/sources/types"
"go.uber.org/zap"
dfv1 "github.com/numaproj/numaflow/pkg/apis/numaflow/v1alpha1"
@@ -21,10 +20,8 @@ import (
)
type SourceProcessor struct {
- ISBSvcType dfv1.ISBSvcType
- Vertex *dfv1.Vertex
- Hostname string
- Replica int
+ ISBSvcType dfv1.ISBSvcType
+ VertexInstance *dfv1.VertexInstance
}
func (u *SourceProcessor) Start(ctx context.Context) error {
@@ -34,7 +31,7 @@ func (u *SourceProcessor) Start(ctx context.Context) error {
var writers []isb.BufferWriter
switch u.ISBSvcType {
case dfv1.ISBSvcTypeRedis:
- for _, e := range u.Vertex.Spec.ToEdges {
+ for _, e := range u.VertexInstance.Vertex.Spec.ToEdges {
writeOpts := []redisisb.Option{}
if x := e.Limits; x != nil && x.BufferMaxLength != nil {
writeOpts = append(writeOpts, redisisb.WithMaxLength(int64(*x.BufferMaxLength)))
@@ -42,23 +39,28 @@ func (u *SourceProcessor) Start(ctx context.Context) error {
if x := e.Limits; x != nil && x.BufferUsageLimit != nil {
writeOpts = append(writeOpts, redisisb.WithBufferUsageLimit(float64(*x.BufferUsageLimit)/100))
}
- buffer := dfv1.GenerateEdgeBufferName(u.Vertex.Namespace, u.Vertex.Spec.PipelineName, e.From, e.To)
+ buffer := dfv1.GenerateEdgeBufferName(u.VertexInstance.Vertex.Namespace, u.VertexInstance.Vertex.Spec.PipelineName, e.From, e.To)
group := buffer + "-group"
redisClient := clients.NewInClusterRedisClient()
writer := redisisb.NewBufferWrite(ctx, redisClient, buffer, group, writeOpts...)
writers = append(writers, writer)
}
case dfv1.ISBSvcTypeJetStream:
- for _, e := range u.Vertex.Spec.ToEdges {
- writeOpts := []jetstreamisb.WriteOption{}
+ for _, e := range u.VertexInstance.Vertex.Spec.ToEdges {
+ writeOpts := []jetstreamisb.WriteOption{
+ jetstreamisb.WithUsingWriteInfoAsRate(true),
+ }
+ if x := u.VertexInstance.Vertex.Spec.Scale.LookbackSeconds; x != nil {
+ writeOpts = append(writeOpts, jetstreamisb.WithWriteRateLookbackSeconds(int64(*x)))
+ }
if x := e.Limits; x != nil && x.BufferMaxLength != nil {
writeOpts = append(writeOpts, jetstreamisb.WithMaxLength(int64(*x.BufferMaxLength)))
}
if x := e.Limits; x != nil && x.BufferUsageLimit != nil {
writeOpts = append(writeOpts, jetstreamisb.WithBufferUsageLimit(float64(*x.BufferUsageLimit)/100))
}
- buffer := dfv1.GenerateEdgeBufferName(u.Vertex.Namespace, u.Vertex.Spec.PipelineName, e.From, e.To)
- streamName := fmt.Sprintf("%s-%s", u.Vertex.Spec.PipelineName, buffer)
+ buffer := dfv1.GenerateEdgeBufferName(u.VertexInstance.Vertex.Namespace, u.VertexInstance.Vertex.Spec.PipelineName, e.From, e.To)
+ streamName := fmt.Sprintf("%s-%s", u.VertexInstance.Vertex.Spec.PipelineName, buffer)
jetStreamClient := clients.NewInClusterJetStreamClient()
writer, err := jetstreamisb.NewJetStreamBufferWriter(ctx, jetStreamClient, buffer, streamName, streamName, writeOpts...)
if err != nil {
@@ -67,14 +69,14 @@ func (u *SourceProcessor) Start(ctx context.Context) error {
writers = append(writers, writer)
}
default:
- return fmt.Errorf("unrecognized isbs type %q", u.ISBSvcType)
+ return fmt.Errorf("unrecognized isb svc type %q", u.ISBSvcType)
}
sourcer, err := u.getSourcer(writers, log)
if err != nil {
return fmt.Errorf("failed to find a sourcer, error: %w", err)
}
- log.Infow("Start processing source messages", zap.String("isbs", string(u.ISBSvcType)), zap.Any("to", u.Vertex.GetToBuffers()))
+ log.Infow("Start processing source messages", zap.String("isbs", string(u.ISBSvcType)), zap.Any("to", u.VertexInstance.Vertex.GetToBuffers()))
stopped := sourcer.Start()
wg := &sync.WaitGroup{}
wg.Add(1)
@@ -87,7 +89,18 @@ func (u *SourceProcessor) Start(ctx context.Context) error {
}
}()
- if shutdown, err := metrics.StartMetricsServer(ctx); err != nil {
+ metricsOpts := []metrics.Option{}
+ if x, ok := sourcer.(isb.LagReader); ok {
+ metricsOpts = append(metricsOpts, metrics.WithLagReader(x))
+ if s := u.VertexInstance.Vertex.Spec.Scale.LookbackSeconds; s != nil {
+ metricsOpts = append(metricsOpts, metrics.WithPendingLookbackSeconds(int64(*s)))
+ }
+ }
+ if x, ok := writers[0].(isb.Ratable); ok { // Only need to use the rate of one of the writer
+ metricsOpts = append(metricsOpts, metrics.WithRater(x))
+ }
+ ms := metrics.NewMetricsServer(u.VertexInstance.Vertex, metricsOpts...)
+ if shutdown, err := ms.Start(ctx); err != nil {
return fmt.Errorf("failed to start metrics server, error: %w", err)
} else {
defer func() { _ = shutdown(context.Background()) }()
@@ -103,18 +116,13 @@ func (u *SourceProcessor) Start(ctx context.Context) error {
// getSourcer is used to send the sourcer information
func (u *SourceProcessor) getSourcer(writers []isb.BufferWriter, logger *zap.SugaredLogger) (Sourcer, error) {
- src := u.Vertex.Spec.Source
- m := &types.SourceMetadata{
- Vertex: u.Vertex,
- Hostname: u.Hostname,
- Replica: u.Replica,
- }
+ src := u.VertexInstance.Vertex.Spec.Source
if x := src.Generator; x != nil {
- return generator.NewMemGen(m, int(*x.RPU), *x.MsgSize, x.Duration.Duration, writers, generator.WithLogger(logger))
+ return generator.NewMemGen(u.VertexInstance, int(*x.RPU), *x.MsgSize, x.Duration.Duration, writers, generator.WithLogger(logger))
} else if x := src.Kafka; x != nil {
- return kafka.NewKafkaSource(u.Vertex, writers, kafka.WithGroupName(x.ConsumerGroupName), kafka.WithLogger(logger))
+ return kafka.NewKafkaSource(u.VertexInstance.Vertex, writers, kafka.WithGroupName(x.ConsumerGroupName), kafka.WithLogger(logger))
} else if x := src.HTTP; x != nil {
- return http.New(u.Vertex, writers, http.WithLogger(logger))
+ return http.New(u.VertexInstance.Vertex, writers, http.WithLogger(logger))
}
return nil, fmt.Errorf("invalid source spec")
}
diff --git a/pkg/sources/types/metadata.go b/pkg/sources/types/metadata.go
deleted file mode 100644
index 26322cf0b..000000000
--- a/pkg/sources/types/metadata.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package types
-
-import dfv1 "github.com/numaproj/numaflow/pkg/apis/numaflow/v1alpha1"
-
-type SourceMetadata struct {
- Vertex *dfv1.Vertex
- Hostname string
- Replica int
-}
diff --git a/pkg/udf/udf.go b/pkg/udf/udf.go
index d50922089..a250648fe 100644
--- a/pkg/udf/udf.go
+++ b/pkg/udf/udf.go
@@ -23,10 +23,8 @@ import (
)
type UDFProcessor struct {
- ISBSvcType dfv1.ISBSvcType
- Vertex *dfv1.Vertex
- Hostname string
- Replica int
+ ISBSvcType dfv1.ISBSvcType
+ VertexInstance *dfv1.VertexInstance
}
func (u *UDFProcessor) Start(ctx context.Context) error {
@@ -35,16 +33,16 @@ func (u *UDFProcessor) Start(ctx context.Context) error {
defer cancel()
var reader isb.BufferReader
var err error
- fromBufferName := u.Vertex.GetFromBuffers()[0].Name
- toBuffers := u.Vertex.GetToBuffers()
+ fromBufferName := u.VertexInstance.Vertex.GetFromBuffers()[0].Name
+ toBuffers := u.VertexInstance.Vertex.GetToBuffers()
writers := make(map[string]isb.BufferWriter)
switch u.ISBSvcType {
case dfv1.ISBSvcTypeRedis:
redisClient := clients.NewInClusterRedisClient()
fromGroup := fromBufferName + "-group"
- consumer := fmt.Sprintf("%s-%v", u.Vertex.Name, u.Replica)
+ consumer := fmt.Sprintf("%s-%v", u.VertexInstance.Vertex.Name, u.VertexInstance.Replica)
reader = redisisb.NewBufferRead(ctx, redisClient, fromBufferName, fromGroup, consumer)
- for _, e := range u.Vertex.Spec.ToEdges {
+ for _, e := range u.VertexInstance.Vertex.Spec.ToEdges {
writeOpts := []redisisb.Option{}
if x := e.Limits; x != nil && x.BufferMaxLength != nil {
writeOpts = append(writeOpts, redisisb.WithMaxLength(int64(*x.BufferMaxLength)))
@@ -52,17 +50,23 @@ func (u *UDFProcessor) Start(ctx context.Context) error {
if x := e.Limits; x != nil && x.BufferUsageLimit != nil {
writeOpts = append(writeOpts, redisisb.WithBufferUsageLimit(float64(*x.BufferUsageLimit)/100))
}
- buffer := dfv1.GenerateEdgeBufferName(u.Vertex.Namespace, u.Vertex.Spec.PipelineName, e.From, e.To)
+ buffer := dfv1.GenerateEdgeBufferName(u.VertexInstance.Vertex.Namespace, u.VertexInstance.Vertex.Spec.PipelineName, e.From, e.To)
writer := redisisb.NewBufferWrite(ctx, redisClient, buffer, buffer+"-group", writeOpts...)
writers[buffer] = writer
}
case dfv1.ISBSvcTypeJetStream:
- fromStreamName := fmt.Sprintf("%s-%s", u.Vertex.Spec.PipelineName, fromBufferName)
- reader, err = jetstreamisb.NewJetStreamBufferReader(ctx, clients.NewInClusterJetStreamClient(), fromBufferName, fromStreamName, fromStreamName)
+ fromStreamName := fmt.Sprintf("%s-%s", u.VertexInstance.Vertex.Spec.PipelineName, fromBufferName)
+ readOptions := []jetstreamisb.ReadOption{
+ jetstreamisb.WithUsingAckInfoAsRate(true),
+ }
+ if x := u.VertexInstance.Vertex.Spec.Scale.LookbackSeconds; x != nil {
+ readOptions = append(readOptions, jetstreamisb.WithAckRateLookbackSeconds(int64(*x)))
+ }
+ reader, err = jetstreamisb.NewJetStreamBufferReader(ctx, clients.NewInClusterJetStreamClient(), fromBufferName, fromStreamName, fromStreamName, readOptions...)
if err != nil {
return err
}
- for _, e := range u.Vertex.Spec.ToEdges {
+ for _, e := range u.VertexInstance.Vertex.Spec.ToEdges {
writeOpts := []jetstreamisb.WriteOption{}
if x := e.Limits; x != nil && x.BufferMaxLength != nil {
writeOpts = append(writeOpts, jetstreamisb.WithMaxLength(int64(*x.BufferMaxLength)))
@@ -70,8 +74,8 @@ func (u *UDFProcessor) Start(ctx context.Context) error {
if x := e.Limits; x != nil && x.BufferUsageLimit != nil {
writeOpts = append(writeOpts, jetstreamisb.WithBufferUsageLimit(float64(*x.BufferUsageLimit)/100))
}
- buffer := dfv1.GenerateEdgeBufferName(u.Vertex.Namespace, u.Vertex.Spec.PipelineName, e.From, e.To)
- streamName := fmt.Sprintf("%s-%s", u.Vertex.Spec.PipelineName, buffer)
+ buffer := dfv1.GenerateEdgeBufferName(u.VertexInstance.Vertex.Namespace, u.VertexInstance.Vertex.Spec.PipelineName, e.From, e.To)
+ streamName := fmt.Sprintf("%s-%s", u.VertexInstance.Vertex.Spec.PipelineName, buffer)
writer, err := jetstreamisb.NewJetStreamBufferWriter(ctx, clients.NewInClusterJetStreamClient(), buffer, streamName, streamName, writeOpts...)
if err != nil {
return err
@@ -89,11 +93,11 @@ func (u *UDFProcessor) Start(ctx context.Context) error {
result = append(result, _key)
return result, nil
}
- for _, to := range u.Vertex.Spec.ToEdges {
+ for _, to := range u.VertexInstance.Vertex.Spec.ToEdges {
// If returned key is not "ALL" or "DROP", and there's no conditions defined in the edge,
// treat it as "ALL"?
if to.Conditions == nil || len(to.Conditions.KeyIn) == 0 || sharedutil.StringSliceContains(to.Conditions.KeyIn, _key) {
- result = append(result, dfv1.GenerateEdgeBufferName(u.Vertex.Namespace, u.Vertex.Spec.PipelineName, to.From, to.To))
+ result = append(result, dfv1.GenerateEdgeBufferName(u.VertexInstance.Vertex.Namespace, u.VertexInstance.Vertex.Spec.PipelineName, to.From, to.To))
}
}
return result, nil
@@ -106,7 +110,7 @@ func (u *UDFProcessor) Start(ctx context.Context) error {
}
log.Infow("Start processing udf messages", zap.String("isbs", string(u.ISBSvcType)), zap.String("from", fromBufferName), zap.Any("to", toBuffers))
opts := []forward.Option{forward.WithLogger(log)}
- if x := u.Vertex.Spec.Limits; x != nil {
+ if x := u.VertexInstance.Vertex.Spec.Limits; x != nil {
if x.ReadBatchSize != nil {
opts = append(opts, forward.WithReadBatchSize(int64(*x.ReadBatchSize)))
}
@@ -122,14 +126,14 @@ func (u *UDFProcessor) Start(ctx context.Context) error {
return err
}
// TODO: remove this once bucket creation has been moved to controller
- err = progress.CreateProcessorBucketIfMissing(fmt.Sprintf("%s_PROCESSORS", progress.GetPublishKeySpace(u.Vertex)), js)
+ err = progress.CreateProcessorBucketIfMissing(fmt.Sprintf("%s_PROCESSORS", progress.GetPublishKeySpace(u.VertexInstance.Vertex)), js)
if err != nil {
return err
}
- wmProgressor = progress.NewGenericProgress(ctx, fmt.Sprintf("%s-%d", u.Vertex.Name, u.Replica), progress.GetFetchKeyspace(u.Vertex), progress.GetPublishKeySpace(u.Vertex), js)
+ wmProgressor = progress.NewGenericProgress(ctx, fmt.Sprintf("%s-%d", u.VertexInstance.Vertex.Name, u.VertexInstance.Replica), progress.GetFetchKeyspace(u.VertexInstance.Vertex), progress.GetPublishKeySpace(u.VertexInstance.Vertex), js)
}
- forwarder, err := forward.NewInterStepDataForward(u.Vertex, reader, writers, conditionalForwarder, udfHandler, wmProgressor, opts...)
+ forwarder, err := forward.NewInterStepDataForward(u.VertexInstance.Vertex, reader, writers, conditionalForwarder, udfHandler, wmProgressor, opts...)
if err != nil {
return err
}
@@ -146,7 +150,18 @@ func (u *UDFProcessor) Start(ctx context.Context) error {
}
}()
- if shutdown, err := metrics.StartMetricsServer(ctx); err != nil {
+ metricsOpts := []metrics.Option{}
+ if x, ok := reader.(isb.LagReader); ok {
+ metricsOpts = append(metricsOpts, metrics.WithLagReader(x))
+ if s := u.VertexInstance.Vertex.Spec.Scale.LookbackSeconds; s != nil {
+ metricsOpts = append(metricsOpts, metrics.WithPendingLookbackSeconds(int64(*s)))
+ }
+ }
+ if x, ok := reader.(isb.Ratable); ok {
+ metricsOpts = append(metricsOpts, metrics.WithRater(x))
+ }
+ ms := metrics.NewMetricsServer(u.VertexInstance.Vertex, metricsOpts...)
+ if shutdown, err := ms.Start(ctx); err != nil {
return fmt.Errorf("failed to start metrics server, error: %w", err)
} else {
defer func() { _ = shutdown(context.Background()) }()
diff --git a/test/fixtures/expect.go b/test/fixtures/expect.go
index 6e36647ac..113a97ec5 100644
--- a/test/fixtures/expect.go
+++ b/test/fixtures/expect.go
@@ -68,7 +68,7 @@ func (t *Expect) VertexPodsRunning() *Expect {
// check pods running
timeout := 2 * time.Minute
for _, v := range t.pipeline.Spec.Vertices {
- if err := WaitForVertexPodRunning(t.kubeClient, Namespace, t.pipeline.Name, v.Name, timeout); err != nil {
+ if err := WaitForVertexPodRunning(t.kubeClient, t.vertexClient, Namespace, t.pipeline.Name, v.Name, timeout); err != nil {
t.t.Fatalf("expected vertex %q pod running: %v", v.Name, err)
}
}
diff --git a/test/fixtures/util.go b/test/fixtures/util.go
index c50abac1f..820ea881d 100644
--- a/test/fixtures/util.go
+++ b/test/fixtures/util.go
@@ -200,7 +200,7 @@ func WaitForPipelineRunning(ctx context.Context, pipelineClient flowpkg.Pipeline
}
}
-func WaitForVertexPodRunning(kubeClient kubernetes.Interface, namespace, pipelineName, vertexName string, timeout time.Duration) error {
+func WaitForVertexPodRunning(kubeClient kubernetes.Interface, vertexClient flowpkg.VertexInterface, namespace, pipelineName, vertexName string, timeout time.Duration) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
labelSelector := fmt.Sprintf("%s=%s,%s=%s", dfv1.KeyPipelineName, pipelineName, dfv1.KeyVertexName, vertexName)
@@ -210,11 +210,16 @@ func WaitForVertexPodRunning(kubeClient kubernetes.Interface, namespace, pipelin
return fmt.Errorf("timeout after %v waiting for vertex pod running", timeout)
default:
}
+ vertexList, err := vertexClient.List(ctx, metav1.ListOptions{LabelSelector: labelSelector})
+ if err != nil {
+ return fmt.Errorf("error getting vertex list: %w", err)
+ }
+ ok := len(vertexList.Items) == 1
podList, err := kubeClient.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{LabelSelector: labelSelector, FieldSelector: "status.phase=Running"})
if err != nil {
return fmt.Errorf("error getting vertex pod name: %w", err)
}
- ok := len(podList.Items) > 0
+ ok = ok && len(podList.Items) > 0 && len(podList.Items) == int(*vertexList.Items[0].Spec.Replicas) // pod number should equal to desired replicas
for _, p := range podList.Items {
ok = ok && p.Status.Phase == corev1.PodRunning
}