lib/db: Keep folder meta data persistently in db (fixes #4400)

This keeps the data we need about sequence numbers and object counts
persistently in the database. The sizeTracker is expanded into a
metadataTracker than handled multiple folders, and the Counts struct is
made protobuf serializable. It gains a Sequence field to assist in
tracking that as well, and a collection of Counts become a CountsSet
(for serialization purposes).

The initial database scan is also a consistency check of the global
entries. This shouldn't strictly be necessary. Nonetheless I added a
created timestamp to the metadata and set a variable to compare against
that. When the time since the metadata creation is old enough, we drop
the metadata and rebuild from scratch like we used to, while also
consistency checking.

A new environment variable STCHECKDBEVERY can override this interval,
and for example be set to zero to force the check immediately.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4547
LGTM: imsodin
This commit is contained in:
Jakob Borg
2017-12-14 09:51:17 +00:00
committed by Audrius Butkevicius
parent 8c91ced784
commit d1d967f0cf
14 changed files with 908 additions and 265 deletions

View File

@@ -11,6 +11,8 @@
FileVersion
VersionList
FileInfoTruncated
Counts
CountsSet
*/
package db
@@ -75,10 +77,39 @@ func (m *FileInfoTruncated) Reset() { *m = FileInfoTruncated{
func (*FileInfoTruncated) ProtoMessage() {}
func (*FileInfoTruncated) Descriptor() ([]byte, []int) { return fileDescriptorStructs, []int{2} }
// For each folder and device we keep one of these to track the current
// counts and sequence. We also keep one for the global state of the folder.
type Counts struct {
Files int32 `protobuf:"varint,1,opt,name=files,proto3" json:"files,omitempty"`
Directories int32 `protobuf:"varint,2,opt,name=directories,proto3" json:"directories,omitempty"`
Symlinks int32 `protobuf:"varint,3,opt,name=symlinks,proto3" json:"symlinks,omitempty"`
Deleted int32 `protobuf:"varint,4,opt,name=deleted,proto3" json:"deleted,omitempty"`
Bytes int64 `protobuf:"varint,5,opt,name=bytes,proto3" json:"bytes,omitempty"`
Sequence int64 `protobuf:"varint,6,opt,name=sequence,proto3" json:"sequence,omitempty"`
DeviceID []byte `protobuf:"bytes,17,opt,name=deviceID,proto3" json:"deviceID,omitempty"`
}
func (m *Counts) Reset() { *m = Counts{} }
func (m *Counts) String() string { return proto.CompactTextString(m) }
func (*Counts) ProtoMessage() {}
func (*Counts) Descriptor() ([]byte, []int) { return fileDescriptorStructs, []int{3} }
type CountsSet struct {
Counts []Counts `protobuf:"bytes,1,rep,name=counts" json:"counts"`
Created int64 `protobuf:"varint,2,opt,name=created,proto3" json:"created,omitempty"`
}
func (m *CountsSet) Reset() { *m = CountsSet{} }
func (m *CountsSet) String() string { return proto.CompactTextString(m) }
func (*CountsSet) ProtoMessage() {}
func (*CountsSet) Descriptor() ([]byte, []int) { return fileDescriptorStructs, []int{4} }
func init() {
proto.RegisterType((*FileVersion)(nil), "db.FileVersion")
proto.RegisterType((*VersionList)(nil), "db.VersionList")
proto.RegisterType((*FileInfoTruncated)(nil), "db.FileInfoTruncated")
proto.RegisterType((*Counts)(nil), "db.Counts")
proto.RegisterType((*CountsSet)(nil), "db.CountsSet")
}
func (m *FileVersion) Marshal() (dAtA []byte, err error) {
size := m.ProtoSize()
@@ -257,6 +288,97 @@ func (m *FileInfoTruncated) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *Counts) Marshal() (dAtA []byte, err error) {
size := m.ProtoSize()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Counts) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Files != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintStructs(dAtA, i, uint64(m.Files))
}
if m.Directories != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintStructs(dAtA, i, uint64(m.Directories))
}
if m.Symlinks != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintStructs(dAtA, i, uint64(m.Symlinks))
}
if m.Deleted != 0 {
dAtA[i] = 0x20
i++
i = encodeVarintStructs(dAtA, i, uint64(m.Deleted))
}
if m.Bytes != 0 {
dAtA[i] = 0x28
i++
i = encodeVarintStructs(dAtA, i, uint64(m.Bytes))
}
if m.Sequence != 0 {
dAtA[i] = 0x30
i++
i = encodeVarintStructs(dAtA, i, uint64(m.Sequence))
}
if len(m.DeviceID) > 0 {
dAtA[i] = 0x8a
i++
dAtA[i] = 0x1
i++
i = encodeVarintStructs(dAtA, i, uint64(len(m.DeviceID)))
i += copy(dAtA[i:], m.DeviceID)
}
return i, nil
}
func (m *CountsSet) Marshal() (dAtA []byte, err error) {
size := m.ProtoSize()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *CountsSet) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Counts) > 0 {
for _, msg := range m.Counts {
dAtA[i] = 0xa
i++
i = encodeVarintStructs(dAtA, i, uint64(msg.ProtoSize()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
if m.Created != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintStructs(dAtA, i, uint64(m.Created))
}
return i, nil
}
func encodeFixed64Structs(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
@@ -357,6 +479,49 @@ func (m *FileInfoTruncated) ProtoSize() (n int) {
return n
}
func (m *Counts) ProtoSize() (n int) {
var l int
_ = l
if m.Files != 0 {
n += 1 + sovStructs(uint64(m.Files))
}
if m.Directories != 0 {
n += 1 + sovStructs(uint64(m.Directories))
}
if m.Symlinks != 0 {
n += 1 + sovStructs(uint64(m.Symlinks))
}
if m.Deleted != 0 {
n += 1 + sovStructs(uint64(m.Deleted))
}
if m.Bytes != 0 {
n += 1 + sovStructs(uint64(m.Bytes))
}
if m.Sequence != 0 {
n += 1 + sovStructs(uint64(m.Sequence))
}
l = len(m.DeviceID)
if l > 0 {
n += 2 + l + sovStructs(uint64(l))
}
return n
}
func (m *CountsSet) ProtoSize() (n int) {
var l int
_ = l
if len(m.Counts) > 0 {
for _, e := range m.Counts {
l = e.ProtoSize()
n += 1 + l + sovStructs(uint64(l))
}
}
if m.Created != 0 {
n += 1 + sovStructs(uint64(m.Created))
}
return n
}
func sovStructs(x uint64) (n int) {
for {
n++
@@ -913,6 +1078,301 @@ func (m *FileInfoTruncated) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *Counts) 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 ErrIntOverflowStructs
}
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: Counts: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Counts: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Files", wireType)
}
m.Files = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Files |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Directories", wireType)
}
m.Directories = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Directories |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Symlinks", wireType)
}
m.Symlinks = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Symlinks |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Deleted", wireType)
}
m.Deleted = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Deleted |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Bytes", wireType)
}
m.Bytes = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Bytes |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType)
}
m.Sequence = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Sequence |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 17:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field DeviceID", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthStructs
}
postIndex := iNdEx + byteLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.DeviceID = append(m.DeviceID[:0], dAtA[iNdEx:postIndex]...)
if m.DeviceID == nil {
m.DeviceID = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipStructs(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *CountsSet) 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 ErrIntOverflowStructs
}
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: CountsSet: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: CountsSet: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Counts", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthStructs
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Counts = append(m.Counts, Counts{})
if err := m.Counts[len(m.Counts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Created", wireType)
}
m.Created = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Created |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipStructs(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthStructs
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipStructs(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
@@ -1021,36 +1481,43 @@ var (
func init() { proto.RegisterFile("structs.proto", fileDescriptorStructs) }
var fileDescriptorStructs = []byte{
// 487 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x52, 0xc1, 0x6a, 0xdb, 0x40,
0x10, 0xf5, 0xc6, 0x4a, 0x6c, 0xaf, 0xe2, 0xb4, 0x59, 0x4a, 0x58, 0x0c, 0x95, 0x85, 0xa1, 0x20,
0x0a, 0x95, 0x5b, 0x87, 0x5e, 0xda, 0x9b, 0x29, 0x81, 0x40, 0x29, 0x45, 0x09, 0x39, 0x15, 0x8c,
0x25, 0x8d, 0xe5, 0xa5, 0xd2, 0xae, 0xa2, 0x5d, 0x19, 0xd4, 0x2f, 0xe9, 0x31, 0x9f, 0xe3, 0x63,
0xcf, 0x3d, 0x84, 0xd6, 0xfd, 0x8e, 0x42, 0xd1, 0x4a, 0x56, 0xd4, 0x5b, 0x7b, 0x9b, 0x37, 0x7a,
0x6f, 0xdf, 0x9b, 0x19, 0xe1, 0xa1, 0x54, 0x59, 0x1e, 0x28, 0xe9, 0xa6, 0x99, 0x50, 0x82, 0x1c,
0x84, 0xfe, 0xe8, 0x45, 0xc4, 0xd4, 0x3a, 0xf7, 0xdd, 0x40, 0x24, 0xd3, 0x48, 0x44, 0x62, 0xaa,
0x3f, 0xf9, 0xf9, 0x4a, 0x23, 0x0d, 0x74, 0x55, 0x49, 0x46, 0xaf, 0x5b, 0x74, 0x59, 0xf0, 0x40,
0xad, 0x19, 0x8f, 0x5a, 0x55, 0xcc, 0xfc, 0xea, 0x85, 0x40, 0xc4, 0x53, 0x1f, 0xd2, 0x4a, 0x36,
0xb9, 0xc5, 0xe6, 0x05, 0x8b, 0xe1, 0x06, 0x32, 0xc9, 0x04, 0x27, 0x2f, 0x71, 0x6f, 0x53, 0x95,
0x14, 0xd9, 0xc8, 0x31, 0x67, 0x8f, 0xdd, 0xbd, 0xc8, 0xbd, 0x81, 0x40, 0x89, 0x6c, 0x6e, 0x6c,
0xef, 0xc7, 0x1d, 0x6f, 0x4f, 0x23, 0x67, 0xf8, 0x28, 0x84, 0x0d, 0x0b, 0x80, 0x1e, 0xd8, 0xc8,
0x39, 0xf6, 0x6a, 0x44, 0x28, 0xee, 0x31, 0xbe, 0x59, 0xc6, 0x2c, 0xa4, 0x5d, 0x1b, 0x39, 0x7d,
0x6f, 0x0f, 0x27, 0x17, 0xd8, 0xac, 0xed, 0xde, 0x33, 0xa9, 0xc8, 0x2b, 0xdc, 0xaf, 0xdf, 0x92,
0x14, 0xd9, 0x5d, 0xc7, 0x9c, 0x3d, 0x72, 0x43, 0xdf, 0x6d, 0xa5, 0xaa, 0x2d, 0x1b, 0xda, 0x1b,
0xe3, 0xeb, 0xdd, 0xb8, 0x33, 0xf9, 0xdd, 0xc5, 0xa7, 0x25, 0xeb, 0x92, 0xaf, 0xc4, 0x75, 0x96,
0xf3, 0x60, 0xa9, 0x20, 0x24, 0x04, 0x1b, 0x7c, 0x99, 0x80, 0x8e, 0x3f, 0xf0, 0x74, 0x4d, 0x9e,
0x63, 0x43, 0x15, 0x69, 0x95, 0xf0, 0x64, 0x76, 0xf6, 0x30, 0x52, 0x23, 0x2f, 0x52, 0xf0, 0x34,
0xa7, 0xd4, 0x4b, 0xf6, 0x05, 0x74, 0xe8, 0xae, 0xa7, 0x6b, 0x62, 0x63, 0x33, 0x85, 0x2c, 0x61,
0xb2, 0x4a, 0x69, 0xd8, 0xc8, 0x19, 0x7a, 0xed, 0x16, 0x79, 0x8a, 0x71, 0x22, 0x42, 0xb6, 0x62,
0x10, 0x2e, 0x24, 0x3d, 0xd4, 0xda, 0xc1, 0xbe, 0x73, 0x55, 0x2e, 0x23, 0x84, 0x18, 0x14, 0x84,
0xf4, 0xa8, 0x5a, 0x46, 0x0d, 0xdb, 0x6b, 0xea, 0xfd, 0xb5, 0x26, 0xf2, 0x0c, 0x9f, 0x70, 0xb1,
0x68, 0xfb, 0xf6, 0x35, 0x61, 0xc8, 0xc5, 0xc7, 0x96, 0x73, 0xeb, 0x62, 0x83, 0x7f, 0xbb, 0xd8,
0x08, 0xf7, 0x25, 0xdc, 0xe6, 0xc0, 0x03, 0xa0, 0x58, 0x27, 0x6d, 0x30, 0x19, 0x63, 0xb3, 0x99,
0x83, 0x4b, 0x6a, 0xda, 0xc8, 0x39, 0xf4, 0x9a, 0xd1, 0x3e, 0x48, 0xf2, 0xa9, 0x45, 0xf0, 0x0b,
0x7a, 0x6c, 0x23, 0xc7, 0x98, 0xbf, 0x2d, 0x0d, 0xbe, 0xdf, 0x8f, 0xcf, 0xff, 0xe3, 0x1f, 0x74,
0xaf, 0xd6, 0x22, 0x53, 0x97, 0xef, 0x1e, 0x5e, 0x9f, 0x17, 0xe5, 0xcc, 0xb2, 0x48, 0x62, 0xc6,
0x3f, 0x2f, 0xd4, 0x32, 0x8b, 0x40, 0xd1, 0x53, 0x7d, 0xc6, 0x61, 0xdd, 0xbd, 0xd6, 0xcd, 0xea,
0xfe, 0xf3, 0x27, 0xdb, 0x9f, 0x56, 0x67, 0xbb, 0xb3, 0xd0, 0xb7, 0x9d, 0x85, 0x7e, 0xec, 0xac,
0xce, 0xdd, 0x2f, 0x0b, 0xf9, 0x47, 0xda, 0xe0, 0xfc, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe,
0xcd, 0x11, 0xef, 0x52, 0x03, 0x00, 0x00,
// 598 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xcd, 0x6a, 0xdb, 0x4c,
0x14, 0xb5, 0x62, 0xc9, 0xb1, 0x47, 0x71, 0xbe, 0x2f, 0x43, 0x08, 0xc2, 0x50, 0x5b, 0x18, 0x0a,
0xa2, 0x50, 0xa5, 0x4d, 0xe8, 0xa6, 0xdd, 0xb9, 0x21, 0x10, 0x28, 0x6d, 0x99, 0x84, 0xac, 0x0a,
0xc1, 0x92, 0xae, 0x9d, 0xa1, 0xf2, 0x8c, 0xa3, 0x19, 0x07, 0xd4, 0x27, 0xe9, 0x32, 0x0f, 0xd3,
0x45, 0x96, 0x5d, 0x77, 0x11, 0x5a, 0xf7, 0x39, 0x0a, 0x45, 0x77, 0x24, 0x45, 0xe9, 0xaa, 0xdd,
0xdd, 0x73, 0xff, 0xef, 0x39, 0x33, 0xa4, 0xaf, 0x74, 0xb6, 0x8a, 0xb5, 0x0a, 0x97, 0x99, 0xd4,
0x92, 0x6e, 0x24, 0xd1, 0xe0, 0xe9, 0x9c, 0xeb, 0xcb, 0x55, 0x14, 0xc6, 0x72, 0xb1, 0x3f, 0x97,
0x73, 0xb9, 0x8f, 0xa1, 0x68, 0x35, 0x43, 0x84, 0x00, 0x2d, 0x53, 0x32, 0x78, 0xd1, 0x48, 0x57,
0xb9, 0x88, 0xf5, 0x25, 0x17, 0xf3, 0x86, 0x95, 0xf2, 0xc8, 0x74, 0x88, 0x65, 0xba, 0x1f, 0xc1,
0xd2, 0x94, 0x8d, 0xaf, 0x88, 0x7b, 0xcc, 0x53, 0x38, 0x87, 0x4c, 0x71, 0x29, 0xe8, 0x33, 0xb2,
0x79, 0x6d, 0x4c, 0xcf, 0xf2, 0xad, 0xc0, 0x3d, 0xf8, 0x3f, 0xac, 0x8a, 0xc2, 0x73, 0x88, 0xb5,
0xcc, 0x26, 0xf6, 0xed, 0xdd, 0xa8, 0xc5, 0xaa, 0x34, 0xba, 0x47, 0x3a, 0x09, 0x5c, 0xf3, 0x18,
0xbc, 0x0d, 0xdf, 0x0a, 0xb6, 0x58, 0x89, 0xa8, 0x47, 0x36, 0xb9, 0xb8, 0x9e, 0xa6, 0x3c, 0xf1,
0xda, 0xbe, 0x15, 0x74, 0x59, 0x05, 0xc7, 0xc7, 0xc4, 0x2d, 0xc7, 0xbd, 0xe1, 0x4a, 0xd3, 0xe7,
0xa4, 0x5b, 0xf6, 0x52, 0x9e, 0xe5, 0xb7, 0x03, 0xf7, 0xe0, 0xbf, 0x30, 0x89, 0xc2, 0xc6, 0x56,
0xe5, 0xc8, 0x3a, 0xed, 0xa5, 0xfd, 0xf9, 0x66, 0xd4, 0x1a, 0xff, 0x6a, 0x93, 0x9d, 0x22, 0xeb,
0x44, 0xcc, 0xe4, 0x59, 0xb6, 0x12, 0xf1, 0x54, 0x43, 0x42, 0x29, 0xb1, 0xc5, 0x74, 0x01, 0xb8,
0x7e, 0x8f, 0xa1, 0x4d, 0x9f, 0x10, 0x5b, 0xe7, 0x4b, 0xb3, 0xe1, 0xf6, 0xc1, 0xde, 0xfd, 0x49,
0x75, 0x79, 0xbe, 0x04, 0x86, 0x39, 0x45, 0xbd, 0xe2, 0x9f, 0x00, 0x97, 0x6e, 0x33, 0xb4, 0xa9,
0x4f, 0xdc, 0x25, 0x64, 0x0b, 0xae, 0xcc, 0x96, 0xb6, 0x6f, 0x05, 0x7d, 0xd6, 0x74, 0xd1, 0x47,
0x84, 0x2c, 0x64, 0xc2, 0x67, 0x1c, 0x92, 0x0b, 0xe5, 0x39, 0x58, 0xdb, 0xab, 0x3c, 0xa7, 0x05,
0x19, 0x09, 0xa4, 0xa0, 0x21, 0xf1, 0x3a, 0x86, 0x8c, 0x12, 0x36, 0x69, 0xda, 0x7c, 0x40, 0x13,
0x7d, 0x4c, 0xb6, 0x85, 0xbc, 0x68, 0xce, 0xed, 0x62, 0x42, 0x5f, 0xc8, 0xf7, 0x8d, 0xc9, 0x0d,
0xc5, 0x7a, 0x7f, 0xa7, 0xd8, 0x80, 0x74, 0x15, 0x5c, 0xad, 0x40, 0xc4, 0xe0, 0x11, 0xdc, 0xb4,
0xc6, 0x74, 0x44, 0xdc, 0xfa, 0x0e, 0xa1, 0x3c, 0xd7, 0xb7, 0x02, 0x87, 0xd5, 0xa7, 0xbd, 0x55,
0xf4, 0x43, 0x23, 0x21, 0xca, 0xbd, 0x2d, 0xdf, 0x0a, 0xec, 0xc9, 0xab, 0x62, 0xc0, 0xb7, 0xbb,
0xd1, 0xe1, 0x3f, 0xbc, 0xc1, 0xf0, 0xf4, 0x52, 0x66, 0xfa, 0xe4, 0xe8, 0xbe, 0xfb, 0x24, 0x2f,
0x6e, 0x56, 0xf9, 0x22, 0xe5, 0xe2, 0xe3, 0x85, 0x9e, 0x66, 0x73, 0xd0, 0xde, 0x0e, 0xca, 0xd8,
0x2f, 0xbd, 0x67, 0xe8, 0x2c, 0xf5, 0xff, 0x62, 0x91, 0xce, 0x6b, 0xb9, 0x12, 0x5a, 0xd1, 0x5d,
0xe2, 0xcc, 0x78, 0x0a, 0x0a, 0x55, 0x77, 0x98, 0x01, 0x85, 0x6c, 0x09, 0xcf, 0x90, 0x03, 0x0e,
0x0a, 0xd5, 0x77, 0x58, 0xd3, 0x85, 0x54, 0x98, 0xce, 0x0a, 0x05, 0x77, 0x58, 0x8d, 0x9b, 0x9a,
0xd9, 0x18, 0xaa, 0x35, 0xdb, 0x25, 0x4e, 0x94, 0x6b, 0xa8, 0x74, 0x36, 0xe0, 0x01, 0xad, 0x9d,
0x3f, 0x68, 0x1d, 0x90, 0xae, 0xf9, 0x16, 0x27, 0x47, 0x78, 0xd1, 0x16, 0xab, 0xf1, 0xf8, 0x1d,
0xe9, 0x99, 0x2b, 0x4e, 0x41, 0xd3, 0x80, 0x74, 0x62, 0x04, 0xe5, 0x57, 0x20, 0xc5, 0x57, 0x30,
0xe1, 0x52, 0xc6, 0x32, 0x5e, 0xac, 0x17, 0x67, 0x50, 0x3c, 0x79, 0x3c, 0xac, 0xcd, 0x2a, 0x38,
0xd9, 0xbd, 0xfd, 0x31, 0x6c, 0xdd, 0xae, 0x87, 0xd6, 0xd7, 0xf5, 0xd0, 0xfa, 0xbe, 0x1e, 0xb6,
0x6e, 0x7e, 0x0e, 0xad, 0xa8, 0x83, 0xc4, 0x1f, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x86,
0x97, 0x21, 0x6a, 0x04, 0x00, 0x00,
}