From 464dff09ac5b2ffec2c7b2645048ade91a22852a Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:54:11 -0800 Subject: [PATCH 01/13] invoices: expose AMPRecord() method on Payload --- htlcswitch/hop/payload.go | 10 ++++++++++ invoices/interface.go | 4 ++++ invoices/invoiceregistry.go | 1 + invoices/test_utils_test.go | 5 +++++ invoices/update.go | 6 ++++-- 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/htlcswitch/hop/payload.go b/htlcswitch/hop/payload.go index d8aafd9c..c6a25ba6 100644 --- a/htlcswitch/hop/payload.go +++ b/htlcswitch/hop/payload.go @@ -86,6 +86,10 @@ type Payload struct { // a TLV onion payload. MPP *record.MPP + // AMP holds the info provided in an option_amp record when parsed from + // a TLV onion payload. + AMP *record.AMP + // customRecords are user-defined records in the custom type range that // were included in the payload. customRecords record.CustomSet @@ -250,6 +254,12 @@ func (h *Payload) MultiPath() *record.MPP { return h.MPP } +// AMPRecord returns the record corresponding with option_amp parsed from the +// onion payload. +func (h *Payload) AMPRecord() *record.AMP { + return h.AMP +} + // CustomRecords returns the custom tlv type records that were parsed from the // payload. func (h *Payload) CustomRecords() record.CustomSet { diff --git a/invoices/interface.go b/invoices/interface.go index c511dded..732b39e1 100644 --- a/invoices/interface.go +++ b/invoices/interface.go @@ -11,6 +11,10 @@ type Payload interface { // the onion payload. MultiPath() *record.MPP + // AMPRecord returns the record corresponding to the option_amp record + // parsed from the onion payload. + AMPRecord() *record.AMP + // CustomRecords returns the custom tlv type records that were parsed // from the payload. CustomRecords() record.CustomSet diff --git a/invoices/invoiceregistry.go b/invoices/invoiceregistry.go index cd7ebe8c..dcaa9898 100644 --- a/invoices/invoiceregistry.go +++ b/invoices/invoiceregistry.go @@ -802,6 +802,7 @@ func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash, finalCltvRejectDelta: i.cfg.FinalCltvRejectDelta, customRecords: payload.CustomRecords(), mpp: payload.MultiPath(), + amp: payload.AMPRecord(), } // Process keysend if present. Do this outside of the lock, because diff --git a/invoices/test_utils_test.go b/invoices/test_utils_test.go index 63cf8d98..73d41346 100644 --- a/invoices/test_utils_test.go +++ b/invoices/test_utils_test.go @@ -23,6 +23,7 @@ import ( type mockPayload struct { mpp *record.MPP + amp *record.AMP customRecords record.CustomSet } @@ -30,6 +31,10 @@ func (p *mockPayload) MultiPath() *record.MPP { return p.mpp } +func (p *mockPayload) AMPRecord() *record.AMP { + return p.amp +} + func (p *mockPayload) CustomRecords() record.CustomSet { // This function should always return a map instance, but for mock // configuration we do accept nil. diff --git a/invoices/update.go b/invoices/update.go index 8e2fd194..f7eaf4e4 100644 --- a/invoices/update.go +++ b/invoices/update.go @@ -20,6 +20,7 @@ type invoiceUpdateCtx struct { finalCltvRejectDelta int32 customRecords record.CustomSet mpp *record.MPP + amp *record.AMP } // invoiceRef returns an identifier that can be used to lookup or update the @@ -34,8 +35,9 @@ func (i *invoiceUpdateCtx) invoiceRef() channeldb.InvoiceRef { // log logs a message specific to this update context. func (i *invoiceUpdateCtx) log(s string) { - log.Debugf("Invoice%v: %v, amt=%v, expiry=%v, circuit=%v, mpp=%v", - i.invoiceRef, s, i.amtPaid, i.expiry, i.circuitKey, i.mpp) + log.Debugf("Invoice%v: %v, amt=%v, expiry=%v, circuit=%v, mpp=%v, "+ + "amp=%v", i.hash[:], s, i.amtPaid, i.expiry, i.circuitKey, + i.mpp, i.amp) } // failRes is a helper function which creates a failure resolution with From 7f05c9d3bb3a391e8c1633dc95dc8a923ea4ffbb Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:55:11 -0800 Subject: [PATCH 02/13] channeldb/invoice: persist optional AMP fields on InvoiceHTLC --- channeldb/invoice_test.go | 64 ++++++++++++++++++++ channeldb/invoices.go | 123 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+) diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index bb118f71..45d072b5 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -1133,6 +1133,70 @@ func TestCustomRecords(t *testing.T) { ) } +// TestInvoiceHtlcAMPFields asserts that the set id and preimage fields are +// properly recorded when updating an invoice. +func TestInvoiceHtlcAMPFields(t *testing.T) { + t.Run("amp", func(t *testing.T) { + testInvoiceHtlcAMPFields(t, true) + }) + t.Run("no amp", func(t *testing.T) { + testInvoiceHtlcAMPFields(t, false) + }) +} + +func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) { + db, cleanUp, err := MakeTestDB() + defer cleanUp() + require.Nil(t, err) + + testInvoice, err := randInvoice(1000) + require.Nil(t, err) + + payHash := testInvoice.Terms.PaymentPreimage.Hash() + _, err = db.AddInvoice(testInvoice, payHash) + require.Nil(t, err) + + // Accept an htlc with custom records on this invoice. + key := CircuitKey{ChanID: lnwire.NewShortChanIDFromInt(1), HtlcID: 4} + records := make(map[uint64][]byte) + + var ampData *InvoiceHtlcAMPData + if isAMP { + amp := record.NewAMP([32]byte{1}, [32]byte{2}, 3) + preimage := &lntypes.Preimage{4} + + ampData = &InvoiceHtlcAMPData{ + Record: *amp, + Hash: preimage.Hash(), + Preimage: preimage, + } + } + + ref := InvoiceRefByHash(payHash) + _, err = db.UpdateInvoice(ref, + func(invoice *Invoice) (*InvoiceUpdateDesc, error) { + return &InvoiceUpdateDesc{ + AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{ + key: { + Amt: 500, + AMP: ampData, + CustomRecords: records, + }, + }, + }, nil + }, + ) + require.Nil(t, err) + + // Retrieve the invoice from that database and verify that the AMP + // fields are as expected. + dbInvoice, err := db.LookupInvoice(ref) + require.Nil(t, err) + + require.Equal(t, 1, len(dbInvoice.Htlcs)) + require.Equal(t, ampData, dbInvoice.Htlcs[key].AMP) +} + // TestInvoiceRef asserts that the proper identifiers are returned from an // InvoiceRef depending on the constructor used. func TestInvoiceRef(t *testing.T) { diff --git a/channeldb/invoices.go b/channeldb/invoices.go index e6bd46a0..cd8ffc83 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -135,6 +135,9 @@ const ( expiryHeightType tlv.Type = 13 htlcStateType tlv.Type = 15 mppTotalAmtType tlv.Type = 17 + htlcAMPType tlv.Type = 19 + htlcHashType tlv.Type = 21 + htlcPreimageType tlv.Type = 23 // A set of tlv type definitions used to serialize invoice bodiees. // @@ -407,6 +410,60 @@ type InvoiceHTLC struct { // CustomRecords contains the custom key/value pairs that accompanied // the htlc. CustomRecords record.CustomSet + + // AMP encapsulates additional data relevant to AMP HTLCs. This includes + // the AMP onion record, in addition to the HTLC's payment hash and + // preimage since these are unique to each AMP HTLC, and not the invoice + // as a whole. + // + // NOTE: This value will only be set for AMP HTLCs. + AMP *InvoiceHtlcAMPData +} + +// InvoiceHtlcAMPData is a struct hodling the additional metadata stored for +// each received AMP HTLC. This includes the AMP onion record, in addition to +// the HTLC's payment hash and preimage. +type InvoiceHtlcAMPData struct { + // AMP is a copy of the AMP record presented in the onion payload + // containing the information necessary to correlate and settle a + // spontaneous HTLC set. Newly accepted legacy keysend payments will + // also have this field set as we automatically promote them into an AMP + // payment for internal processing. + Record record.AMP + + // Hash is an HTLC-level payment hash that is stored only for AMP + // payments. This is done because an AMP HTLC will carry a different + // payment hash from the invoice it might be satisfying, so we track the + // payment hashes individually to able to compute whether or not the + // reconstructed preimage correctly matches the HTLC's hash. + Hash lntypes.Hash + + // Preimage is an HTLC-level preimage that satisfies the AMP HTLC's + // Hash. The preimage will be be derived either from secret share + // reconstruction of the shares in the AMP payload. + // + // NOTE: Preimage will only be present once the HTLC is in + // HltcStateSetteled. + Preimage *lntypes.Preimage +} + +// Copy returns a deep copy of the InvoiceHtlcAMPData. +func (d *InvoiceHtlcAMPData) Copy() *InvoiceHtlcAMPData { + if d == nil { + return nil + } + + var preimage *lntypes.Preimage + if d.Preimage != nil { + pimg := *d.Preimage + preimage = &pimg + } + + return &InvoiceHtlcAMPData{ + Record: d.Record, + Hash: d.Hash, + Preimage: preimage, + } } // HtlcAcceptDesc describes the details of a newly accepted htlc. @@ -427,6 +484,14 @@ type HtlcAcceptDesc struct { // CustomRecords contains the custom key/value pairs that accompanied // the htlc. CustomRecords record.CustomSet + + // AMP encapsulates additional data relevant to AMP HTLCs. This includes + // the AMP onion record, in addition to the HTLC's payment hash and + // preimage since these are unique to each AMP HTLC, and not the invoice + // as a whole. + // + // NOTE: This value will only be set for AMP HTLCs. + AMP *InvoiceHtlcAMPData } // InvoiceUpdateDesc describes the changes that should be applied to the @@ -1205,6 +1270,29 @@ func serializeHtlcs(w io.Writer, htlcs map[CircuitKey]*InvoiceHTLC) error { tlv.MakePrimitiveRecord(mppTotalAmtType, &mppTotalAmt), ) + if htlc.AMP != nil { + setIDRecord := tlv.MakeDynamicRecord( + htlcAMPType, &htlc.AMP.Record, + htlc.AMP.Record.PayloadSize, + record.AMPEncoder, record.AMPDecoder, + ) + records = append(records, setIDRecord) + + hash32 := [32]byte(htlc.AMP.Hash) + hashRecord := tlv.MakePrimitiveRecord( + htlcHashType, &hash32, + ) + records = append(records, hashRecord) + + if htlc.AMP.Preimage != nil { + preimage32 := [32]byte(*htlc.AMP.Preimage) + preimageRecord := tlv.MakePrimitiveRecord( + htlcPreimageType, &preimage32, + ) + records = append(records, preimageRecord) + } + } + // Convert the custom records to tlv.Record types that are ready // for serialization. customRecords := tlv.MapToRecords(htlc.CustomRecords) @@ -1374,6 +1462,9 @@ func deserializeHtlcs(r io.Reader) (map[CircuitKey]*InvoiceHTLC, error) { state uint8 acceptTime, resolveTime uint64 amt, mppTotalAmt uint64 + amp = &record.AMP{} + hash32 = &[32]byte{} + preimage32 = &[32]byte{} ) tlvStream, err := tlv.NewStream( tlv.MakePrimitiveRecord(chanIDType, &chanID), @@ -1387,6 +1478,12 @@ func deserializeHtlcs(r io.Reader) (map[CircuitKey]*InvoiceHTLC, error) { tlv.MakePrimitiveRecord(expiryHeightType, &htlc.Expiry), tlv.MakePrimitiveRecord(htlcStateType, &state), tlv.MakePrimitiveRecord(mppTotalAmtType, &mppTotalAmt), + tlv.MakeDynamicRecord( + htlcAMPType, amp, amp.PayloadSize, + record.AMPEncoder, record.AMPDecoder, + ), + tlv.MakePrimitiveRecord(htlcHashType, hash32), + tlv.MakePrimitiveRecord(htlcPreimageType, preimage32), ) if err != nil { return nil, err @@ -1397,12 +1494,35 @@ func deserializeHtlcs(r io.Reader) (map[CircuitKey]*InvoiceHTLC, error) { return nil, err } + if _, ok := parsedTypes[htlcAMPType]; !ok { + amp = nil + } + + var preimage *lntypes.Preimage + if _, ok := parsedTypes[htlcPreimageType]; ok { + pimg := lntypes.Preimage(*preimage32) + preimage = &pimg + } + + var hash *lntypes.Hash + if _, ok := parsedTypes[htlcHashType]; ok { + h := lntypes.Hash(*hash32) + hash = &h + } + key.ChanID = lnwire.NewShortChanIDFromInt(chanID) htlc.AcceptTime = time.Unix(0, int64(acceptTime)) htlc.ResolveTime = time.Unix(0, int64(resolveTime)) htlc.State = HtlcState(state) htlc.Amt = lnwire.MilliSatoshi(amt) htlc.MppTotalAmt = lnwire.MilliSatoshi(mppTotalAmt) + if amp != nil && hash != nil { + htlc.AMP = &InvoiceHtlcAMPData{ + Record: *amp, + Hash: *hash, + Preimage: preimage, + } + } // Reconstruct the custom records fields from the parsed types // map return from the tlv parser. @@ -1431,6 +1551,8 @@ func copyInvoiceHTLC(src *InvoiceHTLC) *InvoiceHTLC { result.CustomRecords[k] = v } + result.AMP = src.AMP.Copy() + return &result } @@ -1531,6 +1653,7 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex kvdb.RwBucke AcceptTime: now, State: HtlcStateAccepted, CustomRecords: htlcUpdate.CustomRecords, + AMP: htlcUpdate.AMP.Copy(), } invoice.Htlcs[key] = htlc From b2234703f6713894ba5e92f2f6aad4c684ff9385 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:55:56 -0800 Subject: [PATCH 03/13] invoices+channeldb: add HTLCSet method to invoice --- channeldb/invoice_test.go | 88 +++++++++++++++++++++++++++++++++++++++ channeldb/invoices.go | 44 ++++++++++++++++++++ invoices/update.go | 15 ++----- 3 files changed, 135 insertions(+), 12 deletions(-) diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index 45d072b5..4e01f52e 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -1216,6 +1216,94 @@ func TestInvoiceRef(t *testing.T) { require.Equal(t, &payAddr, refByHashAndAddr.PayAddr()) } +// TestHTLCSet asserts that HTLCSet returns the proper set of accepted HTLCs +// that can be considered for settlement. It asserts that MPP and AMP HTLCs do +// not comingle, and also that HTLCs with disjoint set ids appear in different +// sets. +func TestHTLCSet(t *testing.T) { + inv := &Invoice{ + Htlcs: make(map[CircuitKey]*InvoiceHTLC), + } + + // Construct two distinct set id's, in this test we'll also track the + // nil set id as a third group. + setID1 := &[32]byte{1} + setID2 := &[32]byte{2} + + // Create the expected htlc sets for each group, these will be updated + // as the invoice is modified. + expSetNil := make(map[CircuitKey]*InvoiceHTLC) + expSet1 := make(map[CircuitKey]*InvoiceHTLC) + expSet2 := make(map[CircuitKey]*InvoiceHTLC) + + checkHTLCSets := func() { + require.Equal(t, expSetNil, inv.HTLCSet(nil)) + require.Equal(t, expSet1, inv.HTLCSet(setID1)) + require.Equal(t, expSet2, inv.HTLCSet(setID2)) + } + + // All HTLC sets should be empty initially. + checkHTLCSets() + + // Add the following sequence of HTLCs to the invoice, sanity checking + // all three HTLC sets after each transition. This sequence asserts: + // - both nil and non-nil set ids can have multiple htlcs. + // - there may be distinct htlc sets with non-nil set ids. + // - only accepted htlcs are returned as part of the set. + htlcs := []struct { + setID *[32]byte + state HtlcState + }{ + {nil, HtlcStateAccepted}, + {nil, HtlcStateAccepted}, + {setID1, HtlcStateAccepted}, + {setID1, HtlcStateAccepted}, + {setID2, HtlcStateAccepted}, + {setID2, HtlcStateAccepted}, + {nil, HtlcStateCanceled}, + {setID1, HtlcStateCanceled}, + {setID2, HtlcStateCanceled}, + {nil, HtlcStateSettled}, + {setID1, HtlcStateSettled}, + {setID2, HtlcStateSettled}, + } + + for i, h := range htlcs { + var ampData *InvoiceHtlcAMPData + if h.setID != nil { + ampData = &InvoiceHtlcAMPData{ + Record: *record.NewAMP([32]byte{0}, *h.setID, 0), + } + + } + + // Add the HTLC to the invoice's set of HTLCs. + key := CircuitKey{HtlcID: uint64(i)} + htlc := &InvoiceHTLC{ + AMP: ampData, + State: h.state, + } + inv.Htlcs[key] = htlc + + // Update our expected htlc set if the htlc is accepted, + // otherwise it shouldn't be reflected. + if h.state == HtlcStateAccepted { + switch h.setID { + case nil: + expSetNil[key] = htlc + case setID1: + expSet1[key] = htlc + case setID2: + expSet2[key] = htlc + default: + t.Fatalf("unexpected set id") + } + } + + checkHTLCSets() + } +} + // TestDeleteInvoices tests that deleting a list of invoices will succeed // if all delete references are valid, or will fail otherwise. func TestDeleteInvoices(t *testing.T) { diff --git a/channeldb/invoices.go b/channeldb/invoices.go index cd8ffc83..bcff0629 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -362,6 +362,30 @@ type Invoice struct { HodlInvoice bool } +// HTLCSet returns the set of accepted HTLCs belonging to an invoice. Passing a +// nil setID will return all accepted HTLCs in the case of legacy or MPP, and no +// HTLCs in the case of AMP. Otherwise, the returned set will be filtered by +// the populated setID which is used to retrieve AMP HTLC sets. +func (i *Invoice) HTLCSet(setID *[32]byte) map[CircuitKey]*InvoiceHTLC { + htlcSet := make(map[CircuitKey]*InvoiceHTLC) + for key, htlc := range i.Htlcs { + // Only consider accepted mpp htlcs. It is possible that there + // are htlcs registered in the invoice database that previously + // timed out and are in the canceled state now. + if htlc.State != HtlcStateAccepted { + continue + } + + if !htlc.IsInHTLCSet(setID) { + continue + } + + htlcSet[key] = htlc + } + + return htlcSet +} + // HtlcState defines the states an htlc paying to an invoice can be in. type HtlcState uint8 @@ -420,6 +444,26 @@ type InvoiceHTLC struct { AMP *InvoiceHtlcAMPData } +// IsInHTLCSet returns true if this HTLC is part an HTLC set. If nil is passed, +// this method returns true if this is an MPP HTLC. Otherwise, it only returns +// true if the AMP HTLC's set id matches the populated setID. +func (h *InvoiceHTLC) IsInHTLCSet(setID *[32]byte) bool { + wantAMPSet := setID != nil + isAMPHtlc := h.AMP != nil + + // Non-AMP HTLCs cannot be part of AMP HTLC sets, and vice versa. + if wantAMPSet != isAMPHtlc { + return false + } + + // Skip AMP HTLCs that have differing set ids. + if isAMPHtlc && *setID != h.AMP.Record.SetID() { + return false + } + + return true +} + // InvoiceHtlcAMPData is a struct hodling the additional metadata stored for // each received AMP HTLC. This includes the AMP onion record, in addition to // the HTLC's payment hash and preimage. diff --git a/invoices/update.go b/invoices/update.go index f7eaf4e4..41bd690b 100644 --- a/invoices/update.go +++ b/invoices/update.go @@ -143,14 +143,7 @@ func updateMpp(ctx *invoiceUpdateCtx, // Check whether total amt matches other htlcs in the set. var newSetTotal lnwire.MilliSatoshi - for _, htlc := range inv.Htlcs { - // Only consider accepted mpp htlcs. It is possible that there - // are htlcs registered in the invoice database that previously - // timed out and are in the canceled state now. - if htlc.State != channeldb.HtlcStateAccepted { - continue - } - + for _, htlc := range inv.HTLCSet(nil) { if ctx.mpp.TotalMsat() != htlc.MppTotalAmt { return nil, ctx.failRes(ResultHtlcSetTotalMismatch), nil } @@ -250,10 +243,8 @@ func updateLegacy(ctx *invoiceUpdateCtx, // Don't allow settling the invoice with an old style // htlc if we are already in the process of gathering an // mpp set. - for _, htlc := range inv.Htlcs { - if htlc.State == channeldb.HtlcStateAccepted && - htlc.MppTotalAmt > 0 { - + for _, htlc := range inv.HTLCSet(nil) { + if htlc.MppTotalAmt > 0 { return nil, ctx.failRes(ResultMppInProgress), nil } } From da049ebcf7831c23145ce277ad988e08857e5315 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:56:28 -0800 Subject: [PATCH 04/13] channeldb: ensure invoices can't be added with HTLCs --- channeldb/invoice_test.go | 18 ++++++++++++++++++ channeldb/invoices.go | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index 4e01f52e..a66d9f25 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -1304,6 +1304,24 @@ func TestHTLCSet(t *testing.T) { } } +// TestAddInvoiceWithHTLCs asserts that you can't insert an invoice that already +// has HTLCs. +func TestAddInvoiceWithHTLCs(t *testing.T) { + db, cleanUp, err := MakeTestDB() + defer cleanUp() + require.Nil(t, err) + + testInvoice, err := randInvoice(1000) + require.Nil(t, err) + + key := CircuitKey{HtlcID: 1} + testInvoice.Htlcs[key] = &InvoiceHTLC{} + + payHash := testInvoice.Terms.PaymentPreimage.Hash() + _, err = db.AddInvoice(testInvoice, payHash) + require.Equal(t, ErrInvoiceHasHtlcs, err) +} + // TestDeleteInvoices tests that deleting a list of invoices will succeed // if all delete references are valid, or will fail otherwise. func TestDeleteInvoices(t *testing.T) { diff --git a/channeldb/invoices.go b/channeldb/invoices.go index bcff0629..9f867ea8 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -106,6 +106,10 @@ var ( // ErrInvoicePreimageMismatch is returned when the preimage doesn't // match the invoice hash. ErrInvoicePreimageMismatch = errors.New("preimage does not match") + + // ErrInvoiceHasHtlcs is returned when attempting to insert an invoice + // that already has HTLCs. + ErrInvoiceHasHtlcs = errors.New("cannot add invoice with htlcs") ) const ( @@ -588,6 +592,11 @@ func validateInvoice(i *Invoice, paymentHash lntypes.Hash) error { if i.Terms.PaymentPreimage == nil && !i.HodlInvoice { return errors.New("non-hodl invoices must have a preimage") } + + if len(i.Htlcs) > 0 { + return ErrInvoiceHasHtlcs + } + return nil } From 7c0d1e0093611ec93fa41c229f46bc96adb29551 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:56:57 -0800 Subject: [PATCH 05/13] channeldb/invoice: map zero-value timestamps to 0 Mainly affects ResolveTime which can be 0 before its settled. --- channeldb/invoices.go | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 9f867ea8..48f01b83 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -1304,8 +1304,8 @@ func serializeHtlcs(w io.Writer, htlcs map[CircuitKey]*InvoiceHTLC) error { chanID := key.ChanID.ToUint64() amt := uint64(htlc.Amt) mppTotalAmt := uint64(htlc.MppTotalAmt) - acceptTime := uint64(htlc.AcceptTime.UnixNano()) - resolveTime := uint64(htlc.ResolveTime.UnixNano()) + acceptTime := putNanoTime(htlc.AcceptTime) + resolveTime := putNanoTime(htlc.ResolveTime) state := uint8(htlc.State) var records []tlv.Record @@ -1379,6 +1379,25 @@ func serializeHtlcs(w io.Writer, htlcs map[CircuitKey]*InvoiceHTLC) error { return nil } +// putNanoTime returns the unix nano time for the passed timestamp. A zero-value +// timestamp will be mapped to 0, since calling UnixNano in that case is +// undefined. +func putNanoTime(t time.Time) uint64 { + if t.IsZero() { + return 0 + } + return uint64(t.UnixNano()) +} + +// getNanoTime returns a timestamp for the given number of nano seconds. If zero +// is provided, an zero-value time stamp is returned. +func getNanoTime(ns uint64) time.Time { + if ns == 0 { + return time.Time{} + } + return time.Unix(0, int64(ns)) +} + func fetchInvoice(invoiceNum []byte, invoices kvdb.RBucket) (Invoice, error) { invoiceBytes := invoices.Get(invoiceNum) if invoiceBytes == nil { @@ -1564,8 +1583,8 @@ func deserializeHtlcs(r io.Reader) (map[CircuitKey]*InvoiceHTLC, error) { } key.ChanID = lnwire.NewShortChanIDFromInt(chanID) - htlc.AcceptTime = time.Unix(0, int64(acceptTime)) - htlc.ResolveTime = time.Unix(0, int64(resolveTime)) + htlc.AcceptTime = getNanoTime(acceptTime) + htlc.ResolveTime = getNanoTime(resolveTime) htlc.State = HtlcState(state) htlc.Amt = lnwire.MilliSatoshi(amt) htlc.MppTotalAmt = lnwire.MilliSatoshi(mppTotalAmt) From fad25f3f26be6d1ae629cd64cf145f8a42fb87b6 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:57:29 -0800 Subject: [PATCH 06/13] channeldb/invoices: add invoices to set id index on update --- channeldb/db.go | 7 ++ channeldb/invoice_test.go | 163 ++++++++++++++++++++++++++++++++++++++ channeldb/invoices.go | 104 +++++++++++++++++++++--- 3 files changed, 264 insertions(+), 10 deletions(-) diff --git a/channeldb/db.go b/channeldb/db.go index 76d0c37a..9f593513 100644 --- a/channeldb/db.go +++ b/channeldb/db.go @@ -189,6 +189,12 @@ var ( number: 21, migration: migration21.MigrateDatabaseWireMessages, }, + { + // Initialize set id index so that invoices can be + // queried by individual htlc sets. + number: 22, + migration: mig.CreateTLB(setIDIndexBucket), + }, } // Big endian is the preferred byte order, due to cursor scans over @@ -319,6 +325,7 @@ var topLevelBuckets = [][]byte{ fwdPackagesKey, invoiceBucket, payAddrIndexBucket, + setIDIndexBucket, paymentsIndexBucket, peersBucket, nodeInfoBucket, diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index a66d9f25..52b39742 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" @@ -1202,18 +1203,28 @@ func testInvoiceHtlcAMPFields(t *testing.T, isAMP bool) { func TestInvoiceRef(t *testing.T) { payHash := lntypes.Hash{0x01} payAddr := [32]byte{0x02} + setID := [32]byte{0x03} // An InvoiceRef by hash should return the provided hash and a nil // payment addr. refByHash := InvoiceRefByHash(payHash) require.Equal(t, payHash, refByHash.PayHash()) require.Equal(t, (*[32]byte)(nil), refByHash.PayAddr()) + require.Equal(t, (*[32]byte)(nil), refByHash.SetID()) // An InvoiceRef by hash and addr should return the payment hash and // payment addr passed to the constructor. refByHashAndAddr := InvoiceRefByHashAndAddr(payHash, payAddr) require.Equal(t, payHash, refByHashAndAddr.PayHash()) require.Equal(t, &payAddr, refByHashAndAddr.PayAddr()) + require.Equal(t, (*[32]byte)(nil), refByHashAndAddr.SetID()) + + // An InvoiceRef by set id should return an empty pay hash, a nil pay + // addr, and a reference to the given set id. + refBySetID := InvoiceRefBySetID(setID) + require.Equal(t, lntypes.Hash{}, refBySetID.PayHash()) + require.Equal(t, (*[32]byte)(nil), refBySetID.PayAddr()) + require.Equal(t, &setID, refBySetID.SetID()) } // TestHTLCSet asserts that HTLCSet returns the proper set of accepted HTLCs @@ -1322,6 +1333,157 @@ func TestAddInvoiceWithHTLCs(t *testing.T) { require.Equal(t, ErrInvoiceHasHtlcs, err) } +// TestSetIDIndex asserts that the set id index properly adds new invoices as we +// accept HTLCs, that they can be queried by their set id after accepting, and +// that invoices with duplicate set ids are disallowed. +func TestSetIDIndex(t *testing.T) { + testClock := clock.NewTestClock(testNow) + db, cleanUp, err := MakeTestDB(OptionClock(testClock)) + defer cleanUp() + require.Nil(t, err) + + // We'll start out by creating an invoice and writing it to the DB. + amt := lnwire.NewMSatFromSatoshis(1000) + invoice, err := randInvoice(amt) + require.Nil(t, err) + + preimage := *invoice.Terms.PaymentPreimage + payHash := preimage.Hash() + _, err = db.AddInvoice(invoice, payHash) + require.Nil(t, err) + + setID := &[32]byte{1} + + // Update the invoice with an accepted HTLC that also accepts the + // invoice. + ref := InvoiceRefByHashAndAddr(payHash, invoice.Terms.PaymentAddr) + dbInvoice, err := db.UpdateInvoice(ref, updateAcceptAMPHtlc(0, amt, setID, true)) + require.Nil(t, err) + + // We'll update what we expect the accepted invoice to be so that our + // comparison below has the correct assumption. + invoice.State = ContractAccepted + invoice.AmtPaid = amt + invoice.SettleDate = dbInvoice.SettleDate + invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{ + {HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID, preimage), + } + + // We should get back the exact same invoice that we just inserted. + require.Equal(t, invoice, dbInvoice) + + // Now lookup the invoice by set id and see that we get the same one. + refBySetID := InvoiceRefBySetID(*setID) + dbInvoiceBySetID, err := db.LookupInvoice(refBySetID) + require.Nil(t, err) + require.Equal(t, invoice, &dbInvoiceBySetID) + + // Trying to accept an HTLC to a different invoice, but using the same + // set id should fail. + invoice2, err := randInvoice(amt) + require.Nil(t, err) + + payHash2 := invoice2.Terms.PaymentPreimage.Hash() + _, err = db.AddInvoice(invoice2, payHash2) + require.Nil(t, err) + + ref2 := InvoiceRefByHashAndAddr(payHash2, invoice2.Terms.PaymentAddr) + _, err = db.UpdateInvoice(ref2, updateAcceptAMPHtlc(0, amt, setID, true)) + require.Equal(t, ErrDuplicateSetID{setID: *setID}, err) + + // Now, begin constructing a second htlc set under a different set id. + // This set will contain two distinct HTLCs. + setID2 := &[32]byte{2} + + _, err = db.UpdateInvoice(ref, updateAcceptAMPHtlc(1, amt, setID2, false)) + require.Nil(t, err) + dbInvoice, err = db.UpdateInvoice(ref, updateAcceptAMPHtlc(2, amt, setID2, false)) + require.Nil(t, err) + + // We'll update what we expect the settle invoice to be so that our + // comparison below has the correct assumption. + invoice.State = ContractAccepted + invoice.AmtPaid += 2 * amt + invoice.SettleDate = dbInvoice.SettleDate + invoice.Htlcs = map[CircuitKey]*InvoiceHTLC{ + {HtlcID: 0}: makeAMPInvoiceHTLC(amt, *setID, preimage), + {HtlcID: 1}: makeAMPInvoiceHTLC(amt, *setID2, preimage), + {HtlcID: 2}: makeAMPInvoiceHTLC(amt, *setID2, preimage), + } + + // We should get back the exact same invoice that we just inserted. + require.Equal(t, invoice, dbInvoice) + + // Now lookup the invoice by second set id and see that we get the same + // index, including the htlcs under the first set id. + refBySetID = InvoiceRefBySetID(*setID2) + dbInvoiceBySetID, err = db.LookupInvoice(refBySetID) + require.Nil(t, err) + require.Equal(t, invoice, &dbInvoiceBySetID) + + // Lastly, querying for an unknown set id should fail. + refUnknownSetID := InvoiceRefBySetID([32]byte{}) + _, err = db.LookupInvoice(refUnknownSetID) + require.Equal(t, ErrInvoiceNotFound, err) +} + +func makeAMPInvoiceHTLC(amt lnwire.MilliSatoshi, setID [32]byte, + preimage lntypes.Preimage) *InvoiceHTLC { + + return &InvoiceHTLC{ + Amt: amt, + AcceptTime: testNow, + ResolveTime: time.Time{}, + State: HtlcStateAccepted, + CustomRecords: make(record.CustomSet), + AMP: &InvoiceHtlcAMPData{ + Record: *record.NewAMP([32]byte{}, setID, 0), + Hash: preimage.Hash(), + Preimage: &preimage, + }, + } +} + +// updateAcceptAMPHtlc returns an invoice update callback that, when called, +// settles the invoice with the given amount. +func updateAcceptAMPHtlc(id uint64, amt lnwire.MilliSatoshi, + setID *[32]byte, accept bool) InvoiceUpdateCallback { + + return func(invoice *Invoice) (*InvoiceUpdateDesc, error) { + if invoice.State == ContractSettled { + return nil, ErrInvoiceAlreadySettled + } + + noRecords := make(record.CustomSet) + + var state *InvoiceStateUpdateDesc + if accept { + state = &InvoiceStateUpdateDesc{ + NewState: ContractAccepted, + SetID: setID, + } + } + + ampData := &InvoiceHtlcAMPData{ + Record: *record.NewAMP([32]byte{}, *setID, 0), + Hash: invoice.Terms.PaymentPreimage.Hash(), + Preimage: invoice.Terms.PaymentPreimage, + } + update := &InvoiceUpdateDesc{ + State: state, + AddHtlcs: map[CircuitKey]*HtlcAcceptDesc{ + {HtlcID: id}: { + Amt: amt, + CustomRecords: noRecords, + AMP: ampData, + }, + }, + } + + return update, nil + } +} + // TestDeleteInvoices tests that deleting a list of invoices will succeed // if all delete references are valid, or will fail otherwise. func TestDeleteInvoices(t *testing.T) { @@ -1413,4 +1575,5 @@ func TestDeleteInvoices(t *testing.T) { // Delete should succeed with all the valid references. require.NoError(t, db.DeleteInvoice(invoicesToDelete)) assertInvoiceCount(0) + } diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 48f01b83..e81a8fa8 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -53,6 +53,14 @@ var ( // maps: payAddr => invoiceKey payAddrIndexBucket = []byte("pay-addr-index") + // setIDIndexBucket is the name of the top-level bucket that maps set + // ids to their invoice number. This can be used to efficiently query or + // update AMP invoice. Note that legacy or MPP invoices will not be + // included in this index, since their HTLCs do not have a set id. + // + // maps: setID => invoiceKey + setIDIndexBucket = []byte("set-id-index") + // numInvoicesKey is the name of key which houses the auto-incrementing // invoice ID which is essentially used as a primary key. With each // invoice inserted, the primary key is incremented by one. This key is @@ -112,6 +120,17 @@ var ( ErrInvoiceHasHtlcs = errors.New("cannot add invoice with htlcs") ) +// ErrDuplicateSetID is an error returned when attempting to adding an AMP HTLC +// to an invoice, but another invoice is already indexed by the same set id. +type ErrDuplicateSetID struct { + setID [32]byte +} + +// Error returns a human-readable description of ErrDuplicateSetID. +func (e ErrDuplicateSetID) Error() string { + return fmt.Sprintf("invoice with set_id=%x already exists", e.setID) +} + const ( // MaxMemoSize is maximum size of the memo field within invoices stored // in the database. @@ -183,6 +202,14 @@ type InvoiceRef struct { // known it will be used as the primary identifier, falling back to // payHash if no value is known. payAddr *[32]byte + + // setID is the optional set id for an AMP payment. This can be used to + // lookup or update the invoice knowing only this value. Queries by set + // id are only used to facilitate user-facing requests, e.g. lookup, + // settle or cancel an AMP invoice. The regular update flow from the + // invoice registry will always query for the invoice by + // payHash+payAddr. + setID *[32]byte } // InvoiceRefByHash creates an InvoiceRef that queries for an invoice only by @@ -205,6 +232,15 @@ func InvoiceRefByHashAndAddr(payHash lntypes.Hash, } } +// InvoiceRefBySetID creates an InvoiceRef that queries the set id index for an +// invoice with the provided setID. If the invoice is not found, the query will +// not fallback to payHash or payAddr. +func InvoiceRefBySetID(setID [32]byte) InvoiceRef { + return InvoiceRef{ + setID: &setID, + } +} + // PayHash returns the target invoice's payment hash. func (r InvoiceRef) PayHash() lntypes.Hash { return r.payHash @@ -221,6 +257,17 @@ func (r InvoiceRef) PayAddr() *[32]byte { return nil } +// SetID returns the optional set id of the target invoice. +// +// NOTE: This value may be nil. +func (r InvoiceRef) SetID() *[32]byte { + if r.setID != nil { + id := *r.setID + return &id + } + return nil +} + // String returns a human-readable representation of an InvoiceRef. func (r InvoiceRef) String() string { if r.payAddr != nil { @@ -564,6 +611,11 @@ type InvoiceStateUpdateDesc struct { // Preimage must be set to the preimage when NewState is settled. Preimage *lntypes.Preimage + + // SetID identifies a specific set of HTLCs destined for the same + // invoice as part of a larger AMP payment. This value will be nil for + // legacy or MPP payments. + SetID *[32]byte } // InvoiceUpdateCallback is a callback used in the db transaction to update the @@ -772,11 +824,12 @@ func (d *DB) LookupInvoice(ref InvoiceRef) (Invoice, error) { return ErrNoInvoicesCreated } payAddrIndex := tx.ReadBucket(payAddrIndexBucket) + setIDIndex := tx.ReadBucket(setIDIndexBucket) - // Retrieve the invoice number for this invoice using the - // provided invoice reference. + // Retrieve the invoice number for this invoice using + // the provided invoice reference. invoiceNum, err := fetchInvoiceNumByRef( - invoiceIndex, payAddrIndex, ref, + invoiceIndex, payAddrIndex, setIDIndex, ref, ) if err != nil { return err @@ -803,9 +856,22 @@ func (d *DB) LookupInvoice(ref InvoiceRef) (Invoice, error) { // reference. The payment address will be treated as the primary key, falling // back to the payment hash if nothing is found for the payment address. An // error is returned if the invoice is not found. -func fetchInvoiceNumByRef(invoiceIndex, payAddrIndex kvdb.RBucket, +func fetchInvoiceNumByRef(invoiceIndex, payAddrIndex, setIDIndex kvdb.RBucket, ref InvoiceRef) ([]byte, error) { + // If the set id is present, we only consult the set id index for this + // invoice. This type of query is only used to facilitate user-facing + // requests to lookup, settle or cancel an AMP invoice. + setID := ref.SetID() + if setID != nil { + invoiceNumBySetID := setIDIndex.Get(setID[:]) + if invoiceNumBySetID == nil { + return nil, ErrInvoiceNotFound + } + + return invoiceNumBySetID, nil + } + payHash := ref.PayHash() payAddr := ref.PayAddr() @@ -1053,20 +1119,21 @@ func (d *DB) UpdateInvoice(ref InvoiceRef, return err } payAddrIndex := tx.ReadBucket(payAddrIndexBucket) + setIDIndex := tx.ReadWriteBucket(setIDIndexBucket) // Retrieve the invoice number for this invoice using the // provided invoice reference. invoiceNum, err := fetchInvoiceNumByRef( - invoiceIndex, payAddrIndex, ref, + invoiceIndex, payAddrIndex, setIDIndex, ref, ) if err != nil { return err - } + payHash := ref.PayHash() updatedInvoice, err = d.updateInvoice( - payHash, invoices, settleIndex, invoiceNum, - callback, + payHash, invoices, settleIndex, setIDIndex, + invoiceNum, callback, ) return err @@ -1662,8 +1729,9 @@ func copyInvoice(src *Invoice) *Invoice { // updateInvoice fetches the invoice, obtains the update descriptor from the // callback and applies the updates in a single db transaction. -func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex kvdb.RwBucket, - invoiceNum []byte, callback InvoiceUpdateCallback) (*Invoice, error) { +func (d *DB) updateInvoice(hash lntypes.Hash, invoices, + settleIndex, setIDIndex kvdb.RwBucket, invoiceNum []byte, + callback InvoiceUpdateCallback) (*Invoice, error) { invoice, err := fetchInvoice(invoiceNum, invoices) if err != nil { @@ -1717,6 +1785,22 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex kvdb.RwBucke return nil, errors.New("nil custom records map") } + // If a newly added HTLC has an associated set id, use it to + // index this invoice in the set id index. An error is returned + // if we find the index already points to a different invoice. + if htlcUpdate.AMP != nil { + setID := htlcUpdate.AMP.Record.SetID() + setIDInvNum := setIDIndex.Get(setID[:]) + if setIDInvNum == nil { + err = setIDIndex.Put(setID[:], invoiceNum) + if err != nil { + return nil, err + } + } else if !bytes.Equal(setIDInvNum, invoiceNum) { + return nil, ErrDuplicateSetID{setID: setID} + } + } + htlc := &InvoiceHTLC{ Amt: htlcUpdate.Amt, MppTotalAmt: htlcUpdate.MppTotalAmt, From e1b0fe5e9882babb2cab4349281401a6592090f5 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:58:02 -0800 Subject: [PATCH 07/13] channeldb/invoices: update AMP invoice htlcs --- channeldb/invoice_test.go | 35 +++++++++ channeldb/invoices.go | 147 ++++++++++++++++++++++++++++---------- 2 files changed, 144 insertions(+), 38 deletions(-) diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index 52b39742..ad4d84a2 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -1421,6 +1421,23 @@ func TestSetIDIndex(t *testing.T) { require.Nil(t, err) require.Equal(t, invoice, &dbInvoiceBySetID) + // Now settle the first htlc set, asserting that the two htlcs with set + // id 2 get canceled as a result. + dbInvoice, err = db.UpdateInvoice(ref, getUpdateInvoiceAMPSettle(setID)) + require.Nil(t, err) + + invoice.State = ContractSettled + invoice.SettleDate = dbInvoice.SettleDate + invoice.SettleIndex = 1 + invoice.AmtPaid = amt + invoice.Htlcs[CircuitKey{HtlcID: 0}].ResolveTime = time.Unix(1, 0) + invoice.Htlcs[CircuitKey{HtlcID: 0}].State = HtlcStateSettled + invoice.Htlcs[CircuitKey{HtlcID: 1}].ResolveTime = time.Unix(1, 0) + invoice.Htlcs[CircuitKey{HtlcID: 1}].State = HtlcStateCanceled + invoice.Htlcs[CircuitKey{HtlcID: 2}].ResolveTime = time.Unix(1, 0) + invoice.Htlcs[CircuitKey{HtlcID: 2}].State = HtlcStateCanceled + require.Equal(t, invoice, dbInvoice) + // Lastly, querying for an unknown set id should fail. refUnknownSetID := InvoiceRefBySetID([32]byte{}) _, err = db.LookupInvoice(refUnknownSetID) @@ -1484,6 +1501,24 @@ func updateAcceptAMPHtlc(id uint64, amt lnwire.MilliSatoshi, } } +func getUpdateInvoiceAMPSettle(setID *[32]byte) InvoiceUpdateCallback { + return func(invoice *Invoice) (*InvoiceUpdateDesc, error) { + if invoice.State == ContractSettled { + return nil, ErrInvoiceAlreadySettled + } + + update := &InvoiceUpdateDesc{ + State: &InvoiceStateUpdateDesc{ + Preimage: nil, + NewState: ContractSettled, + SetID: setID, + }, + } + + return update, nil + } +} + // TestDeleteInvoices tests that deleting a list of invoices will succeed // if all delete references are valid, or will fail otherwise. func TestDeleteInvoices(t *testing.T) { diff --git a/channeldb/invoices.go b/channeldb/invoices.go index e81a8fa8..3d1188ee 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -1753,6 +1753,11 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, return &invoice, nil } + var setID *[32]byte + if update.State != nil { + setID = update.State.SetID + } + now := d.clock.Now() // Update invoice state if the update descriptor indicates an invoice @@ -1847,7 +1852,7 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, // The invoice state may have changed and this could have // implications for the states of the individual htlcs. Align // the htlc state with the current invoice state. - err := updateHtlc(now, htlc, invoice.State) + err := updateHtlc(now, htlc, invoice.State, setID) if err != nil { return nil, err } @@ -1908,20 +1913,48 @@ func updateInvoiceState(invoice *Invoice, hash lntypes.Hash, // or canceled. The only restriction is on transitioning to settled // where we ensure the preimage is valid. case ContractOpen: - if update.NewState == ContractSettled { - // Validate preimage. - switch { - case update.Preimage != nil: - if update.Preimage.Hash() != hash { - return ErrInvoicePreimageMismatch - } - invoice.Terms.PaymentPreimage = update.Preimage - - case invoice.Terms.PaymentPreimage == nil: - return errors.New("unknown preimage") - } + if update.NewState == ContractCanceled { + invoice.State = update.NewState + return nil } + // For AMP invoices, there are no invoice-level preimage checks. + // However, we still sanity check that we aren't trying to + // settle an AMP invoice with a preimage. + if update.SetID != nil { + if update.Preimage != nil { + return errors.New("AMP set cannot have preimage") + } + invoice.State = update.NewState + return nil + } + + switch { + + // Validate the supplied preimage for non-AMP invoices. + case update.Preimage != nil: + if update.Preimage.Hash() != hash { + return ErrInvoicePreimageMismatch + } + invoice.Terms.PaymentPreimage = update.Preimage + + // Permit non-AMP invoices to be accepted without knowing the + // preimage. When trying to settle we'll have to pass through + // the above check in order to not hit the one below. + case update.NewState == ContractAccepted: + + // Fail if we still don't have a preimage when transitioning to + // settle the non-AMP invoice. + case update.NewState == ContractSettled && + invoice.Terms.PaymentPreimage == nil: + + return errors.New("unknown preimage") + } + + invoice.State = update.NewState + + return nil + // Once settled, we are in a terminal state. case ContractSettled: return ErrInvoiceAlreadySettled @@ -1933,10 +1966,6 @@ func updateInvoiceState(invoice *Invoice, hash lntypes.Hash, default: return errors.New("unknown state transition") } - - invoice.State = update.NewState - - return nil } // cancelSingleHtlc validates cancelation of a single htlc and update its state. @@ -1963,39 +1992,81 @@ func cancelSingleHtlc(resolveTime time.Time, htlc *InvoiceHTLC, // updateHtlc aligns the state of an htlc with the given invoice state. func updateHtlc(resolveTime time.Time, htlc *InvoiceHTLC, - invState ContractState) error { + invState ContractState, setID *[32]byte) error { + + trySettle := func(persist bool) error { + if htlc.State != HtlcStateAccepted { + return nil + } + + // Settle the HTLC if it matches the settled set id. Since we + // only allow settling of one HTLC set (for now) we cancel any + // that do not match the set id. + var htlcState HtlcState + if htlc.IsInHTLCSet(setID) { + // Non-AMP HTLCs can be settled immediately since we + // already know the preimage is valid due to checks at + // the invoice level. For AMP HTLCs, verify that the + // per-HTLC preimage-hash pair is valid. + if setID != nil && !htlc.AMP.Preimage.Matches(htlc.AMP.Hash) { + return fmt.Errorf("AMP preimage mismatch, "+ + "preimage=%v hash=%v", *htlc.AMP.Preimage, + htlc.AMP.Hash) + } + + htlcState = HtlcStateSettled + } else { + htlcState = HtlcStateCanceled + } + + // Only persist the changes if the invoice is moving to the + // settled state. + if persist { + htlc.State = htlcState + htlc.ResolveTime = resolveTime + } + + return nil + } + + if invState == ContractSettled { + // Check that we can settle the HTLCs. For legacy and MPP HTLCs + // this will be a NOP, but for AMP HTLCs this asserts that we + // have a valid hash/preimage pair. Passing true permits the + // method to update the HTLC to HtlcStateSettled. + return trySettle(true) + } + + // We should never find a settled HTLC on an invoice that isn't in + // ContractSettled. + if htlc.State == HtlcStateSettled { + return fmt.Errorf("cannot have a settled htlc with "+ + "invoice in state %v", invState) + } switch invState { - case ContractSettled: - if htlc.State == HtlcStateAccepted { - htlc.State = HtlcStateSettled - htlc.ResolveTime = resolveTime - } - case ContractCanceled: - switch htlc.State { - - case HtlcStateAccepted: + if htlc.State == HtlcStateAccepted { htlc.State = HtlcStateCanceled htlc.ResolveTime = resolveTime - - case HtlcStateSettled: - return fmt.Errorf("cannot have a settled htlc with " + - "invoice in state canceled") } + return nil - case ContractOpen, ContractAccepted: - if htlc.State == HtlcStateSettled { - return fmt.Errorf("cannot have a settled htlc with "+ - "invoice in state %v", invState) - } + case ContractAccepted: + // Check that we can settle the HTLCs. For legacy and MPP HTLCs + // this will be a NOP, but for AMP HTLCs this asserts that we + // have a valid hash/preimage pair. Passing false prevents the + // method from putting the HTLC in HtlcStateSettled, leaving it + // in HtlcStateAccepted. + return trySettle(false) + + case ContractOpen: + return nil default: return errors.New("unknown state transition") } - - return nil } // setSettleMetaFields updates the metadata associated with settlement of an From fc9af92dd93801cdd7545c5246f357e81c03f64f Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:58:33 -0800 Subject: [PATCH 08/13] channeldb: only accept/settle non-empty HTLC sets Prior to AMP, there could only be one HTLC set. Now that there can be multiple, we introduce the inherent risk that we might be persisting a settle/accept of the wrong HTLC set. To migitigate this risk, we add a check to assert that an invoice can only be transitioned into an Accepted or Settled state if the specified HTLC set is non-empty, i.e. has accepted HTLCs. To do this check, we unroll the loops in UpdateInvoice to first process any added or canceled HTLCs. This ensures that the set of accepted HTLCs is up-to-date when we got to transition the invoice into a new state, at which point we can accurately check that the HTLC set is non-empty. Previously this sort of check wasn't possible because a newly added HTLC wouldn't be populated on the invoice when going to call updateInvoiceState. Once the invoice-level transition checks have completed, we complete a final pass to move the HTLCs into their final states and recompute the amount paid. With this refactor, it is now possible to make stronger assertions about the invoice and the state transitions being made by the invoiceregistry before those changes are ultimately persisted. --- channeldb/invoice_test.go | 7 ++++ channeldb/invoices.go | 82 ++++++++++++++++++++++++--------------- 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/channeldb/invoice_test.go b/channeldb/invoice_test.go index ad4d84a2..3b0416d1 100644 --- a/channeldb/invoice_test.go +++ b/channeldb/invoice_test.go @@ -1421,6 +1421,13 @@ func TestSetIDIndex(t *testing.T) { require.Nil(t, err) require.Equal(t, invoice, &dbInvoiceBySetID) + // Now settle the first htlc set, asserting that the two htlcs with set + // id 2 get canceled as a result. + _, err = db.UpdateInvoice( + ref, getUpdateInvoiceAMPSettle(&[32]byte{}), + ) + require.Equal(t, ErrEmptyHTLCSet, err) + // Now settle the first htlc set, asserting that the two htlcs with set // id 2 get canceled as a result. dbInvoice, err = db.UpdateInvoice(ref, getUpdateInvoiceAMPSettle(setID)) diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 3d1188ee..5cb0cdfc 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -118,6 +118,10 @@ var ( // ErrInvoiceHasHtlcs is returned when attempting to insert an invoice // that already has HTLCs. ErrInvoiceHasHtlcs = errors.New("cannot add invoice with htlcs") + + // ErrEmptyHTLCSet is returned when attempting to accept or settle and + // HTLC set that has no HTLCs. + ErrEmptyHTLCSet = errors.New("cannot settle/accept empty HTLC set") ) // ErrDuplicateSetID is an error returned when attempting to adding an AMP HTLC @@ -1753,31 +1757,17 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, return &invoice, nil } - var setID *[32]byte + var ( + newState = invoice.State + setID *[32]byte + ) if update.State != nil { setID = update.State.SetID + newState = update.State.NewState } now := d.clock.Now() - // Update invoice state if the update descriptor indicates an invoice - // state change. - if update.State != nil { - err := updateInvoiceState(&invoice, hash, *update.State) - if err != nil { - return nil, err - } - - if update.State.NewState == ContractSettled { - err := setSettleMetaFields( - settleIndex, invoiceNum, &invoice, now, - ) - if err != nil { - return nil, err - } - } - } - // Process add actions from update descriptor. for key, htlcUpdate := range update.AddHtlcs { if _, exists := invoice.Htlcs[key]; exists { @@ -1820,11 +1810,8 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, invoice.Htlcs[key] = htlc } - // Align htlc states with invoice state and recalculate amount paid. - var ( - amtPaid lnwire.MilliSatoshi - cancelHtlcs = update.CancelHtlcs - ) + // Process cancel actions from update descriptor. + cancelHtlcs := update.CancelHtlcs for key, htlc := range invoice.Htlcs { // Check whether this htlc needs to be canceled. If it does, // update the htlc state to Canceled. @@ -1837,7 +1824,7 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, key) } - err := cancelSingleHtlc(now, htlc, invoice.State) + err := cancelSingleHtlc(now, htlc, newState) if err != nil { return nil, err } @@ -1845,10 +1832,41 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, // Delete processed cancel action, so that we can check // later that there are no actions left. delete(cancelHtlcs, key) + } + } - continue + // Verify that we didn't get an action for htlcs that are not present on + // the invoice. + if len(cancelHtlcs) > 0 { + return nil, errors.New("cancel action on non-existent htlc(s)") + } + + // At this point, the set of accepted HTLCs should be fully + // populated with added HTLCs or removed of canceled ones. Update + // invoice state if the update descriptor indicates an invoice state + // change, which depends on having an accurate view of the accepted + // HTLCs. + if update.State != nil { + err := updateInvoiceState(&invoice, hash, *update.State) + if err != nil { + return nil, err } + if update.State.NewState == ContractSettled { + err := setSettleMetaFields( + settleIndex, invoiceNum, &invoice, now, + ) + if err != nil { + return nil, err + } + } + } + + // With any invoice level state transitions recorded, we'll now finalize + // the process by updating the state transitions for individual HTLCs + // and recalculate the total amount paid to the invoice. + var amtPaid lnwire.MilliSatoshi + for _, htlc := range invoice.Htlcs { // The invoice state may have changed and this could have // implications for the states of the individual htlcs. Align // the htlc state with the current invoice state. @@ -1868,12 +1886,6 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, } invoice.AmtPaid = amtPaid - // Verify that we didn't get an action for htlcs that are not present on - // the invoice. - if len(cancelHtlcs) > 0 { - return nil, errors.New("cancel action on non-existent htlc(s)") - } - // Reserialize and update invoice. var buf bytes.Buffer if err := serializeInvoice(&buf, &invoice); err != nil { @@ -1918,6 +1930,12 @@ func updateInvoiceState(invoice *Invoice, hash lntypes.Hash, return nil } + // Sanity check that the user isn't trying to settle or accept a + // non-existent HTLC set. + if len(invoice.HTLCSet(update.SetID)) == 0 { + return ErrEmptyHTLCSet + } + // For AMP invoices, there are no invoice-level preimage checks. // However, we still sanity check that we aren't trying to // settle an AMP invoice with a preimage. From 5f348800409832aab1bb66a6782fcae734927eec Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:59:05 -0800 Subject: [PATCH 09/13] channeldb/invoices: continue cancel loop early --- channeldb/invoices.go | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/channeldb/invoices.go b/channeldb/invoices.go index 5cb0cdfc..1675f15c 100644 --- a/channeldb/invoices.go +++ b/channeldb/invoices.go @@ -1816,23 +1816,24 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, // Check whether this htlc needs to be canceled. If it does, // update the htlc state to Canceled. _, cancel := cancelHtlcs[key] - if cancel { - // Consistency check to verify that there is no overlap - // between the add and cancel sets. - if _, added := update.AddHtlcs[key]; added { - return nil, fmt.Errorf("added htlc %v canceled", - key) - } - - err := cancelSingleHtlc(now, htlc, newState) - if err != nil { - return nil, err - } - - // Delete processed cancel action, so that we can check - // later that there are no actions left. - delete(cancelHtlcs, key) + if !cancel { + continue } + + // Consistency check to verify that there is no overlap between + // the add and cancel sets. + if _, added := update.AddHtlcs[key]; added { + return nil, fmt.Errorf("added htlc %v canceled", key) + } + + err := cancelSingleHtlc(now, htlc, newState) + if err != nil { + return nil, err + } + + // Delete processed cancel action, so that we can check later + // that there are no actions left. + delete(cancelHtlcs, key) } // Verify that we didn't get an action for htlcs that are not present on From 9da3e7fc909eed494dbc18c39b111b522bcc4b82 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:59:29 -0800 Subject: [PATCH 10/13] invoices: filter HTLC set by set id from AMP payload --- invoices/update.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/invoices/update.go b/invoices/update.go index 41bd690b..45435ca8 100644 --- a/invoices/update.go +++ b/invoices/update.go @@ -33,6 +33,17 @@ func (i *invoiceUpdateCtx) invoiceRef() channeldb.InvoiceRef { return channeldb.InvoiceRefByHash(i.hash) } +// setID returns an identifier that identifies other possible HTLCs that this +// particular one is related to. If nil is returned this means the HTLC is an +// MPP or legacy payment, otherwise the HTLC belongs AMP payment. +func (i invoiceUpdateCtx) setID() *[32]byte { + if i.amp != nil { + setID := i.amp.SetID() + return &setID + } + return nil +} + // log logs a message specific to this update context. func (i *invoiceUpdateCtx) log(s string) { log.Debugf("Invoice%v: %v, amt=%v, expiry=%v, circuit=%v, mpp=%v, "+ @@ -108,6 +119,8 @@ func updateMpp(ctx *invoiceUpdateCtx, inv *channeldb.Invoice) (*channeldb.InvoiceUpdateDesc, HtlcResolution, error) { + setID := ctx.setID() + // Start building the accept descriptor. acceptDesc := &channeldb.HtlcAcceptDesc{ Amt: ctx.amtPaid, @@ -143,7 +156,7 @@ func updateMpp(ctx *invoiceUpdateCtx, // Check whether total amt matches other htlcs in the set. var newSetTotal lnwire.MilliSatoshi - for _, htlc := range inv.HTLCSet(nil) { + for _, htlc := range inv.HTLCSet(setID) { if ctx.mpp.TotalMsat() != htlc.MppTotalAmt { return nil, ctx.failRes(ResultHtlcSetTotalMismatch), nil } @@ -188,6 +201,7 @@ func updateMpp(ctx *invoiceUpdateCtx, if inv.HodlInvoice { update.State = &channeldb.InvoiceStateUpdateDesc{ NewState: channeldb.ContractAccepted, + SetID: setID, } return &update, ctx.acceptRes(resultAccepted), nil } @@ -195,6 +209,7 @@ func updateMpp(ctx *invoiceUpdateCtx, update.State = &channeldb.InvoiceStateUpdateDesc{ NewState: channeldb.ContractSettled, Preimage: inv.Terms.PaymentPreimage, + SetID: setID, } return &update, ctx.settleRes( From 137258fb58e2cc3a5d1bceecb279796931438d8f Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 09:59:51 -0800 Subject: [PATCH 11/13] invoices/invoiceregistry: unbundle invalid preimage error --- invoices/invoiceregistry.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/invoices/invoiceregistry.go b/invoices/invoiceregistry.go index dcaa9898..e6e4093b 100644 --- a/invoices/invoiceregistry.go +++ b/invoices/invoiceregistry.go @@ -707,8 +707,12 @@ func (i *InvoiceRegistry) processKeySend(ctx invoiceUpdateCtx) error { // Cancel htlc is preimage is invalid. preimage, err := lntypes.MakePreimage(preimageSlice) - if err != nil || preimage.Hash() != ctx.hash { - return errors.New("invalid keysend preimage") + if err != nil { + return err + } + if preimage.Hash() != ctx.hash { + return fmt.Errorf("invalid keysend preimage %v for hash %v", + preimage, ctx.hash) } // Only allow keysend for non-mpp payments. From d004442efbd1c3bd02f66efa54e1f71f502f591e Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 10:00:14 -0800 Subject: [PATCH 12/13] lnrpc+itest: expose AMP fields on InvoiceHTLC We also test that legacy keysend payments are promoted to AMP payments on the receiver-sdie by asserting basic properties of the fields returned via the rpc. --- lnrpc/invoicesrpc/invoices.swagger.json | 35 + lnrpc/invoicesrpc/utils.go | 19 + lnrpc/rpc.pb.go | 934 +++++++++++--------- lnrpc/rpc.proto | 25 + lnrpc/rpc.swagger.json | 35 + lntest/itest/lnd_single_hop_invoice_test.go | 16 + 6 files changed, 645 insertions(+), 419 deletions(-) diff --git a/lnrpc/invoicesrpc/invoices.swagger.json b/lnrpc/invoicesrpc/invoices.swagger.json index 45cad92f..93fad0ef 100644 --- a/lnrpc/invoicesrpc/invoices.swagger.json +++ b/lnrpc/invoicesrpc/invoices.swagger.json @@ -256,6 +256,37 @@ "invoicesrpcSettleInvoiceResp": { "type": "object" }, + "lnrpcAMP": { + "type": "object", + "properties": { + "root_share": { + "type": "string", + "format": "byte", + "description": "An n-of-n secret share of the root seed from which child payment hashes\nand preimages are derived." + }, + "set_id": { + "type": "string", + "format": "byte", + "description": "An identifier for the HTLC set that this HTLC belongs to." + }, + "child_index": { + "type": "integer", + "format": "int64", + "description": "A nonce used to randomize the child preimage and child hash from a given\nroot_share." + }, + "hash": { + "type": "string", + "format": "byte", + "description": "The payment hash of the AMP HTLC." + }, + "preimage": { + "type": "string", + "format": "byte", + "description": "The preimage used to settle this AMP htlc. This field will only be\npopulated if the invoice is in InvoiceState_ACCEPTED or\nInvoiceState_SETTLED." + } + }, + "description": "Details specific to AMP HTLCs." + }, "lnrpcFeature": { "type": "object", "properties": { @@ -489,6 +520,10 @@ "type": "string", "format": "uint64", "description": "The total amount of the mpp payment in msat." + }, + "amp": { + "$ref": "#/definitions/lnrpcAMP", + "description": "Details relevant to AMP HTLCs, only populated if this is an AMP HTLC." } }, "title": "Details of an HTLC that paid to an invoice" diff --git a/lnrpc/invoicesrpc/utils.go b/lnrpc/invoicesrpc/utils.go index e68c3f95..ad7c0e68 100644 --- a/lnrpc/invoicesrpc/utils.go +++ b/lnrpc/invoicesrpc/utils.go @@ -116,6 +116,25 @@ func CreateRPCInvoice(invoice *channeldb.Invoice, MppTotalAmtMsat: uint64(htlc.MppTotalAmt), } + // Populate any fields relevant to AMP payments. + if htlc.AMP != nil { + rootShare := htlc.AMP.Record.RootShare() + setID := htlc.AMP.Record.SetID() + + var preimage []byte + if htlc.AMP.Preimage != nil { + preimage = htlc.AMP.Preimage[:] + } + + rpcHtlc.Amp = &lnrpc.AMP{ + RootShare: rootShare[:], + SetId: setID[:], + ChildIndex: uint32(htlc.AMP.Record.ChildIndex()), + Hash: htlc.AMP.Hash[:], + Preimage: preimage, + } + } + // Only report resolved times if htlc is resolved. if htlc.State != channeldb.HtlcStateAccepted { rpcHtlc.ResolveTime = htlc.ResolveTime.Unix() diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index e8013d11..0cf5c442 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -644,7 +644,7 @@ func (x Payment_PaymentStatus) String() string { } func (Payment_PaymentStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{117, 0} + return fileDescriptor_77a6da22d6a3feb1, []int{118, 0} } type HTLCAttempt_HTLCStatus int32 @@ -672,7 +672,7 @@ func (x HTLCAttempt_HTLCStatus) String() string { } func (HTLCAttempt_HTLCStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{118, 0} + return fileDescriptor_77a6da22d6a3feb1, []int{119, 0} } type Failure_FailureCode int32 @@ -783,7 +783,7 @@ func (x Failure_FailureCode) String() string { } func (Failure_FailureCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{158, 0} + return fileDescriptor_77a6da22d6a3feb1, []int{159, 0} } type Utxo struct { @@ -9536,7 +9536,9 @@ type InvoiceHTLC struct { // Custom tlv records. CustomRecords map[uint64][]byte `protobuf:"bytes,9,rep,name=custom_records,json=customRecords,proto3" json:"custom_records,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // The total amount of the mpp payment in msat. - MppTotalAmtMsat uint64 `protobuf:"varint,10,opt,name=mpp_total_amt_msat,json=mppTotalAmtMsat,proto3" json:"mpp_total_amt_msat,omitempty"` + MppTotalAmtMsat uint64 `protobuf:"varint,10,opt,name=mpp_total_amt_msat,json=mppTotalAmtMsat,proto3" json:"mpp_total_amt_msat,omitempty"` + // Details relevant to AMP HTLCs, only populated if this is an AMP HTLC. + Amp *AMP `protobuf:"bytes,11,opt,name=amp,proto3" json:"amp,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -9637,6 +9639,94 @@ func (m *InvoiceHTLC) GetMppTotalAmtMsat() uint64 { return 0 } +func (m *InvoiceHTLC) GetAmp() *AMP { + if m != nil { + return m.Amp + } + return nil +} + +// Details specific to AMP HTLCs. +type AMP struct { + // An n-of-n secret share of the root seed from which child payment hashes + // and preimages are derived. + RootShare []byte `protobuf:"bytes,1,opt,name=root_share,json=rootShare,proto3" json:"root_share,omitempty"` + // An identifier for the HTLC set that this HTLC belongs to. + SetId []byte `protobuf:"bytes,2,opt,name=set_id,json=setId,proto3" json:"set_id,omitempty"` + // A nonce used to randomize the child preimage and child hash from a given + // root_share. + ChildIndex uint32 `protobuf:"varint,3,opt,name=child_index,json=childIndex,proto3" json:"child_index,omitempty"` + // The payment hash of the AMP HTLC. + Hash []byte `protobuf:"bytes,4,opt,name=hash,proto3" json:"hash,omitempty"` + // The preimage used to settle this AMP htlc. This field will only be + // populated if the invoice is in InvoiceState_ACCEPTED or + // InvoiceState_SETTLED. + Preimage []byte `protobuf:"bytes,5,opt,name=preimage,proto3" json:"preimage,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *AMP) Reset() { *m = AMP{} } +func (m *AMP) String() string { return proto.CompactTextString(m) } +func (*AMP) ProtoMessage() {} +func (*AMP) Descriptor() ([]byte, []int) { + return fileDescriptor_77a6da22d6a3feb1, []int{112} +} + +func (m *AMP) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_AMP.Unmarshal(m, b) +} +func (m *AMP) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_AMP.Marshal(b, m, deterministic) +} +func (m *AMP) XXX_Merge(src proto.Message) { + xxx_messageInfo_AMP.Merge(m, src) +} +func (m *AMP) XXX_Size() int { + return xxx_messageInfo_AMP.Size(m) +} +func (m *AMP) XXX_DiscardUnknown() { + xxx_messageInfo_AMP.DiscardUnknown(m) +} + +var xxx_messageInfo_AMP proto.InternalMessageInfo + +func (m *AMP) GetRootShare() []byte { + if m != nil { + return m.RootShare + } + return nil +} + +func (m *AMP) GetSetId() []byte { + if m != nil { + return m.SetId + } + return nil +} + +func (m *AMP) GetChildIndex() uint32 { + if m != nil { + return m.ChildIndex + } + return 0 +} + +func (m *AMP) GetHash() []byte { + if m != nil { + return m.Hash + } + return nil +} + +func (m *AMP) GetPreimage() []byte { + if m != nil { + return m.Preimage + } + return nil +} + type AddInvoiceResponse struct { RHash []byte `protobuf:"bytes,1,opt,name=r_hash,json=rHash,proto3" json:"r_hash,omitempty"` // @@ -9664,7 +9754,7 @@ func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} } func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*AddInvoiceResponse) ProtoMessage() {} func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{112} + return fileDescriptor_77a6da22d6a3feb1, []int{113} } func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error { @@ -9733,7 +9823,7 @@ func (m *PaymentHash) Reset() { *m = PaymentHash{} } func (m *PaymentHash) String() string { return proto.CompactTextString(m) } func (*PaymentHash) ProtoMessage() {} func (*PaymentHash) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{113} + return fileDescriptor_77a6da22d6a3feb1, []int{114} } func (m *PaymentHash) XXX_Unmarshal(b []byte) error { @@ -9793,7 +9883,7 @@ func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} } func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) } func (*ListInvoiceRequest) ProtoMessage() {} func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{114} + return fileDescriptor_77a6da22d6a3feb1, []int{115} } func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error { @@ -9864,7 +9954,7 @@ func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} } func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*ListInvoiceResponse) ProtoMessage() {} func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{115} + return fileDescriptor_77a6da22d6a3feb1, []int{116} } func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error { @@ -9928,7 +10018,7 @@ func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} } func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) } func (*InvoiceSubscription) ProtoMessage() {} func (*InvoiceSubscription) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{116} + return fileDescriptor_77a6da22d6a3feb1, []int{117} } func (m *InvoiceSubscription) XXX_Unmarshal(b []byte) error { @@ -10005,7 +10095,7 @@ func (m *Payment) Reset() { *m = Payment{} } func (m *Payment) String() string { return proto.CompactTextString(m) } func (*Payment) ProtoMessage() {} func (*Payment) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{117} + return fileDescriptor_77a6da22d6a3feb1, []int{118} } func (m *Payment) XXX_Unmarshal(b []byte) error { @@ -10160,7 +10250,7 @@ func (m *HTLCAttempt) Reset() { *m = HTLCAttempt{} } func (m *HTLCAttempt) String() string { return proto.CompactTextString(m) } func (*HTLCAttempt) ProtoMessage() {} func (*HTLCAttempt) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{118} + return fileDescriptor_77a6da22d6a3feb1, []int{119} } func (m *HTLCAttempt) XXX_Unmarshal(b []byte) error { @@ -10260,7 +10350,7 @@ func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} } func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*ListPaymentsRequest) ProtoMessage() {} func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{119} + return fileDescriptor_77a6da22d6a3feb1, []int{120} } func (m *ListPaymentsRequest) XXX_Unmarshal(b []byte) error { @@ -10329,7 +10419,7 @@ func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} } func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*ListPaymentsResponse) ProtoMessage() {} func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{120} + return fileDescriptor_77a6da22d6a3feb1, []int{121} } func (m *ListPaymentsResponse) XXX_Unmarshal(b []byte) error { @@ -10386,7 +10476,7 @@ func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsReque func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsRequest) ProtoMessage() {} func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{121} + return fileDescriptor_77a6da22d6a3feb1, []int{122} } func (m *DeleteAllPaymentsRequest) XXX_Unmarshal(b []byte) error { @@ -10431,7 +10521,7 @@ func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResp func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsResponse) ProtoMessage() {} func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{122} + return fileDescriptor_77a6da22d6a3feb1, []int{123} } func (m *DeleteAllPaymentsResponse) XXX_Unmarshal(b []byte) error { @@ -10464,7 +10554,7 @@ func (m *AbandonChannelRequest) Reset() { *m = AbandonChannelRequest{} } func (m *AbandonChannelRequest) String() string { return proto.CompactTextString(m) } func (*AbandonChannelRequest) ProtoMessage() {} func (*AbandonChannelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{123} + return fileDescriptor_77a6da22d6a3feb1, []int{124} } func (m *AbandonChannelRequest) XXX_Unmarshal(b []byte) error { @@ -10509,7 +10599,7 @@ func (m *AbandonChannelResponse) Reset() { *m = AbandonChannelResponse{} func (m *AbandonChannelResponse) String() string { return proto.CompactTextString(m) } func (*AbandonChannelResponse) ProtoMessage() {} func (*AbandonChannelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{124} + return fileDescriptor_77a6da22d6a3feb1, []int{125} } func (m *AbandonChannelResponse) XXX_Unmarshal(b []byte) error { @@ -10542,7 +10632,7 @@ func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} } func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) } func (*DebugLevelRequest) ProtoMessage() {} func (*DebugLevelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{125} + return fileDescriptor_77a6da22d6a3feb1, []int{126} } func (m *DebugLevelRequest) XXX_Unmarshal(b []byte) error { @@ -10588,7 +10678,7 @@ func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} } func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) } func (*DebugLevelResponse) ProtoMessage() {} func (*DebugLevelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{126} + return fileDescriptor_77a6da22d6a3feb1, []int{127} } func (m *DebugLevelResponse) XXX_Unmarshal(b []byte) error { @@ -10628,7 +10718,7 @@ func (m *PayReqString) Reset() { *m = PayReqString{} } func (m *PayReqString) String() string { return proto.CompactTextString(m) } func (*PayReqString) ProtoMessage() {} func (*PayReqString) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{127} + return fileDescriptor_77a6da22d6a3feb1, []int{128} } func (m *PayReqString) XXX_Unmarshal(b []byte) error { @@ -10679,7 +10769,7 @@ func (m *PayReq) Reset() { *m = PayReq{} } func (m *PayReq) String() string { return proto.CompactTextString(m) } func (*PayReq) ProtoMessage() {} func (*PayReq) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{128} + return fileDescriptor_77a6da22d6a3feb1, []int{129} } func (m *PayReq) XXX_Unmarshal(b []byte) error { @@ -10804,7 +10894,7 @@ func (m *Feature) Reset() { *m = Feature{} } func (m *Feature) String() string { return proto.CompactTextString(m) } func (*Feature) ProtoMessage() {} func (*Feature) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{129} + return fileDescriptor_77a6da22d6a3feb1, []int{130} } func (m *Feature) XXX_Unmarshal(b []byte) error { @@ -10856,7 +10946,7 @@ func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} } func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) } func (*FeeReportRequest) ProtoMessage() {} func (*FeeReportRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{130} + return fileDescriptor_77a6da22d6a3feb1, []int{131} } func (m *FeeReportRequest) XXX_Unmarshal(b []byte) error { @@ -10899,7 +10989,7 @@ func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} } func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) } func (*ChannelFeeReport) ProtoMessage() {} func (*ChannelFeeReport) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{131} + return fileDescriptor_77a6da22d6a3feb1, []int{132} } func (m *ChannelFeeReport) XXX_Unmarshal(b []byte) error { @@ -10977,7 +11067,7 @@ func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} } func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) } func (*FeeReportResponse) ProtoMessage() {} func (*FeeReportResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{132} + return fileDescriptor_77a6da22d6a3feb1, []int{133} } func (m *FeeReportResponse) XXX_Unmarshal(b []byte) error { @@ -11055,7 +11145,7 @@ func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} } func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateRequest) ProtoMessage() {} func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{133} + return fileDescriptor_77a6da22d6a3feb1, []int{134} } func (m *PolicyUpdateRequest) XXX_Unmarshal(b []byte) error { @@ -11173,7 +11263,7 @@ func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} } func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateResponse) ProtoMessage() {} func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{134} + return fileDescriptor_77a6da22d6a3feb1, []int{135} } func (m *PolicyUpdateResponse) XXX_Unmarshal(b []byte) error { @@ -11218,7 +11308,7 @@ func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryReque func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryRequest) ProtoMessage() {} func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{135} + return fileDescriptor_77a6da22d6a3feb1, []int{136} } func (m *ForwardingHistoryRequest) XXX_Unmarshal(b []byte) error { @@ -11301,7 +11391,7 @@ func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} } func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) } func (*ForwardingEvent) ProtoMessage() {} func (*ForwardingEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{136} + return fileDescriptor_77a6da22d6a3feb1, []int{137} } func (m *ForwardingEvent) XXX_Unmarshal(b []byte) error { @@ -11401,7 +11491,7 @@ func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResp func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryResponse) ProtoMessage() {} func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{137} + return fileDescriptor_77a6da22d6a3feb1, []int{138} } func (m *ForwardingHistoryResponse) XXX_Unmarshal(b []byte) error { @@ -11448,7 +11538,7 @@ func (m *ExportChannelBackupRequest) Reset() { *m = ExportChannelBackupR func (m *ExportChannelBackupRequest) String() string { return proto.CompactTextString(m) } func (*ExportChannelBackupRequest) ProtoMessage() {} func (*ExportChannelBackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{138} + return fileDescriptor_77a6da22d6a3feb1, []int{139} } func (m *ExportChannelBackupRequest) XXX_Unmarshal(b []byte) error { @@ -11495,7 +11585,7 @@ func (m *ChannelBackup) Reset() { *m = ChannelBackup{} } func (m *ChannelBackup) String() string { return proto.CompactTextString(m) } func (*ChannelBackup) ProtoMessage() {} func (*ChannelBackup) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{139} + return fileDescriptor_77a6da22d6a3feb1, []int{140} } func (m *ChannelBackup) XXX_Unmarshal(b []byte) error { @@ -11549,7 +11639,7 @@ func (m *MultiChanBackup) Reset() { *m = MultiChanBackup{} } func (m *MultiChanBackup) String() string { return proto.CompactTextString(m) } func (*MultiChanBackup) ProtoMessage() {} func (*MultiChanBackup) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{140} + return fileDescriptor_77a6da22d6a3feb1, []int{141} } func (m *MultiChanBackup) XXX_Unmarshal(b []byte) error { @@ -11594,7 +11684,7 @@ func (m *ChanBackupExportRequest) Reset() { *m = ChanBackupExportRequest func (m *ChanBackupExportRequest) String() string { return proto.CompactTextString(m) } func (*ChanBackupExportRequest) ProtoMessage() {} func (*ChanBackupExportRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{141} + return fileDescriptor_77a6da22d6a3feb1, []int{142} } func (m *ChanBackupExportRequest) XXX_Unmarshal(b []byte) error { @@ -11633,7 +11723,7 @@ func (m *ChanBackupSnapshot) Reset() { *m = ChanBackupSnapshot{} } func (m *ChanBackupSnapshot) String() string { return proto.CompactTextString(m) } func (*ChanBackupSnapshot) ProtoMessage() {} func (*ChanBackupSnapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{142} + return fileDescriptor_77a6da22d6a3feb1, []int{143} } func (m *ChanBackupSnapshot) XXX_Unmarshal(b []byte) error { @@ -11681,7 +11771,7 @@ func (m *ChannelBackups) Reset() { *m = ChannelBackups{} } func (m *ChannelBackups) String() string { return proto.CompactTextString(m) } func (*ChannelBackups) ProtoMessage() {} func (*ChannelBackups) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{143} + return fileDescriptor_77a6da22d6a3feb1, []int{144} } func (m *ChannelBackups) XXX_Unmarshal(b []byte) error { @@ -11723,7 +11813,7 @@ func (m *RestoreChanBackupRequest) Reset() { *m = RestoreChanBackupReque func (m *RestoreChanBackupRequest) String() string { return proto.CompactTextString(m) } func (*RestoreChanBackupRequest) ProtoMessage() {} func (*RestoreChanBackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{144} + return fileDescriptor_77a6da22d6a3feb1, []int{145} } func (m *RestoreChanBackupRequest) XXX_Unmarshal(b []byte) error { @@ -11799,7 +11889,7 @@ func (m *RestoreBackupResponse) Reset() { *m = RestoreBackupResponse{} } func (m *RestoreBackupResponse) String() string { return proto.CompactTextString(m) } func (*RestoreBackupResponse) ProtoMessage() {} func (*RestoreBackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{145} + return fileDescriptor_77a6da22d6a3feb1, []int{146} } func (m *RestoreBackupResponse) XXX_Unmarshal(b []byte) error { @@ -11830,7 +11920,7 @@ func (m *ChannelBackupSubscription) Reset() { *m = ChannelBackupSubscrip func (m *ChannelBackupSubscription) String() string { return proto.CompactTextString(m) } func (*ChannelBackupSubscription) ProtoMessage() {} func (*ChannelBackupSubscription) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{146} + return fileDescriptor_77a6da22d6a3feb1, []int{147} } func (m *ChannelBackupSubscription) XXX_Unmarshal(b []byte) error { @@ -11861,7 +11951,7 @@ func (m *VerifyChanBackupResponse) Reset() { *m = VerifyChanBackupRespon func (m *VerifyChanBackupResponse) String() string { return proto.CompactTextString(m) } func (*VerifyChanBackupResponse) ProtoMessage() {} func (*VerifyChanBackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{147} + return fileDescriptor_77a6da22d6a3feb1, []int{148} } func (m *VerifyChanBackupResponse) XXX_Unmarshal(b []byte) error { @@ -11896,7 +11986,7 @@ func (m *MacaroonPermission) Reset() { *m = MacaroonPermission{} } func (m *MacaroonPermission) String() string { return proto.CompactTextString(m) } func (*MacaroonPermission) ProtoMessage() {} func (*MacaroonPermission) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{148} + return fileDescriptor_77a6da22d6a3feb1, []int{149} } func (m *MacaroonPermission) XXX_Unmarshal(b []byte) error { @@ -11945,7 +12035,7 @@ func (m *BakeMacaroonRequest) Reset() { *m = BakeMacaroonRequest{} } func (m *BakeMacaroonRequest) String() string { return proto.CompactTextString(m) } func (*BakeMacaroonRequest) ProtoMessage() {} func (*BakeMacaroonRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{149} + return fileDescriptor_77a6da22d6a3feb1, []int{150} } func (m *BakeMacaroonRequest) XXX_Unmarshal(b []byte) error { @@ -11992,7 +12082,7 @@ func (m *BakeMacaroonResponse) Reset() { *m = BakeMacaroonResponse{} } func (m *BakeMacaroonResponse) String() string { return proto.CompactTextString(m) } func (*BakeMacaroonResponse) ProtoMessage() {} func (*BakeMacaroonResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{150} + return fileDescriptor_77a6da22d6a3feb1, []int{151} } func (m *BakeMacaroonResponse) XXX_Unmarshal(b []byte) error { @@ -12030,7 +12120,7 @@ func (m *ListMacaroonIDsRequest) Reset() { *m = ListMacaroonIDsRequest{} func (m *ListMacaroonIDsRequest) String() string { return proto.CompactTextString(m) } func (*ListMacaroonIDsRequest) ProtoMessage() {} func (*ListMacaroonIDsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{151} + return fileDescriptor_77a6da22d6a3feb1, []int{152} } func (m *ListMacaroonIDsRequest) XXX_Unmarshal(b []byte) error { @@ -12063,7 +12153,7 @@ func (m *ListMacaroonIDsResponse) Reset() { *m = ListMacaroonIDsResponse func (m *ListMacaroonIDsResponse) String() string { return proto.CompactTextString(m) } func (*ListMacaroonIDsResponse) ProtoMessage() {} func (*ListMacaroonIDsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{152} + return fileDescriptor_77a6da22d6a3feb1, []int{153} } func (m *ListMacaroonIDsResponse) XXX_Unmarshal(b []byte) error { @@ -12103,7 +12193,7 @@ func (m *DeleteMacaroonIDRequest) Reset() { *m = DeleteMacaroonIDRequest func (m *DeleteMacaroonIDRequest) String() string { return proto.CompactTextString(m) } func (*DeleteMacaroonIDRequest) ProtoMessage() {} func (*DeleteMacaroonIDRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{153} + return fileDescriptor_77a6da22d6a3feb1, []int{154} } func (m *DeleteMacaroonIDRequest) XXX_Unmarshal(b []byte) error { @@ -12143,7 +12233,7 @@ func (m *DeleteMacaroonIDResponse) Reset() { *m = DeleteMacaroonIDRespon func (m *DeleteMacaroonIDResponse) String() string { return proto.CompactTextString(m) } func (*DeleteMacaroonIDResponse) ProtoMessage() {} func (*DeleteMacaroonIDResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{154} + return fileDescriptor_77a6da22d6a3feb1, []int{155} } func (m *DeleteMacaroonIDResponse) XXX_Unmarshal(b []byte) error { @@ -12183,7 +12273,7 @@ func (m *MacaroonPermissionList) Reset() { *m = MacaroonPermissionList{} func (m *MacaroonPermissionList) String() string { return proto.CompactTextString(m) } func (*MacaroonPermissionList) ProtoMessage() {} func (*MacaroonPermissionList) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{155} + return fileDescriptor_77a6da22d6a3feb1, []int{156} } func (m *MacaroonPermissionList) XXX_Unmarshal(b []byte) error { @@ -12221,7 +12311,7 @@ func (m *ListPermissionsRequest) Reset() { *m = ListPermissionsRequest{} func (m *ListPermissionsRequest) String() string { return proto.CompactTextString(m) } func (*ListPermissionsRequest) ProtoMessage() {} func (*ListPermissionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{156} + return fileDescriptor_77a6da22d6a3feb1, []int{157} } func (m *ListPermissionsRequest) XXX_Unmarshal(b []byte) error { @@ -12256,7 +12346,7 @@ func (m *ListPermissionsResponse) Reset() { *m = ListPermissionsResponse func (m *ListPermissionsResponse) String() string { return proto.CompactTextString(m) } func (*ListPermissionsResponse) ProtoMessage() {} func (*ListPermissionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{157} + return fileDescriptor_77a6da22d6a3feb1, []int{158} } func (m *ListPermissionsResponse) XXX_Unmarshal(b []byte) error { @@ -12312,7 +12402,7 @@ func (m *Failure) Reset() { *m = Failure{} } func (m *Failure) String() string { return proto.CompactTextString(m) } func (*Failure) ProtoMessage() {} func (*Failure) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{158} + return fileDescriptor_77a6da22d6a3feb1, []int{159} } func (m *Failure) XXX_Unmarshal(b []byte) error { @@ -12456,7 +12546,7 @@ func (m *ChannelUpdate) Reset() { *m = ChannelUpdate{} } func (m *ChannelUpdate) String() string { return proto.CompactTextString(m) } func (*ChannelUpdate) ProtoMessage() {} func (*ChannelUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{159} + return fileDescriptor_77a6da22d6a3feb1, []int{160} } func (m *ChannelUpdate) XXX_Unmarshal(b []byte) error { @@ -12574,7 +12664,7 @@ func (m *MacaroonId) Reset() { *m = MacaroonId{} } func (m *MacaroonId) String() string { return proto.CompactTextString(m) } func (*MacaroonId) ProtoMessage() {} func (*MacaroonId) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{160} + return fileDescriptor_77a6da22d6a3feb1, []int{161} } func (m *MacaroonId) XXX_Unmarshal(b []byte) error { @@ -12628,7 +12718,7 @@ func (m *Op) Reset() { *m = Op{} } func (m *Op) String() string { return proto.CompactTextString(m) } func (*Op) ProtoMessage() {} func (*Op) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{161} + return fileDescriptor_77a6da22d6a3feb1, []int{162} } func (m *Op) XXX_Unmarshal(b []byte) error { @@ -12812,6 +12902,7 @@ func init() { proto.RegisterMapType((map[uint32]*Feature)(nil), "lnrpc.Invoice.FeaturesEntry") proto.RegisterType((*InvoiceHTLC)(nil), "lnrpc.InvoiceHTLC") proto.RegisterMapType((map[uint64][]byte)(nil), "lnrpc.InvoiceHTLC.CustomRecordsEntry") + proto.RegisterType((*AMP)(nil), "lnrpc.AMP") proto.RegisterType((*AddInvoiceResponse)(nil), "lnrpc.AddInvoiceResponse") proto.RegisterType((*PaymentHash)(nil), "lnrpc.PaymentHash") proto.RegisterType((*ListInvoiceRequest)(nil), "lnrpc.ListInvoiceRequest") @@ -12869,17 +12960,17 @@ func init() { func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) } var fileDescriptor_77a6da22d6a3feb1 = []byte{ - // 12448 bytes of a gzipped FileDescriptorProto + // 12524 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, 0xaa, 0xc5, 0x6d, 0x89, 0xd4, 0x16, 0xa9, 0x19, 0xcf, 0xc2, 0x76, 0xb9, 0x44, 0x5e, 0x49, 0xf5, 0x35, 0x59, 0xc5, 0xad, 0x2a, 0xaa, 0xa5, 0x0d, 0x02, 0xf8, 0x87, 0xe3, 0x04, 0x86, 0x11, 0x20, 0x80, 0x1d, 0xe4, 0x65, 0x24, 0x41, 0x80, 0xe4, 0x9f, 0x61, 0xc0, 0xf6, 0xbf, 0xfc, 0x0b, 0x10, - 0x23, 0x40, 0x82, 0x20, 0x88, 0x8d, 0x3c, 0x10, 0x38, 0x08, 0x90, 0x38, 0x3f, 0x02, 0x04, 0x06, - 0xfc, 0x37, 0x41, 0x82, 0x7b, 0xee, 0xa3, 0x6e, 0x3d, 0xd4, 0xdd, 0xb3, 0x3b, 0xd9, 0x3f, 0x12, + 0x23, 0x40, 0x82, 0x20, 0x88, 0x8d, 0x3c, 0x10, 0x24, 0x08, 0x90, 0x38, 0x3f, 0x02, 0x04, 0x06, + 0xfc, 0xd7, 0x41, 0x82, 0x7b, 0xee, 0xa3, 0x6e, 0x3d, 0xd4, 0xdd, 0xb3, 0x3b, 0xd9, 0x3f, 0x12, 0xeb, 0x9c, 0x73, 0xdf, 0xf7, 0x9e, 0x7b, 0xee, 0x39, 0xe7, 0x9e, 0x0b, 0x55, 0x7f, 0x36, 0xda, - 0x9a, 0xf9, 0x5e, 0xe8, 0x91, 0xd2, 0xc4, 0xf5, 0x67, 0x23, 0xe3, 0xcf, 0x72, 0x50, 0x3c, 0x0e, + 0x9a, 0xf9, 0x5e, 0xe8, 0x91, 0xd2, 0xc4, 0xf5, 0x67, 0x23, 0xe3, 0x4f, 0x73, 0x50, 0x3c, 0x0e, 0x2f, 0x3d, 0xf2, 0x08, 0xea, 0xf6, 0x78, 0xec, 0xd3, 0x20, 0xb0, 0xc2, 0xab, 0x19, 0x6d, 0xe5, 0xee, 0xe6, 0xee, 0x2d, 0x3e, 0x24, 0x5b, 0x48, 0xb6, 0xd5, 0xe6, 0xa8, 0xe1, 0xd5, 0x8c, 0x9a, 0x35, 0x3b, 0xfa, 0x20, 0x2d, 0x28, 0x8b, 0xcf, 0x56, 0xfe, 0x6e, 0xee, 0x5e, 0xd5, 0x94, 0x9f, @@ -12951,7 +13042,7 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x7d, 0xce, 0x44, 0x8a, 0x51, 0x80, 0x8c, 0xc8, 0xbe, 0x6a, 0xd5, 0x70, 0x81, 0x57, 0x46, 0x01, 0x63, 0x41, 0xf6, 0x15, 0x5b, 0x84, 0xac, 0xb6, 0x36, 0x8e, 0x02, 0x1d, 0x63, 0xf6, 0x01, 0x72, 0xd4, 0x06, 0x56, 0xb6, 0x2d, 0x10, 0xac, 0x9c, 0x80, 0xcd, 0x7a, 0x59, 0xd9, 0xd3, 0x89, 0x7d, - 0x16, 0x20, 0x4b, 0x69, 0x98, 0x75, 0x01, 0xdc, 0x63, 0x30, 0xe3, 0x2f, 0xf2, 0xb0, 0x96, 0x18, + 0x16, 0x20, 0x4b, 0x69, 0x98, 0x75, 0x01, 0xdc, 0x63, 0x30, 0xe3, 0xcf, 0xf3, 0xb0, 0x96, 0x18, 0x5c, 0xb1, 0x68, 0x98, 0x0c, 0x81, 0x10, 0x1c, 0xd8, 0x8a, 0x29, 0xbe, 0xb2, 0x46, 0x2d, 0x9f, 0x35, 0x6a, 0xab, 0x50, 0xe2, 0x8b, 0xad, 0xc0, 0x77, 0x5e, 0x2a, 0x57, 0xd9, 0x7c, 0x76, 0xea, 0x7b, 0x4c, 0xa4, 0x3a, 0x9f, 0x87, 0x63, 0xef, 0xb9, 0x2b, 0x44, 0x8b, 0x25, 0x01, 0x1f, 0x08, @@ -12982,96 +13073,96 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0xbe, 0xa0, 0x89, 0xeb, 0x8c, 0x13, 0xb0, 0x85, 0xc5, 0x72, 0x0d, 0x84, 0x74, 0xc6, 0xd8, 0x2b, 0xcb, 0x33, 0x60, 0x67, 0x9a, 0x80, 0x71, 0x1e, 0x6b, 0xee, 0x8a, 0x73, 0x0d, 0x1d, 0xe3, 0xf2, 0xad, 0x98, 0x4d, 0x44, 0x1c, 0x47, 0xf0, 0x9f, 0x7e, 0x98, 0xde, 0x86, 0x66, 0xd4, 0x2d, 0x62, - 0x8c, 0x08, 0x14, 0xd9, 0x94, 0x17, 0x19, 0xe0, 0x6f, 0xe3, 0x7f, 0xe5, 0x38, 0xe1, 0x8e, 0xe7, - 0x44, 0x87, 0x0b, 0x02, 0x45, 0x76, 0x98, 0x91, 0x84, 0xec, 0xf7, 0xb5, 0x47, 0xb5, 0x6f, 0xa0, - 0x33, 0x6f, 0x42, 0x25, 0x60, 0x1d, 0x63, 0x4f, 0x78, 0x7f, 0x56, 0xcc, 0x32, 0xfb, 0x6e, 0x4f, - 0x26, 0x51, 0x3f, 0x97, 0xaf, 0xed, 0xe7, 0xca, 0xab, 0xf4, 0x73, 0x35, 0xbb, 0x9f, 0x8d, 0x77, - 0x60, 0x59, 0x6b, 0xfd, 0x0b, 0xfa, 0xa9, 0x07, 0xe4, 0xc0, 0x09, 0xc2, 0x63, 0x97, 0x65, 0xa1, - 0x24, 0x8b, 0x58, 0x45, 0x72, 0x89, 0x8a, 0x30, 0xa4, 0x7d, 0x29, 0x90, 0x79, 0x81, 0xb4, 0x2f, - 0x11, 0x69, 0x7c, 0x06, 0x2b, 0xb1, 0xfc, 0x44, 0xd1, 0x6f, 0x40, 0x69, 0x1e, 0x5e, 0x7a, 0xf2, - 0xdc, 0x55, 0x13, 0x33, 0xfc, 0x38, 0xbc, 0xf4, 0x4c, 0x8e, 0x31, 0x1e, 0xc3, 0x72, 0x8f, 0x3e, - 0x17, 0x4c, 0x48, 0x56, 0xe4, 0x6d, 0x28, 0xbe, 0x44, 0x93, 0x80, 0x78, 0x63, 0x0b, 0x88, 0x9e, - 0x58, 0x94, 0xaa, 0x29, 0x16, 0x72, 0x31, 0xc5, 0x82, 0xf1, 0x36, 0x90, 0x81, 0x73, 0xe6, 0x1e, - 0xd2, 0x20, 0xb0, 0xcf, 0x14, 0xdb, 0x6a, 0x42, 0x61, 0x1a, 0x9c, 0x09, 0x1e, 0xcb, 0x7e, 0x1a, - 0x1f, 0xc1, 0x4a, 0x8c, 0x4e, 0x64, 0xfc, 0x1a, 0x54, 0x03, 0xe7, 0xcc, 0x45, 0xa9, 0x59, 0x64, - 0x1d, 0x01, 0x8c, 0x3d, 0x58, 0xfd, 0x82, 0xfa, 0xce, 0xe9, 0xd5, 0xcb, 0xb2, 0x8f, 0xe7, 0x93, - 0x4f, 0xe6, 0xd3, 0x81, 0xb5, 0x44, 0x3e, 0xa2, 0x78, 0xbe, 0x3c, 0xc4, 0x48, 0x56, 0x4c, 0xfe, - 0xa1, 0xf1, 0xed, 0xbc, 0xce, 0xb7, 0x0d, 0x0f, 0xc8, 0x8e, 0xe7, 0xba, 0x74, 0x14, 0x1e, 0x51, - 0xea, 0xcb, 0xca, 0xbc, 0xab, 0xad, 0x85, 0xda, 0xc3, 0x0d, 0xd1, 0xb3, 0xc9, 0xcd, 0x40, 0x2c, - 0x12, 0x02, 0xc5, 0x19, 0xf5, 0xa7, 0x98, 0x71, 0xc5, 0xc4, 0xdf, 0xac, 0x73, 0x43, 0x67, 0x4a, - 0xbd, 0x39, 0x3f, 0x6a, 0x16, 0x4d, 0xf9, 0x69, 0xac, 0xc1, 0x4a, 0xac, 0x40, 0x5e, 0x6b, 0xe3, - 0x01, 0xac, 0xed, 0x3a, 0xc1, 0x28, 0x5d, 0x95, 0x0d, 0x28, 0xcf, 0xe6, 0x27, 0x56, 0x7c, 0xc7, - 0x79, 0x4a, 0xaf, 0x8c, 0x16, 0xac, 0x27, 0x53, 0x88, 0xbc, 0x7e, 0x3d, 0x0f, 0xc5, 0xfd, 0xe1, - 0xc1, 0x0e, 0xd9, 0x84, 0x8a, 0xe3, 0x8e, 0xbc, 0x29, 0x93, 0xb7, 0x79, 0x6f, 0xa8, 0xef, 0x6b, - 0x97, 0xf6, 0x2d, 0xa8, 0xa2, 0x98, 0x3e, 0xf1, 0x46, 0xcf, 0x84, 0xc4, 0x5b, 0x61, 0x80, 0x03, - 0x6f, 0xf4, 0x8c, 0x2d, 0x33, 0x7a, 0x39, 0x73, 0x7c, 0x54, 0xc2, 0x48, 0x25, 0x43, 0x91, 0x8b, - 0x78, 0x11, 0x22, 0x52, 0x45, 0x08, 0x69, 0x84, 0xed, 0xaf, 0x5c, 0xf4, 0xad, 0x9e, 0xa3, 0x34, - 0x32, 0xa6, 0x97, 0xe4, 0x7d, 0x20, 0xa7, 0x9e, 0xff, 0xdc, 0xf6, 0x95, 0xb4, 0xe6, 0x0a, 0xd6, - 0x5a, 0x34, 0x97, 0x23, 0x8c, 0x90, 0x44, 0xc8, 0x43, 0x58, 0xd3, 0xc8, 0xb5, 0x8c, 0xb9, 0xd4, - 0xb4, 0x12, 0x21, 0xf7, 0x65, 0x11, 0xc6, 0xaf, 0xe5, 0x81, 0x88, 0xf4, 0x3b, 0x9e, 0x1b, 0x84, - 0xbe, 0xed, 0xb8, 0x61, 0x10, 0x97, 0xdd, 0x72, 0x09, 0xd9, 0xed, 0x1e, 0x34, 0x51, 0x72, 0xd4, - 0x05, 0xb8, 0x7c, 0x24, 0x46, 0x9b, 0x91, 0x10, 0xf7, 0x16, 0x2c, 0x46, 0xd2, 0xbb, 0xd2, 0xc1, - 0x15, 0xcd, 0xba, 0x92, 0xe0, 0xc5, 0x56, 0xc8, 0x18, 0x82, 0x94, 0x4a, 0x95, 0xaa, 0x81, 0x1f, - 0x14, 0x96, 0xa7, 0xf6, 0xe5, 0x11, 0x95, 0x67, 0x05, 0x14, 0xf7, 0x0c, 0x68, 0x28, 0x41, 0x0e, - 0x29, 0x79, 0xcf, 0xd5, 0x84, 0x28, 0x87, 0x34, 0xd9, 0xb2, 0xf6, 0x42, 0xb6, 0xac, 0x6d, 0xfc, - 0xbb, 0x2a, 0x94, 0x65, 0x37, 0xa2, 0xe0, 0x1c, 0x3a, 0x17, 0x34, 0x12, 0x9c, 0xd9, 0x17, 0x93, - 0xc7, 0x7d, 0x3a, 0xf5, 0x42, 0x75, 0x60, 0xe2, 0xcb, 0xa4, 0xce, 0x81, 0xe2, 0xc8, 0xa4, 0x09, - 0xed, 0x5c, 0x75, 0xc8, 0xa5, 0x67, 0x29, 0xb4, 0x73, 0x91, 0xec, 0x16, 0x94, 0xa5, 0xe8, 0x5d, - 0x54, 0x3a, 0x85, 0x85, 0x11, 0x97, 0xbb, 0x37, 0xa1, 0x32, 0xb2, 0x67, 0xf6, 0xc8, 0x09, 0xaf, - 0xc4, 0x9e, 0xa0, 0xbe, 0x59, 0xee, 0x13, 0x6f, 0x64, 0x4f, 0xac, 0x13, 0x7b, 0x62, 0xbb, 0x23, - 0x2a, 0x74, 0x72, 0x75, 0x04, 0x6e, 0x73, 0x18, 0xf9, 0x16, 0x2c, 0x8a, 0x7a, 0x4a, 0x2a, 0xae, - 0x9a, 0x13, 0xb5, 0x97, 0x64, 0xec, 0x70, 0xe7, 0x4d, 0xd9, 0xb8, 0x9c, 0x52, 0x7e, 0x0c, 0x2a, - 0x98, 0x55, 0x0e, 0xd9, 0xa3, 0xd8, 0x5a, 0x81, 0x7e, 0xce, 0xe7, 0x70, 0x95, 0x17, 0xc5, 0x81, - 0x5f, 0xf2, 0xf9, 0x9b, 0x3e, 0x0b, 0x15, 0xb4, 0xb3, 0xd0, 0xbb, 0xb0, 0x3c, 0x77, 0x03, 0x1a, - 0x86, 0x13, 0x3a, 0x56, 0x75, 0xa9, 0x21, 0x51, 0x53, 0x21, 0x64, 0x75, 0xb6, 0x60, 0x85, 0x2b, - 0x13, 0x03, 0x3b, 0xf4, 0x82, 0x73, 0x27, 0xb0, 0x02, 0xea, 0x4a, 0x75, 0xd3, 0x32, 0xa2, 0x06, - 0x02, 0x33, 0xe0, 0x2a, 0x8a, 0x8d, 0x04, 0xbd, 0x4f, 0x47, 0xd4, 0xb9, 0xa0, 0x63, 0x3c, 0x27, - 0x15, 0xcc, 0xb5, 0x58, 0x1a, 0x53, 0x20, 0xf1, 0xd0, 0x3b, 0x9f, 0x5a, 0xf3, 0xd9, 0xd8, 0x66, - 0xf2, 0xf0, 0x22, 0x3f, 0x78, 0xb8, 0xf3, 0xe9, 0x31, 0x87, 0x90, 0x07, 0x20, 0x0f, 0x42, 0x62, - 0xce, 0x2c, 0xc5, 0xb6, 0x1c, 0xc6, 0x35, 0xcc, 0xba, 0xa0, 0xe0, 0x07, 0xb5, 0x3b, 0xfa, 0x62, - 0x69, 0xb2, 0x19, 0x86, 0x87, 0xf6, 0x68, 0xc1, 0xb4, 0xa0, 0x3c, 0xf3, 0x9d, 0x0b, 0x3b, 0xa4, - 0xad, 0x65, 0xbe, 0x8f, 0x8b, 0x4f, 0xc6, 0xc0, 0x1d, 0xd7, 0x09, 0x1d, 0x3b, 0xf4, 0xfc, 0x16, - 0x41, 0x5c, 0x04, 0x20, 0xf7, 0x61, 0x19, 0xe7, 0x49, 0x10, 0xda, 0xe1, 0x3c, 0x10, 0xa7, 0xc0, - 0x15, 0x7e, 0xda, 0x62, 0x88, 0x01, 0xc2, 0xf1, 0x20, 0x48, 0x3e, 0x85, 0x75, 0x3e, 0x35, 0x52, - 0x4b, 0x73, 0x95, 0x75, 0x07, 0xd6, 0x68, 0x05, 0x29, 0x76, 0xe2, 0x6b, 0xf4, 0x73, 0xd8, 0x10, - 0xd3, 0x25, 0x95, 0x72, 0x4d, 0xa5, 0x5c, 0xe5, 0x24, 0x89, 0xa4, 0x5b, 0xb0, 0xcc, 0xaa, 0xe6, - 0x8c, 0x2c, 0x91, 0x03, 0x5b, 0x15, 0xeb, 0xac, 0x15, 0x98, 0x68, 0x89, 0x23, 0x4d, 0xc4, 0x3d, - 0xa5, 0x57, 0xe4, 0xbb, 0xb0, 0xc4, 0xa7, 0x0f, 0xaa, 0x3a, 0x70, 0x63, 0xde, 0xc4, 0x8d, 0x79, - 0x4d, 0x74, 0xee, 0x8e, 0xc2, 0xe2, 0xde, 0xbc, 0x38, 0x8a, 0x7d, 0xb3, 0xa5, 0x31, 0x71, 0x4e, - 0x29, 0xdb, 0x27, 0x5a, 0x1b, 0x7c, 0xb2, 0xc9, 0x6f, 0xb6, 0x6a, 0xe7, 0x33, 0xc4, 0xb4, 0x38, - 0xb3, 0xe6, 0x5f, 0x38, 0x8f, 0x27, 0x5e, 0x40, 0xa5, 0x1a, 0xba, 0x75, 0x53, 0x2c, 0x48, 0x06, - 0x94, 0x47, 0x16, 0x76, 0x26, 0xe6, 0x0a, 0x08, 0x65, 0x2c, 0xb8, 0x85, 0x13, 0xa3, 0xc1, 0xf5, - 0x10, 0xd2, 0x60, 0xc0, 0x84, 0xba, 0x73, 0xfb, 0xb9, 0x64, 0xeb, 0xaf, 0x21, 0x37, 0x01, 0x06, - 0x12, 0x0c, 0x7d, 0x0f, 0x96, 0xc5, 0x28, 0x44, 0xcc, 0xb4, 0x75, 0x1b, 0xb7, 0xc8, 0x9b, 0xb2, - 0x8d, 0x29, 0x6e, 0x6b, 0x36, 0xf9, 0xb8, 0x68, 0xfc, 0x77, 0x1f, 0x88, 0x1c, 0x14, 0x2d, 0xa3, - 0xd7, 0x5f, 0x96, 0xd1, 0xb2, 0x18, 0xa6, 0x08, 0x64, 0xfc, 0x7e, 0x8e, 0x4b, 0x54, 0x82, 0x3a, - 0xd0, 0x94, 0x3f, 0x9c, 0xaf, 0x59, 0x9e, 0x3b, 0xb9, 0x12, 0xac, 0x0e, 0x38, 0xa8, 0xef, 0x4e, - 0x90, 0xd7, 0x38, 0xae, 0x4e, 0xc2, 0x37, 0xef, 0xba, 0x04, 0x22, 0xd1, 0x1d, 0xa8, 0xcd, 0xe6, - 0x27, 0x13, 0x67, 0xc4, 0x49, 0x0a, 0x3c, 0x17, 0x0e, 0x42, 0x82, 0x37, 0xa0, 0x2e, 0xe6, 0x3a, - 0xa7, 0x28, 0x22, 0x45, 0x4d, 0xc0, 0x90, 0x04, 0x85, 0x03, 0xea, 0x23, 0xb3, 0xab, 0x9b, 0xf8, - 0xdb, 0xd8, 0x86, 0xd5, 0x78, 0xa5, 0x85, 0xe4, 0x72, 0x1f, 0x2a, 0x82, 0x93, 0x4a, 0xb5, 0xe8, - 0x62, 0xbc, 0x37, 0x4c, 0x85, 0x37, 0xfe, 0x7d, 0x09, 0x56, 0x64, 0x1f, 0xb1, 0xc1, 0x1e, 0xcc, - 0xa7, 0x53, 0xdb, 0xcf, 0x60, 0xd1, 0xb9, 0x17, 0xb3, 0xe8, 0x7c, 0x8a, 0x45, 0xc7, 0xf5, 0x62, - 0x9c, 0xc3, 0xc7, 0xf5, 0x62, 0x6c, 0x76, 0xf1, 0xd3, 0xb8, 0x6e, 0x7d, 0x69, 0x08, 0xf0, 0x90, - 0x5b, 0x79, 0x52, 0x1b, 0x4a, 0x29, 0x63, 0x43, 0xd1, 0xb7, 0x83, 0x85, 0xc4, 0x76, 0xf0, 0x06, - 0xf0, 0x69, 0x2c, 0xe7, 0x63, 0x99, 0x1f, 0xd0, 0x11, 0x26, 0x26, 0xe4, 0x3b, 0xb0, 0x94, 0xe4, - 0xc0, 0x9c, 0xd5, 0x2f, 0x66, 0xf0, 0x5f, 0x67, 0x4a, 0x51, 0xa8, 0xd1, 0x88, 0xab, 0x82, 0xff, - 0x3a, 0x53, 0x7a, 0x80, 0x18, 0x49, 0xdf, 0x01, 0xe0, 0x65, 0xe3, 0x32, 0x06, 0x5c, 0xc6, 0x6f, - 0x27, 0x66, 0xa6, 0xd6, 0xeb, 0x5b, 0xec, 0x63, 0xee, 0x53, 0x5c, 0xd7, 0x55, 0x4c, 0x89, 0x4b, - 0xfa, 0x53, 0x58, 0xf4, 0x66, 0xd4, 0xb5, 0x22, 0x2e, 0x58, 0xc3, 0xac, 0x9a, 0x22, 0xab, 0xae, - 0x84, 0x9b, 0x0d, 0x46, 0xa7, 0x3e, 0xc9, 0xe7, 0xbc, 0x93, 0xa9, 0x96, 0xb2, 0x7e, 0x4d, 0xca, - 0x45, 0x24, 0x8c, 0x92, 0x7e, 0x84, 0xba, 0x27, 0x6f, 0x32, 0xe7, 0xa6, 0x9c, 0x06, 0xce, 0x23, - 0xa9, 0xdb, 0x36, 0x15, 0xc6, 0xd4, 0xa9, 0x8c, 0xdf, 0xc8, 0x41, 0x4d, 0x6b, 0x03, 0x59, 0x83, - 0xe5, 0x9d, 0x7e, 0xff, 0xa8, 0x63, 0xb6, 0x87, 0xdd, 0x2f, 0x3a, 0xd6, 0xce, 0x41, 0x7f, 0xd0, - 0x69, 0xde, 0x60, 0xe0, 0x83, 0xfe, 0x4e, 0xfb, 0xc0, 0xda, 0xeb, 0x9b, 0x3b, 0x12, 0x9c, 0x23, - 0xeb, 0x40, 0xcc, 0xce, 0x61, 0x7f, 0xd8, 0x89, 0xc1, 0xf3, 0xa4, 0x09, 0xf5, 0x6d, 0xb3, 0xd3, - 0xde, 0xd9, 0x17, 0x90, 0x02, 0x59, 0x85, 0xe6, 0xde, 0x71, 0x6f, 0xb7, 0xdb, 0x7b, 0x62, 0xed, - 0xb4, 0x7b, 0x3b, 0x9d, 0x83, 0xce, 0x6e, 0xb3, 0x48, 0x1a, 0x50, 0x6d, 0x6f, 0xb7, 0x7b, 0xbb, - 0xfd, 0x5e, 0x67, 0xb7, 0x59, 0x32, 0xfe, 0x47, 0x0e, 0x20, 0xaa, 0x28, 0xe3, 0xab, 0x51, 0x55, - 0x75, 0xd3, 0xe9, 0x5a, 0xaa, 0x51, 0x9c, 0xaf, 0xfa, 0xb1, 0x6f, 0xf2, 0x10, 0xca, 0xde, 0x3c, - 0x1c, 0x79, 0x53, 0x7e, 0x88, 0x58, 0x7c, 0xd8, 0x4a, 0xa5, 0xeb, 0x73, 0xbc, 0x29, 0x09, 0x63, - 0xe6, 0xd1, 0xc2, 0xcb, 0xcc, 0xa3, 0x71, 0x3b, 0x2c, 0x97, 0xeb, 0x34, 0x3b, 0xec, 0x6d, 0x80, - 0xe0, 0x39, 0xa5, 0x33, 0x54, 0x5e, 0x89, 0x55, 0x50, 0x45, 0xc8, 0x90, 0x9d, 0x31, 0xff, 0x34, + 0x8c, 0x08, 0x14, 0xd9, 0x94, 0x17, 0x19, 0xe0, 0x6f, 0xe3, 0x2f, 0x72, 0x9c, 0x70, 0xc7, 0x73, + 0xa2, 0xc3, 0x05, 0x81, 0x22, 0x3b, 0xcc, 0x48, 0x42, 0xf6, 0xfb, 0xda, 0xa3, 0xda, 0x37, 0xd0, + 0x99, 0x37, 0xa1, 0x12, 0xb0, 0x8e, 0xb1, 0x27, 0xbc, 0x3f, 0x2b, 0x66, 0x99, 0x7d, 0xb7, 0x27, + 0x93, 0xa8, 0x9f, 0xcb, 0xd7, 0xf6, 0x73, 0xe5, 0x55, 0xfa, 0xb9, 0x9a, 0xdd, 0xcf, 0xc6, 0x3b, + 0xb0, 0xac, 0xb5, 0xfe, 0x05, 0xfd, 0xd4, 0x03, 0x72, 0xe0, 0x04, 0xe1, 0xb1, 0xcb, 0xb2, 0x50, + 0x92, 0x45, 0xac, 0x22, 0xb9, 0x44, 0x45, 0x18, 0xd2, 0xbe, 0x14, 0xc8, 0xbc, 0x40, 0xda, 0x97, + 0x88, 0x34, 0x3e, 0x83, 0x95, 0x58, 0x7e, 0xa2, 0xe8, 0x37, 0xa0, 0x34, 0x0f, 0x2f, 0x3d, 0x79, + 0xee, 0xaa, 0x89, 0x19, 0x7e, 0x1c, 0x5e, 0x7a, 0x26, 0xc7, 0x18, 0x8f, 0x61, 0xb9, 0x47, 0x9f, + 0x0b, 0x26, 0x24, 0x2b, 0xf2, 0x36, 0x14, 0x5f, 0xa2, 0x49, 0x40, 0xbc, 0xb1, 0x05, 0x44, 0x4f, + 0x2c, 0x4a, 0xd5, 0x14, 0x0b, 0xb9, 0x98, 0x62, 0xc1, 0x78, 0x1b, 0xc8, 0xc0, 0x39, 0x73, 0x0f, + 0x69, 0x10, 0xd8, 0x67, 0x8a, 0x6d, 0x35, 0xa1, 0x30, 0x0d, 0xce, 0x04, 0x8f, 0x65, 0x3f, 0x8d, + 0x8f, 0x60, 0x25, 0x46, 0x27, 0x32, 0x7e, 0x0d, 0xaa, 0x81, 0x73, 0xe6, 0xa2, 0xd4, 0x2c, 0xb2, + 0x8e, 0x00, 0xc6, 0x1e, 0xac, 0x7e, 0x41, 0x7d, 0xe7, 0xf4, 0xea, 0x65, 0xd9, 0xc7, 0xf3, 0xc9, + 0x27, 0xf3, 0xe9, 0xc0, 0x5a, 0x22, 0x1f, 0x51, 0x3c, 0x5f, 0x1e, 0x62, 0x24, 0x2b, 0x26, 0xff, + 0xd0, 0xf8, 0x76, 0x5e, 0xe7, 0xdb, 0x86, 0x07, 0x64, 0xc7, 0x73, 0x5d, 0x3a, 0x0a, 0x8f, 0x28, + 0xf5, 0x65, 0x65, 0xde, 0xd5, 0xd6, 0x42, 0xed, 0xe1, 0x86, 0xe8, 0xd9, 0xe4, 0x66, 0x20, 0x16, + 0x09, 0x81, 0xe2, 0x8c, 0xfa, 0x53, 0xcc, 0xb8, 0x62, 0xe2, 0x6f, 0xd6, 0xb9, 0xa1, 0x33, 0xa5, + 0xde, 0x9c, 0x1f, 0x35, 0x8b, 0xa6, 0xfc, 0x34, 0xd6, 0x60, 0x25, 0x56, 0x20, 0xaf, 0xb5, 0xf1, + 0x00, 0xd6, 0x76, 0x9d, 0x60, 0x94, 0xae, 0xca, 0x06, 0x94, 0x67, 0xf3, 0x13, 0x2b, 0xbe, 0xe3, + 0x3c, 0xa5, 0x57, 0x46, 0x0b, 0xd6, 0x93, 0x29, 0x44, 0x5e, 0xbf, 0x9e, 0x87, 0xe2, 0xfe, 0xf0, + 0x60, 0x87, 0x6c, 0x42, 0xc5, 0x71, 0x47, 0xde, 0x94, 0xc9, 0xdb, 0xbc, 0x37, 0xd4, 0xf7, 0xb5, + 0x4b, 0xfb, 0x16, 0x54, 0x51, 0x4c, 0x9f, 0x78, 0xa3, 0x67, 0x42, 0xe2, 0xad, 0x30, 0xc0, 0x81, + 0x37, 0x7a, 0xc6, 0x96, 0x19, 0xbd, 0x9c, 0x39, 0x3e, 0x2a, 0x61, 0xa4, 0x92, 0xa1, 0xc8, 0x45, + 0xbc, 0x08, 0x11, 0xa9, 0x22, 0x84, 0x34, 0xc2, 0xf6, 0x57, 0x2e, 0xfa, 0x56, 0xcf, 0x51, 0x1a, + 0x19, 0xd3, 0x4b, 0xf2, 0x3e, 0x90, 0x53, 0xcf, 0x7f, 0x6e, 0xfb, 0x4a, 0x5a, 0x73, 0x05, 0x6b, + 0x2d, 0x9a, 0xcb, 0x11, 0x46, 0x48, 0x22, 0xe4, 0x21, 0xac, 0x69, 0xe4, 0x5a, 0xc6, 0x5c, 0x6a, + 0x5a, 0x89, 0x90, 0xfb, 0xb2, 0x08, 0xe3, 0xd7, 0xf2, 0x40, 0x44, 0xfa, 0x1d, 0xcf, 0x0d, 0x42, + 0xdf, 0x76, 0xdc, 0x30, 0x88, 0xcb, 0x6e, 0xb9, 0x84, 0xec, 0x76, 0x0f, 0x9a, 0x28, 0x39, 0xea, + 0x02, 0x5c, 0x3e, 0x12, 0xa3, 0xcd, 0x48, 0x88, 0x7b, 0x0b, 0x16, 0x23, 0xe9, 0x5d, 0xe9, 0xe0, + 0x8a, 0x66, 0x5d, 0x49, 0xf0, 0x62, 0x2b, 0x64, 0x0c, 0x41, 0x4a, 0xa5, 0x4a, 0xd5, 0xc0, 0x0f, + 0x0a, 0xcb, 0x53, 0xfb, 0xf2, 0x88, 0xca, 0xb3, 0x02, 0x8a, 0x7b, 0x06, 0x34, 0x94, 0x20, 0x87, + 0x94, 0xbc, 0xe7, 0x6a, 0x42, 0x94, 0x43, 0x9a, 0x6c, 0x59, 0x7b, 0x21, 0x5b, 0xd6, 0x36, 0xfe, + 0x5d, 0x15, 0xca, 0xb2, 0x1b, 0x51, 0x70, 0x0e, 0x9d, 0x0b, 0x1a, 0x09, 0xce, 0xec, 0x8b, 0xc9, + 0xe3, 0x3e, 0x9d, 0x7a, 0xa1, 0x3a, 0x30, 0xf1, 0x65, 0x52, 0xe7, 0x40, 0x71, 0x64, 0xd2, 0x84, + 0x76, 0xae, 0x3a, 0xe4, 0xd2, 0xb3, 0x14, 0xda, 0xb9, 0x48, 0x76, 0x0b, 0xca, 0x52, 0xf4, 0x2e, + 0x2a, 0x9d, 0xc2, 0xc2, 0x88, 0xcb, 0xdd, 0x9b, 0x50, 0x19, 0xd9, 0x33, 0x7b, 0xe4, 0x84, 0x57, + 0x62, 0x4f, 0x50, 0xdf, 0x2c, 0xf7, 0x89, 0x37, 0xb2, 0x27, 0xd6, 0x89, 0x3d, 0xb1, 0xdd, 0x11, + 0x15, 0x3a, 0xb9, 0x3a, 0x02, 0xb7, 0x39, 0x8c, 0x7c, 0x0b, 0x16, 0x45, 0x3d, 0x25, 0x15, 0x57, + 0xcd, 0x89, 0xda, 0x4b, 0x32, 0x76, 0xb8, 0xf3, 0xa6, 0x6c, 0x5c, 0x4e, 0x29, 0x3f, 0x06, 0x15, + 0xcc, 0x2a, 0x87, 0xec, 0x51, 0x6c, 0xad, 0x40, 0x3f, 0xe7, 0x73, 0xb8, 0xca, 0x8b, 0xe2, 0xc0, + 0x2f, 0xf9, 0xfc, 0x4d, 0x9f, 0x85, 0x0a, 0xda, 0x59, 0xe8, 0x5d, 0x58, 0x9e, 0xbb, 0x01, 0x0d, + 0xc3, 0x09, 0x1d, 0xab, 0xba, 0xd4, 0x90, 0xa8, 0xa9, 0x10, 0xb2, 0x3a, 0x5b, 0xb0, 0xc2, 0x95, + 0x89, 0x81, 0x1d, 0x7a, 0xc1, 0xb9, 0x13, 0x58, 0x01, 0x75, 0xa5, 0xba, 0x69, 0x19, 0x51, 0x03, + 0x81, 0x19, 0x70, 0x15, 0xc5, 0x46, 0x82, 0xde, 0xa7, 0x23, 0xea, 0x5c, 0xd0, 0x31, 0x9e, 0x93, + 0x0a, 0xe6, 0x5a, 0x2c, 0x8d, 0x29, 0x90, 0x78, 0xe8, 0x9d, 0x4f, 0xad, 0xf9, 0x6c, 0x6c, 0x33, + 0x79, 0x78, 0x91, 0x1f, 0x3c, 0xdc, 0xf9, 0xf4, 0x98, 0x43, 0xc8, 0x03, 0x90, 0x07, 0x21, 0x31, + 0x67, 0x96, 0x62, 0x5b, 0x0e, 0xe3, 0x1a, 0x66, 0x5d, 0x50, 0xf0, 0x83, 0xda, 0x1d, 0x7d, 0xb1, + 0x34, 0xd9, 0x0c, 0xc3, 0x43, 0x7b, 0xb4, 0x60, 0x5a, 0x50, 0x9e, 0xf9, 0xce, 0x85, 0x1d, 0xd2, + 0xd6, 0x32, 0xdf, 0xc7, 0xc5, 0x27, 0x63, 0xe0, 0x8e, 0xeb, 0x84, 0x8e, 0x1d, 0x7a, 0x7e, 0x8b, + 0x20, 0x2e, 0x02, 0x90, 0xfb, 0xb0, 0x8c, 0xf3, 0x24, 0x08, 0xed, 0x70, 0x1e, 0x88, 0x53, 0xe0, + 0x0a, 0x3f, 0x6d, 0x31, 0xc4, 0x00, 0xe1, 0x78, 0x10, 0x24, 0x9f, 0xc2, 0x3a, 0x9f, 0x1a, 0xa9, + 0xa5, 0xb9, 0xca, 0xba, 0x03, 0x6b, 0xb4, 0x82, 0x14, 0x3b, 0xf1, 0x35, 0xfa, 0x39, 0x6c, 0x88, + 0xe9, 0x92, 0x4a, 0xb9, 0xa6, 0x52, 0xae, 0x72, 0x92, 0x44, 0xd2, 0x2d, 0x58, 0x66, 0x55, 0x73, + 0x46, 0x96, 0xc8, 0x81, 0xad, 0x8a, 0x75, 0xd6, 0x0a, 0x4c, 0xb4, 0xc4, 0x91, 0x26, 0xe2, 0x9e, + 0xd2, 0x2b, 0xf2, 0x5d, 0x58, 0xe2, 0xd3, 0x07, 0x55, 0x1d, 0xb8, 0x31, 0x6f, 0xe2, 0xc6, 0xbc, + 0x26, 0x3a, 0x77, 0x47, 0x61, 0x71, 0x6f, 0x5e, 0x1c, 0xc5, 0xbe, 0xd9, 0xd2, 0x98, 0x38, 0xa7, + 0x94, 0xed, 0x13, 0xad, 0x0d, 0x3e, 0xd9, 0xe4, 0x37, 0x5b, 0xb5, 0xf3, 0x19, 0x62, 0x5a, 0x9c, + 0x59, 0xf3, 0x2f, 0x9c, 0xc7, 0x13, 0x2f, 0xa0, 0x52, 0x0d, 0xdd, 0xba, 0x29, 0x16, 0x24, 0x03, + 0xca, 0x23, 0x0b, 0x3b, 0x13, 0x73, 0x05, 0x84, 0x32, 0x16, 0xdc, 0xc2, 0x89, 0xd1, 0xe0, 0x7a, + 0x08, 0x69, 0x30, 0x60, 0x42, 0xdd, 0xb9, 0xfd, 0x5c, 0xb2, 0xf5, 0xd7, 0x90, 0x9b, 0x00, 0x03, + 0x09, 0x86, 0xbe, 0x07, 0xcb, 0x62, 0x14, 0x22, 0x66, 0xda, 0xba, 0x8d, 0x5b, 0xe4, 0x4d, 0xd9, + 0xc6, 0x14, 0xb7, 0x35, 0x9b, 0x7c, 0x5c, 0x34, 0xfe, 0xbb, 0x0f, 0x44, 0x0e, 0x8a, 0x96, 0xd1, + 0xeb, 0x2f, 0xcb, 0x68, 0x59, 0x0c, 0x53, 0x04, 0x32, 0x7e, 0x3f, 0xc7, 0x25, 0x2a, 0x41, 0x1d, + 0x68, 0xca, 0x1f, 0xce, 0xd7, 0x2c, 0xcf, 0x9d, 0x5c, 0x09, 0x56, 0x07, 0x1c, 0xd4, 0x77, 0x27, + 0xc8, 0x6b, 0x1c, 0x57, 0x27, 0xe1, 0x9b, 0x77, 0x5d, 0x02, 0x91, 0xe8, 0x0e, 0xd4, 0x66, 0xf3, + 0x93, 0x89, 0x33, 0xe2, 0x24, 0x05, 0x9e, 0x0b, 0x07, 0x21, 0xc1, 0x1b, 0x50, 0x17, 0x73, 0x9d, + 0x53, 0x14, 0x91, 0xa2, 0x26, 0x60, 0x48, 0x82, 0xc2, 0x01, 0xf5, 0x91, 0xd9, 0xd5, 0x4d, 0xfc, + 0x6d, 0x6c, 0xc3, 0x6a, 0xbc, 0xd2, 0x42, 0x72, 0xb9, 0x0f, 0x15, 0xc1, 0x49, 0xa5, 0x5a, 0x74, + 0x31, 0xde, 0x1b, 0xa6, 0xc2, 0x1b, 0xff, 0xbe, 0x04, 0x2b, 0xb2, 0x8f, 0xd8, 0x60, 0x0f, 0xe6, + 0xd3, 0xa9, 0xed, 0x67, 0xb0, 0xe8, 0xdc, 0x8b, 0x59, 0x74, 0x3e, 0xc5, 0xa2, 0xe3, 0x7a, 0x31, + 0xce, 0xe1, 0xe3, 0x7a, 0x31, 0x36, 0xbb, 0xf8, 0x69, 0x5c, 0xb7, 0xbe, 0x34, 0x04, 0x78, 0xc8, + 0xad, 0x3c, 0xa9, 0x0d, 0xa5, 0x94, 0xb1, 0xa1, 0xe8, 0xdb, 0xc1, 0x42, 0x62, 0x3b, 0x78, 0x03, + 0xf8, 0x34, 0x96, 0xf3, 0xb1, 0xcc, 0x0f, 0xe8, 0x08, 0x13, 0x13, 0xf2, 0x1d, 0x58, 0x4a, 0x72, + 0x60, 0xce, 0xea, 0x17, 0x33, 0xf8, 0xaf, 0x33, 0xa5, 0x28, 0xd4, 0x68, 0xc4, 0x55, 0xc1, 0x7f, + 0x9d, 0x29, 0x3d, 0x40, 0x8c, 0xa4, 0xef, 0x00, 0xf0, 0xb2, 0x71, 0x19, 0x03, 0x2e, 0xe3, 0xb7, + 0x13, 0x33, 0x53, 0xeb, 0xf5, 0x2d, 0xf6, 0x31, 0xf7, 0x29, 0xae, 0xeb, 0x2a, 0xa6, 0xc4, 0x25, + 0xfd, 0x29, 0x2c, 0x7a, 0x33, 0xea, 0x5a, 0x11, 0x17, 0xac, 0x61, 0x56, 0x4d, 0x91, 0x55, 0x57, + 0xc2, 0xcd, 0x06, 0xa3, 0x53, 0x9f, 0xe4, 0x73, 0xde, 0xc9, 0x54, 0x4b, 0x59, 0xbf, 0x26, 0xe5, + 0x22, 0x12, 0x46, 0x49, 0x3f, 0x42, 0xdd, 0x93, 0x37, 0x99, 0x73, 0x53, 0x4e, 0x03, 0xe7, 0x91, + 0xd4, 0x6d, 0x9b, 0x0a, 0x63, 0xea, 0x54, 0xc6, 0x6f, 0xe4, 0xa0, 0xa6, 0xb5, 0x81, 0xac, 0xc1, + 0xf2, 0x4e, 0xbf, 0x7f, 0xd4, 0x31, 0xdb, 0xc3, 0xee, 0x17, 0x1d, 0x6b, 0xe7, 0xa0, 0x3f, 0xe8, + 0x34, 0x6f, 0x30, 0xf0, 0x41, 0x7f, 0xa7, 0x7d, 0x60, 0xed, 0xf5, 0xcd, 0x1d, 0x09, 0xce, 0x91, + 0x75, 0x20, 0x66, 0xe7, 0xb0, 0x3f, 0xec, 0xc4, 0xe0, 0x79, 0xd2, 0x84, 0xfa, 0xb6, 0xd9, 0x69, + 0xef, 0xec, 0x0b, 0x48, 0x81, 0xac, 0x42, 0x73, 0xef, 0xb8, 0xb7, 0xdb, 0xed, 0x3d, 0xb1, 0x76, + 0xda, 0xbd, 0x9d, 0xce, 0x41, 0x67, 0xb7, 0x59, 0x24, 0x0d, 0xa8, 0xb6, 0xb7, 0xdb, 0xbd, 0xdd, + 0x7e, 0xaf, 0xb3, 0xdb, 0x2c, 0x19, 0xff, 0x33, 0x07, 0x10, 0x55, 0x94, 0xf1, 0xd5, 0xa8, 0xaa, + 0xba, 0xe9, 0x74, 0x2d, 0xd5, 0x28, 0xce, 0x57, 0xfd, 0xd8, 0x37, 0x79, 0x08, 0x65, 0x6f, 0x1e, + 0x8e, 0xbc, 0x29, 0x3f, 0x44, 0x2c, 0x3e, 0x6c, 0xa5, 0xd2, 0xf5, 0x39, 0xde, 0x94, 0x84, 0x31, + 0xf3, 0x68, 0xe1, 0x65, 0xe6, 0xd1, 0xb8, 0x1d, 0x96, 0xcb, 0x75, 0x9a, 0x1d, 0xf6, 0x36, 0x40, + 0xf0, 0x9c, 0xd2, 0x19, 0x2a, 0xaf, 0xc4, 0x2a, 0xa8, 0x22, 0x64, 0xc8, 0xce, 0x98, 0xff, 0x39, 0x07, 0x6b, 0x38, 0x97, 0xc6, 0x49, 0x26, 0x76, 0x17, 0x6a, 0x23, 0xcf, 0x9b, 0x51, 0x26, 0x54, 0x2b, 0x79, 0x4d, 0x07, 0x31, 0x06, 0xc5, 0x19, 0xf2, 0xa9, 0xe7, 0x8f, 0xa8, 0xe0, 0x61, 0x80, 0xa0, 0x3d, 0x06, 0x61, 0x6b, 0x48, 0x2c, 0x42, 0x4e, 0xc1, 0x59, 0x58, 0x8d, 0xc3, 0x38, 0xc9, @@ -13079,7 +13170,7 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x88, 0xad, 0x89, 0x09, 0xe5, 0x95, 0xaf, 0x98, 0x4b, 0x02, 0xbe, 0x23, 0xc0, 0x6c, 0x9f, 0xb7, 0x4f, 0x6c, 0x77, 0xec, 0xb9, 0x74, 0x2c, 0xce, 0xf2, 0x11, 0xc0, 0x38, 0x82, 0xf5, 0x64, 0xfb, 0x04, 0xbf, 0xfb, 0x44, 0xe3, 0x77, 0xfc, 0xe8, 0xbb, 0x79, 0xfd, 0x1a, 0xd3, 0x78, 0xdf, 0x7f, - 0x2e, 0x42, 0x91, 0x1d, 0x78, 0xae, 0x3d, 0x1b, 0xe9, 0x67, 0xdb, 0x42, 0xca, 0x68, 0x8e, 0xba, + 0x29, 0x42, 0x91, 0x1d, 0x78, 0xae, 0x3d, 0x1b, 0xe9, 0x67, 0xdb, 0x42, 0xca, 0x68, 0x8e, 0xba, 0x42, 0x2e, 0x80, 0x89, 0xc1, 0x42, 0x08, 0x0a, 0x5e, 0x0a, 0xed, 0xd3, 0xd1, 0x85, 0x3c, 0xb3, 0x20, 0xc4, 0xa4, 0xa3, 0x0b, 0x54, 0x5a, 0xd8, 0x21, 0x4f, 0xcb, 0xf9, 0x55, 0x39, 0xb0, 0x43, 0x4c, 0x29, 0x50, 0x98, 0xae, 0xac, 0x50, 0x98, 0xaa, 0x05, 0x65, 0xc7, 0x3d, 0xf1, 0xe6, 0xae, @@ -13155,7 +13246,7 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x81, 0x3b, 0xa2, 0x3d, 0x19, 0x8e, 0x42, 0xbc, 0x17, 0x96, 0x50, 0x52, 0xdd, 0xe4, 0x64, 0x87, 0x09, 0x9f, 0xa1, 0x44, 0xa7, 0x48, 0x37, 0x93, 0x80, 0x2b, 0x7a, 0x65, 0xa7, 0x1c, 0x72, 0x3f, 0x93, 0x00, 0xbb, 0xd8, 0xbe, 0xb4, 0x84, 0x12, 0x30, 0xb8, 0x40, 0x39, 0xa9, 0x61, 0xd6, 0xa6, - 0xf6, 0xe5, 0x01, 0x2a, 0xf9, 0x82, 0x0b, 0xe3, 0x2f, 0x72, 0xd0, 0x64, 0x53, 0x33, 0xb6, 0xea, + 0xf6, 0xe5, 0x01, 0x2a, 0xf9, 0x82, 0x0b, 0xe3, 0xcf, 0x73, 0xd0, 0x64, 0x53, 0x33, 0xb6, 0xea, 0x3f, 0x07, 0xe4, 0x4f, 0xaf, 0xb8, 0xe8, 0x6b, 0x8c, 0x56, 0xae, 0xf9, 0x4f, 0x01, 0x17, 0xb1, 0xe5, 0xcd, 0xa8, 0x2b, 0x96, 0x7c, 0x2b, 0xbe, 0xe4, 0x23, 0xb6, 0xbe, 0x7f, 0x83, 0x9f, 0x12, 0x19, 0x84, 0x7c, 0x0e, 0x55, 0xb6, 0x56, 0x70, 0xe2, 0x0a, 0x1f, 0xe7, 0x4d, 0x75, 0xf2, 0x4f, @@ -13165,7 +13256,7 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x4b, 0xc9, 0xac, 0x3c, 0xa3, 0x57, 0x9c, 0xab, 0x58, 0xd0, 0x78, 0x4a, 0xaf, 0x76, 0x29, 0x17, 0xde, 0x3d, 0x9f, 0x75, 0xba, 0x6f, 0x3f, 0x67, 0xd2, 0x7a, 0xcc, 0xcb, 0xa5, 0xe6, 0xdb, 0xcf, 0x9f, 0xd2, 0x2b, 0xe9, 0x71, 0x53, 0x66, 0xf8, 0x89, 0x37, 0x12, 0xe2, 0x86, 0x54, 0xf8, 0x44, - 0x95, 0x32, 0x17, 0x9e, 0xe1, 0x6f, 0xe3, 0xcf, 0x73, 0xd0, 0x60, 0xf5, 0xc7, 0x9d, 0x02, 0x67, + 0x95, 0x32, 0x17, 0x9e, 0xe1, 0x6f, 0xe3, 0xcf, 0x72, 0xd0, 0x60, 0xf5, 0xc7, 0x9d, 0x02, 0x67, 0x91, 0xf0, 0x89, 0xcd, 0x45, 0x3e, 0xb1, 0x0f, 0x05, 0xa3, 0xe5, 0xdb, 0x4e, 0xfe, 0xfa, 0x6d, 0x07, 0xc7, 0x86, 0xef, 0x39, 0x1f, 0x42, 0x95, 0x4f, 0x0c, 0xc6, 0x7a, 0x0a, 0xb1, 0x01, 0x8e, 0x35, 0xc8, 0xac, 0x20, 0xd9, 0x53, 0xee, 0x82, 0xa7, 0xe9, 0xd6, 0x79, 0x17, 0x57, 0x7d, 0xa5, @@ -13205,7 +13296,7 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x67, 0xd8, 0xe0, 0x74, 0xd3, 0x57, 0xe1, 0x65, 0x9e, 0x10, 0xc5, 0x57, 0xf2, 0x84, 0x28, 0x65, 0x79, 0x42, 0x7c, 0x74, 0xad, 0xe9, 0x9c, 0x2b, 0xb0, 0x33, 0xcd, 0xe6, 0x8f, 0xae, 0x37, 0x9b, 0x73, 0x91, 0xfc, 0x3a, 0x93, 0xb9, 0x66, 0xf0, 0xaf, 0x5c, 0x63, 0xb0, 0xd2, 0x5c, 0x00, 0x32, - 0x4c, 0xe6, 0xd5, 0xaf, 0x61, 0x32, 0xdf, 0xfc, 0xf3, 0x1c, 0x90, 0xf4, 0xea, 0x20, 0x4f, 0xb8, + 0x4c, 0xe6, 0xd5, 0xaf, 0x61, 0x32, 0xdf, 0xfc, 0xb3, 0x1c, 0x90, 0xf4, 0xea, 0x20, 0x4f, 0xb8, 0x79, 0xd3, 0xa5, 0x13, 0xc1, 0xb9, 0xdf, 0x7f, 0xb5, 0x15, 0x26, 0x27, 0x84, 0x4c, 0x4d, 0x3e, 0x80, 0x15, 0xfd, 0x36, 0x9a, 0xae, 0x8a, 0x68, 0x98, 0x44, 0x47, 0x45, 0x4a, 0x35, 0xcd, 0xed, 0xa4, 0xf8, 0x52, 0xb7, 0x93, 0xd2, 0x4b, 0xdd, 0x4e, 0x16, 0xe2, 0x6e, 0x27, 0x9b, 0xff, 0x26, @@ -13218,7 +13309,7 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x10, 0xd9, 0x3c, 0xff, 0x10, 0xd6, 0x94, 0x03, 0x43, 0x2c, 0x05, 0x37, 0x18, 0x11, 0xe9, 0xa8, 0xa0, 0x25, 0xf9, 0x1e, 0xdc, 0x4e, 0xd4, 0x29, 0x91, 0x94, 0x3b, 0xbe, 0xdd, 0x8c, 0xd5, 0x4e, 0xcf, 0x61, 0xf3, 0x2f, 0x41, 0x23, 0xc6, 0x28, 0xbf, 0xb9, 0x21, 0x4f, 0x2a, 0xaf, 0x78, 0x8f, - 0xea, 0xca, 0xab, 0xcd, 0xff, 0x59, 0x00, 0x92, 0xe6, 0xd5, 0x3f, 0xcb, 0x2a, 0xa4, 0x27, 0x66, + 0xea, 0xca, 0xab, 0xcd, 0xff, 0x55, 0x00, 0x92, 0xe6, 0xd5, 0x3f, 0xcb, 0x2a, 0xa4, 0x27, 0x66, 0x21, 0x63, 0x62, 0xfe, 0x3f, 0x93, 0x1f, 0x22, 0x1d, 0xaa, 0xe6, 0x3f, 0xc0, 0x17, 0x67, 0x53, 0x21, 0x64, 0x2d, 0x3e, 0x4d, 0x7a, 0x59, 0x55, 0x62, 0x17, 0x2a, 0x35, 0x01, 0x2a, 0xe1, 0x6c, 0x75, 0x0c, 0x0b, 0xb6, 0x3b, 0x3a, 0xf7, 0x7c, 0xc1, 0x07, 0x7f, 0xee, 0x6b, 0x6f, 0x9f, 0x5b, @@ -13280,7 +13371,7 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x89, 0xdb, 0xf2, 0x56, 0x83, 0x37, 0xdb, 0xca, 0x58, 0x9c, 0x8d, 0x91, 0x0e, 0xdb, 0xfc, 0x1e, 0x90, 0x9f, 0x32, 0xb4, 0xc3, 0x10, 0xaa, 0xaa, 0x7e, 0x7a, 0x64, 0x04, 0xbc, 0x4a, 0x56, 0x8b, 0x45, 0x46, 0x68, 0x8f, 0xc7, 0x3e, 0xe3, 0x8b, 0x5c, 0xfa, 0x51, 0x2c, 0x1f, 0x34, 0xf1, 0x47, - 0xdc, 0x07, 0x32, 0xfe, 0x4b, 0x0e, 0x4a, 0x3c, 0x4c, 0xc3, 0xdb, 0xb0, 0xc4, 0xe9, 0x95, 0x2f, + 0xdc, 0x07, 0x32, 0xfe, 0x6b, 0x0e, 0x4a, 0x3c, 0x4c, 0xc3, 0xdb, 0xb0, 0xc4, 0xe9, 0x95, 0x2f, 0xb3, 0x70, 0x38, 0xe1, 0x42, 0xd4, 0x50, 0xb8, 0x31, 0xb3, 0x65, 0xa1, 0x85, 0xae, 0x89, 0xc4, 0x08, 0x2d, 0x7c, 0xcd, 0x1d, 0xa8, 0xaa, 0xa2, 0xb5, 0xa9, 0x53, 0x91, 0x25, 0x93, 0xd7, 0xa1, 0x78, 0xee, 0xcd, 0xa4, 0x1a, 0x0f, 0xa2, 0x9e, 0x34, 0x11, 0x1e, 0xd5, 0x85, 0x95, 0x11, 0xdd, @@ -13377,7 +13468,7 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x13, 0x3c, 0xe5, 0x80, 0x94, 0x16, 0x6a, 0x33, 0xa5, 0x85, 0xfa, 0x66, 0xb7, 0xa0, 0x36, 0xd4, 0xf5, 0x9e, 0x20, 0x15, 0x28, 0xf6, 0x8f, 0x3a, 0xbd, 0xe6, 0x0d, 0x52, 0x83, 0xf2, 0xa0, 0x33, 0x1c, 0x1e, 0xa0, 0x9d, 0xb9, 0x0e, 0x15, 0x75, 0xff, 0x3b, 0xcf, 0xbe, 0xda, 0x3b, 0x3b, 0x9d, - 0xa3, 0x61, 0x67, 0xb7, 0x59, 0xf8, 0x7e, 0xb1, 0x92, 0x6f, 0x16, 0x8c, 0x3f, 0x2d, 0x40, 0x4d, + 0xa3, 0x61, 0x67, 0xb7, 0x59, 0xf8, 0x7e, 0xb1, 0x92, 0x6f, 0x16, 0x8c, 0xbf, 0x28, 0x40, 0x4d, 0xeb, 0xa8, 0x17, 0xf3, 0xeb, 0x78, 0xa4, 0xa1, 0x7c, 0x32, 0xd2, 0x90, 0x6e, 0x54, 0x11, 0xd1, 0x98, 0xa4, 0x51, 0xe5, 0x4d, 0x68, 0x88, 0x88, 0x88, 0x9a, 0xb7, 0x40, 0xc9, 0xac, 0x73, 0xa0, 0xe0, 0xe6, 0x18, 0x4d, 0x02, 0x89, 0xf0, 0x9e, 0xae, 0x88, 0x65, 0xc6, 0x41, 0x78, 0x53, 0x17, @@ -13385,269 +13476,274 @@ var fileDescriptor_77a6da22d6a3feb1 = []byte{ 0x08, 0x96, 0xa9, 0x85, 0x33, 0x28, 0x99, 0x75, 0x0e, 0x14, 0x05, 0xbd, 0x2f, 0xe7, 0x18, 0xf7, 0x9d, 0xda, 0x48, 0x4f, 0x98, 0xd8, 0xfc, 0x3a, 0x48, 0xe9, 0x3d, 0xab, 0x38, 0x77, 0xbe, 0x95, 0x4e, 0xf7, 0x72, 0xfd, 0x27, 0x79, 0x17, 0xc8, 0x74, 0x36, 0xb3, 0x32, 0x34, 0x92, 0x45, 0x73, - 0x69, 0x3a, 0x9b, 0x0d, 0x35, 0x85, 0xdd, 0x37, 0xa0, 0x2c, 0xfd, 0xad, 0x1c, 0x90, 0x36, 0x5b, - 0xe4, 0x58, 0x47, 0x75, 0x78, 0x8c, 0x58, 0x77, 0x4e, 0x67, 0xdd, 0x19, 0x1c, 0x32, 0x9f, 0xc9, - 0x21, 0x5f, 0xc6, 0x4b, 0x62, 0xab, 0x61, 0x39, 0xb5, 0x1a, 0x8c, 0x3d, 0xa8, 0x1d, 0x69, 0xc1, - 0x6b, 0xef, 0xb2, 0x8d, 0x46, 0x86, 0xad, 0xe5, 0x5b, 0x10, 0x57, 0x94, 0xfa, 0x22, 0x5a, 0xad, - 0x56, 0xe1, 0xbc, 0x56, 0x61, 0xe3, 0x1f, 0xe4, 0x78, 0xec, 0x38, 0xd5, 0xbe, 0x28, 0x5e, 0xae, - 0xb4, 0x37, 0x46, 0x91, 0x49, 0x6a, 0xd2, 0xa2, 0x28, 0x82, 0x8a, 0x60, 0xed, 0x2d, 0xef, 0xf4, - 0x34, 0xa0, 0xd2, 0x0b, 0xa9, 0x86, 0xb0, 0x3e, 0x82, 0xe4, 0x89, 0x82, 0x1d, 0x5b, 0x1c, 0x9e, - 0x7f, 0x20, 0x5c, 0x8f, 0xd8, 0x89, 0xe2, 0xd0, 0xbe, 0x14, 0xa5, 0x06, 0x4c, 0x92, 0x11, 0x46, - 0x0f, 0x79, 0x33, 0x5f, 0x7d, 0x1b, 0x7f, 0x57, 0x04, 0x4f, 0x49, 0x0e, 0xc1, 0x7d, 0xa8, 0xa8, - 0x5c, 0xe3, 0x1b, 0xb5, 0xa4, 0x54, 0x78, 0x26, 0x0e, 0xa0, 0x86, 0x27, 0x56, 0x63, 0xbe, 0x00, - 0xd1, 0x70, 0xd5, 0xd5, 0x6a, 0xfd, 0x1e, 0x90, 0x53, 0xc7, 0x4f, 0x12, 0xf3, 0x05, 0xd9, 0x44, - 0x8c, 0x46, 0x6d, 0x1c, 0xc3, 0x8a, 0xe4, 0x24, 0xda, 0x31, 0x27, 0x3e, 0xbe, 0xb9, 0x97, 0xec, - 0x15, 0xf9, 0xd4, 0x5e, 0x61, 0xfc, 0x46, 0x09, 0xca, 0x32, 0x10, 0x74, 0x56, 0xf0, 0xe2, 0x6a, - 0x3c, 0x78, 0x71, 0x2b, 0x16, 0x6b, 0x11, 0x87, 0x5e, 0x88, 0x0d, 0xef, 0x24, 0x77, 0x7e, 0xcd, - 0x00, 0x13, 0xdb, 0xfd, 0x85, 0x01, 0xa6, 0x14, 0x37, 0xc0, 0x64, 0x05, 0x74, 0xe6, 0x12, 0x6c, - 0x2a, 0xa0, 0xf3, 0x2d, 0xe0, 0xe2, 0x88, 0xe6, 0x7e, 0x59, 0x41, 0x80, 0x88, 0x2e, 0xa1, 0x49, - 0x2f, 0x95, 0xa4, 0xf4, 0xf2, 0xca, 0x92, 0xc5, 0xc7, 0xb0, 0xc0, 0x03, 0x31, 0x89, 0x48, 0x03, - 0x72, 0xff, 0x11, 0x7d, 0x25, 0xff, 0xf3, 0x5b, 0x3d, 0xa6, 0xa0, 0xd5, 0x03, 0x80, 0xd6, 0x62, - 0x01, 0x40, 0x75, 0xc3, 0x50, 0x3d, 0x6e, 0x18, 0xba, 0x07, 0x4d, 0xd5, 0x71, 0xa8, 0x66, 0x75, - 0x03, 0x71, 0xa9, 0x78, 0x51, 0xc2, 0x19, 0xc7, 0xec, 0x05, 0xd1, 0xfe, 0xb9, 0x18, 0xdb, 0x3f, - 0x19, 0x3f, 0x6b, 0x87, 0x21, 0x9d, 0xce, 0x42, 0xb9, 0x7f, 0x6a, 0x31, 0xb4, 0xf9, 0xc8, 0xf3, - 0x5b, 0x4f, 0x72, 0x78, 0xf9, 0xec, 0xd8, 0x86, 0xc5, 0x53, 0xdb, 0x99, 0xcc, 0x7d, 0x6a, 0xf9, - 0xd4, 0x0e, 0x3c, 0x17, 0xf9, 0x43, 0xb4, 0x95, 0x8b, 0x26, 0xee, 0x71, 0x1a, 0x13, 0x49, 0xcc, - 0xc6, 0xa9, 0xfe, 0x89, 0x77, 0x07, 0xf5, 0x9e, 0x60, 0xdb, 0x9a, 0x88, 0x37, 0xc0, 0xbd, 0xa9, - 0xba, 0x3d, 0x6b, 0xef, 0xa0, 0xfb, 0x64, 0x7f, 0xd8, 0xcc, 0xb1, 0xcf, 0xc1, 0xf1, 0xce, 0x4e, - 0xa7, 0xb3, 0x8b, 0xdb, 0x1c, 0xc0, 0xc2, 0x5e, 0xbb, 0x7b, 0x20, 0x36, 0xb9, 0x62, 0xb3, 0x64, - 0xfc, 0x49, 0x1e, 0x6a, 0x5a, 0x6b, 0x30, 0x92, 0x08, 0xff, 0xc9, 0xf6, 0xb9, 0xb2, 0x88, 0x24, - 0xc2, 0x21, 0xdd, 0x31, 0x79, 0xa4, 0xc6, 0x88, 0x07, 0x40, 0xb9, 0x9d, 0xee, 0x90, 0x2d, 0xb9, - 0x49, 0x68, 0x83, 0xa4, 0x82, 0x69, 0xe7, 0xaf, 0x0d, 0xa6, 0x4d, 0xde, 0x86, 0x25, 0x59, 0xb2, - 0x1c, 0x13, 0x61, 0xd0, 0x10, 0x60, 0x31, 0x24, 0x6f, 0x8b, 0x60, 0x2c, 0x62, 0xa7, 0x63, 0x74, - 0x45, 0xe9, 0x75, 0xac, 0x36, 0x3b, 0x1c, 0xba, 0xb2, 0xe8, 0x38, 0xe1, 0x80, 0xa0, 0x64, 0x06, - 0xd1, 0x9d, 0x12, 0xcd, 0xef, 0x1b, 0x6b, 0x0b, 0xa0, 0x6e, 0xaa, 0x6f, 0xe3, 0x13, 0x80, 0xa8, - 0x3d, 0xf1, 0xde, 0xbd, 0x11, 0xef, 0xdd, 0x9c, 0xd6, 0xbb, 0x79, 0xe3, 0x1f, 0x0b, 0xce, 0x26, - 0x86, 0x4a, 0xa9, 0x37, 0xdf, 0x07, 0xa9, 0x70, 0xb5, 0xf0, 0x96, 0xc2, 0x6c, 0x42, 0x43, 0x79, - 0x65, 0x7a, 0x59, 0x60, 0xba, 0x0a, 0x91, 0xe2, 0xc4, 0xf9, 0x34, 0x27, 0x7e, 0x03, 0xea, 0x18, - 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, - 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, + 0x69, 0x3a, 0x9b, 0x0d, 0x35, 0x85, 0x1d, 0x79, 0x0d, 0x0a, 0xf6, 0x74, 0x86, 0xac, 0x25, 0xd2, + 0x0e, 0xb6, 0x0f, 0x8f, 0x4c, 0x06, 0xfe, 0x06, 0x54, 0xa9, 0xbf, 0x99, 0x83, 0x42, 0xfb, 0xf0, + 0x08, 0x19, 0xbd, 0xe7, 0x85, 0x56, 0x70, 0x6e, 0x8b, 0x60, 0x62, 0x8c, 0xd1, 0x7b, 0x5e, 0x38, + 0x60, 0x00, 0xc6, 0xe8, 0x03, 0x1a, 0x46, 0x3e, 0xc0, 0xa5, 0x80, 0x86, 0xdc, 0x21, 0x7c, 0x74, + 0xee, 0x4c, 0xc6, 0xb1, 0xd0, 0x8e, 0x80, 0x20, 0x3e, 0x23, 0x08, 0x14, 0xb5, 0xed, 0x01, 0x7f, + 0xf3, 0x8b, 0x6f, 0x62, 0x47, 0xe1, 0x6e, 0xe6, 0xea, 0xdb, 0xf8, 0xad, 0x1c, 0x90, 0x36, 0xe3, + 0x48, 0xd8, 0xa1, 0xea, 0xa4, 0x1b, 0xed, 0x33, 0x39, 0x7d, 0x9f, 0xc9, 0x60, 0xe7, 0xf9, 0x4c, + 0x76, 0xfe, 0x32, 0xc6, 0x17, 0x5b, 0xba, 0xcb, 0xa9, 0xa5, 0x6b, 0xec, 0x41, 0xed, 0x48, 0x8b, + 0xb4, 0x7b, 0x97, 0xed, 0x8a, 0x32, 0xc6, 0x2e, 0xdf, 0x2f, 0xb9, 0x56, 0xd7, 0x17, 0xa1, 0x75, + 0xb5, 0x0a, 0xe7, 0xb5, 0x0a, 0x1b, 0xff, 0x20, 0xc7, 0x03, 0xdd, 0xa9, 0xf6, 0x45, 0xc1, 0x7d, + 0xa5, 0x71, 0x34, 0x0a, 0xa3, 0x52, 0x93, 0xe6, 0x4f, 0x11, 0x01, 0x05, 0x6b, 0x6f, 0x79, 0xa7, + 0xa7, 0x01, 0x95, 0x2e, 0x53, 0x35, 0x84, 0xf5, 0x11, 0x24, 0x8f, 0x3f, 0xec, 0x8c, 0xe5, 0xf0, + 0xfc, 0x03, 0xe1, 0x27, 0xc5, 0x8e, 0x3f, 0x87, 0xf6, 0xa5, 0x28, 0x35, 0x60, 0x23, 0x20, 0x2c, + 0x34, 0x32, 0x8c, 0x80, 0xfa, 0x36, 0xfe, 0xae, 0x88, 0xf4, 0x92, 0x1c, 0x82, 0xfb, 0x50, 0x51, + 0xb9, 0xc6, 0xa5, 0x0a, 0x49, 0xa9, 0xf0, 0x4c, 0x76, 0x41, 0x75, 0x54, 0xac, 0xc6, 0x9c, 0x5b, + 0xa0, 0x95, 0xad, 0xab, 0xd5, 0xfa, 0x3d, 0x20, 0xa7, 0x8e, 0x9f, 0x24, 0xe6, 0xdc, 0xa3, 0x89, + 0x18, 0x8d, 0xda, 0x38, 0x86, 0x15, 0xc9, 0xf6, 0xb4, 0x33, 0x59, 0x7c, 0x7c, 0x73, 0x2f, 0xd9, + 0xd8, 0xf2, 0xa9, 0x8d, 0xcd, 0xf8, 0x8d, 0x12, 0x94, 0x65, 0xd4, 0xea, 0xac, 0x48, 0xcb, 0xd5, + 0x78, 0xa4, 0xe5, 0x56, 0x2c, 0x30, 0x24, 0x0e, 0xbd, 0x90, 0x71, 0xde, 0x49, 0x8a, 0x29, 0x9a, + 0xb5, 0x28, 0x26, 0xaa, 0x08, 0x6b, 0x51, 0x29, 0x6e, 0x2d, 0xca, 0x8a, 0x3e, 0xcd, 0xc5, 0xed, + 0x54, 0xf4, 0xe9, 0x5b, 0xc0, 0x65, 0x27, 0xcd, 0x57, 0xb4, 0x82, 0x00, 0x11, 0x0a, 0x43, 0x13, + 0xb5, 0x2a, 0x49, 0x51, 0xeb, 0x95, 0xc5, 0xa0, 0x8f, 0x61, 0x81, 0x47, 0x8d, 0x12, 0x61, 0x11, + 0xe4, 0x66, 0x29, 0xfa, 0x4a, 0xfe, 0xe7, 0x57, 0x90, 0x4c, 0x41, 0xab, 0x47, 0x2b, 0xad, 0xc5, + 0xa2, 0x95, 0xea, 0x56, 0xac, 0x7a, 0xdc, 0x8a, 0x75, 0x0f, 0x9a, 0xaa, 0xe3, 0x50, 0x27, 0xec, + 0x06, 0xe2, 0x06, 0xf4, 0xa2, 0x84, 0x33, 0xf6, 0xde, 0x0b, 0xa2, 0xcd, 0x7e, 0x31, 0xb6, 0xd9, + 0x33, 0xe6, 0xdb, 0x0e, 0x43, 0x3a, 0x9d, 0x85, 0x72, 0xb3, 0xd7, 0x02, 0x7e, 0xf3, 0x91, 0xe7, + 0x57, 0xb4, 0xe4, 0xf0, 0xf2, 0xd9, 0xb1, 0x0d, 0x8b, 0xa7, 0xb6, 0x33, 0x99, 0xfb, 0xd4, 0xf2, + 0xa9, 0x1d, 0x78, 0x2e, 0xf2, 0x87, 0x48, 0xee, 0x10, 0x4d, 0xdc, 0xe3, 0x34, 0x26, 0x92, 0x98, + 0x8d, 0x53, 0xfd, 0x13, 0x2f, 0x3a, 0xea, 0x3d, 0xc1, 0xf6, 0x60, 0x11, 0x1c, 0x81, 0xbb, 0x7e, + 0x75, 0x7b, 0xd6, 0xde, 0x41, 0xf7, 0xc9, 0xfe, 0xb0, 0x99, 0x63, 0x9f, 0x83, 0xe3, 0x9d, 0x9d, + 0x4e, 0x67, 0x17, 0xf7, 0x64, 0x80, 0x85, 0xbd, 0x76, 0xf7, 0x40, 0xec, 0xc8, 0xc5, 0x66, 0xc9, + 0xf8, 0x93, 0x3c, 0xd4, 0xb4, 0xd6, 0x60, 0xd8, 0x13, 0xfe, 0x93, 0xf1, 0xdf, 0xb2, 0x08, 0x7b, + 0xc2, 0x21, 0xdd, 0x31, 0x79, 0xa4, 0xc6, 0x88, 0x47, 0x6b, 0xb9, 0x9d, 0xee, 0x90, 0x2d, 0xb9, + 0xa3, 0x69, 0x83, 0xa4, 0x22, 0x7f, 0xe7, 0xaf, 0x8d, 0xfc, 0x4d, 0xde, 0x86, 0x25, 0x59, 0xb2, + 0x1c, 0x13, 0x61, 0x7d, 0x11, 0x60, 0x31, 0x24, 0x6f, 0x8b, 0xc8, 0x31, 0x62, 0x5b, 0x66, 0x74, + 0x45, 0xe9, 0x22, 0xad, 0x76, 0x66, 0x1c, 0xba, 0xb2, 0xe8, 0x38, 0xe1, 0x2d, 0xa1, 0x04, 0x1c, + 0xd1, 0x9d, 0x12, 0x1d, 0xdb, 0x23, 0x16, 0x12, 0x7b, 0xc4, 0x27, 0x00, 0x51, 0x7b, 0xe2, 0xbd, + 0x7b, 0x23, 0xde, 0xbb, 0x39, 0xad, 0x77, 0xf3, 0xc6, 0x3f, 0x16, 0x9c, 0x4d, 0x0c, 0x95, 0xd2, + 0xc5, 0xbe, 0x0f, 0x52, 0x3b, 0x6c, 0xe1, 0x95, 0x8a, 0xd9, 0x84, 0x86, 0xf2, 0x7e, 0xf7, 0xb2, + 0xc0, 0x74, 0x15, 0x22, 0xc5, 0x89, 0xf3, 0x69, 0x4e, 0xfc, 0x06, 0xd4, 0x31, 0x14, 0xa1, 0x28, + 0x48, 0x70, 0xb3, 0xda, 0xd4, 0xbe, 0x94, 0x65, 0xc7, 0x58, 0x70, 0x31, 0xc1, 0x82, 0xff, 0x5e, + 0x8e, 0xc7, 0xad, 0x8a, 0x2a, 0x1a, 0xf1, 0x60, 0x95, 0x67, 0x9c, 0x07, 0x0b, 0x52, 0x53, 0xe1, + 0xaf, 0xe1, 0xab, 0xf9, 0x6c, 0xbe, 0x9a, 0xcd, 0xb1, 0x0b, 0x99, 0x1c, 0xdb, 0xb8, 0x84, 0xd6, + 0x2e, 0x65, 0x5d, 0xd1, 0x9e, 0x4c, 0x92, 0x7d, 0xf9, 0x00, 0x56, 0xd9, 0x10, 0xa2, 0xab, 0x08, + 0xc7, 0xe8, 0x3b, 0x1a, 0xe1, 0x38, 0x99, 0x08, 0x37, 0xb6, 0xfb, 0xb0, 0x2c, 0x52, 0xe0, 0xa2, + 0xd5, 0x83, 0x84, 0x2d, 0x71, 0x04, 0x7a, 0x6c, 0x32, 0x5a, 0xe3, 0x16, 0xdc, 0xcc, 0x28, 0x59, + 0x28, 0xed, 0x7e, 0x33, 0x07, 0x6b, 0x6d, 0x1e, 0x0c, 0xe7, 0x1b, 0xbb, 0xde, 0xfd, 0x39, 0xdc, + 0x54, 0xb7, 0x2f, 0xb4, 0x5b, 0xa3, 0x7a, 0x25, 0xe5, 0xc5, 0x0d, 0xed, 0xce, 0x11, 0xd6, 0xb5, + 0x05, 0xeb, 0xc9, 0xda, 0x88, 0x8a, 0xee, 0xc1, 0xf2, 0x2e, 0x3d, 0x99, 0x9f, 0x1d, 0xd0, 0x8b, + 0xa8, 0x8e, 0x04, 0x8a, 0xc1, 0xb9, 0xf7, 0x5c, 0x74, 0x14, 0xfe, 0x46, 0xf7, 0x6c, 0x46, 0x63, + 0x05, 0x33, 0x3a, 0x92, 0x46, 0x1f, 0x84, 0x0c, 0x66, 0x74, 0x64, 0x3c, 0x02, 0xa2, 0xe7, 0x23, + 0xe6, 0x08, 0x3b, 0x03, 0xcf, 0x4f, 0xac, 0xe0, 0x2a, 0x08, 0xe9, 0x54, 0xde, 0x88, 0x86, 0x60, + 0x7e, 0x32, 0xe0, 0x10, 0xe3, 0x1d, 0xa8, 0x1f, 0xd9, 0x57, 0x26, 0xfd, 0x91, 0xb8, 0x78, 0xbc, + 0x01, 0xe5, 0x99, 0x7d, 0xc5, 0x36, 0x02, 0x65, 0xff, 0x45, 0xb4, 0xf1, 0x7b, 0x45, 0x58, 0xe0, + 0x94, 0xe4, 0x2e, 0x7f, 0xf1, 0xc3, 0x71, 0x91, 0x11, 0xcb, 0x2d, 0x51, 0x03, 0xa5, 0x76, 0xcd, + 0x7c, 0x7a, 0xd7, 0x14, 0xca, 0x6a, 0x19, 0x69, 0x51, 0x5a, 0xea, 0xdc, 0xf9, 0x54, 0x86, 0x57, + 0x8c, 0x87, 0x7e, 0x29, 0x46, 0x2f, 0xc5, 0xf0, 0xb0, 0x17, 0x71, 0x5f, 0x8a, 0xe8, 0xa4, 0xcd, + 0x6b, 0x27, 0x85, 0x01, 0xb1, 0x61, 0xea, 0xa0, 0xcc, 0xe3, 0x7c, 0x59, 0xde, 0xa6, 0x8f, 0x1f, + 0xe7, 0x53, 0xc7, 0xf6, 0xca, 0xcb, 0x8f, 0xed, 0x5c, 0x8b, 0xfd, 0x82, 0x63, 0x3b, 0xbc, 0xc2, + 0xb1, 0xfd, 0x15, 0xfc, 0x18, 0x6e, 0x42, 0x05, 0x25, 0x3c, 0x6d, 0xff, 0x64, 0x92, 0x1d, 0xdb, + 0x3f, 0x3f, 0xd5, 0x0e, 0xb6, 0xdc, 0x89, 0x4a, 0xdb, 0xc0, 0x4c, 0xfa, 0xa3, 0x9f, 0x8d, 0x62, + 0xf4, 0x2b, 0x28, 0x0b, 0x28, 0x9b, 0xd0, 0xae, 0x3d, 0x95, 0xf1, 0x84, 0xf1, 0x37, 0xeb, 0x36, + 0x8c, 0xb0, 0xf9, 0xa3, 0xb9, 0xe3, 0xd3, 0xb1, 0x8c, 0xf3, 0xe7, 0x20, 0xf7, 0x60, 0x10, 0xd6, + 0x40, 0x76, 0xc8, 0x76, 0xe5, 0x7b, 0x00, 0x15, 0xb3, 0xec, 0x04, 0x4f, 0xd9, 0xa7, 0x41, 0xa0, + 0x89, 0x11, 0xd1, 0x67, 0x9e, 0x2f, 0xc5, 0x13, 0xe3, 0xf7, 0x73, 0xd0, 0x14, 0xab, 0x4b, 0xe1, + 0xf4, 0x03, 0x6c, 0xe9, 0x3a, 0x9f, 0x9f, 0x17, 0x47, 0xed, 0x33, 0xa0, 0x81, 0xaa, 0x3d, 0x25, + 0xab, 0x70, 0xd5, 0x64, 0x8d, 0x01, 0xf7, 0x84, 0xbc, 0xf2, 0x3a, 0xd4, 0xe4, 0xe5, 0x91, 0xa9, + 0x33, 0x91, 0x8f, 0x42, 0xf1, 0xdb, 0x23, 0x87, 0xce, 0x44, 0x8a, 0x3a, 0xbe, 0x2d, 0xa2, 0x3b, + 0xe4, 0x50, 0xd4, 0x31, 0xed, 0x90, 0x1a, 0x7f, 0x98, 0x83, 0x65, 0xad, 0x29, 0x62, 0xdd, 0x7e, + 0x07, 0xea, 0xea, 0x9d, 0x06, 0xaa, 0x64, 0xec, 0x8d, 0x38, 0x8f, 0x8a, 0x92, 0xd5, 0x46, 0x0a, + 0x12, 0xb0, 0xca, 0x8c, 0xed, 0x2b, 0x7e, 0xc3, 0x61, 0x3e, 0x95, 0xe7, 0xf2, 0xb1, 0x7d, 0xb5, + 0x47, 0xe9, 0x60, 0x3e, 0x25, 0x77, 0xa1, 0xfe, 0x9c, 0xd2, 0x67, 0x8a, 0x80, 0x33, 0x76, 0x60, + 0x30, 0x41, 0x61, 0x40, 0x63, 0xea, 0xb9, 0xe1, 0xb9, 0x22, 0x11, 0xe7, 0x0b, 0x04, 0x72, 0x1a, + 0xe3, 0x8f, 0xf3, 0xb0, 0xc2, 0x15, 0xc8, 0xc2, 0x8c, 0x20, 0x58, 0x57, 0x0b, 0x16, 0xb8, 0x56, + 0x9f, 0x33, 0xaf, 0xfd, 0x1b, 0xa6, 0xf8, 0x26, 0x1f, 0xbf, 0xa2, 0xd2, 0x5b, 0x06, 0x90, 0xb8, + 0xa6, 0xfb, 0x0b, 0xe9, 0xee, 0xbf, 0xbe, 0x7b, 0xb3, 0x9c, 0x0a, 0x4a, 0x59, 0x4e, 0x05, 0xaf, + 0x62, 0xca, 0x4f, 0x85, 0x3a, 0x28, 0xa7, 0x43, 0x04, 0x3f, 0x82, 0x8d, 0x18, 0x0d, 0x72, 0x6b, + 0xe7, 0xd4, 0x51, 0xf1, 0xe7, 0x57, 0x35, 0xea, 0x81, 0xc4, 0x6d, 0x97, 0xa1, 0x14, 0x8c, 0xbc, + 0x19, 0x35, 0xd6, 0x61, 0x35, 0xde, 0xab, 0x62, 0x9b, 0xf8, 0x9d, 0x1c, 0xb4, 0xf6, 0xa2, 0x58, + 0xcb, 0x4e, 0x10, 0x7a, 0xbe, 0x0a, 0xd9, 0x7f, 0x1b, 0x80, 0x3f, 0x50, 0x85, 0x6a, 0x10, 0x11, + 0x24, 0x0b, 0x21, 0xa8, 0x04, 0xb9, 0x09, 0x15, 0xea, 0x8e, 0x39, 0x92, 0xcf, 0x86, 0x32, 0x75, + 0xc7, 0x52, 0x85, 0x92, 0xda, 0xe4, 0x1b, 0x71, 0xf1, 0x45, 0x84, 0x7b, 0x61, 0xbd, 0x43, 0x2f, + 0x50, 0xd8, 0x28, 0xaa, 0x70, 0x2f, 0x87, 0xf6, 0x25, 0x7a, 0xc7, 0x07, 0xc6, 0x6f, 0xe5, 0x61, + 0x29, 0xaa, 0x1f, 0x0f, 0x78, 0xf5, 0xe2, 0xd0, 0x5d, 0x77, 0xc5, 0x74, 0x70, 0xd8, 0x49, 0x4d, + 0x53, 0xab, 0x57, 0xf8, 0xe2, 0xec, 0xba, 0xc4, 0x80, 0x9a, 0xa4, 0xf0, 0xe6, 0xa1, 0x16, 0xd6, + 0xb8, 0xca, 0x49, 0xfa, 0xf3, 0x90, 0x1d, 0xad, 0xed, 0x29, 0x93, 0x54, 0xc4, 0xe1, 0xb6, 0x64, + 0x4f, 0xc3, 0x2e, 0xbe, 0x82, 0xc6, 0xc0, 0x2c, 0x19, 0x1f, 0x48, 0x46, 0xc5, 0xe8, 0x9b, 0xfc, + 0xa4, 0xc5, 0x47, 0x0e, 0x4f, 0x59, 0xfa, 0x31, 0x84, 0x3f, 0xdc, 0xa2, 0x8e, 0x21, 0xaf, 0x43, + 0x8d, 0x67, 0x1e, 0x45, 0xb6, 0xc0, 0x18, 0x83, 0x61, 0xd7, 0x45, 0xbc, 0x50, 0x71, 0x7a, 0xf3, + 0x98, 0xd6, 0x06, 0x78, 0x51, 0xe8, 0x61, 0xf5, 0x9b, 0x39, 0xb8, 0x99, 0x31, 0x6c, 0x62, 0x95, + 0xef, 0x80, 0x16, 0x71, 0x5b, 0xf6, 0x2e, 0x5f, 0xea, 0xeb, 0x92, 0xad, 0xc6, 0xfb, 0xd4, 0x6c, + 0x9e, 0xc6, 0x01, 0xd1, 0xf1, 0x9a, 0x8f, 0x60, 0x2c, 0x6e, 0x0a, 0x0a, 0x6b, 0x7c, 0x18, 0xf9, + 0xc9, 0xf6, 0x08, 0x36, 0x3b, 0x97, 0x8c, 0x63, 0x28, 0x8f, 0xf9, 0xd1, 0xb3, 0xb9, 0x34, 0x7c, + 0x26, 0xcc, 0x27, 0xb9, 0x57, 0x32, 0x9f, 0x8c, 0x79, 0x54, 0x03, 0x95, 0xd7, 0x4f, 0x92, 0x09, + 0x57, 0x1c, 0xd9, 0xae, 0x75, 0x82, 0x59, 0xc8, 0x00, 0x2a, 0x0c, 0xc4, 0x33, 0x35, 0x02, 0x58, + 0x3a, 0x9c, 0x4f, 0x42, 0x67, 0x47, 0x81, 0xc8, 0xc7, 0x22, 0x0d, 0x96, 0x23, 0x7b, 0x2d, 0xb3, + 0x20, 0x50, 0x05, 0x61, 0x67, 0x4d, 0x59, 0x46, 0x56, 0xba, 0xbc, 0xa5, 0x69, 0xbc, 0x04, 0xe3, + 0x26, 0x6c, 0x44, 0x5f, 0xbc, 0xdb, 0xe4, 0x56, 0xf3, 0xf7, 0x73, 0xfc, 0x2a, 0x0e, 0xc7, 0x0d, + 0x5c, 0x7b, 0x16, 0x9c, 0x7b, 0x21, 0xe9, 0xc0, 0x4a, 0xe0, 0xb8, 0x67, 0x13, 0xaa, 0x67, 0x1f, + 0x88, 0x4e, 0x58, 0x8b, 0xd7, 0x8d, 0x27, 0x0d, 0xcc, 0x65, 0x9e, 0x22, 0xca, 0x2d, 0x20, 0xdb, + 0xd7, 0x55, 0x32, 0x9a, 0x16, 0x89, 0xde, 0x48, 0x57, 0xbe, 0x0b, 0x8b, 0xf1, 0x82, 0xc8, 0xa7, + 0x22, 0x18, 0x48, 0x54, 0xab, 0x42, 0x22, 0x14, 0x42, 0x34, 0x21, 0x6a, 0x51, 0xdf, 0x07, 0xc6, + 0x5f, 0xcf, 0x41, 0xcb, 0xa4, 0x6c, 0xe6, 0x6a, 0xb5, 0x94, 0x73, 0xe6, 0x3b, 0xa9, 0x5c, 0xaf, + 0x6f, 0xab, 0x8c, 0x31, 0x22, 0x6b, 0xf4, 0xde, 0xb5, 0x83, 0xb1, 0x7f, 0x23, 0xd5, 0xa2, 0xed, + 0x0a, 0x2c, 0x70, 0x12, 0x63, 0x03, 0xd6, 0x44, 0x7d, 0x64, 0x5d, 0x22, 0x4b, 0x7d, 0xac, 0xc4, + 0x98, 0xa5, 0x7e, 0x13, 0x5a, 0xfc, 0xce, 0xbe, 0xde, 0x08, 0x91, 0x70, 0x17, 0xc8, 0xa1, 0x3d, + 0xb2, 0x7d, 0xcf, 0x73, 0x8f, 0xa8, 0x2f, 0x7c, 0xe1, 0x51, 0xc2, 0x44, 0x43, 0xb6, 0x14, 0x85, + 0xf9, 0x97, 0x0c, 0xe6, 0xee, 0xb9, 0xd2, 0xf5, 0x8f, 0x7f, 0x19, 0x3e, 0xac, 0x6c, 0xdb, 0xcf, + 0xa8, 0xcc, 0x49, 0x76, 0xd1, 0x63, 0xa8, 0xcd, 0x54, 0xa6, 0xb2, 0xdf, 0x65, 0xfc, 0xa4, 0x74, + 0xb1, 0xa6, 0x4e, 0xcd, 0x58, 0x10, 0x6a, 0x62, 0x31, 0x72, 0xc9, 0x58, 0x6e, 0xe6, 0x0c, 0xf4, + 0x94, 0x5e, 0x75, 0xc7, 0xc6, 0x43, 0x58, 0x8d, 0x97, 0x29, 0x58, 0xcb, 0x26, 0x54, 0xa6, 0x02, + 0x26, 0x6a, 0xaf, 0xbe, 0xd9, 0x61, 0x84, 0x1d, 0x28, 0x65, 0x9a, 0xee, 0xae, 0xba, 0x7e, 0xff, + 0x18, 0x36, 0x52, 0x18, 0x91, 0xe1, 0x5d, 0xa8, 0x6b, 0x15, 0xe1, 0xcd, 0x28, 0x9a, 0xa0, 0x6a, + 0x12, 0x18, 0x9f, 0xc3, 0x06, 0x3f, 0x8f, 0x45, 0xc9, 0x65, 0x17, 0x24, 0x5a, 0x91, 0x4b, 0xb6, + 0xe2, 0x63, 0x79, 0x88, 0xd4, 0x93, 0x46, 0x71, 0x09, 0xc7, 0x88, 0x93, 0xde, 0x5b, 0xf2, 0xd3, + 0x38, 0x86, 0xf5, 0x74, 0xf7, 0xb1, 0xfa, 0xff, 0x54, 0x5d, 0x2e, 0xbb, 0x27, 0x42, 0xab, 0xee, + 0xf9, 0x6f, 0x39, 0xde, 0x3f, 0x31, 0x94, 0xa8, 0xe6, 0x18, 0xc8, 0x94, 0x86, 0xe7, 0xde, 0xd8, + 0x4a, 0x97, 0xfc, 0x48, 0x39, 0x8f, 0x65, 0xa6, 0xdd, 0x3a, 0xc4, 0x84, 0x1a, 0x46, 0x5c, 0x63, + 0x98, 0x26, 0xe1, 0x9b, 0x23, 0x58, 0xcf, 0x26, 0xce, 0x70, 0xb9, 0xfa, 0x28, 0x2e, 0xa8, 0xdf, + 0xbe, 0xb6, 0xf9, 0xac, 0x5a, 0xba, 0xdc, 0xfe, 0xdb, 0x15, 0x28, 0x0b, 0x1d, 0x0c, 0xd9, 0x82, + 0xe2, 0x48, 0xba, 0xef, 0x46, 0xb1, 0x29, 0x05, 0x56, 0xfe, 0xdf, 0x41, 0x27, 0x5e, 0x46, 0x47, + 0x1e, 0xc3, 0x62, 0xdc, 0x83, 0x25, 0x11, 0x93, 0x26, 0xee, 0x7a, 0xd2, 0x18, 0x25, 0xbc, 0x03, + 0xaa, 0x91, 0x70, 0xc5, 0x65, 0xce, 0xca, 0xb9, 0x26, 0x7d, 0x79, 0x2e, 0x3b, 0xaf, 0x05, 0xe7, + 0xb6, 0xf5, 0xf0, 0xd1, 0x27, 0xc2, 0x5a, 0x50, 0x43, 0xe0, 0xe0, 0xdc, 0x7e, 0xf8, 0xe8, 0x93, + 0xe4, 0x49, 0x4c, 0x84, 0xa4, 0xd1, 0x4e, 0x62, 0xab, 0x50, 0xe2, 0x11, 0xef, 0xb9, 0x1f, 0x26, + 0xff, 0x90, 0x7a, 0x8a, 0xb9, 0x4f, 0x2d, 0x71, 0x63, 0x86, 0xef, 0xa2, 0xfc, 0xc1, 0x2f, 0x22, + 0x70, 0x03, 0x44, 0x71, 0x3d, 0xe1, 0x3a, 0x2c, 0x9c, 0x47, 0x4f, 0x18, 0x34, 0x4c, 0xf1, 0x65, + 0xfc, 0x71, 0x09, 0x6a, 0x5a, 0xa7, 0x90, 0x3a, 0x54, 0xcc, 0xce, 0xa0, 0x63, 0x7e, 0xd1, 0xd9, + 0x6d, 0xde, 0x20, 0xf7, 0xe0, 0xad, 0x6e, 0x6f, 0xa7, 0x6f, 0x9a, 0x9d, 0x9d, 0xa1, 0xd5, 0x37, + 0x2d, 0x19, 0x32, 0xf5, 0xa8, 0xfd, 0xd5, 0x61, 0xa7, 0x37, 0xb4, 0x76, 0x3b, 0xc3, 0x76, 0xf7, + 0x60, 0xd0, 0xcc, 0x91, 0xd7, 0xa0, 0x15, 0x51, 0x4a, 0x74, 0xfb, 0xb0, 0x7f, 0xdc, 0x1b, 0x36, + 0xf3, 0xe4, 0x0e, 0xdc, 0xda, 0xeb, 0xf6, 0xda, 0x07, 0x56, 0x44, 0xb3, 0x73, 0x30, 0xfc, 0xc2, + 0xea, 0xfc, 0xc2, 0x51, 0xd7, 0xfc, 0xaa, 0x59, 0xc8, 0x22, 0xd8, 0x1f, 0x1e, 0xec, 0xc8, 0x1c, + 0x8a, 0xe4, 0x26, 0xac, 0x71, 0x02, 0x9e, 0xc4, 0x1a, 0xf6, 0xfb, 0xd6, 0xa0, 0xdf, 0xef, 0x35, + 0x4b, 0x64, 0x19, 0x1a, 0xdd, 0xde, 0x17, 0xed, 0x83, 0xee, 0xae, 0x65, 0x76, 0xda, 0x07, 0x87, + 0xcd, 0x05, 0xb2, 0x02, 0x4b, 0x49, 0xba, 0x32, 0xcb, 0x42, 0xd2, 0xf5, 0x7b, 0xdd, 0x7e, 0xcf, + 0xfa, 0xa2, 0x63, 0x0e, 0xba, 0xfd, 0x5e, 0xb3, 0x42, 0xd6, 0x81, 0xc4, 0x51, 0xfb, 0x87, 0xed, + 0x9d, 0x66, 0x95, 0xac, 0xc1, 0x72, 0x1c, 0xfe, 0xb4, 0xf3, 0x55, 0x13, 0x48, 0x0b, 0x56, 0x79, + 0xc5, 0xac, 0xed, 0xce, 0x41, 0xff, 0x4b, 0xeb, 0xb0, 0xdb, 0xeb, 0x1e, 0x1e, 0x1f, 0x36, 0x6b, + 0x18, 0xb8, 0xba, 0xd3, 0xb1, 0xba, 0xbd, 0xc1, 0xf1, 0xde, 0x5e, 0x77, 0xa7, 0xdb, 0xe9, 0x0d, + 0x9b, 0x75, 0x5e, 0x72, 0x56, 0xc3, 0x1b, 0x2c, 0x81, 0xb8, 0x23, 0x69, 0xed, 0x76, 0x07, 0xed, + 0xed, 0x83, 0xce, 0x6e, 0x73, 0x91, 0xdc, 0x86, 0x9b, 0xc3, 0xce, 0xe1, 0x51, 0xdf, 0x6c, 0x9b, + 0x5f, 0xc9, 0x3b, 0x94, 0xd6, 0x5e, 0xbb, 0x7b, 0x70, 0x6c, 0x76, 0x9a, 0x4b, 0xe4, 0x0d, 0xb8, + 0x6d, 0x76, 0x7e, 0x70, 0xdc, 0x35, 0x3b, 0xbb, 0x56, 0xaf, 0xbf, 0xdb, 0xb1, 0xf6, 0x3a, 0xed, + 0xe1, 0xb1, 0xd9, 0xb1, 0x0e, 0xbb, 0x83, 0x41, 0xb7, 0xf7, 0xa4, 0xd9, 0x24, 0x6f, 0xc1, 0x5d, + 0x45, 0xa2, 0x32, 0x48, 0x50, 0x2d, 0xb3, 0xf6, 0xc9, 0x21, 0xed, 0x75, 0x7e, 0x61, 0x68, 0x1d, + 0x75, 0x3a, 0x66, 0x93, 0x90, 0x4d, 0x58, 0x8f, 0x8a, 0xe7, 0x05, 0x88, 0xb2, 0x57, 0x18, 0xee, + 0xa8, 0x63, 0x1e, 0xb6, 0x7b, 0x6c, 0x80, 0x63, 0xb8, 0x55, 0x56, 0xed, 0x08, 0x97, 0xac, 0xf6, + 0x1a, 0x21, 0xb0, 0xa8, 0x8d, 0xca, 0x5e, 0xdb, 0x6c, 0xae, 0x93, 0x25, 0xa8, 0x1d, 0x1e, 0x1d, + 0x59, 0xc3, 0xee, 0x61, 0xa7, 0x7f, 0x3c, 0x6c, 0x6e, 0x90, 0x35, 0x68, 0x76, 0x7b, 0xc3, 0x8e, + 0xc9, 0xc6, 0x5a, 0x26, 0xfd, 0xef, 0x65, 0xb2, 0x0a, 0x4b, 0xb2, 0xa6, 0x12, 0xfa, 0xa7, 0x65, + 0xb2, 0x01, 0xe4, 0xb8, 0x67, 0x76, 0xda, 0xbb, 0xac, 0xe3, 0x14, 0xe2, 0x7f, 0x94, 0x85, 0x71, + 0xf8, 0xf7, 0x0b, 0x4a, 0xd8, 0x8b, 0xdc, 0xc3, 0xe2, 0x6f, 0x0e, 0xd5, 0xb5, 0xb7, 0x82, 0x5e, + 0xf6, 0xd4, 0xa3, 0x76, 0x34, 0x2f, 0xa4, 0x8e, 0xe6, 0x29, 0xdd, 0x4f, 0x43, 0x3f, 0x3b, 0xbc, + 0x09, 0x8d, 0x29, 0x7f, 0x7f, 0x48, 0x3c, 0x60, 0x01, 0xc2, 0x57, 0x92, 0x03, 0xf9, 0xeb, 0x15, + 0xa9, 0xb7, 0x0e, 0x4b, 0xe9, 0xb7, 0x0e, 0xb3, 0xce, 0x87, 0x0b, 0x59, 0xe7, 0xc3, 0xfb, 0xb0, + 0xcc, 0x59, 0x93, 0xe3, 0x3a, 0x53, 0xa9, 0x75, 0x11, 0x2f, 0x07, 0x22, 0x8b, 0xe2, 0x70, 0x79, + 0x1c, 0x95, 0x47, 0x56, 0xc1, 0x42, 0xca, 0xe2, 0xb4, 0x1a, 0x3b, 0xa9, 0x72, 0xce, 0xa1, 0x4e, + 0xaa, 0xaa, 0x04, 0xfb, 0x32, 0x2a, 0xa1, 0xa6, 0x95, 0xc0, 0xe1, 0x58, 0xc2, 0x7d, 0x58, 0xa6, + 0x97, 0xa1, 0x6f, 0x5b, 0xde, 0xcc, 0xfe, 0xd1, 0x1c, 0x1d, 0x5c, 0x6c, 0xd4, 0x01, 0xd5, 0xcd, + 0x25, 0x44, 0xf4, 0x11, 0xbe, 0x6b, 0x87, 0xb6, 0xf1, 0x4b, 0x00, 0x6a, 0x57, 0xc5, 0x17, 0x18, + 0x5d, 0x4f, 0xde, 0x88, 0xad, 0x9b, 0xfc, 0x03, 0xc7, 0x31, 0xf4, 0x7c, 0xfb, 0x8c, 0x76, 0xa5, + 0x4d, 0x37, 0x02, 0x90, 0x5b, 0x50, 0xf0, 0x66, 0xd2, 0x93, 0xb0, 0x2a, 0x23, 0xb2, 0xcf, 0x4c, + 0x06, 0x35, 0x3e, 0x81, 0x7c, 0x7f, 0x76, 0xad, 0xa8, 0xd4, 0x82, 0xb2, 0x7c, 0xdd, 0x38, 0x8f, + 0xde, 0x83, 0xf2, 0xf3, 0xfe, 0x5f, 0x86, 0x9a, 0xf6, 0x64, 0x16, 0xd9, 0x80, 0x95, 0x2f, 0xbb, + 0xc3, 0x5e, 0x67, 0x30, 0xb0, 0x8e, 0x8e, 0xb7, 0x9f, 0x76, 0xbe, 0xb2, 0xf6, 0xdb, 0x83, 0xfd, + 0xe6, 0x0d, 0xc6, 0x4b, 0x7a, 0x9d, 0xc1, 0xb0, 0xb3, 0x1b, 0x83, 0xe7, 0xc8, 0xeb, 0xb0, 0x79, + 0xdc, 0x3b, 0x1e, 0x74, 0x76, 0xad, 0xac, 0x74, 0x79, 0xb6, 0x78, 0x04, 0x3e, 0x23, 0x79, 0xe1, + 0xfe, 0x2f, 0xc3, 0x62, 0x3c, 0xca, 0x09, 0x01, 0x58, 0x38, 0xe8, 0x3c, 0x69, 0xef, 0x7c, 0xc5, + 0x23, 0xee, 0x0f, 0x86, 0xed, 0x61, 0x77, 0xc7, 0x12, 0x11, 0xf6, 0x19, 0xa3, 0xca, 0x91, 0x1a, + 0x94, 0xdb, 0xbd, 0x9d, 0xfd, 0xbe, 0x39, 0x68, 0xe6, 0xc9, 0x6b, 0xb0, 0x21, 0x97, 0xd0, 0x4e, + 0xff, 0xf0, 0xb0, 0x3b, 0x44, 0x1e, 0x3d, 0xfc, 0xea, 0x88, 0xad, 0x98, 0xfb, 0x36, 0x54, 0xa3, + 0xc7, 0x01, 0x90, 0xef, 0x75, 0x87, 0xdd, 0xf6, 0x30, 0x62, 0xfa, 0xcd, 0x1b, 0x8c, 0xad, 0x46, + 0x60, 0x8c, 0xf0, 0xdf, 0xcc, 0xf1, 0x8b, 0xe0, 0x12, 0xc8, 0x4b, 0x6f, 0xe6, 0xd9, 0x5a, 0x8f, + 0xa0, 0xdb, 0xfd, 0x21, 0x6b, 0xc2, 0xaf, 0xc0, 0x62, 0x3c, 0x06, 0x3f, 0x69, 0x42, 0x9d, 0x95, + 0xaf, 0x15, 0x01, 0xb0, 0xc0, 0x6b, 0xdc, 0xcc, 0x71, 0xc6, 0xbe, 0xd3, 0x3f, 0xec, 0xf6, 0x9e, + 0xe0, 0x6e, 0xd0, 0xcc, 0x33, 0x50, 0xff, 0x78, 0xf8, 0xa4, 0xaf, 0x40, 0x05, 0x96, 0x82, 0x37, + 0xa7, 0x59, 0xbc, 0xff, 0x23, 0x58, 0x4e, 0x45, 0xeb, 0x67, 0xb5, 0xee, 0x1f, 0x0f, 0x77, 0xfa, + 0x87, 0x7a, 0x39, 0x35, 0x28, 0xef, 0x1c, 0xb4, 0xbb, 0x87, 0x68, 0x66, 0x69, 0x40, 0xf5, 0xb8, + 0x27, 0x3f, 0xf3, 0xf1, 0x77, 0x06, 0x0a, 0x8c, 0x45, 0xed, 0x75, 0xcd, 0xc1, 0xd0, 0x1a, 0x0c, + 0xdb, 0x4f, 0x3a, 0xcd, 0x22, 0x4b, 0x2b, 0xf9, 0x55, 0xe9, 0xfe, 0xe7, 0xb0, 0x18, 0x77, 0x7b, + 0x8f, 0x5b, 0xcf, 0x36, 0x61, 0x7d, 0xbb, 0x33, 0xfc, 0xb2, 0xd3, 0xe9, 0xe1, 0x90, 0xef, 0x74, + 0x7a, 0x43, 0xb3, 0x7d, 0xd0, 0x1d, 0x7e, 0xd5, 0xcc, 0xdd, 0x7f, 0x0c, 0xcd, 0xa4, 0xcb, 0x46, + 0xcc, 0xc7, 0xe5, 0x45, 0xce, 0x30, 0xf7, 0xff, 0x43, 0x0e, 0x56, 0xb3, 0x8c, 0x7b, 0x6c, 0x62, + 0x0a, 0x46, 0xc8, 0xb6, 0xc3, 0x41, 0xbf, 0x67, 0xf5, 0xfa, 0x18, 0x67, 0x7b, 0x13, 0xd6, 0x13, + 0x08, 0xd9, 0x8a, 0x1c, 0xb9, 0x05, 0x1b, 0xa9, 0x44, 0x96, 0xd9, 0x3f, 0xc6, 0xb1, 0x6c, 0xc1, + 0x6a, 0x02, 0xd9, 0x31, 0xcd, 0xbe, 0xd9, 0x2c, 0x90, 0xf7, 0xe0, 0x5e, 0x02, 0x93, 0x16, 0x02, + 0xa4, 0x8c, 0x50, 0x24, 0xef, 0xc0, 0x9b, 0x29, 0xea, 0x68, 0x9f, 0xb4, 0xb6, 0xdb, 0x07, 0xac, + 0x79, 0xcd, 0xd2, 0xfd, 0x3f, 0x2c, 0x02, 0x44, 0xf7, 0x4a, 0x59, 0xf9, 0xbb, 0xed, 0x61, 0xfb, + 0xa0, 0xcf, 0xd6, 0x8c, 0xd9, 0x1f, 0xb2, 0xdc, 0xcd, 0xce, 0x0f, 0x9a, 0x37, 0x32, 0x31, 0xfd, + 0x23, 0xd6, 0xa0, 0x0d, 0x58, 0xe1, 0xf3, 0xef, 0x80, 0x35, 0x83, 0x4d, 0x17, 0x1e, 0xb2, 0x9d, + 0x49, 0x1a, 0xc7, 0x47, 0x7b, 0x66, 0xbf, 0x37, 0xb4, 0x06, 0xfb, 0xc7, 0xc3, 0x5d, 0x8c, 0x00, + 0xbf, 0x63, 0x76, 0x8f, 0x78, 0x9e, 0xc5, 0x17, 0x11, 0xb0, 0xac, 0x4b, 0x6c, 0x81, 0x3f, 0xe9, + 0x0f, 0x06, 0xdd, 0x23, 0xeb, 0x07, 0xc7, 0x1d, 0xb3, 0xdb, 0x19, 0x60, 0xc2, 0x85, 0x0c, 0x38, + 0xa3, 0x2f, 0xb3, 0x39, 0x3b, 0x3c, 0xf8, 0x42, 0x08, 0x10, 0x8c, 0xb4, 0x12, 0x07, 0x31, 0xaa, + 0x2a, 0x1b, 0x1d, 0xb6, 0x03, 0x67, 0xe4, 0x0c, 0xd7, 0xe0, 0x58, 0xba, 0x1a, 0x93, 0x2d, 0x52, + 0x2b, 0x1f, 0x93, 0xd5, 0xb3, 0x51, 0x2c, 0x15, 0x8a, 0x1d, 0x4a, 0x48, 0xdb, 0xdd, 0x35, 0x31, + 0xc1, 0x62, 0x0a, 0xca, 0x68, 0x97, 0xd8, 0x24, 0x64, 0x5b, 0x34, 0x23, 0x69, 0xca, 0x0f, 0x86, + 0x59, 0x66, 0x2d, 0xfe, 0xf2, 0xf8, 0x70, 0xbb, 0x2f, 0xf7, 0x7a, 0x5e, 0x5f, 0x92, 0x01, 0x67, + 0xf4, 0x2b, 0x18, 0x62, 0x9f, 0xb3, 0x23, 0x24, 0x5c, 0xd5, 0x01, 0x8c, 0x62, 0x8d, 0x31, 0x41, + 0x09, 0xf8, 0x61, 0xc7, 0xec, 0x5b, 0x4c, 0x98, 0x42, 0x41, 0x90, 0xd1, 0xaf, 0x5f, 0x8f, 0x66, + 0xa9, 0x37, 0x1e, 0xfe, 0x8b, 0x37, 0xa0, 0xaa, 0xee, 0xbb, 0x90, 0xef, 0x43, 0x23, 0x16, 0x4d, + 0x82, 0x48, 0x93, 0x42, 0x56, 0xf0, 0x89, 0xcd, 0xd7, 0xb2, 0x91, 0xe2, 0xb0, 0x74, 0xa8, 0x69, + 0x27, 0x78, 0x66, 0xaf, 0x25, 0x35, 0x06, 0xb1, 0xdc, 0x6e, 0x5f, 0x83, 0x15, 0xd9, 0x3d, 0xc5, + 0x68, 0xf6, 0xfa, 0xd3, 0xfd, 0xe4, 0x76, 0x14, 0x5a, 0x3c, 0xe3, 0x49, 0xff, 0xcd, 0x9b, 0xe9, + 0x47, 0xf6, 0xe5, 0xab, 0xfc, 0xbb, 0x50, 0xd3, 0x1e, 0x5d, 0x25, 0x37, 0xaf, 0x7d, 0x20, 0x76, + 0x73, 0x33, 0x0b, 0x25, 0xaa, 0xf4, 0x5d, 0xa8, 0xaa, 0xc7, 0x2e, 0xc9, 0x86, 0xf6, 0x78, 0xaa, + 0xfe, 0xf8, 0xe7, 0x66, 0x2b, 0x8d, 0x10, 0xe9, 0x77, 0xa1, 0xa6, 0xbd, 0x59, 0xa9, 0x6a, 0x91, + 0x7e, 0x17, 0x53, 0xd5, 0x22, 0xeb, 0x89, 0xcb, 0x03, 0x58, 0x13, 0x3a, 0x90, 0x13, 0xfa, 0x75, + 0xba, 0x87, 0xa4, 0xbb, 0xe7, 0x41, 0x8e, 0x3c, 0x86, 0x8a, 0x7c, 0xe7, 0x94, 0xac, 0x67, 0xbf, + 0x07, 0xbb, 0xb9, 0x91, 0x82, 0x8b, 0xaa, 0xb4, 0x01, 0xa2, 0xd7, 0x30, 0x89, 0x6c, 0x78, 0xea, + 0x75, 0x4d, 0x35, 0x32, 0x19, 0x4f, 0x67, 0xee, 0x42, 0x4d, 0x7b, 0xf8, 0x52, 0xf5, 0x49, 0xfa, + 0xd1, 0x4c, 0xd5, 0x27, 0x59, 0xef, 0x64, 0x7e, 0x1f, 0x1a, 0xb1, 0x17, 0x2c, 0xd5, 0x3c, 0xce, + 0x7a, 0x1f, 0x53, 0xcd, 0xe3, 0xec, 0x47, 0x2f, 0x77, 0xa1, 0xa6, 0xbd, 0x2a, 0xa9, 0x6a, 0x94, + 0x7e, 0xda, 0x52, 0xd5, 0x28, 0xe3, 0x11, 0x4a, 0xb6, 0x1a, 0xe2, 0x4f, 0x4a, 0xaa, 0xd5, 0x90, + 0xf9, 0x36, 0xa5, 0x5a, 0x0d, 0xd9, 0xef, 0x50, 0xb2, 0xa9, 0xa7, 0x9e, 0xb1, 0x20, 0x1b, 0x31, + 0xd5, 0x43, 0xf4, 0x1e, 0x86, 0x9a, 0x7a, 0xe9, 0x17, 0x2f, 0x9e, 0xc0, 0x8a, 0x9a, 0x34, 0xea, + 0x11, 0x8a, 0x40, 0xd5, 0x29, 0xf3, 0xa9, 0x8b, 0xcd, 0x66, 0x12, 0xfb, 0x20, 0x47, 0x3e, 0x83, + 0xb2, 0x88, 0xec, 0x4f, 0xd6, 0x92, 0x91, 0xfe, 0x79, 0x25, 0xd6, 0xb3, 0x1f, 0x00, 0x20, 0x47, + 0xb8, 0xa0, 0xf5, 0xd0, 0xfb, 0xfa, 0x8c, 0xcd, 0x88, 0xd6, 0xbf, 0xf9, 0xfa, 0x75, 0xe8, 0x28, + 0xc7, 0xe4, 0x73, 0x11, 0xb7, 0xaf, 0x8b, 0xf2, 0x14, 0xcf, 0xf1, 0xba, 0x70, 0x94, 0x4f, 0xa0, + 0xae, 0x3f, 0x27, 0x46, 0xf4, 0x75, 0x98, 0xcc, 0xeb, 0x56, 0x26, 0x4e, 0x64, 0xf4, 0x05, 0xac, + 0xab, 0xfe, 0xd6, 0x43, 0x0e, 0x05, 0xe4, 0x4e, 0x46, 0x20, 0xa2, 0x58, 0xaf, 0xdf, 0xbc, 0x36, + 0x52, 0xd1, 0x83, 0x1c, 0x32, 0xd9, 0xd8, 0x0b, 0x40, 0x11, 0x93, 0xcd, 0x7a, 0xf8, 0x28, 0x62, + 0xb2, 0xd9, 0xcf, 0x06, 0xb5, 0x61, 0x49, 0x0b, 0x99, 0x34, 0xb8, 0x72, 0x47, 0x6a, 0xbe, 0xa7, + 0x63, 0xa2, 0x6f, 0x66, 0x69, 0xe2, 0xc9, 0x0e, 0xd4, 0xf4, 0xa8, 0x4b, 0x2f, 0x48, 0xbe, 0xa1, + 0xa1, 0xf4, 0x90, 0xd6, 0x0f, 0x72, 0xe4, 0x00, 0x9a, 0xc9, 0x18, 0xa9, 0x6a, 0x09, 0x67, 0xc5, + 0x95, 0xdd, 0x4c, 0x20, 0x63, 0x91, 0x55, 0xd9, 0xbc, 0x88, 0x3d, 0x75, 0xef, 0xf9, 0xc9, 0xad, + 0x28, 0xfe, 0x04, 0xbe, 0xca, 0x2d, 0x81, 0xc5, 0x6a, 0xdf, 0xcb, 0x3d, 0xc8, 0x91, 0x3d, 0xa8, + 0xc7, 0x42, 0x04, 0xc6, 0xae, 0x5e, 0x25, 0x9a, 0xd9, 0xd2, 0x71, 0x89, 0x76, 0x1e, 0xc2, 0x62, + 0xdc, 0x65, 0x44, 0x55, 0x2c, 0xd3, 0xaf, 0x45, 0x0d, 0x5f, 0xb6, 0x9f, 0x09, 0xf9, 0x79, 0xa8, + 0x31, 0x9e, 0x2c, 0xfd, 0x1a, 0x89, 0xc6, 0xa7, 0x93, 0x63, 0xc6, 0x61, 0x42, 0x35, 0x5e, 0xf8, + 0x6b, 0xf9, 0x1c, 0xb6, 0xeb, 0x3b, 0xfc, 0xa9, 0x70, 0xe9, 0xda, 0xc6, 0xc6, 0xff, 0x55, 0x33, + 0x21, 0x7b, 0xbc, 0xf0, 0xa1, 0xc7, 0x23, 0x2a, 0xdc, 0xd4, 0x68, 0x04, 0xec, 0xd5, 0xea, 0xd0, + 0xe6, 0x75, 0x10, 0x69, 0x62, 0x73, 0xf0, 0x15, 0xf3, 0x22, 0x9f, 0x02, 0x44, 0x2e, 0xc5, 0x24, + 0xe1, 0xb5, 0xaa, 0x16, 0x54, 0x86, 0xd7, 0x71, 0x87, 0xaf, 0x77, 0xe5, 0x36, 0xab, 0x6f, 0xc9, + 0x71, 0x0f, 0xde, 0xd8, 0x96, 0x9c, 0xcc, 0xe6, 0x23, 0x68, 0x1c, 0x78, 0xde, 0xb3, 0xf9, 0x4c, + 0x5d, 0xb4, 0x89, 0x3b, 0x6d, 0xed, 0xdb, 0xc1, 0xf9, 0x66, 0xa2, 0x5a, 0xa4, 0x0d, 0xcb, 0x8a, + 0x45, 0x44, 0x7e, 0xbb, 0x71, 0xa2, 0x18, 0x63, 0x48, 0x64, 0xf0, 0x20, 0x47, 0x1e, 0x42, 0x7d, + 0x97, 0x8e, 0x30, 0xea, 0x0b, 0x3a, 0xf1, 0xac, 0xc4, 0x1c, 0x42, 0xb8, 0xf7, 0xcf, 0x66, 0x23, + 0x06, 0x94, 0x2c, 0x2e, 0x72, 0x53, 0xd3, 0xf7, 0x8c, 0xb8, 0xaf, 0x57, 0x8c, 0xc5, 0xa5, 0x5c, + 0xd5, 0xbe, 0x80, 0xe5, 0x94, 0xab, 0x96, 0xe2, 0x6e, 0xd7, 0xb9, 0x8f, 0x6d, 0xde, 0xbd, 0x9e, + 0x40, 0xe4, 0xfb, 0x3d, 0x68, 0xf0, 0x08, 0xe7, 0x27, 0x94, 0xdf, 0xda, 0x4e, 0xc4, 0xaf, 0xd3, + 0xaf, 0x84, 0x27, 0x59, 0x12, 0x4f, 0xf0, 0x04, 0xdf, 0x46, 0xd2, 0xee, 0x44, 0xab, 0x71, 0x4d, + 0xdf, 0xd3, 0x56, 0xe3, 0x9a, 0x75, 0xfd, 0xfa, 0x73, 0xa8, 0x3d, 0xa1, 0xa1, 0xbc, 0x65, 0xac, + 0xe4, 0xa3, 0xc4, 0xb5, 0xe3, 0xcd, 0x8c, 0xbb, 0xe1, 0xe4, 0x13, 0x4c, 0xaa, 0x22, 0x66, 0xac, + 0x6b, 0xa5, 0xe8, 0x49, 0x97, 0x12, 0x70, 0x26, 0x7d, 0x68, 0x71, 0x73, 0x54, 0xc5, 0xd3, 0x71, + 0x92, 0x54, 0xc5, 0xb3, 0xc2, 0xec, 0xfc, 0x3c, 0xef, 0x01, 0xed, 0x5e, 0x73, 0x24, 0x82, 0x25, + 0xaf, 0x40, 0xab, 0xea, 0xeb, 0xe4, 0x8f, 0x00, 0x06, 0xa1, 0x37, 0xdb, 0xb5, 0xe9, 0xd4, 0x73, + 0x23, 0x9e, 0x10, 0xdd, 0xa8, 0x8d, 0x16, 0xa2, 0x76, 0xad, 0x96, 0x7c, 0xa9, 0xc9, 0xa6, 0xb1, + 0x21, 0x91, 0xc3, 0x7e, 0xed, 0xa5, 0x5b, 0xd5, 0x9c, 0x8c, 0x8b, 0xb7, 0xc8, 0x24, 0x20, 0xf2, + 0x84, 0x53, 0x92, 0x66, 0xca, 0xc9, 0x4e, 0xad, 0xf5, 0x0c, 0xb7, 0xb9, 0xef, 0x42, 0x35, 0x72, + 0x21, 0xda, 0x88, 0x82, 0x78, 0xc5, 0x1c, 0x8e, 0x14, 0xf7, 0x4e, 0xbb, 0xef, 0xf4, 0x60, 0x85, + 0x57, 0x47, 0x6d, 0x7f, 0x78, 0xd3, 0x52, 0x3d, 0xed, 0x95, 0xf6, 0x9b, 0x51, 0xeb, 0x27, 0xcb, + 0xfb, 0x83, 0xad, 0x9f, 0x94, 0x17, 0x81, 0x5a, 0x3f, 0xd7, 0xb9, 0x85, 0xa8, 0xf5, 0x73, 0xbd, + 0x03, 0x42, 0x0f, 0x56, 0x32, 0xfc, 0x01, 0xc8, 0x1b, 0xf2, 0x60, 0x73, 0xad, 0xaf, 0xc0, 0x66, + 0xa6, 0xdd, 0x98, 0x0c, 0x61, 0x83, 0xa7, 0x69, 0x4f, 0x26, 0x09, 0xf3, 0xf3, 0xeb, 0x5a, 0x82, + 0x0c, 0x93, 0x7a, 0x4c, 0x94, 0x49, 0x98, 0xd5, 0x7b, 0xd0, 0x4c, 0x5a, 0x6e, 0xc9, 0xf5, 0xe4, + 0x9b, 0x77, 0x62, 0x22, 0x7b, 0xda, 0xda, 0x4b, 0xbe, 0x50, 0xf6, 0xe3, 0x44, 0x1d, 0xef, 0x44, + 0x4f, 0x54, 0x66, 0x5a, 0xbb, 0xd5, 0x69, 0x20, 0xd3, 0xfc, 0x4c, 0x7e, 0x01, 0x36, 0x92, 0x33, + 0x5a, 0xe6, 0x7c, 0x37, 0xab, 0xbb, 0xae, 0x15, 0xe5, 0xe2, 0x0d, 0x7a, 0x90, 0x63, 0x8c, 0x58, + 0xb7, 0xf2, 0xaa, 0x89, 0x94, 0x61, 0x6e, 0x56, 0x13, 0x29, 0xd3, 0x2c, 0x7c, 0x04, 0x4b, 0x09, + 0x03, 0xaf, 0x12, 0x83, 0xb3, 0x4d, 0xc2, 0x4a, 0x0c, 0xbe, 0xce, 0x2e, 0x3c, 0x80, 0x66, 0xd2, + 0x74, 0xab, 0xc6, 0xfa, 0x1a, 0x73, 0xf0, 0xe6, 0x9d, 0x6b, 0xf1, 0xf1, 0x6a, 0x6a, 0x46, 0xce, + 0x58, 0x35, 0xd3, 0xa6, 0xd9, 0x58, 0x35, 0x33, 0x4c, 0xac, 0xdb, 0xef, 0xfc, 0xf0, 0x5b, 0x67, + 0x4e, 0x78, 0x3e, 0x3f, 0xd9, 0x1a, 0x79, 0xd3, 0x0f, 0x26, 0x52, 0xab, 0x21, 0xc2, 0x20, 0x7c, + 0x30, 0x71, 0xc7, 0x1f, 0x60, 0x06, 0x27, 0x0b, 0x33, 0xdf, 0x0b, 0xbd, 0x8f, 0xfe, 0x6f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x16, 0x60, 0xf2, 0x7f, 0x53, 0x92, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index 088338f5..cfcfe440 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -2954,6 +2954,31 @@ message InvoiceHTLC { // The total amount of the mpp payment in msat. uint64 mpp_total_amt_msat = 10; + + // Details relevant to AMP HTLCs, only populated if this is an AMP HTLC. + AMP amp = 11; +} + +// Details specific to AMP HTLCs. +message AMP { + // An n-of-n secret share of the root seed from which child payment hashes + // and preimages are derived. + bytes root_share = 1; + + // An identifier for the HTLC set that this HTLC belongs to. + bytes set_id = 2; + + // A nonce used to randomize the child preimage and child hash from a given + // root_share. + uint32 child_index = 3; + + // The payment hash of the AMP HTLC. + bytes hash = 4; + + // The preimage used to settle this AMP htlc. This field will only be + // populated if the invoice is in InvoiceState_ACCEPTED or + // InvoiceState_SETTLED. + bytes preimage = 5; } message AddInvoiceResponse { diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index 291171ae..6daca87f 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -2468,6 +2468,37 @@ } } }, + "lnrpcAMP": { + "type": "object", + "properties": { + "root_share": { + "type": "string", + "format": "byte", + "description": "An n-of-n secret share of the root seed from which child payment hashes\nand preimages are derived." + }, + "set_id": { + "type": "string", + "format": "byte", + "description": "An identifier for the HTLC set that this HTLC belongs to." + }, + "child_index": { + "type": "integer", + "format": "int64", + "description": "A nonce used to randomize the child preimage and child hash from a given\nroot_share." + }, + "hash": { + "type": "string", + "format": "byte", + "description": "The payment hash of the AMP HTLC." + }, + "preimage": { + "type": "string", + "format": "byte", + "description": "The preimage used to settle this AMP htlc. This field will only be\npopulated if the invoice is in InvoiceState_ACCEPTED or\nInvoiceState_SETTLED." + } + }, + "description": "Details specific to AMP HTLCs." + }, "lnrpcAbandonChannelResponse": { "type": "object" }, @@ -4186,6 +4217,10 @@ "type": "string", "format": "uint64", "description": "The total amount of the mpp payment in msat." + }, + "amp": { + "$ref": "#/definitions/lnrpcAMP", + "description": "Details relevant to AMP HTLCs, only populated if this is an AMP HTLC." } }, "title": "Details of an HTLC that paid to an invoice" diff --git a/lntest/itest/lnd_single_hop_invoice_test.go b/lntest/itest/lnd_single_hop_invoice_test.go index 9827f2cc..0020b6dc 100644 --- a/lntest/itest/lnd_single_hop_invoice_test.go +++ b/lntest/itest/lnd_single_hop_invoice_test.go @@ -15,6 +15,7 @@ import ( "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" + "github.com/stretchr/testify/require" ) func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) { @@ -162,6 +163,21 @@ func testSingleHopInvoice(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf(err.Error()) } + // Assert that the invoice has the proper AMP fields set, since the + // legacy keysend payment should have been promoted into an AMP payment + // internally. + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + keysendInvoice, err := net.Bob.LookupInvoice( + ctxt, &lnrpc.PaymentHash{ + RHash: keySendHash[:], + }, + ) + require.NoError(t.t, err) + require.Equal(t.t, 1, len(keysendInvoice.Htlcs)) + htlc := keysendInvoice.Htlcs[0] + require.Equal(t.t, uint64(0), htlc.MppTotalAmtMsat) + require.Nil(t.t, htlc.Amp) + // Now create an invoice and specify routing hints. // We will test that the routing hints are encoded properly. hintChannel := lnwire.ShortChannelID{BlockHeight: 10} From 68688d6346047e0c60923a311a7e22cd8fb0f426 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Wed, 3 Mar 2021 10:00:28 -0800 Subject: [PATCH 13/13] invoices: replace all asserts with requires --- invoices/invoiceregistry_test.go | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/invoices/invoiceregistry_test.go b/invoices/invoiceregistry_test.go index 3d12ef2b..9e465eaa 100644 --- a/invoices/invoiceregistry_test.go +++ b/invoices/invoiceregistry_test.go @@ -10,7 +10,6 @@ import ( "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -20,7 +19,7 @@ func TestSettleInvoice(t *testing.T) { defer ctx.cleanup() allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - assert.Nil(t, err) + require.Nil(t, err) defer allSubscriptions.Cancel() // Subscribe to the not yet existing invoice. @@ -229,7 +228,7 @@ func testCancelInvoice(t *testing.T, gc bool) { ctx.registry.cfg.GcCanceledInvoicesOnTheFly = gc allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - assert.Nil(t, err) + require.Nil(t, err) defer allSubscriptions.Cancel() // Try to cancel the not yet existing invoice. This should fail. @@ -395,7 +394,7 @@ func TestSettleHoldInvoice(t *testing.T) { defer registry.Stop() allSubscriptions, err := registry.SubscribeNotifications(0, 0) - assert.Nil(t, err) + require.Nil(t, err) defer allSubscriptions.Cancel() // Subscribe to the not yet existing invoice. @@ -695,7 +694,7 @@ func testKeySend(t *testing.T, keySendEnabled bool) { ctx.registry.cfg.AcceptKeySend = keySendEnabled allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - assert.Nil(t, err) + require.Nil(t, err) defer allSubscriptions.Cancel() hodlChan := make(chan interface{}, 1) @@ -767,17 +766,17 @@ func testKeySend(t *testing.T, keySendEnabled bool) { checkResolution := func(res HtlcResolution, pimg lntypes.Preimage) { // Otherwise we expect no error and a settle res for the htlc. settleResolution, ok := res.(*HtlcSettleResolution) - assert.True(t, ok) - assert.Equal(t, settleResolution.Preimage, pimg) + require.True(t, ok) + require.Equal(t, settleResolution.Preimage, pimg) } checkSubscription := func() { // We expect a new invoice notification to be sent out. newInvoice := <-allSubscriptions.NewInvoices - assert.Equal(t, newInvoice.State, channeldb.ContractOpen) + require.Equal(t, newInvoice.State, channeldb.ContractOpen) // We expect a settled notification to be sent out. settledInvoice := <-allSubscriptions.SettledInvoices - assert.Equal(t, settledInvoice.State, channeldb.ContractSettled) + require.Equal(t, settledInvoice.State, channeldb.ContractSettled) } checkResolution(resolution, preimage) @@ -789,7 +788,7 @@ func testKeySend(t *testing.T, keySendEnabled bool) { hash, amt, expiry, testCurrentHeight, getCircuitKey(10), hodlChan, keySendPayload, ) - assert.Nil(t, err) + require.Nil(t, err) checkResolution(resolution, preimage) select { @@ -813,7 +812,7 @@ func testKeySend(t *testing.T, keySendEnabled bool) { hash2, amt, expiry, testCurrentHeight, getCircuitKey(20), hodlChan, keySendPayload2, ) - assert.Nil(t, err) + require.Nil(t, err) checkResolution(resolution, preimage2) checkSubscription() @@ -842,7 +841,7 @@ func testHoldKeysend(t *testing.T, timeoutKeysend bool) { ctx.registry.cfg.KeysendHoldTime = holdDuration allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - assert.Nil(t, err) + require.Nil(t, err) defer allSubscriptions.Cancel() hodlChan := make(chan interface{}, 1) @@ -915,7 +914,7 @@ func testHoldKeysend(t *testing.T, timeoutKeysend bool) { // We expect a settled notification to be sent out. settledInvoice := <-allSubscriptions.SettledInvoices - assert.Equal(t, settledInvoice.State, channeldb.ContractSettled) + require.Equal(t, settledInvoice.State, channeldb.ContractSettled) } // TestMppPayment tests settling of an invoice with multiple partial payments. @@ -1201,7 +1200,7 @@ func TestSettleInvoicePaymentAddrRequired(t *testing.T) { defer ctx.cleanup() allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - assert.Nil(t, err) + require.Nil(t, err) defer allSubscriptions.Cancel() // Subscribe to the not yet existing invoice. @@ -1277,7 +1276,7 @@ func TestSettleInvoicePaymentAddrRequiredOptionalGrace(t *testing.T) { defer ctx.cleanup() allSubscriptions, err := ctx.registry.SubscribeNotifications(0, 0) - assert.Nil(t, err) + require.Nil(t, err) defer allSubscriptions.Cancel() // Subscribe to the not yet existing invoice.