Merge pull request #4338 from cfromknecht/set-id-index

channeldb+invoices: add set id index for AMP
This commit is contained in:
Conner Fromknecht 2021-03-04 12:17:08 -08:00 committed by GitHub
commit 56b61078c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1572 additions and 564 deletions

@ -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,

@ -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"
@ -1133,23 +1134,396 @@ 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) {
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
// 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()
}
}
// 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)
}
// 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)
// 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))
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)
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
}
}
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
@ -1243,4 +1617,5 @@ func TestDeleteInvoices(t *testing.T) {
// Delete should succeed with all the valid references.
require.NoError(t, db.DeleteInvoice(invoicesToDelete))
assertInvoiceCount(0)
}

@ -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
@ -106,8 +114,27 @@ 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")
// 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
// 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.
@ -135,6 +162,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.
//
@ -176,6 +206,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
@ -198,6 +236,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
@ -214,6 +261,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 {
@ -359,6 +417,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
@ -407,6 +489,80 @@ 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
}
// 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.
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 +583,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
@ -451,6 +615,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
@ -479,6 +648,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
}
@ -654,11 +828,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
@ -685,9 +860,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()
@ -935,20 +1123,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
@ -1186,8 +1375,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
@ -1205,6 +1394,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)
@ -1238,6 +1450,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 {
@ -1374,6 +1605,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 +1621,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 +1637,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.AcceptTime = getNanoTime(acceptTime)
htlc.ResolveTime = getNanoTime(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 +1694,8 @@ func copyInvoiceHTLC(src *InvoiceHTLC) *InvoiceHTLC {
result.CustomRecords[k] = v
}
result.AMP = src.AMP.Copy()
return &result
}
@ -1468,8 +1733,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 {
@ -1491,10 +1757,96 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex kvdb.RwBucke
return &invoice, nil
}
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.
// Process add actions from update descriptor.
for key, htlcUpdate := range update.AddHtlcs {
if _, exists := invoice.Htlcs[key]; exists {
return nil, fmt.Errorf("duplicate add of htlc %v", key)
}
// Force caller to supply htlc without custom records in a
// consistent way.
if htlcUpdate.CustomRecords == nil {
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,
Expiry: htlcUpdate.Expiry,
AcceptHeight: uint32(htlcUpdate.AcceptHeight),
AcceptTime: now,
State: HtlcStateAccepted,
CustomRecords: htlcUpdate.CustomRecords,
AMP: htlcUpdate.AMP.Copy(),
}
invoice.Htlcs[key] = htlc
}
// 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.
_, cancel := 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
// 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 {
@ -1511,64 +1863,15 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex kvdb.RwBucke
}
}
// Process add actions from update descriptor.
for key, htlcUpdate := range update.AddHtlcs {
if _, exists := invoice.Htlcs[key]; exists {
return nil, fmt.Errorf("duplicate add of htlc %v", key)
}
// Force caller to supply htlc without custom records in a
// consistent way.
if htlcUpdate.CustomRecords == nil {
return nil, errors.New("nil custom records map")
}
htlc := &InvoiceHTLC{
Amt: htlcUpdate.Amt,
MppTotalAmt: htlcUpdate.MppTotalAmt,
Expiry: htlcUpdate.Expiry,
AcceptHeight: uint32(htlcUpdate.AcceptHeight),
AcceptTime: now,
State: HtlcStateAccepted,
CustomRecords: htlcUpdate.CustomRecords,
}
invoice.Htlcs[key] = htlc
}
// Align htlc states with invoice state and recalculate amount paid.
var (
amtPaid lnwire.MilliSatoshi
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.
_, 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, invoice.State)
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)
continue
}
// 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.
err := updateHtlc(now, htlc, invoice.State)
err := updateHtlc(now, htlc, invoice.State, setID)
if err != nil {
return nil, err
}
@ -1584,12 +1887,6 @@ func (d *DB) updateInvoice(hash lntypes.Hash, invoices, settleIndex kvdb.RwBucke
}
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 {
@ -1629,20 +1926,54 @@ 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
}
// 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.
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
@ -1654,10 +1985,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.
@ -1684,39 +2011,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

@ -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 {

@ -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

@ -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.
@ -802,6 +806,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

@ -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.

@ -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.

@ -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
@ -32,10 +33,22 @@ 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",
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
@ -106,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,
@ -141,14 +156,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(setID) {
if ctx.mpp.TotalMsat() != htlc.MppTotalAmt {
return nil, ctx.failRes(ResultHtlcSetTotalMismatch), nil
}
@ -193,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
}
@ -200,6 +209,7 @@ func updateMpp(ctx *invoiceUpdateCtx,
update.State = &channeldb.InvoiceStateUpdateDesc{
NewState: channeldb.ContractSettled,
Preimage: inv.Terms.PaymentPreimage,
SetID: setID,
}
return &update, ctx.settleRes(
@ -248,10 +258,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
}
}

@ -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"

@ -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()

@ -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.

@ -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 {

@ -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"

@ -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}