From 82fe6f5f593c199a8cc6f66bfba9cc8ac31b08e1 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 22 Jan 2021 14:04:20 +0100 Subject: [PATCH 1/5] channeldb/payments_test: handle that dupe payments will always have StatusSuccess Legacy duplicate payments would only be migrated over if they had succeeded. Alter the test to reflect this. --- channeldb/payment_control_test.go | 2 +- channeldb/payments_test.go | 32 +++++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/channeldb/payment_control_test.go b/channeldb/payment_control_test.go index e395a93f..7949e610 100644 --- a/channeldb/payment_control_test.go +++ b/channeldb/payment_control_test.go @@ -466,7 +466,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) { if p.hasDuplicate { appendDuplicatePayment( t, pControl.db, info.PaymentHash, - uint64(duplicateSeqNr), + uint64(duplicateSeqNr), preimg, ) duplicateSeqNr++ } diff --git a/channeldb/payments_test.go b/channeldb/payments_test.go index f3de2053..ca84613e 100644 --- a/channeldb/payments_test.go +++ b/channeldb/payments_test.go @@ -340,9 +340,9 @@ func TestQueryPayments(t *testing.T) { Reversed: false, IncludeIncomplete: false, }, - firstIndex: 0, - lastIndex: 0, - expectedSeqNrs: nil, + firstIndex: 7, + lastIndex: 7, + expectedSeqNrs: []uint64{7}, }, { name: "query payments at index gap", @@ -423,7 +423,7 @@ func TestQueryPayments(t *testing.T) { for i := 0; i < nonDuplicatePayments; i++ { // Generate a test payment. - info, _, _, err := genInfo() + info, _, preimg, err := genInfo() if err != nil { t.Fatalf("unable to create test "+ "payment: %v", err) @@ -449,7 +449,8 @@ func TestQueryPayments(t *testing.T) { // If we are on the last payment entry, add a // duplicate payment with sequence number equal - // to the parent payment + 1. + // to the parent payment + 1. Note that + // duplicate payments will always be succeeded. if i == (nonDuplicatePayments - 1) { pmt, err := pControl.FetchPayment( info.PaymentHash, @@ -460,6 +461,7 @@ func TestQueryPayments(t *testing.T) { t, pControl.db, info.PaymentHash, pmt.SequenceNum+1, + preimg, ) } } @@ -492,7 +494,7 @@ func TestQueryPayments(t *testing.T) { if len(querySlice.Payments) != len(tt.expectedSeqNrs) { t.Errorf("expected: %v payments, got: %v", - len(allPayments), len(querySlice.Payments)) + len(tt.expectedSeqNrs), len(querySlice.Payments)) } for i, seqNr := range tt.expectedSeqNrs { @@ -534,7 +536,7 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) { require.NoError(t, err) // Generate a test payment which we will add duplicates to. - hasDuplicates, _, _, err := genInfo() + hasDuplicates, _, preimg, err := genInfo() require.NoError(t, err) // Create a new payment entry in the database. @@ -556,10 +558,10 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) { // Add two duplicates to our second payment. appendDuplicatePayment( - t, db, hasDuplicates.PaymentHash, duplicateOneSeqNr, + t, db, hasDuplicates.PaymentHash, duplicateOneSeqNr, preimg, ) appendDuplicatePayment( - t, db, hasDuplicates.PaymentHash, duplicateTwoSeqNr, + t, db, hasDuplicates.PaymentHash, duplicateTwoSeqNr, preimg, ) tests := []struct { @@ -634,7 +636,7 @@ func TestFetchPaymentWithSequenceNumber(t *testing.T) { // This code is *only* intended to replicate legacy duplicate payments in lnd, // our current schema does not allow duplicates. func appendDuplicatePayment(t *testing.T, db *DB, paymentHash lntypes.Hash, - seqNr uint64) { + seqNr uint64, preImg lntypes.Preimage) { err := kvdb.Update(db, func(tx walletdb.ReadWriteTx) error { bucket, err := fetchPaymentBucketUpdate( @@ -658,7 +660,7 @@ func appendDuplicatePayment(t *testing.T, db *DB, paymentHash lntypes.Hash, // Create duplicate payments for the two dup // sequence numbers we've setup. - putDuplicatePayment(t, dup, sequenceKey[:], paymentHash) + putDuplicatePayment(t, dup, sequenceKey[:], paymentHash, preImg) // Finally, once we have created our entry we add an index for // it. @@ -675,7 +677,8 @@ func appendDuplicatePayment(t *testing.T, db *DB, paymentHash lntypes.Hash, // putDuplicatePayment creates a duplicate payment in the duplicates bucket // provided with the minimal information required for successful reading. func putDuplicatePayment(t *testing.T, duplicateBucket kvdb.RwBucket, - sequenceKey []byte, paymentHash lntypes.Hash) { + sequenceKey []byte, paymentHash lntypes.Hash, + preImg lntypes.Preimage) { paymentBucket, err := duplicateBucket.CreateBucketIfNotExists( sequenceKey, @@ -711,4 +714,9 @@ func putDuplicatePayment(t *testing.T, duplicateBucket kvdb.RwBucket, // Get the PaymentCreationInfo. err = paymentBucket.Put(duplicatePaymentCreationInfoKey, b.Bytes()) require.NoError(t, err) + + // Duolicate payments are only stored for successes, so add the + // preimage. + err = paymentBucket.Put(duplicatePaymentSettleInfoKey, preImg[:]) + require.NoError(t, err) } From 0ef2ca06c1e08f63c078fcf217108214fa871a19 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Tue, 11 Jun 2019 15:06:13 +0200 Subject: [PATCH 2/5] lnrpc: add failed_payments_only and failed_htlcs_only option to DeleteAllPayments --- lnrpc/rpc.pb.go | 469 +++++++++++++++++++++-------------------- lnrpc/rpc.pb.gw.go | 15 ++ lnrpc/rpc.proto | 7 + lnrpc/rpc.swagger.json | 18 ++ 4 files changed, 285 insertions(+), 224 deletions(-) diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index 3b00f78f..e8013d11 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -10372,6 +10372,11 @@ func (m *ListPaymentsResponse) GetLastIndexOffset() uint64 { } type DeleteAllPaymentsRequest struct { + // Only delete failed payments. + FailedPaymentsOnly bool `protobuf:"varint,1,opt,name=failed_payments_only,json=failedPaymentsOnly,proto3" json:"failed_payments_only,omitempty"` + // + //Only delete failed HTLCs from payments, not the payment itself. + FailedHtlcsOnly bool `protobuf:"varint,2,opt,name=failed_htlcs_only,json=failedHtlcsOnly,proto3" json:"failed_htlcs_only,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -10402,6 +10407,20 @@ func (m *DeleteAllPaymentsRequest) XXX_DiscardUnknown() { var xxx_messageInfo_DeleteAllPaymentsRequest proto.InternalMessageInfo +func (m *DeleteAllPaymentsRequest) GetFailedPaymentsOnly() bool { + if m != nil { + return m.FailedPaymentsOnly + } + return false +} + +func (m *DeleteAllPaymentsRequest) GetFailedHtlcsOnly() bool { + if m != nil { + return m.FailedHtlcsOnly + } + return false +} + type DeleteAllPaymentsResponse struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -12850,7 +12869,7 @@ func init() { func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) } var fileDescriptor_77a6da22d6a3feb1 = []byte{ - // 12415 bytes of a gzipped FileDescriptorProto + // 12448 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0xbd, 0x6b, 0x6c, 0x23, 0x59, 0x76, 0x18, 0xdc, 0x7c, 0x89, 0xe4, 0x21, 0x29, 0x51, 0x57, 0x2f, 0xb6, 0x7a, 0x7a, 0xba, 0xa7, 0x66, 0x76, 0xa6, 0xb7, 0x67, 0x46, 0xd3, 0xd3, 0x33, 0x3d, 0x8f, 0xed, 0xcf, 0xeb, 0xa5, 0x24, @@ -13404,229 +13423,231 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0xdd, 0x4f, 0x14, 0x24, 0xb8, 0x59, 0x6d, 0x6a, 0x5f, 0xca, 0xb2, 0x63, 0x2c, 0xb8, 0x98, 0x60, 0xc1, 0x7f, 0x2f, 0xc7, 0x43, 0x41, 0x45, 0x15, 0x8d, 0x78, 0xb0, 0xca, 0x33, 0xce, 0x83, 0x05, 0xa9, 0xa9, 0xf0, 0xd7, 0xf0, 0xd5, 0x7c, 0x36, 0x5f, 0xcd, 0xe6, 0xd8, 0x85, 0x4c, 0x8e, 0x6d, - 0x6c, 0x42, 0x6b, 0x97, 0xb2, 0xae, 0x68, 0x4f, 0x26, 0x89, 0xbe, 0x34, 0x6e, 0xc1, 0xcd, 0x0c, - 0x9c, 0xd0, 0x54, 0xfd, 0x66, 0x0e, 0xd6, 0xda, 0x3c, 0x02, 0xcc, 0x37, 0x76, 0xa7, 0xf9, 0x73, - 0xb8, 0xa9, 0xae, 0x1c, 0x68, 0x57, 0x25, 0xf5, 0xf0, 0x5d, 0xf2, 0xb6, 0x82, 0x76, 0xd1, 0x86, - 0x6d, 0xa9, 0x46, 0x0b, 0xd6, 0x93, 0xb5, 0x11, 0x15, 0xdd, 0x83, 0xe5, 0x5d, 0x7a, 0x32, 0x3f, - 0x3b, 0xa0, 0x17, 0x51, 0x1d, 0x09, 0x14, 0x83, 0x73, 0xef, 0xb9, 0x98, 0x18, 0xf8, 0x1b, 0x7d, - 0x92, 0x19, 0x8d, 0x15, 0xcc, 0xe8, 0x48, 0x5a, 0x3a, 0x10, 0x32, 0x98, 0xd1, 0x91, 0xf1, 0x08, - 0x88, 0x9e, 0x8f, 0x18, 0x45, 0x76, 0xf0, 0x9b, 0x9f, 0x58, 0xc1, 0x55, 0x10, 0xd2, 0xa9, 0xbc, - 0x06, 0x0c, 0xc1, 0xfc, 0x64, 0xc0, 0x21, 0xc6, 0x3b, 0x50, 0x3f, 0xb2, 0xaf, 0x4c, 0xfa, 0x23, - 0x71, 0xdb, 0x76, 0x03, 0xca, 0x33, 0xfb, 0x8a, 0xb1, 0x6a, 0x65, 0xf4, 0x44, 0xb4, 0xf1, 0x7b, - 0x45, 0x58, 0xe0, 0x94, 0xe4, 0x2e, 0x7f, 0xe6, 0xc2, 0x71, 0x91, 0x55, 0xca, 0x4d, 0x4b, 0x03, - 0xa5, 0xf6, 0xb5, 0x7c, 0x7a, 0x5f, 0x13, 0x1a, 0x5a, 0x19, 0x5e, 0x50, 0x9a, 0xa7, 0xdc, 0xf9, - 0x54, 0xc6, 0x14, 0x8c, 0xc7, 0x3b, 0x29, 0x46, 0xcf, 0xa3, 0xf0, 0x58, 0x0f, 0x71, 0x07, 0x82, - 0xe8, 0x78, 0xc9, 0x6b, 0x27, 0xb7, 0x6b, 0xb1, 0xa5, 0xe9, 0xa0, 0xcc, 0x33, 0x6c, 0x59, 0x5e, - 0x21, 0x8f, 0x9f, 0x61, 0x53, 0x67, 0xd5, 0xca, 0xcb, 0xcf, 0xaa, 0x5c, 0x75, 0xfb, 0x82, 0xb3, - 0x2a, 0xbc, 0xc2, 0x59, 0xf5, 0x15, 0x8c, 0xf7, 0x37, 0xa1, 0x82, 0x32, 0x98, 0xb6, 0xc3, 0x31, - 0xd9, 0x8b, 0xed, 0x70, 0x9f, 0x6a, 0xa7, 0x39, 0xee, 0x39, 0xa4, 0x6d, 0x31, 0x26, 0xfd, 0xd1, - 0xcf, 0x46, 0x1b, 0xf8, 0x15, 0x94, 0x05, 0x94, 0x4d, 0x68, 0xd7, 0x9e, 0xca, 0x20, 0xba, 0xf8, - 0x9b, 0x75, 0x1b, 0x86, 0x95, 0xfc, 0xd1, 0xdc, 0xf1, 0xe9, 0x58, 0x06, 0xb7, 0x73, 0x70, 0x7d, - 0x33, 0x08, 0x6b, 0x20, 0x3b, 0x59, 0xba, 0x32, 0x08, 0x7e, 0xc5, 0x2c, 0x3b, 0xc1, 0x53, 0xf6, - 0x69, 0x10, 0x68, 0x62, 0x18, 0xf0, 0x99, 0xe7, 0x4b, 0x01, 0xc2, 0xf8, 0xfd, 0x1c, 0x34, 0xc5, - 0xea, 0x52, 0x38, 0xfd, 0xd4, 0x56, 0xba, 0xce, 0xd1, 0xe5, 0xc5, 0xa1, 0xea, 0x0c, 0x68, 0xa0, - 0x3e, 0x4b, 0x49, 0x13, 0x5c, 0x1f, 0x57, 0x63, 0xc0, 0x3d, 0x21, 0x51, 0xbc, 0x0e, 0x35, 0x79, - 0x63, 0x62, 0xea, 0x4c, 0xe4, 0x4b, 0x48, 0xfc, 0xca, 0xc4, 0xa1, 0x33, 0x91, 0xc2, 0x88, 0x6f, - 0x8b, 0x90, 0x06, 0x39, 0x14, 0x46, 0x4c, 0x3b, 0xa4, 0xc6, 0x1f, 0xe6, 0x60, 0x59, 0x6b, 0x8a, - 0x58, 0xb7, 0xdf, 0x81, 0xba, 0x7a, 0x9c, 0x80, 0x2a, 0x29, 0x78, 0x23, 0xce, 0xa3, 0xa2, 0x64, - 0xb5, 0x91, 0x82, 0x04, 0xac, 0x32, 0x63, 0xfb, 0x8a, 0xbb, 0xf5, 0xcf, 0xa7, 0xf2, 0x30, 0x3a, - 0xb6, 0xaf, 0xf6, 0x28, 0x1d, 0xcc, 0xa7, 0xe4, 0x2e, 0xd4, 0x9f, 0x53, 0xfa, 0x4c, 0x11, 0x70, - 0xd6, 0x0b, 0x0c, 0x26, 0x28, 0x0c, 0x68, 0x4c, 0x3d, 0x37, 0x3c, 0x57, 0x24, 0xe2, 0x04, 0x80, - 0x40, 0x4e, 0x63, 0xfc, 0x71, 0x1e, 0x56, 0xb8, 0xd6, 0x54, 0xe8, 0xce, 0x05, 0xeb, 0x6a, 0xc1, - 0x02, 0x57, 0x65, 0x73, 0xe6, 0xb5, 0x7f, 0xc3, 0x14, 0xdf, 0xe4, 0xe3, 0x57, 0xd4, 0xf4, 0xca, - 0xa8, 0x09, 0xd7, 0x74, 0x7f, 0x21, 0xdd, 0xfd, 0xd7, 0x77, 0x6f, 0x96, 0x25, 0xbd, 0x94, 0x65, - 0x49, 0x7f, 0x15, 0xfb, 0x75, 0xea, 0x7e, 0x7f, 0x39, 0x1d, 0x17, 0xf7, 0x11, 0x6c, 0xc4, 0x68, - 0x90, 0x5b, 0x3b, 0xa7, 0x8e, 0x0a, 0xba, 0xbe, 0xaa, 0x51, 0x0f, 0x24, 0x6e, 0xbb, 0x0c, 0xa5, - 0x60, 0xe4, 0xcd, 0xa8, 0xb1, 0x0e, 0xab, 0xf1, 0x5e, 0x15, 0xdb, 0xc4, 0xef, 0xe4, 0xa0, 0xb5, - 0x17, 0x05, 0x18, 0x76, 0x82, 0xd0, 0xf3, 0x55, 0x9c, 0xfa, 0xdb, 0x00, 0xfc, 0x55, 0x26, 0x3c, - 0xfb, 0x8b, 0xc8, 0x50, 0x08, 0xc1, 0x93, 0xff, 0x4d, 0xa8, 0x50, 0x77, 0xcc, 0x91, 0x7c, 0x36, - 0x94, 0xa9, 0x3b, 0x96, 0x7a, 0x83, 0xd4, 0x36, 0xdc, 0x88, 0x0b, 0x18, 0x22, 0xc6, 0x09, 0xeb, - 0x1d, 0x7a, 0x81, 0xe2, 0x40, 0x51, 0xc5, 0x38, 0x39, 0xb4, 0x2f, 0xd1, 0x25, 0x3c, 0x30, 0x7e, - 0x2b, 0x0f, 0x4b, 0x51, 0xfd, 0x78, 0x94, 0xa7, 0x17, 0xc7, 0xab, 0xba, 0x2b, 0xa6, 0x83, 0xc3, - 0xce, 0x52, 0x9a, 0x2e, 0xb9, 0xc2, 0x17, 0x67, 0xd7, 0x25, 0x06, 0xd4, 0x24, 0x85, 0x37, 0x0f, - 0xb5, 0x58, 0xbe, 0x55, 0x4e, 0xd2, 0x9f, 0x87, 0xec, 0xf0, 0x6b, 0x4f, 0x99, 0x2c, 0x21, 0x8e, - 0x9f, 0x25, 0x7b, 0x1a, 0x76, 0xf1, 0xe9, 0x2f, 0x06, 0x66, 0xc9, 0xf8, 0x40, 0x32, 0x2a, 0x46, - 0xdf, 0xe4, 0x67, 0x21, 0x3e, 0x72, 0x78, 0x0e, 0xd2, 0x0f, 0x0a, 0xfc, 0xb5, 0x12, 0x75, 0x50, - 0x78, 0x1d, 0x6a, 0x3c, 0xf3, 0x28, 0x9c, 0x03, 0x06, 0xd6, 0x0b, 0xbb, 0x2e, 0xe2, 0x85, 0x5e, - 0xcf, 0x9b, 0xc7, 0x54, 0x15, 0xc0, 0x8b, 0x42, 0xb7, 0xa2, 0xdf, 0xcc, 0xc1, 0xcd, 0x8c, 0x61, - 0x13, 0xab, 0x7c, 0x07, 0xb4, 0x30, 0xd3, 0xb2, 0x77, 0xf9, 0x52, 0x5f, 0x97, 0x6c, 0x35, 0xde, - 0xa7, 0x66, 0xf3, 0x34, 0x0e, 0x88, 0x0e, 0xc0, 0x7c, 0x04, 0x63, 0xc1, 0x42, 0x50, 0x9c, 0xe2, - 0xc3, 0xc8, 0xcf, 0x9e, 0x47, 0xb0, 0xd9, 0xb9, 0x64, 0x1c, 0x43, 0xb9, 0x89, 0x8f, 0x9e, 0xcd, - 0xa5, 0xb5, 0x2f, 0x61, 0x33, 0xc8, 0xbd, 0x92, 0xcd, 0x60, 0xcc, 0xaf, 0xf2, 0xab, 0xbc, 0x7e, - 0x92, 0x4c, 0x70, 0x03, 0x65, 0x69, 0x4e, 0x30, 0x0b, 0x19, 0x35, 0x84, 0x81, 0x78, 0xa6, 0x46, - 0x00, 0x4b, 0x87, 0xf3, 0x49, 0xe8, 0xec, 0x28, 0x10, 0xf9, 0x58, 0xa4, 0xc1, 0x72, 0x64, 0xaf, - 0x65, 0x16, 0x04, 0xaa, 0x20, 0xec, 0xac, 0x29, 0xcb, 0xc8, 0x4a, 0x97, 0xb7, 0x34, 0x8d, 0x97, - 0x60, 0xdc, 0x84, 0x8d, 0xe8, 0x8b, 0x77, 0x9b, 0xdc, 0x6a, 0xfe, 0x7e, 0x8e, 0xdf, 0x3f, 0xe1, - 0xb8, 0x81, 0x6b, 0xcf, 0x82, 0x73, 0x2f, 0x24, 0x1d, 0x58, 0x09, 0x1c, 0xf7, 0x6c, 0x42, 0xf5, - 0xec, 0x03, 0xd1, 0x09, 0x6b, 0xf1, 0xba, 0xf1, 0xa4, 0x81, 0xb9, 0xcc, 0x53, 0x44, 0xb9, 0x05, - 0x64, 0xfb, 0xba, 0x4a, 0x46, 0xd3, 0x22, 0xd1, 0x1b, 0xe9, 0xca, 0x77, 0x61, 0x31, 0x5e, 0x10, - 0xf9, 0x54, 0x44, 0xc0, 0x88, 0x6a, 0x55, 0x48, 0xdc, 0xff, 0x8f, 0x26, 0x44, 0x2d, 0xea, 0xfb, - 0xc0, 0xf8, 0xeb, 0x39, 0x68, 0x99, 0x94, 0xcd, 0x5c, 0xad, 0x96, 0x72, 0xce, 0x7c, 0x27, 0x95, - 0xeb, 0xf5, 0x6d, 0x95, 0x81, 0x35, 0x64, 0x8d, 0xde, 0xbb, 0x76, 0x30, 0xf6, 0x6f, 0xa4, 0x5a, - 0xb4, 0x5d, 0x81, 0x05, 0x4e, 0x62, 0x6c, 0xc0, 0x9a, 0xa8, 0x8f, 0xac, 0x4b, 0x64, 0x9e, 0x8e, - 0x95, 0x18, 0x33, 0x4f, 0x6f, 0x42, 0x8b, 0x5f, 0x54, 0xd7, 0x1b, 0x21, 0x12, 0xee, 0x02, 0x39, - 0xb4, 0x47, 0xb6, 0xef, 0x79, 0xee, 0x11, 0xf5, 0x85, 0x03, 0x38, 0x4a, 0x98, 0x68, 0xbd, 0x95, - 0xa2, 0x30, 0xff, 0x92, 0x11, 0xcc, 0x3d, 0x57, 0xfa, 0xbb, 0xf1, 0x2f, 0xc3, 0x87, 0x95, 0x6d, - 0xfb, 0x19, 0x95, 0x39, 0xc9, 0x2e, 0x7a, 0x0c, 0xb5, 0x99, 0xca, 0x54, 0xf6, 0xbb, 0x0c, 0x1a, - 0x94, 0x2e, 0xd6, 0xd4, 0xa9, 0x19, 0x0b, 0xf2, 0x3d, 0x2f, 0xc4, 0xe0, 0x1b, 0xd2, 0xe4, 0x66, - 0x56, 0x19, 0xe8, 0x29, 0xbd, 0xea, 0x8e, 0x8d, 0x87, 0xb0, 0x1a, 0x2f, 0x53, 0xb0, 0x96, 0x4d, - 0xa8, 0x4c, 0x05, 0x4c, 0xd4, 0x5e, 0x7d, 0xb3, 0xc3, 0x08, 0x3b, 0xf2, 0xc9, 0x34, 0xdd, 0x5d, - 0x75, 0xa4, 0x7a, 0x0c, 0x1b, 0x29, 0x8c, 0xc8, 0xf0, 0x2e, 0xd4, 0xb5, 0x8a, 0xf0, 0x66, 0x14, - 0x99, 0xc8, 0x2a, 0x6a, 0x12, 0x18, 0x9f, 0xc3, 0x06, 0x3f, 0x8f, 0x45, 0xc9, 0x65, 0x17, 0x24, - 0x5a, 0x91, 0x4b, 0xb6, 0xe2, 0x63, 0x79, 0xcc, 0xd3, 0x93, 0x46, 0xc1, 0xf8, 0xc6, 0x88, 0x93, - 0x2e, 0x4b, 0xf2, 0xd3, 0x38, 0x86, 0xf5, 0x74, 0xf7, 0xb1, 0xfa, 0xff, 0x54, 0x5d, 0x2e, 0xbb, - 0x27, 0x42, 0xab, 0xee, 0xf9, 0xaf, 0x39, 0xde, 0x3f, 0x31, 0x94, 0xa8, 0xe6, 0x18, 0xc8, 0x94, - 0x86, 0xe7, 0xde, 0xd8, 0x4a, 0x97, 0xfc, 0x48, 0x79, 0x4c, 0x65, 0xa6, 0xdd, 0x3a, 0xc4, 0x84, - 0x1a, 0x46, 0xf8, 0xee, 0x4f, 0x93, 0xf0, 0xcd, 0x11, 0xac, 0x67, 0x13, 0x67, 0xf8, 0x19, 0x7d, - 0x14, 0x17, 0xd4, 0x6f, 0x5f, 0xdb, 0x7c, 0x56, 0x2d, 0x5d, 0x6e, 0xff, 0xed, 0x0a, 0x94, 0x85, - 0x96, 0x84, 0x6c, 0x41, 0x71, 0x24, 0x7d, 0x56, 0xa3, 0x80, 0x8c, 0x02, 0x2b, 0xff, 0xef, 0xa0, - 0xe7, 0x2a, 0xa3, 0x23, 0x8f, 0x61, 0x31, 0xee, 0xb6, 0x91, 0x08, 0xc4, 0x12, 0xf7, 0xb7, 0x68, - 0x8c, 0x12, 0x26, 0xf1, 0x6a, 0x24, 0x5c, 0x71, 0x99, 0xb3, 0x72, 0xae, 0x49, 0x5f, 0x9e, 0xcb, - 0xce, 0x6b, 0xc1, 0xb9, 0x6d, 0x3d, 0x7c, 0xf4, 0x89, 0x88, 0xc4, 0x52, 0x43, 0xe0, 0xe0, 0xdc, - 0x7e, 0xf8, 0xe8, 0x93, 0xe4, 0x49, 0x4c, 0xc4, 0x61, 0xd1, 0x4e, 0x62, 0xab, 0x50, 0xe2, 0x61, - 0xde, 0xb9, 0xf3, 0x21, 0xff, 0x20, 0x0f, 0x60, 0x55, 0xea, 0xe5, 0xc4, 0x35, 0x11, 0xbe, 0x8b, - 0xf2, 0x57, 0xae, 0x88, 0xc0, 0x0d, 0x10, 0xc5, 0x35, 0x79, 0xeb, 0xb0, 0x70, 0x1e, 0xc5, 0xed, - 0x6f, 0x98, 0xe2, 0xcb, 0xf8, 0xe3, 0x12, 0xd4, 0xb4, 0x4e, 0x21, 0x75, 0xa8, 0x98, 0x9d, 0x41, - 0xc7, 0xfc, 0xa2, 0xb3, 0xdb, 0xbc, 0x41, 0xee, 0xc1, 0x5b, 0xdd, 0xde, 0x4e, 0xdf, 0x34, 0x3b, - 0x3b, 0x43, 0xab, 0x6f, 0x5a, 0x32, 0x4e, 0xe8, 0x51, 0xfb, 0xab, 0xc3, 0x4e, 0x6f, 0x68, 0xed, - 0x76, 0x86, 0xed, 0xee, 0xc1, 0xa0, 0x99, 0x23, 0xaf, 0x41, 0x2b, 0xa2, 0x94, 0xe8, 0xf6, 0x61, - 0xff, 0xb8, 0x37, 0x6c, 0xe6, 0xc9, 0x1d, 0xb8, 0xb5, 0xd7, 0xed, 0xb5, 0x0f, 0xac, 0x88, 0x66, - 0xe7, 0x60, 0xf8, 0x85, 0xd5, 0xf9, 0x85, 0xa3, 0xae, 0xf9, 0x55, 0xb3, 0x90, 0x45, 0xb0, 0x3f, - 0x3c, 0xd8, 0x91, 0x39, 0x14, 0xc9, 0x4d, 0x58, 0xe3, 0x04, 0x3c, 0x89, 0x35, 0xec, 0xf7, 0xad, - 0x41, 0xbf, 0xdf, 0x6b, 0x96, 0xc8, 0x32, 0x34, 0xba, 0xbd, 0x2f, 0xda, 0x07, 0xdd, 0x5d, 0xcb, - 0xec, 0xb4, 0x0f, 0x0e, 0x9b, 0x0b, 0x64, 0x05, 0x96, 0x92, 0x74, 0x65, 0x96, 0x85, 0xa4, 0xeb, - 0xf7, 0xba, 0xfd, 0x9e, 0xf5, 0x45, 0xc7, 0x1c, 0x74, 0xfb, 0xbd, 0x66, 0x85, 0xac, 0x03, 0x89, - 0xa3, 0xf6, 0x0f, 0xdb, 0x3b, 0xcd, 0x2a, 0x59, 0x83, 0xe5, 0x38, 0xfc, 0x69, 0xe7, 0xab, 0x26, - 0x90, 0x16, 0xac, 0xf2, 0x8a, 0x59, 0xdb, 0x9d, 0x83, 0xfe, 0x97, 0xd6, 0x61, 0xb7, 0xd7, 0x3d, - 0x3c, 0x3e, 0x6c, 0xd6, 0x30, 0x5a, 0x73, 0xa7, 0x63, 0x75, 0x7b, 0x83, 0xe3, 0xbd, 0xbd, 0xee, - 0x4e, 0xb7, 0xd3, 0x1b, 0x36, 0xeb, 0xbc, 0xe4, 0xac, 0x86, 0x37, 0x58, 0x02, 0x71, 0x31, 0xd0, - 0xda, 0xed, 0x0e, 0xda, 0xdb, 0x07, 0x9d, 0xdd, 0xe6, 0x22, 0xb9, 0x0d, 0x37, 0x87, 0x9d, 0xc3, - 0xa3, 0xbe, 0xd9, 0x36, 0xbf, 0x92, 0x17, 0x07, 0xad, 0xbd, 0x76, 0xf7, 0xe0, 0xd8, 0xec, 0x34, - 0x97, 0xc8, 0x1b, 0x70, 0xdb, 0xec, 0xfc, 0xe0, 0xb8, 0x6b, 0x76, 0x76, 0xad, 0x5e, 0x7f, 0xb7, - 0x63, 0xed, 0x75, 0xda, 0xc3, 0x63, 0xb3, 0x63, 0x1d, 0x76, 0x07, 0x83, 0x6e, 0xef, 0x49, 0xb3, - 0x49, 0xde, 0x82, 0xbb, 0x8a, 0x44, 0x65, 0x90, 0xa0, 0x5a, 0x66, 0xed, 0x93, 0x43, 0xda, 0xeb, - 0xfc, 0xc2, 0xd0, 0x3a, 0xea, 0x74, 0xcc, 0x26, 0x21, 0x9b, 0xb0, 0x1e, 0x15, 0xcf, 0x0b, 0x10, - 0x65, 0xaf, 0x30, 0xdc, 0x51, 0xc7, 0x3c, 0x6c, 0xf7, 0xd8, 0x00, 0xc7, 0x70, 0xab, 0xac, 0xda, - 0x11, 0x2e, 0x59, 0xed, 0x35, 0x42, 0x60, 0x51, 0x1b, 0x95, 0xbd, 0xb6, 0xd9, 0x5c, 0x27, 0x4b, - 0x50, 0x3b, 0x3c, 0x3a, 0xb2, 0x86, 0xdd, 0xc3, 0x4e, 0xff, 0x78, 0xd8, 0xdc, 0x20, 0x6b, 0xd0, - 0xec, 0xf6, 0x86, 0x1d, 0x93, 0x8d, 0xb5, 0x4c, 0xfa, 0xdf, 0xca, 0x64, 0x15, 0x96, 0x64, 0x4d, - 0x25, 0xf4, 0xcf, 0xca, 0x64, 0x03, 0xc8, 0x71, 0xcf, 0xec, 0xb4, 0x77, 0x59, 0xc7, 0x29, 0xc4, - 0x7f, 0x2f, 0x0b, 0x8b, 0xe8, 0xef, 0x17, 0x94, 0xb0, 0x17, 0xf9, 0x44, 0xc5, 0x1f, 0xda, 0xa9, - 0x6b, 0x0f, 0xe4, 0xbc, 0xec, 0x7d, 0x43, 0xed, 0x68, 0x5e, 0x48, 0x1d, 0xcd, 0x53, 0xba, 0x9f, - 0x86, 0x7e, 0x76, 0x78, 0x13, 0x1a, 0x53, 0xfe, 0xe8, 0x8e, 0x78, 0xb5, 0x01, 0x84, 0x83, 0x20, - 0x07, 0xf2, 0x27, 0x1b, 0x52, 0x0f, 0xfc, 0x95, 0xd2, 0x0f, 0xfc, 0x65, 0x9d, 0x0f, 0x17, 0xb2, - 0xce, 0x87, 0xf7, 0x61, 0x99, 0xb3, 0x26, 0xc7, 0x75, 0xa6, 0x52, 0xeb, 0x22, 0x9e, 0xcb, 0x43, - 0x16, 0xc5, 0xe1, 0xf2, 0x38, 0x2a, 0x8f, 0xac, 0x82, 0x85, 0x94, 0xc5, 0x69, 0x35, 0x76, 0x52, - 0xe5, 0x9c, 0x43, 0x9d, 0x54, 0x55, 0x09, 0xf6, 0x65, 0x54, 0x42, 0x4d, 0x2b, 0x81, 0xc3, 0xb1, - 0x84, 0xfb, 0xb0, 0x4c, 0x2f, 0x43, 0xdf, 0xb6, 0xbc, 0x99, 0xfd, 0xa3, 0x39, 0x7a, 0x75, 0xd8, - 0xa8, 0x03, 0xaa, 0x9b, 0x4b, 0x88, 0xe8, 0x23, 0x7c, 0xd7, 0x0e, 0x6d, 0xe3, 0x97, 0x00, 0xd4, - 0xae, 0x8a, 0xcf, 0x0e, 0xba, 0x9e, 0xbc, 0x06, 0x5a, 0x37, 0xf9, 0x07, 0x8e, 0x63, 0xe8, 0xf9, - 0xf6, 0x19, 0xed, 0xca, 0x60, 0x46, 0x11, 0x80, 0xdc, 0x82, 0x82, 0x37, 0x93, 0xee, 0x73, 0x55, - 0x19, 0x86, 0x7c, 0x66, 0x32, 0xa8, 0xf1, 0x09, 0xe4, 0xfb, 0xb3, 0x6b, 0x45, 0xa5, 0x16, 0x94, - 0xe5, 0x93, 0xbe, 0x79, 0x74, 0x99, 0x93, 0x9f, 0xf7, 0xff, 0x32, 0xd4, 0xb4, 0x77, 0xa2, 0xc8, - 0x06, 0xac, 0x7c, 0xd9, 0x1d, 0xf6, 0x3a, 0x83, 0x81, 0x75, 0x74, 0xbc, 0xfd, 0xb4, 0xf3, 0x95, - 0xb5, 0xdf, 0x1e, 0xec, 0x37, 0x6f, 0x30, 0x5e, 0xd2, 0xeb, 0x0c, 0x86, 0x9d, 0xdd, 0x18, 0x3c, - 0x47, 0x5e, 0x87, 0xcd, 0xe3, 0xde, 0xf1, 0xa0, 0xb3, 0x6b, 0x65, 0xa5, 0xcb, 0xb3, 0xc5, 0x23, - 0xf0, 0x19, 0xc9, 0x0b, 0xf7, 0x7f, 0x19, 0x16, 0xe3, 0xa1, 0x3d, 0x08, 0xc0, 0xc2, 0x41, 0xe7, - 0x49, 0x7b, 0xe7, 0x2b, 0x1e, 0x66, 0x7e, 0x30, 0x6c, 0x0f, 0xbb, 0x3b, 0x96, 0x08, 0x2b, 0xcf, - 0x18, 0x55, 0x8e, 0xd4, 0xa0, 0xdc, 0xee, 0xed, 0xec, 0xf7, 0xcd, 0x41, 0x33, 0x4f, 0x5e, 0x83, - 0x0d, 0xb9, 0x84, 0x76, 0xfa, 0x87, 0x87, 0xdd, 0x21, 0xf2, 0xe8, 0xe1, 0x57, 0x47, 0x6c, 0xc5, - 0xdc, 0xb7, 0xa1, 0x1a, 0x45, 0xc4, 0x47, 0xbe, 0xd7, 0x1d, 0x76, 0xdb, 0xc3, 0x88, 0xe9, 0x37, - 0x6f, 0x30, 0xb6, 0x1a, 0x81, 0x31, 0xac, 0x7d, 0x33, 0xc7, 0x6f, 0x3f, 0x4b, 0x20, 0x2f, 0xbd, - 0x99, 0x67, 0x6b, 0x3d, 0x82, 0x6e, 0xf7, 0x87, 0xac, 0x09, 0xbf, 0x02, 0x8b, 0xf1, 0xc0, 0xf3, - 0xa4, 0x09, 0x75, 0x56, 0xbe, 0x56, 0x04, 0xc0, 0x02, 0xaf, 0x71, 0x33, 0xc7, 0x19, 0xfb, 0x4e, - 0xff, 0xb0, 0xdb, 0x7b, 0x82, 0xbb, 0x41, 0x33, 0xcf, 0x40, 0xfd, 0xe3, 0xe1, 0x93, 0xbe, 0x02, - 0x15, 0x58, 0x0a, 0xde, 0x9c, 0x66, 0xf1, 0xfe, 0x8f, 0x60, 0x39, 0x15, 0xa2, 0x9e, 0xd5, 0xba, - 0x7f, 0x3c, 0xdc, 0xe9, 0x1f, 0xea, 0xe5, 0xd4, 0xa0, 0xbc, 0x73, 0xd0, 0xee, 0x1e, 0xa2, 0x21, - 0xa4, 0x01, 0xd5, 0xe3, 0x9e, 0xfc, 0xcc, 0xc7, 0x83, 0xeb, 0x17, 0x18, 0x8b, 0xda, 0xeb, 0x9a, - 0x83, 0xa1, 0x35, 0x18, 0xb6, 0x9f, 0x74, 0x9a, 0x45, 0x96, 0x56, 0xf2, 0xab, 0xd2, 0xfd, 0xcf, - 0x61, 0x31, 0xee, 0xeb, 0x1d, 0xb7, 0x6f, 0x6d, 0xc2, 0xfa, 0x76, 0x67, 0xf8, 0x65, 0xa7, 0xd3, - 0xc3, 0x21, 0xdf, 0xe9, 0xf4, 0x86, 0x66, 0xfb, 0xa0, 0x3b, 0xfc, 0xaa, 0x99, 0xbb, 0xff, 0x18, - 0x9a, 0x49, 0x3f, 0x85, 0x98, 0x63, 0xc7, 0x8b, 0x3c, 0x40, 0xee, 0xff, 0x87, 0x1c, 0xac, 0x66, - 0x99, 0xdf, 0xd8, 0xc4, 0x14, 0x8c, 0x90, 0x6d, 0x87, 0x83, 0x7e, 0xcf, 0xea, 0xf5, 0x31, 0xb8, - 0xf4, 0x26, 0xac, 0x27, 0x10, 0xb2, 0x15, 0x39, 0x72, 0x0b, 0x36, 0x52, 0x89, 0x2c, 0xb3, 0x7f, - 0x8c, 0x63, 0xd9, 0x82, 0xd5, 0x04, 0xb2, 0x63, 0x9a, 0x7d, 0xb3, 0x59, 0x20, 0xef, 0xc1, 0xbd, - 0x04, 0x26, 0x2d, 0x04, 0x48, 0x19, 0xa1, 0x48, 0xde, 0x81, 0x37, 0x53, 0xd4, 0xd1, 0x3e, 0x69, - 0x6d, 0xb7, 0x0f, 0x58, 0xf3, 0x9a, 0xa5, 0xfb, 0x7f, 0x58, 0x04, 0x88, 0x2e, 0x53, 0xb2, 0xf2, - 0x77, 0xdb, 0xc3, 0xf6, 0x41, 0x9f, 0xad, 0x19, 0xb3, 0x3f, 0x64, 0xb9, 0x9b, 0x9d, 0x1f, 0x34, - 0x6f, 0x64, 0x62, 0xfa, 0x47, 0xac, 0x41, 0x1b, 0xb0, 0xc2, 0xe7, 0xdf, 0x01, 0x6b, 0x06, 0x9b, - 0x2e, 0x3c, 0x4e, 0x39, 0x93, 0x34, 0x8e, 0x8f, 0xf6, 0xcc, 0x7e, 0x6f, 0x68, 0x0d, 0xf6, 0x8f, - 0x87, 0xbb, 0x18, 0xf6, 0x7c, 0xc7, 0xec, 0x1e, 0xf1, 0x3c, 0x8b, 0x2f, 0x22, 0x60, 0x59, 0x97, - 0xd8, 0x02, 0x7f, 0xd2, 0x1f, 0x0c, 0xba, 0x47, 0xd6, 0x0f, 0x8e, 0x3b, 0x66, 0xb7, 0x33, 0xc0, - 0x84, 0x0b, 0x19, 0x70, 0x46, 0x5f, 0x66, 0x73, 0x76, 0x78, 0xf0, 0x85, 0x10, 0x20, 0x18, 0x69, - 0x25, 0x0e, 0x62, 0x54, 0x55, 0x36, 0x3a, 0x6c, 0x07, 0xce, 0xc8, 0x19, 0xae, 0xc1, 0xb1, 0x74, - 0x35, 0x26, 0x5b, 0xa4, 0x56, 0x3e, 0x26, 0xab, 0x67, 0xa3, 0x58, 0x2a, 0x14, 0x3b, 0x94, 0x90, - 0xb6, 0xbb, 0x6b, 0x62, 0x82, 0xc5, 0x14, 0x94, 0xd1, 0x2e, 0xb1, 0x49, 0xc8, 0xb6, 0x68, 0x46, - 0xd2, 0x94, 0x1f, 0x0c, 0xb3, 0xcc, 0x5a, 0xfc, 0xe5, 0xf1, 0xe1, 0x76, 0x5f, 0xee, 0xf5, 0xbc, - 0xbe, 0x24, 0x03, 0xce, 0xe8, 0x57, 0x30, 0xae, 0x3c, 0x67, 0x47, 0x48, 0xb8, 0xaa, 0x03, 0x18, - 0xc5, 0x1a, 0x63, 0x82, 0x12, 0xf0, 0xc3, 0x8e, 0xd9, 0xb7, 0x98, 0x30, 0x85, 0x82, 0x20, 0xa3, - 0x5f, 0xbf, 0x1e, 0xcd, 0x52, 0x6f, 0x3c, 0xfc, 0x17, 0x6f, 0x40, 0x55, 0x5d, 0xf2, 0x20, 0xdf, - 0x87, 0x46, 0x2c, 0x84, 0x02, 0x91, 0x26, 0x85, 0xac, 0x88, 0x0b, 0x9b, 0xaf, 0x65, 0x23, 0xc5, - 0x61, 0xe9, 0x50, 0xd3, 0x4e, 0xf0, 0xcc, 0x5e, 0x4b, 0x6a, 0x0c, 0x62, 0xb9, 0xdd, 0xbe, 0x06, - 0x2b, 0xb2, 0x7b, 0x8a, 0x21, 0xdc, 0xf5, 0xf7, 0xea, 0xc9, 0xed, 0x28, 0x9e, 0x76, 0xc6, 0x3b, - 0xf6, 0x9b, 0x37, 0xd3, 0x2f, 0xcb, 0xcb, 0xa7, 0xe8, 0x77, 0xa1, 0xa6, 0xbd, 0x34, 0x4a, 0x6e, - 0x5e, 0xfb, 0x2a, 0xea, 0xe6, 0x66, 0x16, 0x4a, 0x54, 0xe9, 0xbb, 0x50, 0x55, 0x2f, 0x3c, 0x92, - 0x0d, 0xed, 0xc5, 0x50, 0xfd, 0xc5, 0xcb, 0xcd, 0x56, 0x1a, 0x21, 0xd2, 0xef, 0x42, 0x4d, 0x7b, - 0xa8, 0x51, 0xd5, 0x22, 0xfd, 0x18, 0xa4, 0xaa, 0x45, 0xd6, 0xbb, 0x8e, 0x07, 0xb0, 0x26, 0x74, - 0x20, 0x27, 0xf4, 0xeb, 0x74, 0x4f, 0xc6, 0xc3, 0xfb, 0x0f, 0x72, 0xe4, 0x31, 0x54, 0xe4, 0xe3, - 0x9e, 0x64, 0x3d, 0xfb, 0x11, 0xd4, 0xcd, 0x8d, 0x14, 0x5c, 0x54, 0xa5, 0x0d, 0x10, 0x3d, 0x01, - 0x49, 0x64, 0xc3, 0x53, 0x4f, 0x4a, 0xaa, 0x91, 0xc9, 0x78, 0x2f, 0x72, 0x17, 0x6a, 0xda, 0x6b, - 0x8f, 0xaa, 0x4f, 0xd2, 0x2f, 0x45, 0xaa, 0x3e, 0xc9, 0x7a, 0x1c, 0xf2, 0xfb, 0xd0, 0x88, 0x3d, - 0xdb, 0xa8, 0xe6, 0x71, 0xd6, 0xa3, 0x90, 0x6a, 0x1e, 0x67, 0xbf, 0xf4, 0xb8, 0x0b, 0x35, 0xed, - 0x29, 0x45, 0x55, 0xa3, 0xf4, 0x7b, 0x8e, 0xaa, 0x46, 0x19, 0x2f, 0x2f, 0xb2, 0xd5, 0x10, 0x7f, - 0x47, 0x51, 0xad, 0x86, 0xcc, 0x07, 0x19, 0xd5, 0x6a, 0xc8, 0x7e, 0x7c, 0x91, 0x4d, 0x3d, 0xf5, - 0x76, 0x03, 0xd9, 0x88, 0xa9, 0x1e, 0xa2, 0x47, 0x20, 0xd4, 0xd4, 0x4b, 0x3f, 0xf3, 0xf0, 0x04, - 0x56, 0xd4, 0xa4, 0x51, 0x2f, 0x2f, 0x04, 0xaa, 0x4e, 0x99, 0xef, 0x3b, 0x6c, 0x36, 0x93, 0xd8, - 0x07, 0x39, 0xf2, 0x19, 0x94, 0x45, 0x38, 0x7b, 0xb2, 0x96, 0x0c, 0x6f, 0xcf, 0x2b, 0xb1, 0x9e, - 0x1d, 0xf5, 0x9e, 0x1c, 0xe1, 0x82, 0xd6, 0xe3, 0xcd, 0xeb, 0x33, 0x36, 0x23, 0x44, 0xfd, 0xe6, - 0xeb, 0xd7, 0xa1, 0xa3, 0x1c, 0x93, 0x6f, 0x24, 0xdc, 0xbe, 0x2e, 0xb4, 0x51, 0x3c, 0xc7, 0xeb, - 0x62, 0x30, 0x3e, 0x81, 0xba, 0xfe, 0x86, 0x16, 0xd1, 0xd7, 0x61, 0x32, 0xaf, 0x5b, 0x99, 0x38, - 0x91, 0xd1, 0x17, 0xb0, 0xae, 0xfa, 0x5b, 0x8f, 0xb3, 0x13, 0x90, 0x3b, 0x19, 0xd1, 0x77, 0x62, - 0xbd, 0x7e, 0xf3, 0xda, 0xf0, 0x3c, 0x0f, 0x72, 0xc8, 0x64, 0x63, 0xcf, 0xde, 0x44, 0x4c, 0x36, - 0xeb, 0xb5, 0x9f, 0x88, 0xc9, 0x66, 0xbf, 0x95, 0xd3, 0x86, 0x25, 0x2d, 0x4e, 0xd0, 0xe0, 0xca, - 0x1d, 0xa9, 0xf9, 0x9e, 0x0e, 0x04, 0xbe, 0x99, 0xa5, 0x89, 0x27, 0x3b, 0x50, 0xd3, 0x43, 0x0d, - 0xbd, 0x20, 0xf9, 0x86, 0x86, 0xd2, 0xe3, 0x38, 0x3f, 0xc8, 0x91, 0x03, 0x68, 0x26, 0x03, 0x83, - 0xaa, 0x25, 0x9c, 0x15, 0x4c, 0x75, 0x33, 0x81, 0x8c, 0x85, 0x13, 0x65, 0xf3, 0x22, 0xf6, 0xbe, - 0xbb, 0xe7, 0x27, 0xb7, 0xa2, 0xf8, 0xbb, 0xef, 0x2a, 0xb7, 0xac, 0x27, 0xff, 0xef, 0xe5, 0x1e, - 0xe4, 0xc8, 0x1e, 0xd4, 0x63, 0x71, 0xf1, 0x62, 0xf7, 0x8d, 0x12, 0xcd, 0x6c, 0xe9, 0xb8, 0x44, - 0x3b, 0x0f, 0x61, 0x31, 0xee, 0x32, 0xa2, 0x2a, 0x96, 0xe9, 0xd7, 0xa2, 0x86, 0x2f, 0xdb, 0xcf, - 0x84, 0xfc, 0x3c, 0xd4, 0x18, 0x4f, 0x96, 0x9e, 0x87, 0x44, 0xe3, 0xd3, 0xc9, 0x31, 0xe3, 0x30, - 0xa1, 0x1a, 0x2f, 0xfc, 0xb5, 0x7c, 0x0e, 0xdb, 0xf5, 0x1d, 0xfe, 0x3e, 0xb6, 0x74, 0x3e, 0x63, - 0xe3, 0xff, 0xaa, 0x99, 0x90, 0x3d, 0x5e, 0xf8, 0xd0, 0xe3, 0x61, 0x04, 0x6e, 0x6a, 0x34, 0x02, - 0xf6, 0x6a, 0x75, 0x68, 0xf3, 0x3a, 0x88, 0x34, 0xb1, 0x39, 0xf8, 0x8a, 0x79, 0x91, 0x4f, 0x01, - 0x22, 0xa7, 0x5f, 0x92, 0xf0, 0x2b, 0x55, 0x0b, 0x2a, 0xc3, 0x2f, 0xb8, 0xc3, 0xd7, 0xbb, 0x72, - 0x6c, 0xd5, 0xb7, 0xe4, 0xb8, 0x8f, 0x6d, 0x6c, 0x4b, 0x4e, 0x66, 0xf3, 0x11, 0x34, 0x0e, 0x3c, - 0xef, 0xd9, 0x7c, 0xa6, 0x6e, 0x97, 0xc4, 0xdd, 0xaa, 0xf6, 0xed, 0xe0, 0x7c, 0x33, 0x51, 0x2d, - 0xd2, 0x86, 0x65, 0xc5, 0x22, 0x22, 0xcf, 0xda, 0x38, 0x51, 0x8c, 0x31, 0x24, 0x32, 0x78, 0x90, - 0x23, 0x0f, 0xa1, 0xbe, 0x4b, 0x47, 0x18, 0xea, 0x04, 0x9d, 0x78, 0x56, 0x62, 0x0e, 0x21, 0xdc, - 0xfb, 0x67, 0xb3, 0x11, 0x03, 0x4a, 0x16, 0x17, 0x39, 0x92, 0xe9, 0x7b, 0x46, 0xdc, 0x1b, 0x2b, - 0xc6, 0xe2, 0x52, 0xce, 0x64, 0x5f, 0xc0, 0x72, 0xca, 0x55, 0x4b, 0x71, 0xb7, 0xeb, 0x1c, 0xbc, - 0x36, 0xef, 0x5e, 0x4f, 0x20, 0xf2, 0xfd, 0x1e, 0x34, 0x78, 0x58, 0xef, 0x13, 0xca, 0xaf, 0x2a, - 0x27, 0x82, 0xb6, 0xe9, 0xf7, 0xa0, 0x93, 0x2c, 0x89, 0x27, 0x78, 0x82, 0x0f, 0x02, 0x69, 0x17, - 0x81, 0xd5, 0xb8, 0xa6, 0x2f, 0x27, 0xab, 0x71, 0xcd, 0xba, 0x73, 0xfc, 0x39, 0xd4, 0x9e, 0xd0, - 0x50, 0x5e, 0xad, 0x55, 0xf2, 0x51, 0xe2, 0xae, 0xed, 0x66, 0xc6, 0x85, 0x68, 0xf2, 0x09, 0x26, - 0x55, 0x61, 0x22, 0xd6, 0xb5, 0x52, 0xf4, 0xa4, 0x4b, 0x09, 0x38, 0x93, 0x3e, 0xb4, 0x60, 0x31, - 0xaa, 0xe2, 0xe9, 0xe0, 0x40, 0xaa, 0xe2, 0x59, 0xb1, 0x65, 0x7e, 0x9e, 0xf7, 0x80, 0x76, 0x99, - 0x37, 0x12, 0xc1, 0x92, 0xf7, 0x7e, 0x55, 0xf5, 0x75, 0xf2, 0x47, 0x00, 0x83, 0xd0, 0x9b, 0xed, - 0xda, 0x74, 0xea, 0xb9, 0x11, 0x4f, 0x88, 0xae, 0x91, 0x46, 0x0b, 0x51, 0xbb, 0x4b, 0x4a, 0xbe, - 0xd4, 0x64, 0xd3, 0xd8, 0x90, 0xc8, 0x61, 0xbf, 0xf6, 0xa6, 0xa9, 0x6a, 0x4e, 0xc6, 0x6d, 0x53, - 0x64, 0x12, 0x10, 0x79, 0xc2, 0x29, 0x49, 0x33, 0xe5, 0x64, 0xa7, 0xd6, 0x7a, 0x86, 0xdb, 0xdc, - 0x77, 0xa1, 0x1a, 0xb9, 0x10, 0x6d, 0x44, 0x91, 0xab, 0x62, 0x0e, 0x47, 0x8a, 0x7b, 0xa7, 0xdd, - 0x77, 0x7a, 0xb0, 0xc2, 0xab, 0xa3, 0xb6, 0x3f, 0xbc, 0x5e, 0xa8, 0xde, 0xb3, 0x4a, 0xfb, 0xcd, - 0xa8, 0xf5, 0x93, 0xe5, 0xfd, 0xc1, 0xd6, 0x4f, 0xca, 0x8b, 0x40, 0xad, 0x9f, 0xeb, 0xdc, 0x42, - 0xd4, 0xfa, 0xb9, 0xde, 0x01, 0xa1, 0x07, 0x2b, 0x19, 0xfe, 0x00, 0xe4, 0x0d, 0x79, 0xb0, 0xb9, - 0xd6, 0x57, 0x60, 0x33, 0xd3, 0x6e, 0x4c, 0x86, 0xb0, 0xc1, 0xd3, 0xb4, 0x27, 0x93, 0x84, 0xf9, - 0xf9, 0x75, 0x2d, 0x41, 0x86, 0x49, 0x3d, 0x26, 0xca, 0x24, 0xcc, 0xea, 0x3d, 0x68, 0x26, 0x2d, - 0xb7, 0xe4, 0x7a, 0xf2, 0xcd, 0x3b, 0x31, 0x91, 0x3d, 0x6d, 0xed, 0x25, 0x5f, 0x28, 0xfb, 0x71, - 0xa2, 0x8e, 0x77, 0xa2, 0x77, 0x19, 0x33, 0xad, 0xdd, 0xea, 0x34, 0x90, 0x69, 0x7e, 0x26, 0xbf, - 0x00, 0x1b, 0xc9, 0x19, 0x2d, 0x73, 0xbe, 0x9b, 0xd5, 0x5d, 0xd7, 0x8a, 0x72, 0xf1, 0x06, 0x3d, - 0xc8, 0x31, 0x46, 0xac, 0x5b, 0x79, 0xd5, 0x44, 0xca, 0x30, 0x37, 0xab, 0x89, 0x94, 0x69, 0x16, - 0x3e, 0x82, 0xa5, 0x84, 0x81, 0x57, 0x89, 0xc1, 0xd9, 0x26, 0x61, 0x25, 0x06, 0x5f, 0x67, 0x17, - 0x1e, 0x40, 0x33, 0x69, 0xba, 0x55, 0x63, 0x7d, 0x8d, 0x39, 0x78, 0xf3, 0xce, 0xb5, 0xf8, 0x78, - 0x35, 0x35, 0x23, 0x67, 0xac, 0x9a, 0x69, 0xd3, 0x6c, 0xac, 0x9a, 0x19, 0x26, 0xd6, 0xed, 0x77, - 0x7e, 0xf8, 0xad, 0x33, 0x27, 0x3c, 0x9f, 0x9f, 0x6c, 0x8d, 0xbc, 0xe9, 0x07, 0x13, 0xa9, 0xd5, - 0x10, 0x77, 0xff, 0x3f, 0x98, 0xb8, 0xe3, 0x0f, 0x30, 0x83, 0x93, 0x85, 0x99, 0xef, 0x85, 0xde, - 0x47, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x6d, 0x2d, 0xa4, 0x48, 0x91, 0x00, 0x00, + 0x5c, 0x42, 0x6b, 0x97, 0xb2, 0xae, 0x68, 0x4f, 0x26, 0xc9, 0xbe, 0x7c, 0x00, 0xab, 0x6c, 0x08, + 0xd1, 0xfb, 0x82, 0x63, 0xf4, 0x1d, 0x8d, 0x70, 0x9c, 0x4c, 0x84, 0x1b, 0xdb, 0x7d, 0x58, 0x16, + 0x29, 0x70, 0xd1, 0xea, 0x71, 0xb7, 0x96, 0x38, 0x02, 0x9d, 0x20, 0x19, 0xad, 0x71, 0x0b, 0x6e, + 0x66, 0x94, 0x2c, 0xf4, 0x60, 0xbf, 0x99, 0x83, 0xb5, 0x36, 0x8f, 0x2f, 0xf3, 0x8d, 0xdd, 0x98, + 0xfe, 0x1c, 0x6e, 0xaa, 0x0b, 0x0d, 0xda, 0x45, 0x4c, 0xbd, 0x92, 0xf2, 0x2e, 0x84, 0x76, 0x8d, + 0x07, 0xeb, 0xda, 0x82, 0xf5, 0x64, 0x6d, 0x44, 0x45, 0xf7, 0x60, 0x79, 0x97, 0x9e, 0xcc, 0xcf, + 0x0e, 0xe8, 0x45, 0x54, 0x47, 0x02, 0xc5, 0xe0, 0xdc, 0x7b, 0x2e, 0x3a, 0x0a, 0x7f, 0xa3, 0xc7, + 0x33, 0xa3, 0xb1, 0x82, 0x19, 0x1d, 0x49, 0x3b, 0x0a, 0x42, 0x06, 0x33, 0x3a, 0x32, 0x1e, 0x01, + 0xd1, 0xf3, 0x11, 0x73, 0x84, 0x1d, 0x2b, 0xe7, 0x27, 0x56, 0x70, 0x15, 0x84, 0x74, 0x2a, 0x2f, + 0x19, 0x43, 0x30, 0x3f, 0x19, 0x70, 0x88, 0xf1, 0x0e, 0xd4, 0x8f, 0xec, 0x2b, 0x93, 0xfe, 0x48, + 0xdc, 0xe5, 0xdd, 0x80, 0xf2, 0xcc, 0xbe, 0x62, 0x1b, 0x81, 0x32, 0xa9, 0x22, 0xda, 0xf8, 0xbd, + 0x22, 0x2c, 0x70, 0x4a, 0x72, 0x97, 0x3f, 0xa2, 0xe1, 0xb8, 0xc8, 0x88, 0xe5, 0x96, 0xa8, 0x81, + 0x52, 0xbb, 0x66, 0x3e, 0xbd, 0x6b, 0x0a, 0xfd, 0xaf, 0x0c, 0x5e, 0x28, 0x8d, 0x5f, 0xee, 0x7c, + 0x2a, 0x23, 0x16, 0xc6, 0xa3, 0xa9, 0x14, 0xa3, 0xc7, 0x57, 0x78, 0x24, 0x89, 0xb8, 0x7b, 0x42, + 0x74, 0x78, 0xe5, 0xb5, 0x93, 0xc2, 0x80, 0xd8, 0x30, 0x75, 0x50, 0xe6, 0x09, 0xb9, 0x2c, 0x2f, + 0xa8, 0xc7, 0x4f, 0xc8, 0xa9, 0x93, 0x70, 0xe5, 0xe5, 0x27, 0x61, 0xae, 0x18, 0x7e, 0xc1, 0x49, + 0x18, 0x5e, 0xe1, 0x24, 0xfc, 0x0a, 0xae, 0x01, 0x37, 0xa1, 0x82, 0x12, 0x9e, 0xb6, 0x7f, 0x32, + 0xc9, 0x8e, 0xed, 0x9f, 0x9f, 0x6a, 0x67, 0x45, 0xee, 0x97, 0xa4, 0x6d, 0x60, 0x26, 0xfd, 0xd1, + 0xcf, 0x46, 0xd7, 0xf8, 0x15, 0x94, 0x05, 0x94, 0x4d, 0x68, 0xd7, 0x9e, 0xca, 0x10, 0xbd, 0xf8, + 0x9b, 0x75, 0x1b, 0x06, 0xad, 0xfc, 0xd1, 0xdc, 0xf1, 0xe9, 0x58, 0x86, 0xce, 0x73, 0x90, 0x7b, + 0x30, 0x08, 0x6b, 0x20, 0x3b, 0xb7, 0xba, 0x32, 0xc4, 0x7e, 0xc5, 0x2c, 0x3b, 0xc1, 0x53, 0xf6, + 0x69, 0x10, 0x68, 0x62, 0x90, 0xf1, 0x99, 0xe7, 0x4b, 0xf1, 0xc4, 0xf8, 0xfd, 0x1c, 0x34, 0xc5, + 0xea, 0x52, 0x38, 0xfd, 0x4c, 0x58, 0xba, 0xce, 0x8d, 0xe6, 0xc5, 0x81, 0xf0, 0x0c, 0x68, 0xa0, + 0xb6, 0x4c, 0xc9, 0x2a, 0x5c, 0xdb, 0x57, 0x63, 0xc0, 0x3d, 0x21, 0xaf, 0xbc, 0x0e, 0x35, 0x79, + 0x1f, 0x63, 0xea, 0x4c, 0xe4, 0x3b, 0x4b, 0xfc, 0x42, 0xc6, 0xa1, 0x33, 0x91, 0xa2, 0x8e, 0x6f, + 0x8b, 0x80, 0x09, 0x39, 0x14, 0x75, 0x4c, 0x3b, 0xa4, 0xc6, 0x1f, 0xe6, 0x60, 0x59, 0x6b, 0x8a, + 0x58, 0xb7, 0xdf, 0x81, 0xba, 0x7a, 0xfa, 0x80, 0x2a, 0x19, 0x7b, 0x23, 0xce, 0xa3, 0xa2, 0x64, + 0xb5, 0x91, 0x82, 0x04, 0xac, 0x32, 0x63, 0xfb, 0x8a, 0x5f, 0x1a, 0x98, 0x4f, 0xe5, 0x51, 0x77, + 0x6c, 0x5f, 0xed, 0x51, 0x3a, 0x98, 0x4f, 0xc9, 0x5d, 0xa8, 0x3f, 0xa7, 0xf4, 0x99, 0x22, 0xe0, + 0x8c, 0x1d, 0x18, 0x4c, 0x50, 0x18, 0xd0, 0x98, 0x7a, 0x6e, 0x78, 0xae, 0x48, 0xc4, 0xf9, 0x02, + 0x81, 0x9c, 0xc6, 0xf8, 0xe3, 0x3c, 0xac, 0x70, 0x9d, 0xac, 0xd0, 0xcc, 0x0b, 0xd6, 0xd5, 0x82, + 0x05, 0xae, 0x28, 0xe7, 0xcc, 0x6b, 0xff, 0x86, 0x29, 0xbe, 0xc9, 0xc7, 0xaf, 0xa8, 0x47, 0x96, + 0x31, 0x19, 0xae, 0xe9, 0xfe, 0x42, 0xba, 0xfb, 0xaf, 0xef, 0xde, 0x2c, 0x3b, 0x7d, 0x29, 0xcb, + 0x4e, 0xff, 0x2a, 0xd6, 0xf1, 0x54, 0xf4, 0x80, 0x72, 0x3a, 0xea, 0xee, 0x23, 0xd8, 0x88, 0xd1, + 0x20, 0xb7, 0x76, 0x4e, 0x1d, 0x15, 0xd2, 0x7d, 0x55, 0xa3, 0x1e, 0x48, 0xdc, 0x76, 0x19, 0x4a, + 0xc1, 0xc8, 0x9b, 0x51, 0x63, 0x1d, 0x56, 0xe3, 0xbd, 0x2a, 0xb6, 0x89, 0xdf, 0xc9, 0x41, 0x6b, + 0x2f, 0x0a, 0x5f, 0xec, 0x04, 0xa1, 0xe7, 0xab, 0x28, 0xf8, 0xb7, 0x01, 0xf8, 0x9b, 0x4f, 0xa8, + 0x59, 0x10, 0x71, 0xa7, 0x10, 0x82, 0x7a, 0x85, 0x9b, 0x50, 0xa1, 0xee, 0x98, 0x23, 0xf9, 0x6c, + 0x28, 0x53, 0x77, 0x2c, 0xb5, 0x12, 0xa9, 0x4d, 0xbe, 0x11, 0x17, 0x5f, 0x44, 0x04, 0x15, 0xd6, + 0x3b, 0xf4, 0x02, 0x85, 0x8d, 0xa2, 0x8a, 0xa0, 0x72, 0x68, 0x5f, 0xa2, 0xc3, 0x79, 0x60, 0xfc, + 0x56, 0x1e, 0x96, 0xa2, 0xfa, 0xf1, 0x18, 0x52, 0x2f, 0x8e, 0x86, 0x75, 0x57, 0x4c, 0x07, 0x87, + 0x9d, 0xd4, 0x34, 0x4d, 0x75, 0x85, 0x2f, 0xce, 0xae, 0x4b, 0x0c, 0xa8, 0x49, 0x0a, 0x6f, 0x1e, + 0x6a, 0x91, 0x82, 0xab, 0x9c, 0xa4, 0x3f, 0x0f, 0xd9, 0xd1, 0xda, 0x9e, 0x32, 0x49, 0x45, 0x1c, + 0x6e, 0x4b, 0xf6, 0x34, 0xec, 0xe2, 0xc3, 0x62, 0x0c, 0xcc, 0x92, 0xf1, 0x81, 0x64, 0x54, 0x8c, + 0xbe, 0xc9, 0x4f, 0x5a, 0x7c, 0xe4, 0xf0, 0x94, 0xa5, 0x1f, 0x43, 0xf8, 0x5b, 0x28, 0xea, 0x18, + 0xf2, 0x3a, 0xd4, 0x78, 0xe6, 0x51, 0xb0, 0x08, 0x0c, 0xdb, 0x17, 0x76, 0x5d, 0xc4, 0x0b, 0xad, + 0xa1, 0x37, 0x8f, 0x29, 0x42, 0x80, 0x17, 0x85, 0x4e, 0x4b, 0xbf, 0x99, 0x83, 0x9b, 0x19, 0xc3, + 0x26, 0x56, 0xf9, 0x0e, 0x68, 0x41, 0xac, 0x65, 0xef, 0xf2, 0xa5, 0xbe, 0x2e, 0xd9, 0x6a, 0xbc, + 0x4f, 0xcd, 0xe6, 0x69, 0x1c, 0x10, 0x1d, 0xaf, 0xf9, 0x08, 0xc6, 0x42, 0x91, 0xa0, 0xb0, 0xc6, + 0x87, 0x91, 0x9f, 0x6c, 0x8f, 0x60, 0xb3, 0x73, 0xc9, 0x38, 0x86, 0x72, 0x42, 0x1f, 0x3d, 0x9b, + 0x4b, 0x5b, 0x62, 0xc2, 0x22, 0x91, 0x7b, 0x25, 0x8b, 0xc4, 0x98, 0x07, 0x0a, 0x50, 0x79, 0xfd, + 0x24, 0x99, 0xe0, 0x06, 0xca, 0xd2, 0x9c, 0x60, 0x16, 0x32, 0x26, 0x09, 0x03, 0xf1, 0x4c, 0x8d, + 0x00, 0x96, 0x0e, 0xe7, 0x93, 0xd0, 0xd9, 0x51, 0x20, 0xf2, 0xb1, 0x48, 0x83, 0xe5, 0xc8, 0x5e, + 0xcb, 0x2c, 0x08, 0x54, 0x41, 0xd8, 0x59, 0x53, 0x96, 0x91, 0x95, 0x2e, 0x6f, 0x69, 0x1a, 0x2f, + 0xc1, 0xb8, 0x09, 0x1b, 0xd1, 0x17, 0xef, 0x36, 0xb9, 0xd5, 0xfc, 0xfd, 0x1c, 0xbf, 0xdd, 0xc2, + 0x71, 0x03, 0xd7, 0x9e, 0x05, 0xe7, 0x5e, 0x48, 0x3a, 0xb0, 0x12, 0x38, 0xee, 0xd9, 0x84, 0xea, + 0xd9, 0x07, 0xa2, 0x13, 0xd6, 0xe2, 0x75, 0xe3, 0x49, 0x03, 0x73, 0x99, 0xa7, 0x88, 0x72, 0x0b, + 0xc8, 0xf6, 0x75, 0x95, 0x8c, 0xa6, 0x45, 0xa2, 0x37, 0xd2, 0x95, 0xef, 0xc2, 0x62, 0xbc, 0x20, + 0xf2, 0xa9, 0x88, 0xaf, 0x11, 0xd5, 0xaa, 0x90, 0x88, 0x2e, 0x10, 0x4d, 0x88, 0x5a, 0xd4, 0xf7, + 0x81, 0xf1, 0xd7, 0x73, 0xd0, 0x32, 0x29, 0x9b, 0xb9, 0x5a, 0x2d, 0xe5, 0x9c, 0xf9, 0x4e, 0x2a, + 0xd7, 0xeb, 0xdb, 0x2a, 0xc3, 0x76, 0xc8, 0x1a, 0xbd, 0x77, 0xed, 0x60, 0xec, 0xdf, 0x48, 0xb5, + 0x68, 0xbb, 0x02, 0x0b, 0x9c, 0xc4, 0xd8, 0x80, 0x35, 0x51, 0x1f, 0x59, 0x97, 0xc8, 0xf8, 0x1d, + 0x2b, 0x31, 0x66, 0xfc, 0xde, 0x84, 0x16, 0xbf, 0x06, 0xaf, 0x37, 0x42, 0x24, 0xdc, 0x05, 0x72, + 0x68, 0x8f, 0x6c, 0xdf, 0xf3, 0xdc, 0x23, 0xea, 0x0b, 0xf7, 0x72, 0x94, 0x30, 0xd1, 0x36, 0x2c, + 0x45, 0x61, 0xfe, 0x25, 0xe3, 0xa3, 0x7b, 0xae, 0xf4, 0xa6, 0xe3, 0x5f, 0x86, 0x0f, 0x2b, 0xdb, + 0xf6, 0x33, 0x2a, 0x73, 0x92, 0x5d, 0xf4, 0x18, 0x6a, 0x33, 0x95, 0xa9, 0xec, 0x77, 0x19, 0x92, + 0x28, 0x5d, 0xac, 0xa9, 0x53, 0x33, 0x16, 0xe4, 0x7b, 0x5e, 0x88, 0xa1, 0x3d, 0xa4, 0x41, 0xcf, + 0xac, 0x32, 0xd0, 0x53, 0x7a, 0xd5, 0x1d, 0x1b, 0x0f, 0x61, 0x35, 0x5e, 0xa6, 0x60, 0x2d, 0x9b, + 0x50, 0x99, 0x0a, 0x98, 0xa8, 0xbd, 0xfa, 0x66, 0x87, 0x11, 0x76, 0xa0, 0x94, 0x69, 0xba, 0xbb, + 0xea, 0x46, 0xfb, 0x63, 0xd8, 0x48, 0x61, 0x44, 0x86, 0x77, 0xa1, 0xae, 0x55, 0x84, 0x37, 0xa3, + 0xc8, 0x44, 0x56, 0x51, 0x93, 0xc0, 0xf8, 0x1c, 0x36, 0xf8, 0x79, 0x2c, 0x4a, 0x2e, 0xbb, 0x20, + 0xd1, 0x8a, 0x5c, 0xb2, 0x15, 0x1f, 0xcb, 0x43, 0xa4, 0x9e, 0x34, 0x0a, 0xf5, 0x37, 0x46, 0x9c, + 0x74, 0x88, 0x92, 0x9f, 0xc6, 0x31, 0xac, 0xa7, 0xbb, 0x8f, 0xd5, 0xff, 0xa7, 0xea, 0x72, 0xd9, + 0x3d, 0x11, 0x5a, 0x75, 0xcf, 0x7f, 0xcd, 0xf1, 0xfe, 0x89, 0xa1, 0x44, 0x35, 0xc7, 0x40, 0xa6, + 0x34, 0x3c, 0xf7, 0xc6, 0x56, 0xba, 0xe4, 0x47, 0xca, 0x1f, 0x2b, 0x33, 0xed, 0xd6, 0x21, 0x26, + 0xd4, 0x30, 0xe2, 0x66, 0xc0, 0x34, 0x09, 0xdf, 0x1c, 0xc1, 0x7a, 0x36, 0x71, 0x86, 0x17, 0xd3, + 0x47, 0x71, 0x41, 0xfd, 0xf6, 0xb5, 0xcd, 0x67, 0xd5, 0xd2, 0xe5, 0xf6, 0xdf, 0xae, 0x40, 0x59, + 0xe8, 0x60, 0xc8, 0x16, 0x14, 0x47, 0xd2, 0x23, 0x36, 0x0a, 0xf7, 0x28, 0xb0, 0xf2, 0xff, 0x0e, + 0xfa, 0xc5, 0x32, 0x3a, 0xf2, 0x18, 0x16, 0xe3, 0x4e, 0x21, 0x89, 0x30, 0x2f, 0x71, 0x6f, 0x8e, + 0xc6, 0x28, 0x61, 0x70, 0xaf, 0x46, 0xc2, 0x15, 0x97, 0x39, 0x2b, 0xe7, 0x9a, 0xf4, 0xe5, 0xb9, + 0xec, 0xbc, 0x16, 0x9c, 0xdb, 0xd6, 0xc3, 0x47, 0x9f, 0x88, 0x38, 0x2f, 0x35, 0x04, 0x0e, 0xce, + 0xed, 0x87, 0x8f, 0x3e, 0x49, 0x9e, 0xc4, 0x44, 0x94, 0x17, 0xed, 0x24, 0xb6, 0x0a, 0x25, 0x1e, + 0x44, 0x9e, 0xbb, 0x36, 0xf2, 0x0f, 0xa9, 0xa7, 0x98, 0xfb, 0xd4, 0x12, 0x97, 0x50, 0xf8, 0x2e, + 0xca, 0xdf, 0xd0, 0x22, 0x02, 0x37, 0x40, 0x14, 0xd7, 0x13, 0xae, 0xc3, 0xc2, 0x79, 0xf4, 0x2a, + 0x40, 0xc3, 0x14, 0x5f, 0xc6, 0x1f, 0x97, 0xa0, 0xa6, 0x75, 0x0a, 0xa9, 0x43, 0xc5, 0xec, 0x0c, + 0x3a, 0xe6, 0x17, 0x9d, 0xdd, 0xe6, 0x0d, 0x72, 0x0f, 0xde, 0xea, 0xf6, 0x76, 0xfa, 0xa6, 0xd9, + 0xd9, 0x19, 0x5a, 0x7d, 0xd3, 0x92, 0x51, 0x48, 0x8f, 0xda, 0x5f, 0x1d, 0x76, 0x7a, 0x43, 0x6b, + 0xb7, 0x33, 0x6c, 0x77, 0x0f, 0x06, 0xcd, 0x1c, 0x79, 0x0d, 0x5a, 0x11, 0xa5, 0x44, 0xb7, 0x0f, + 0xfb, 0xc7, 0xbd, 0x61, 0x33, 0x4f, 0xee, 0xc0, 0xad, 0xbd, 0x6e, 0xaf, 0x7d, 0x60, 0x45, 0x34, + 0x3b, 0x07, 0xc3, 0x2f, 0xac, 0xce, 0x2f, 0x1c, 0x75, 0xcd, 0xaf, 0x9a, 0x85, 0x2c, 0x82, 0xfd, + 0xe1, 0xc1, 0x8e, 0xcc, 0xa1, 0x48, 0x6e, 0xc2, 0x1a, 0x27, 0xe0, 0x49, 0xac, 0x61, 0xbf, 0x6f, + 0x0d, 0xfa, 0xfd, 0x5e, 0xb3, 0x44, 0x96, 0xa1, 0xd1, 0xed, 0x7d, 0xd1, 0x3e, 0xe8, 0xee, 0x5a, + 0x66, 0xa7, 0x7d, 0x70, 0xd8, 0x5c, 0x20, 0x2b, 0xb0, 0x94, 0xa4, 0x2b, 0xb3, 0x2c, 0x24, 0x5d, + 0xbf, 0xd7, 0xed, 0xf7, 0xac, 0x2f, 0x3a, 0xe6, 0xa0, 0xdb, 0xef, 0x35, 0x2b, 0x64, 0x1d, 0x48, + 0x1c, 0xb5, 0x7f, 0xd8, 0xde, 0x69, 0x56, 0xc9, 0x1a, 0x2c, 0xc7, 0xe1, 0x4f, 0x3b, 0x5f, 0x35, + 0x81, 0xb4, 0x60, 0x95, 0x57, 0xcc, 0xda, 0xee, 0x1c, 0xf4, 0xbf, 0xb4, 0x0e, 0xbb, 0xbd, 0xee, + 0xe1, 0xf1, 0x61, 0xb3, 0x86, 0xb1, 0xa0, 0x3b, 0x1d, 0xab, 0xdb, 0x1b, 0x1c, 0xef, 0xed, 0x75, + 0x77, 0xba, 0x9d, 0xde, 0xb0, 0x59, 0xe7, 0x25, 0x67, 0x35, 0xbc, 0xc1, 0x12, 0x88, 0x6b, 0x87, + 0xd6, 0x6e, 0x77, 0xd0, 0xde, 0x3e, 0xe8, 0xec, 0x36, 0x17, 0xc9, 0x6d, 0xb8, 0x39, 0xec, 0x1c, + 0x1e, 0xf5, 0xcd, 0xb6, 0xf9, 0x95, 0xbc, 0x96, 0x68, 0xed, 0xb5, 0xbb, 0x07, 0xc7, 0x66, 0xa7, + 0xb9, 0x44, 0xde, 0x80, 0xdb, 0x66, 0xe7, 0x07, 0xc7, 0x5d, 0xb3, 0xb3, 0x6b, 0xf5, 0xfa, 0xbb, + 0x1d, 0x6b, 0xaf, 0xd3, 0x1e, 0x1e, 0x9b, 0x1d, 0xeb, 0xb0, 0x3b, 0x18, 0x74, 0x7b, 0x4f, 0x9a, + 0x4d, 0xf2, 0x16, 0xdc, 0x55, 0x24, 0x2a, 0x83, 0x04, 0xd5, 0x32, 0x6b, 0x9f, 0x1c, 0xd2, 0x5e, + 0xe7, 0x17, 0x86, 0xd6, 0x51, 0xa7, 0x63, 0x36, 0x09, 0xd9, 0x84, 0xf5, 0xa8, 0x78, 0x5e, 0x80, + 0x28, 0x7b, 0x85, 0xe1, 0x8e, 0x3a, 0xe6, 0x61, 0xbb, 0xc7, 0x06, 0x38, 0x86, 0x5b, 0x65, 0xd5, + 0x8e, 0x70, 0xc9, 0x6a, 0xaf, 0x11, 0x02, 0x8b, 0xda, 0xa8, 0xec, 0xb5, 0xcd, 0xe6, 0x3a, 0x59, + 0x82, 0xda, 0xe1, 0xd1, 0x91, 0x35, 0xec, 0x1e, 0x76, 0xfa, 0xc7, 0xc3, 0xe6, 0x06, 0x59, 0x83, + 0x66, 0xb7, 0x37, 0xec, 0x98, 0x6c, 0xac, 0x65, 0xd2, 0xff, 0x56, 0x26, 0xab, 0xb0, 0x24, 0x6b, + 0x2a, 0xa1, 0x7f, 0x56, 0x26, 0x1b, 0x40, 0x8e, 0x7b, 0x66, 0xa7, 0xbd, 0xcb, 0x3a, 0x4e, 0x21, + 0xfe, 0x7b, 0x59, 0xd8, 0x5b, 0x7f, 0xbf, 0xa0, 0x84, 0xbd, 0xc8, 0xe3, 0x2a, 0xfe, 0x8c, 0x4f, + 0x5d, 0x7b, 0x7e, 0xe7, 0x65, 0xaf, 0x27, 0x6a, 0x47, 0xf3, 0x42, 0xea, 0x68, 0x9e, 0xd2, 0xfd, + 0x34, 0xf4, 0xb3, 0xc3, 0x9b, 0xd0, 0x98, 0xf2, 0x27, 0x7d, 0xc4, 0x9b, 0x10, 0x20, 0xdc, 0x0f, + 0x39, 0x90, 0x3f, 0x08, 0x91, 0x7a, 0x3e, 0xb0, 0x94, 0x7e, 0x3e, 0x30, 0xeb, 0x7c, 0xb8, 0x90, + 0x75, 0x3e, 0xbc, 0x0f, 0xcb, 0x9c, 0x35, 0x39, 0xae, 0x33, 0x95, 0x5a, 0x17, 0xf1, 0x18, 0x1f, + 0xb2, 0x28, 0x0e, 0x97, 0xc7, 0x51, 0x79, 0x64, 0x15, 0x2c, 0xa4, 0x2c, 0x4e, 0xab, 0xb1, 0x93, + 0x2a, 0xe7, 0x1c, 0xea, 0xa4, 0xaa, 0x4a, 0xb0, 0x2f, 0xa3, 0x12, 0x6a, 0x5a, 0x09, 0x1c, 0x8e, + 0x25, 0xdc, 0x87, 0x65, 0x7a, 0x19, 0xfa, 0xb6, 0xe5, 0xcd, 0xec, 0x1f, 0xcd, 0xd1, 0x67, 0xc4, + 0x46, 0x1d, 0x50, 0xdd, 0x5c, 0x42, 0x44, 0x1f, 0xe1, 0xbb, 0x76, 0x68, 0x1b, 0xbf, 0x04, 0xa0, + 0x76, 0x55, 0x7c, 0xd4, 0xd0, 0xf5, 0xe4, 0x25, 0xd3, 0xba, 0xc9, 0x3f, 0x70, 0x1c, 0x43, 0xcf, + 0xb7, 0xcf, 0x68, 0x57, 0x86, 0x4a, 0x8a, 0x00, 0xe4, 0x16, 0x14, 0xbc, 0x99, 0x74, 0xce, 0xab, + 0xca, 0x20, 0xe7, 0x33, 0x93, 0x41, 0x8d, 0x4f, 0x20, 0xdf, 0x9f, 0x5d, 0x2b, 0x2a, 0xb5, 0xa0, + 0x2c, 0x1f, 0x0c, 0xce, 0xa3, 0x43, 0x9e, 0xfc, 0xbc, 0xff, 0x97, 0xa1, 0xa6, 0xbd, 0x42, 0x45, + 0x36, 0x60, 0xe5, 0xcb, 0xee, 0xb0, 0xd7, 0x19, 0x0c, 0xac, 0xa3, 0xe3, 0xed, 0xa7, 0x9d, 0xaf, + 0xac, 0xfd, 0xf6, 0x60, 0xbf, 0x79, 0x83, 0xf1, 0x92, 0x5e, 0x67, 0x30, 0xec, 0xec, 0xc6, 0xe0, + 0x39, 0xf2, 0x3a, 0x6c, 0x1e, 0xf7, 0x8e, 0x07, 0x9d, 0x5d, 0x2b, 0x2b, 0x5d, 0x9e, 0x2d, 0x1e, + 0x81, 0xcf, 0x48, 0x5e, 0xb8, 0xff, 0xcb, 0xb0, 0x18, 0x0f, 0x1c, 0x42, 0x00, 0x16, 0x0e, 0x3a, + 0x4f, 0xda, 0x3b, 0x5f, 0xf1, 0x20, 0xf6, 0x83, 0x61, 0x7b, 0xd8, 0xdd, 0xb1, 0x44, 0xd0, 0x7a, + 0xc6, 0xa8, 0x72, 0xa4, 0x06, 0xe5, 0x76, 0x6f, 0x67, 0xbf, 0x6f, 0x0e, 0x9a, 0x79, 0xf2, 0x1a, + 0x6c, 0xc8, 0x25, 0xb4, 0xd3, 0x3f, 0x3c, 0xec, 0x0e, 0x91, 0x47, 0x0f, 0xbf, 0x3a, 0x62, 0x2b, + 0xe6, 0xbe, 0x0d, 0xd5, 0x28, 0xde, 0x3e, 0xf2, 0xbd, 0xee, 0xb0, 0xdb, 0x1e, 0x46, 0x4c, 0xbf, + 0x79, 0x83, 0xb1, 0xd5, 0x08, 0x8c, 0x41, 0xf3, 0x9b, 0x39, 0x7e, 0xb7, 0x5a, 0x02, 0x79, 0xe9, + 0xcd, 0x3c, 0x5b, 0xeb, 0x11, 0x74, 0xbb, 0x3f, 0x64, 0x4d, 0xf8, 0x15, 0x58, 0x8c, 0x87, 0xb5, + 0x27, 0x4d, 0xa8, 0xb3, 0xf2, 0xb5, 0x22, 0x00, 0x16, 0x78, 0x8d, 0x9b, 0x39, 0xce, 0xd8, 0x77, + 0xfa, 0x87, 0xdd, 0xde, 0x13, 0xdc, 0x0d, 0x9a, 0x79, 0x06, 0xea, 0x1f, 0x0f, 0x9f, 0xf4, 0x15, + 0xa8, 0xc0, 0x52, 0xf0, 0xe6, 0x34, 0x8b, 0xf7, 0x7f, 0x04, 0xcb, 0xa9, 0x00, 0xf8, 0xac, 0xd6, + 0xfd, 0xe3, 0xe1, 0x4e, 0xff, 0x50, 0x2f, 0xa7, 0x06, 0xe5, 0x9d, 0x83, 0x76, 0xf7, 0x10, 0xcd, + 0x2c, 0x0d, 0xa8, 0x1e, 0xf7, 0xe4, 0x67, 0x3e, 0x1e, 0xba, 0xbf, 0xc0, 0x58, 0xd4, 0x5e, 0xd7, + 0x1c, 0x0c, 0xad, 0xc1, 0xb0, 0xfd, 0xa4, 0xd3, 0x2c, 0xb2, 0xb4, 0x92, 0x5f, 0x95, 0xee, 0x7f, + 0x0e, 0x8b, 0x71, 0x4f, 0xf2, 0xb8, 0xf5, 0x6c, 0x13, 0xd6, 0xb7, 0x3b, 0xc3, 0x2f, 0x3b, 0x9d, + 0x1e, 0x0e, 0xf9, 0x4e, 0xa7, 0x37, 0x34, 0xdb, 0x07, 0xdd, 0xe1, 0x57, 0xcd, 0xdc, 0xfd, 0xc7, + 0xd0, 0x4c, 0x7a, 0x41, 0xc4, 0xdc, 0x46, 0x5e, 0xe4, 0x5f, 0x72, 0xff, 0x3f, 0xe4, 0x60, 0x35, + 0xcb, 0xb8, 0xc7, 0x26, 0xa6, 0x60, 0x84, 0x6c, 0x3b, 0x1c, 0xf4, 0x7b, 0x56, 0xaf, 0x8f, 0xa1, + 0xab, 0x37, 0x61, 0x3d, 0x81, 0x90, 0xad, 0xc8, 0x91, 0x5b, 0xb0, 0x91, 0x4a, 0x64, 0x99, 0xfd, + 0x63, 0x1c, 0xcb, 0x16, 0xac, 0x26, 0x90, 0x1d, 0xd3, 0xec, 0x9b, 0xcd, 0x02, 0x79, 0x0f, 0xee, + 0x25, 0x30, 0x69, 0x21, 0x40, 0xca, 0x08, 0x45, 0xf2, 0x0e, 0xbc, 0x99, 0xa2, 0x8e, 0xf6, 0x49, + 0x6b, 0xbb, 0x7d, 0xc0, 0x9a, 0xd7, 0x2c, 0xdd, 0xff, 0xc3, 0x22, 0x40, 0x74, 0x55, 0x93, 0x95, + 0xbf, 0xdb, 0x1e, 0xb6, 0x0f, 0xfa, 0x6c, 0xcd, 0x98, 0xfd, 0x21, 0xcb, 0xdd, 0xec, 0xfc, 0xa0, + 0x79, 0x23, 0x13, 0xd3, 0x3f, 0x62, 0x0d, 0xda, 0x80, 0x15, 0x3e, 0xff, 0x0e, 0x58, 0x33, 0xd8, + 0x74, 0xe1, 0x51, 0xd0, 0x99, 0xa4, 0x71, 0x7c, 0xb4, 0x67, 0xf6, 0x7b, 0x43, 0x6b, 0xb0, 0x7f, + 0x3c, 0xdc, 0xc5, 0xa0, 0xea, 0x3b, 0x66, 0xf7, 0x88, 0xe7, 0x59, 0x7c, 0x11, 0x01, 0xcb, 0xba, + 0xc4, 0x16, 0xf8, 0x93, 0xfe, 0x60, 0xd0, 0x3d, 0xb2, 0x7e, 0x70, 0xdc, 0x31, 0xbb, 0x9d, 0x01, + 0x26, 0x5c, 0xc8, 0x80, 0x33, 0xfa, 0x32, 0x9b, 0xb3, 0xc3, 0x83, 0x2f, 0x84, 0x00, 0xc1, 0x48, + 0x2b, 0x71, 0x10, 0xa3, 0xaa, 0xb2, 0xd1, 0x61, 0x3b, 0x70, 0x46, 0xce, 0x70, 0x0d, 0x8e, 0xa5, + 0xab, 0x31, 0xd9, 0x22, 0xb5, 0xf2, 0x31, 0x59, 0x3d, 0x1b, 0xc5, 0x52, 0xa1, 0xd8, 0xa1, 0x84, + 0xb4, 0xdd, 0x5d, 0x13, 0x13, 0x2c, 0xa6, 0xa0, 0x8c, 0x76, 0x89, 0x4d, 0x42, 0xb6, 0x45, 0x33, + 0x92, 0xa6, 0xfc, 0x60, 0x98, 0x65, 0xd6, 0xe2, 0x2f, 0x8f, 0x0f, 0xb7, 0xfb, 0x72, 0xaf, 0xe7, + 0xf5, 0x25, 0x19, 0x70, 0x46, 0xbf, 0x82, 0x51, 0xeb, 0x39, 0x3b, 0x42, 0xc2, 0x55, 0x1d, 0xc0, + 0x28, 0xd6, 0x18, 0x13, 0x94, 0x80, 0x1f, 0x76, 0xcc, 0xbe, 0xc5, 0x84, 0x29, 0x14, 0x04, 0x19, + 0xfd, 0xfa, 0xf5, 0x68, 0x96, 0x7a, 0xe3, 0xe1, 0xbf, 0x78, 0x03, 0xaa, 0xea, 0x0a, 0x09, 0xf9, + 0x3e, 0x34, 0x62, 0x01, 0x1a, 0x88, 0x34, 0x29, 0x64, 0xc5, 0x73, 0xd8, 0x7c, 0x2d, 0x1b, 0x29, + 0x0e, 0x4b, 0x87, 0x9a, 0x76, 0x82, 0x67, 0xf6, 0x5a, 0x52, 0x63, 0x10, 0xcb, 0xed, 0xf6, 0x35, + 0x58, 0x91, 0xdd, 0x53, 0x0c, 0x10, 0xaf, 0xbf, 0x86, 0x4f, 0x6e, 0x47, 0xd1, 0xba, 0x33, 0x5e, + 0xc9, 0xdf, 0xbc, 0x99, 0x7e, 0xb7, 0x5e, 0x3e, 0x74, 0xbf, 0x0b, 0x35, 0xed, 0x1d, 0x53, 0x72, + 0xf3, 0xda, 0x37, 0x57, 0x37, 0x37, 0xb3, 0x50, 0xa2, 0x4a, 0xdf, 0x85, 0xaa, 0x7a, 0x3f, 0x92, + 0x6c, 0x68, 0xef, 0x91, 0xea, 0xef, 0x69, 0x6e, 0xb6, 0xd2, 0x08, 0x91, 0x7e, 0x17, 0x6a, 0xda, + 0x33, 0x90, 0xaa, 0x16, 0xe9, 0xa7, 0x26, 0x55, 0x2d, 0xb2, 0x5e, 0x8d, 0x3c, 0x80, 0x35, 0xa1, + 0x03, 0x39, 0xa1, 0x5f, 0xa7, 0x7b, 0x32, 0x9e, 0xf5, 0x7f, 0x90, 0x23, 0x8f, 0xa1, 0x22, 0x9f, + 0x0e, 0x25, 0xeb, 0xd9, 0x4f, 0xac, 0x6e, 0x6e, 0xa4, 0xe0, 0xa2, 0x2a, 0x6d, 0x80, 0xe8, 0x81, + 0x49, 0x22, 0x1b, 0x9e, 0x7a, 0xb0, 0x52, 0x8d, 0x4c, 0xc6, 0x6b, 0x94, 0xbb, 0x50, 0xd3, 0xde, + 0x92, 0x54, 0x7d, 0x92, 0x7e, 0x87, 0x52, 0xf5, 0x49, 0xd6, 0xd3, 0x93, 0xdf, 0x87, 0x46, 0xec, + 0x51, 0x48, 0x35, 0x8f, 0xb3, 0x9e, 0x9c, 0x54, 0xf3, 0x38, 0xfb, 0x1d, 0xc9, 0x5d, 0xa8, 0x69, + 0x0f, 0x35, 0xaa, 0x1a, 0xa5, 0x5f, 0x8b, 0x54, 0x35, 0xca, 0x78, 0xd7, 0x91, 0xad, 0x86, 0xf8, + 0x2b, 0x8d, 0x6a, 0x35, 0x64, 0x3e, 0xf7, 0xa8, 0x56, 0x43, 0xf6, 0xd3, 0x8e, 0x6c, 0xea, 0xa9, + 0x97, 0x21, 0xc8, 0x46, 0x4c, 0xf5, 0x10, 0x3d, 0x31, 0xa1, 0xa6, 0x5e, 0xfa, 0x11, 0x89, 0x27, + 0xb0, 0xa2, 0x26, 0x8d, 0x7a, 0xd7, 0x21, 0x50, 0x75, 0xca, 0x7c, 0x3d, 0x62, 0xb3, 0x99, 0xc4, + 0x3e, 0xc8, 0x91, 0xcf, 0xa0, 0x2c, 0x82, 0xe5, 0x93, 0xb5, 0x64, 0xf0, 0x7c, 0x5e, 0x89, 0xf5, + 0xec, 0x98, 0xfa, 0xe4, 0x08, 0x17, 0xb4, 0x1e, 0xcd, 0x5e, 0x9f, 0xb1, 0x19, 0x01, 0xf0, 0x37, + 0x5f, 0xbf, 0x0e, 0x1d, 0xe5, 0x98, 0x7c, 0x81, 0xe1, 0xf6, 0x75, 0x81, 0x93, 0xe2, 0x39, 0x5e, + 0x17, 0xe1, 0xf1, 0x09, 0xd4, 0xf5, 0x17, 0xba, 0x88, 0xbe, 0x0e, 0x93, 0x79, 0xdd, 0xca, 0xc4, + 0x89, 0x8c, 0xbe, 0x80, 0x75, 0xd5, 0xdf, 0x7a, 0x14, 0x9f, 0x80, 0xdc, 0xc9, 0x88, 0xed, 0x13, + 0xeb, 0xf5, 0x9b, 0xd7, 0x06, 0xff, 0x79, 0x90, 0x43, 0x26, 0x1b, 0x7b, 0x54, 0x27, 0x62, 0xb2, + 0x59, 0x6f, 0x09, 0x45, 0x4c, 0x36, 0xfb, 0x25, 0x9e, 0x36, 0x2c, 0x69, 0x51, 0x88, 0x06, 0x57, + 0xee, 0x48, 0xcd, 0xf7, 0x74, 0x98, 0xf1, 0xcd, 0x2c, 0x4d, 0x3c, 0xd9, 0x81, 0x9a, 0x1e, 0xc8, + 0xe8, 0x05, 0xc9, 0x37, 0x34, 0x94, 0x1e, 0x25, 0xfa, 0x41, 0x8e, 0x1c, 0x40, 0x33, 0x19, 0x76, + 0x54, 0x2d, 0xe1, 0xac, 0x50, 0xad, 0x9b, 0x09, 0x64, 0x2c, 0x58, 0x29, 0x9b, 0x17, 0xb1, 0xd7, + 0xe3, 0x3d, 0x3f, 0xb9, 0x15, 0xc5, 0x5f, 0x95, 0x57, 0xb9, 0x25, 0xb0, 0x58, 0xed, 0x7b, 0xb9, + 0x07, 0x39, 0xb2, 0x07, 0xf5, 0x58, 0xd4, 0xbd, 0xd8, 0x6d, 0xa6, 0x44, 0x33, 0x5b, 0x3a, 0x2e, + 0xd1, 0xce, 0x43, 0x58, 0x8c, 0xbb, 0x8c, 0xa8, 0x8a, 0x65, 0xfa, 0xb5, 0xa8, 0xe1, 0xcb, 0xf6, + 0x33, 0x21, 0x3f, 0x0f, 0x35, 0xc6, 0x93, 0xa5, 0x5f, 0x23, 0xd1, 0xf8, 0x74, 0x72, 0xcc, 0x38, + 0x4c, 0xa8, 0xc6, 0x0b, 0x7f, 0x2d, 0x9f, 0xc3, 0x76, 0x7d, 0x87, 0xbf, 0xbe, 0x2d, 0x5d, 0xdb, + 0xd8, 0xf8, 0xbf, 0x6a, 0x26, 0x64, 0x8f, 0x17, 0x3e, 0xf4, 0x78, 0x90, 0x82, 0x9b, 0x1a, 0x8d, + 0x80, 0xbd, 0x5a, 0x1d, 0xda, 0xbc, 0x0e, 0x22, 0x4d, 0x6c, 0x0e, 0xbe, 0x62, 0x5e, 0xe4, 0x53, + 0x80, 0xc8, 0xa5, 0x98, 0x24, 0xbc, 0x56, 0xd5, 0x82, 0xca, 0xf0, 0x3a, 0xee, 0xf0, 0xf5, 0xae, + 0xdc, 0x66, 0xf5, 0x2d, 0x39, 0xee, 0xc1, 0x1b, 0xdb, 0x92, 0x93, 0xd9, 0x7c, 0x04, 0x8d, 0x03, + 0xcf, 0x7b, 0x36, 0x9f, 0xa9, 0xbb, 0x2b, 0x71, 0xa7, 0xad, 0x7d, 0x3b, 0x38, 0xdf, 0x4c, 0x54, + 0x8b, 0xb4, 0x61, 0x59, 0xb1, 0x88, 0xc8, 0x6f, 0x37, 0x4e, 0x14, 0x63, 0x0c, 0x89, 0x0c, 0x1e, + 0xe4, 0xc8, 0x43, 0xa8, 0xef, 0xd2, 0x11, 0x06, 0x52, 0x41, 0x27, 0x9e, 0x95, 0x98, 0x43, 0x08, + 0xf7, 0xfe, 0xd9, 0x6c, 0xc4, 0x80, 0x92, 0xc5, 0x45, 0x6e, 0x6a, 0xfa, 0x9e, 0x11, 0xf7, 0xf5, + 0x8a, 0xb1, 0xb8, 0x94, 0xab, 0xda, 0x17, 0xb0, 0x9c, 0x72, 0xd5, 0x52, 0xdc, 0xed, 0x3a, 0xf7, + 0xb1, 0xcd, 0xbb, 0xd7, 0x13, 0x88, 0x7c, 0xbf, 0x07, 0x0d, 0x1e, 0x34, 0xfc, 0x84, 0xf2, 0x8b, + 0xd0, 0x89, 0x90, 0x70, 0xfa, 0x2d, 0xeb, 0x24, 0x4b, 0xe2, 0x09, 0x9e, 0xe0, 0x73, 0x43, 0xda, + 0x35, 0x63, 0x35, 0xae, 0xe9, 0xab, 0xcf, 0x6a, 0x5c, 0xb3, 0x6e, 0x34, 0x7f, 0x0e, 0xb5, 0x27, + 0x34, 0x94, 0x17, 0x77, 0x95, 0x7c, 0x94, 0xb8, 0xc9, 0xbb, 0x99, 0x71, 0xdd, 0x9a, 0x7c, 0x82, + 0x49, 0x55, 0x10, 0x8a, 0x75, 0xad, 0x14, 0x3d, 0xe9, 0x52, 0x02, 0xce, 0xa4, 0x0f, 0x2d, 0x14, + 0x8d, 0xaa, 0x78, 0x3a, 0xf4, 0x90, 0xaa, 0x78, 0x56, 0xe4, 0x9a, 0x9f, 0xe7, 0x3d, 0xa0, 0x5d, + 0x15, 0x8e, 0x44, 0xb0, 0xe4, 0xad, 0x62, 0x55, 0x7d, 0x9d, 0xfc, 0x11, 0xc0, 0x20, 0xf4, 0x66, + 0xbb, 0x36, 0x9d, 0x7a, 0x6e, 0xc4, 0x13, 0xa2, 0x4b, 0xaa, 0xd1, 0x42, 0xd4, 0x6e, 0xaa, 0x92, + 0x2f, 0x35, 0xd9, 0x34, 0x36, 0x24, 0x72, 0xd8, 0xaf, 0xbd, 0xc7, 0xaa, 0x9a, 0x93, 0x71, 0x97, + 0x15, 0x99, 0x04, 0x44, 0x9e, 0x70, 0x4a, 0xd2, 0x4c, 0x39, 0xd9, 0xa9, 0xb5, 0x9e, 0xe1, 0x36, + 0xf7, 0x5d, 0xa8, 0x46, 0x2e, 0x44, 0x1b, 0x51, 0x5c, 0xac, 0x98, 0xc3, 0x91, 0xe2, 0xde, 0x69, + 0xf7, 0x9d, 0x1e, 0xac, 0xf0, 0xea, 0xa8, 0xed, 0x0f, 0x2f, 0x2f, 0xaa, 0xd7, 0xb2, 0xd2, 0x7e, + 0x33, 0x6a, 0xfd, 0x64, 0x79, 0x7f, 0xb0, 0xf5, 0x93, 0xf2, 0x22, 0x50, 0xeb, 0xe7, 0x3a, 0xb7, + 0x10, 0xb5, 0x7e, 0xae, 0x77, 0x40, 0xe8, 0xc1, 0x4a, 0x86, 0x3f, 0x00, 0x79, 0x43, 0x1e, 0x6c, + 0xae, 0xf5, 0x15, 0xd8, 0xcc, 0xb4, 0x1b, 0x93, 0x21, 0x6c, 0xf0, 0x34, 0xed, 0xc9, 0x24, 0x61, + 0x7e, 0x7e, 0x5d, 0x4b, 0x90, 0x61, 0x52, 0x8f, 0x89, 0x32, 0x09, 0xb3, 0x7a, 0x0f, 0x9a, 0x49, + 0xcb, 0x2d, 0xb9, 0x9e, 0x7c, 0xf3, 0x4e, 0x4c, 0x64, 0x4f, 0x5b, 0x7b, 0xc9, 0x17, 0xca, 0x7e, + 0x9c, 0xa8, 0xe3, 0x9d, 0xe8, 0xd5, 0xc7, 0x4c, 0x6b, 0xb7, 0x3a, 0x0d, 0x64, 0x9a, 0x9f, 0xc9, + 0x2f, 0xc0, 0x46, 0x72, 0x46, 0xcb, 0x9c, 0xef, 0x66, 0x75, 0xd7, 0xb5, 0xa2, 0x5c, 0xbc, 0x41, + 0x0f, 0x72, 0x8c, 0x11, 0xeb, 0x56, 0x5e, 0x35, 0x91, 0x32, 0xcc, 0xcd, 0x6a, 0x22, 0x65, 0x9a, + 0x85, 0x8f, 0x60, 0x29, 0x61, 0xe0, 0x55, 0x62, 0x70, 0xb6, 0x49, 0x58, 0x89, 0xc1, 0xd7, 0xd9, + 0x85, 0x07, 0xd0, 0x4c, 0x9a, 0x6e, 0xd5, 0x58, 0x5f, 0x63, 0x0e, 0xde, 0xbc, 0x73, 0x2d, 0x3e, + 0x5e, 0x4d, 0xcd, 0xc8, 0x19, 0xab, 0x66, 0xda, 0x34, 0x1b, 0xab, 0x66, 0x86, 0x89, 0x75, 0xfb, + 0x9d, 0x1f, 0x7e, 0xeb, 0xcc, 0x09, 0xcf, 0xe7, 0x27, 0x5b, 0x23, 0x6f, 0xfa, 0xc1, 0x44, 0x6a, + 0x35, 0x44, 0x64, 0x81, 0x0f, 0x26, 0xee, 0xf8, 0x03, 0xcc, 0xe0, 0x64, 0x61, 0xe6, 0x7b, 0xa1, + 0xf7, 0xd1, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xd0, 0xbe, 0x90, 0xd7, 0xa6, 0x91, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/lnrpc/rpc.pb.gw.go b/lnrpc/rpc.pb.gw.go index e3f63d79..41021334 100644 --- a/lnrpc/rpc.pb.gw.go +++ b/lnrpc/rpc.pb.gw.go @@ -1198,10 +1198,21 @@ func local_request_Lightning_ListPayments_0(ctx context.Context, marshaler runti } +var ( + filter_Lightning_DeleteAllPayments_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + func request_Lightning_DeleteAllPayments_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq DeleteAllPaymentsRequest var metadata runtime.ServerMetadata + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Lightning_DeleteAllPayments_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.DeleteAllPayments(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -1211,6 +1222,10 @@ func local_request_Lightning_DeleteAllPayments_0(ctx context.Context, marshaler var protoReq DeleteAllPaymentsRequest var metadata runtime.ServerMetadata + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Lightning_DeleteAllPayments_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.DeleteAllPayments(ctx, &protoReq) return msg, metadata, err diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index b33e2f10..088338f5 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -3229,6 +3229,13 @@ message ListPaymentsResponse { } message DeleteAllPaymentsRequest { + // Only delete failed payments. + bool failed_payments_only = 1; + + /* + Only delete failed HTLCs from payments, not the payment itself. + */ + bool failed_htlcs_only = 2; } message DeleteAllPaymentsResponse { diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index 4a18cd3d..291171ae 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -1630,6 +1630,24 @@ } } }, + "parameters": [ + { + "name": "failed_payments_only", + "description": "Only delete failed payments.", + "in": "query", + "required": false, + "type": "boolean", + "format": "boolean" + }, + { + "name": "failed_htlcs_only", + "description": "Only delete failed HTLCs from payments, not the payment itself.", + "in": "query", + "required": false, + "type": "boolean", + "format": "boolean" + } + ], "tags": [ "Lightning" ] From 7e3738d773193ee96ea9e471fbf8ec3798fe7b13 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Tue, 11 Jun 2019 15:11:24 +0200 Subject: [PATCH 3/5] rpcserver+channeldb: delete only failed payments if requested --- channeldb/payment_control_test.go | 61 +++++++++++++++++++++++++++---- channeldb/payments.go | 8 +++- rpcserver.go | 11 ++++-- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/channeldb/payment_control_test.go b/channeldb/payment_control_test.go index 7949e610..63499d71 100644 --- a/channeldb/payment_control_test.go +++ b/channeldb/payment_control_test.go @@ -388,6 +388,8 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) { }, } + var numSuccess, numInflight int + for _, p := range payments { info, attempt, preimg, err := genInfo() if err != nil { @@ -454,11 +456,15 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) { assertPaymentInfo( t, pControl, info.PaymentHash, info, nil, htlc, ) + + numSuccess++ } else { assertPaymentStatus(t, pControl, info.PaymentHash, StatusInFlight) assertPaymentInfo( t, pControl, info.PaymentHash, info, nil, htlc, ) + + numInflight++ } // If the payment is intended to have a duplicate payment, we @@ -469,27 +475,66 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) { uint64(duplicateSeqNr), preimg, ) duplicateSeqNr++ + numSuccess++ } } - // Delete payments. - if err := db.DeletePayments(); err != nil { + // Delete all failed payments. + if err := db.DeletePayments(true); err != nil { t.Fatal(err) } - // This should leave the in-flight payment. + // This should leave the succeeded and in-flight payments. dbPayments, err := db.FetchPayments() if err != nil { t.Fatal(err) } - if len(dbPayments) != 1 { - t.Fatalf("expected one payment, got %d", len(dbPayments)) + if len(dbPayments) != numSuccess+numInflight { + t.Fatalf("expected %d payments, got %d", + numSuccess+numInflight, len(dbPayments)) } - status := dbPayments[0].Status - if status != StatusInFlight { - t.Fatalf("expected in-fligth status, got %v", status) + var s, i int + for _, p := range dbPayments { + fmt.Println("fetch payment has status", p.Status) + switch p.Status { + case StatusSucceeded: + s++ + case StatusInFlight: + i++ + } + } + + if s != numSuccess { + t.Fatalf("expected %d succeeded payments , got %d", + numSuccess, s) + } + if i != numInflight { + t.Fatalf("expected %d in-flight payments, got %d", + numInflight, i) + } + + // Now delete all payments except in-flight. + if err := db.DeletePayments(false); err != nil { + t.Fatal(err) + } + + // This should leave the in-flight payment. + dbPayments, err = db.FetchPayments() + if err != nil { + t.Fatal(err) + } + + if len(dbPayments) != numInflight { + t.Fatalf("expected %d payments, got %d", numInflight, + len(dbPayments)) + } + + for _, p := range dbPayments { + if p.Status != StatusInFlight { + t.Fatalf("expected in-fligth status, got %v", p.Status) + } } // Finally, check that we only have a single index left in the payment diff --git a/channeldb/payments.go b/channeldb/payments.go index 1a42d718..680c798c 100644 --- a/channeldb/payments.go +++ b/channeldb/payments.go @@ -677,7 +677,7 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash, } // DeletePayments deletes all completed and failed payments from the DB. -func (db *DB) DeletePayments() error { +func (db *DB) DeletePayments(failedOnly bool) error { return kvdb.Update(db, func(tx kvdb.RwTx) error { payments := tx.ReadWriteBucket(paymentsRootBucket) if payments == nil { @@ -715,6 +715,12 @@ func (db *DB) DeletePayments() error { return nil } + // If we requested to only delete failed payments, we + // can return if this one is not. + if failedOnly && paymentStatus != StatusFailed { + return nil + } + // Add the bucket to the set of buckets we can delete. deleteBuckets = append(deleteBuckets, k) diff --git a/rpcserver.go b/rpcserver.go index 9d1a0d28..7a09f3d7 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -5710,11 +5710,16 @@ func (r *rpcServer) ListPayments(ctx context.Context, // DeleteAllPayments deletes all outgoing payments from DB. func (r *rpcServer) DeleteAllPayments(ctx context.Context, - _ *lnrpc.DeleteAllPaymentsRequest) (*lnrpc.DeleteAllPaymentsResponse, error) { + req *lnrpc.DeleteAllPaymentsRequest) ( + *lnrpc.DeleteAllPaymentsResponse, error) { - rpcsLog.Debugf("[DeleteAllPayments]") + rpcsLog.Debugf("[DeleteAllPayments] failed_payments_only=%v", + req.FailedPaymentsOnly) - if err := r.server.remoteChanDB.DeletePayments(); err != nil { + err := r.server.remoteChanDB.DeletePayments( + req.FailedPaymentsOnly, + ) + if err != nil { return nil, err } From 6eb42aec0aff5ec55ecf74a75cd943795ff4ae97 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 22 Jan 2021 14:43:32 +0100 Subject: [PATCH 4/5] channeldb/payments: use only Read bucket when iterating --- channeldb/payments.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channeldb/payments.go b/channeldb/payments.go index 680c798c..93556438 100644 --- a/channeldb/payments.go +++ b/channeldb/payments.go @@ -694,7 +694,7 @@ func (db *DB) DeletePayments(failedOnly bool) error { deleteIndexes [][]byte ) err := payments.ForEach(func(k, _ []byte) error { - bucket := payments.NestedReadWriteBucket(k) + bucket := payments.NestedReadBucket(k) if bucket == nil { // We only expect sub-buckets to be found in // this top-level bucket. From 59f41e518ddcb9f62902cf37bc823620ac6c1d76 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Fri, 22 Jan 2021 15:47:55 +0100 Subject: [PATCH 5/5] channeldb: add failedHtlcsOnly option to DeletePayments --- channeldb/payment_control_test.go | 221 +++++++++++++++++++++++++++++- channeldb/payments.go | 70 +++++++++- rpcserver.go | 7 +- 3 files changed, 290 insertions(+), 8 deletions(-) diff --git a/channeldb/payment_control_test.go b/channeldb/payment_control_test.go index 63499d71..e13f9d72 100644 --- a/channeldb/payment_control_test.go +++ b/channeldb/payment_control_test.go @@ -480,7 +480,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) { } // Delete all failed payments. - if err := db.DeletePayments(true); err != nil { + if err := db.DeletePayments(true, false); err != nil { t.Fatal(err) } @@ -516,7 +516,7 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) { } // Now delete all payments except in-flight. - if err := db.DeletePayments(false); err != nil { + if err := db.DeletePayments(false, false); err != nil { t.Fatal(err) } @@ -553,6 +553,223 @@ func TestPaymentControlDeleteNonInFligt(t *testing.T) { require.Equal(t, 1, indexCount) } +// TestPaymentControlDeletePayments tests that DeletePayments correcly deletes +// information about completed payments from the database. +func TestPaymentControlDeletePayments(t *testing.T) { + t.Parallel() + + db, cleanup, err := MakeTestDB() + defer cleanup() + + if err != nil { + t.Fatalf("unable to init db: %v", err) + } + + pControl := NewPaymentControl(db) + + // Register three payments: + // 1. A payment with two failed attempts. + // 2. A Payment with one failed and one settled attempt. + // 3. A payment with one failed and one in-flight attempt. + attemptID := uint64(0) + for i := 0; i < 3; i++ { + info, attempt, preimg, err := genInfo() + if err != nil { + t.Fatalf("unable to generate htlc message: %v", err) + } + + attempt.AttemptID = attemptID + attemptID++ + + // Init the payment. + err = pControl.InitPayment(info.PaymentHash, info) + if err != nil { + t.Fatalf("unable to send htlc message: %v", err) + } + + // Register and fail the first attempt for all three payments. + _, err = pControl.RegisterAttempt(info.PaymentHash, attempt) + if err != nil { + t.Fatalf("unable to send htlc message: %v", err) + } + + htlcFailure := HTLCFailUnreadable + _, err = pControl.FailAttempt( + info.PaymentHash, attempt.AttemptID, + &HTLCFailInfo{ + Reason: htlcFailure, + }, + ) + if err != nil { + t.Fatalf("unable to fail htlc: %v", err) + } + + // Depending on the test case, fail or succeed the next + // attempt. + attempt.AttemptID = attemptID + attemptID++ + + _, err = pControl.RegisterAttempt(info.PaymentHash, attempt) + if err != nil { + t.Fatalf("unable to send htlc message: %v", err) + } + + switch i { + + // Fail the attempt and the payment overall. + case 0: + htlcFailure := HTLCFailUnreadable + _, err = pControl.FailAttempt( + info.PaymentHash, attempt.AttemptID, + &HTLCFailInfo{ + Reason: htlcFailure, + }, + ) + if err != nil { + t.Fatalf("unable to fail htlc: %v", err) + } + + failReason := FailureReasonNoRoute + _, err = pControl.Fail(info.PaymentHash, failReason) + if err != nil { + t.Fatalf("unable to fail payment hash: %v", err) + } + + // Settle the attempt + case 1: + _, err := pControl.SettleAttempt( + info.PaymentHash, attempt.AttemptID, + &HTLCSettleInfo{ + Preimage: preimg, + }, + ) + if err != nil { + t.Fatalf("error shouldn't have been received, got: %v", err) + } + + // We leave the attmpet in-flight by doing nothing. + case 2: + } + } + + type fetchedPayment struct { + status PaymentStatus + htlcs int + } + + assertPayments := func(expPayments []fetchedPayment) { + t.Helper() + + dbPayments, err := db.FetchPayments() + if err != nil { + t.Fatal(err) + } + + if len(dbPayments) != len(expPayments) { + t.Fatalf("expected %d payments, got %d", + len(expPayments), len(dbPayments)) + } + + for i := range dbPayments { + if dbPayments[i].Status != expPayments[i].status { + t.Fatalf("unexpected payment status") + } + + if len(dbPayments[i].HTLCs) != expPayments[i].htlcs { + t.Fatalf("unexpected number of htlcs") + } + + } + } + + // Check that all payments are there as we added them. + assertPayments([]fetchedPayment{ + { + status: StatusFailed, + htlcs: 2, + }, + { + status: StatusSucceeded, + htlcs: 2, + }, + { + status: StatusInFlight, + htlcs: 2, + }, + }) + + // Delete HTLC attempts for failed payments only. + if err := db.DeletePayments(true, true); err != nil { + t.Fatal(err) + } + + // The failed payment is the only altered one. + assertPayments([]fetchedPayment{ + { + status: StatusFailed, + htlcs: 0, + }, + { + status: StatusSucceeded, + htlcs: 2, + }, + { + status: StatusInFlight, + htlcs: 2, + }, + }) + + // Delete failed attempts for all payments. + if err := db.DeletePayments(false, true); err != nil { + t.Fatal(err) + } + + // The failed attempts should be deleted, except for the in-flight + // payment, that shouldn't be altered until it has completed. + assertPayments([]fetchedPayment{ + { + status: StatusFailed, + htlcs: 0, + }, + { + status: StatusSucceeded, + htlcs: 1, + }, + { + status: StatusInFlight, + htlcs: 2, + }, + }) + + // Now delete all failed payments. + if err := db.DeletePayments(true, false); err != nil { + t.Fatal(err) + } + + assertPayments([]fetchedPayment{ + { + status: StatusSucceeded, + htlcs: 1, + }, + { + status: StatusInFlight, + htlcs: 2, + }, + }) + + // Finally delete all completed payments. + if err := db.DeletePayments(false, false); err != nil { + t.Fatal(err) + } + + assertPayments([]fetchedPayment{ + { + status: StatusInFlight, + htlcs: 2, + }, + }) +} + // TestPaymentControlMultiShard checks the ability of payment control to // have multiple in-flight HTLCs for a single payment. func TestPaymentControlMultiShard(t *testing.T) { diff --git a/channeldb/payments.go b/channeldb/payments.go index 93556438..7e659d05 100644 --- a/channeldb/payments.go +++ b/channeldb/payments.go @@ -676,8 +676,11 @@ func fetchPaymentWithSequenceNumber(tx kvdb.RTx, paymentHash lntypes.Hash, return duplicatePayment, nil } -// DeletePayments deletes all completed and failed payments from the DB. -func (db *DB) DeletePayments(failedOnly bool) error { +// DeletePayments deletes all completed and failed payments from the DB. If +// failedOnly is set, only failed payments will be considered for deletion. If +// failedHtlsOnly is set, the payment itself won't be deleted, only failed HTLC +// attempts. +func (db *DB) DeletePayments(failedOnly, failedHtlcsOnly bool) error { return kvdb.Update(db, func(tx kvdb.RwTx) error { payments := tx.ReadWriteBucket(paymentsRootBucket) if payments == nil { @@ -692,6 +695,10 @@ func (db *DB) DeletePayments(failedOnly bool) error { // deleteIndexes is the set of indexes pointing to these // payments that need to be deleted. deleteIndexes [][]byte + + // deleteHtlcs maps a payment hash to the HTLC IDs we + // want to delete for that payment. + deleteHtlcs = make(map[lntypes.Hash][][]byte) ) err := payments.ForEach(func(k, _ []byte) error { bucket := payments.NestedReadBucket(k) @@ -721,6 +728,49 @@ func (db *DB) DeletePayments(failedOnly bool) error { return nil } + // If we are only deleting failed HTLCs, fetch them. + if failedHtlcsOnly { + htlcsBucket := bucket.NestedReadBucket( + paymentHtlcsBucket, + ) + + var htlcs []HTLCAttempt + if htlcsBucket != nil { + htlcs, err = fetchHtlcAttempts( + htlcsBucket, + ) + if err != nil { + return err + } + } + + // Now iterate though them and save the bucket + // keys for the failed HTLCs. + var toDelete [][]byte + for _, h := range htlcs { + if h.Failure == nil { + continue + } + + htlcIDBytes := make([]byte, 8) + binary.BigEndian.PutUint64( + htlcIDBytes, h.AttemptID, + ) + + toDelete = append(toDelete, htlcIDBytes) + } + + hash, err := lntypes.MakeHash(k) + if err != nil { + return err + } + + deleteHtlcs[hash] = toDelete + + // We return, we are only deleting attempts. + return nil + } + // Add the bucket to the set of buckets we can delete. deleteBuckets = append(deleteBuckets, k) @@ -732,13 +782,27 @@ func (db *DB) DeletePayments(failedOnly bool) error { } deleteIndexes = append(deleteIndexes, seqNrs...) - return nil }) if err != nil { return err } + // Delete the failed HTLC attempts we found. + for hash, htlcIDs := range deleteHtlcs { + bucket := payments.NestedReadWriteBucket(hash[:]) + htlcsBucket := bucket.NestedReadWriteBucket( + paymentHtlcsBucket, + ) + + for _, aid := range htlcIDs { + err := htlcsBucket.DeleteNestedBucket(aid) + if err != nil { + return err + } + } + } + for _, k := range deleteBuckets { if err := payments.DeleteNestedBucket(k); err != nil { return err diff --git a/rpcserver.go b/rpcserver.go index 7a09f3d7..d8883351 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -5713,11 +5713,12 @@ func (r *rpcServer) DeleteAllPayments(ctx context.Context, req *lnrpc.DeleteAllPaymentsRequest) ( *lnrpc.DeleteAllPaymentsResponse, error) { - rpcsLog.Debugf("[DeleteAllPayments] failed_payments_only=%v", - req.FailedPaymentsOnly) + rpcsLog.Infof("[DeleteAllPayments] failed_payments_only=%v, "+ + "failed_htlcs_only=%v", req.FailedPaymentsOnly, + req.FailedHtlcsOnly) err := r.server.remoteChanDB.DeletePayments( - req.FailedPaymentsOnly, + req.FailedPaymentsOnly, req.FailedHtlcsOnly, ) if err != nil { return nil, err