Merge pull request #1125 from Roasbeef/streaming-invoice-improvements

channeldb+lnrpc: re-work invoicing API to implement robust streaming notification delivery
This commit is contained in:
Olaoluwa Osuntokun 2018-07-10 20:42:00 -07:00 committed by GitHub
commit 93207608b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1771 additions and 532 deletions

@ -47,6 +47,12 @@ var (
number: 1,
migration: migrateNodeAndEdgeUpdateIndex,
},
{
// The DB version that added the invoice event time
// series.
number: 2,
migration: migrateInvoiceTimeSeries,
},
}
// Big endian is the preferred byte order, due to cursor scans over

@ -70,7 +70,7 @@ func TestInvoiceWorkflow(t *testing.T) {
// Add the invoice to the database, this should succeed as there aren't
// any existing invoices within the database with the same payment
// hash.
if err := db.AddInvoice(fakeInvoice); err != nil {
if _, err := db.AddInvoice(fakeInvoice); err != nil {
t.Fatalf("unable to find invoice: %v", err)
}
@ -82,15 +82,24 @@ func TestInvoiceWorkflow(t *testing.T) {
if err != nil {
t.Fatalf("unable to find invoice: %v", err)
}
if !reflect.DeepEqual(fakeInvoice, dbInvoice) {
if !reflect.DeepEqual(*fakeInvoice, dbInvoice) {
t.Fatalf("invoice fetched from db doesn't match original %v vs %v",
spew.Sdump(fakeInvoice), spew.Sdump(dbInvoice))
}
// The add index of the invoice retrieved from the database should now
// be fully populated. As this is the first index written to the DB,
// the addIndex should be 1.
if dbInvoice.AddIndex != 1 {
t.Fatalf("wrong add index: expected %v, got %v", 1,
dbInvoice.AddIndex)
}
// Settle the invoice, the version retrieved from the database should
// now have the settled bit toggle to true and a non-default
// SettledDate
if err := db.SettleInvoice(paymentHash); err != nil {
payAmt := fakeInvoice.Terms.Value * 2
if _, err := db.SettleInvoice(paymentHash, payAmt); err != nil {
t.Fatalf("unable to settle invoice: %v", err)
}
dbInvoice2, err := db.LookupInvoice(paymentHash)
@ -100,14 +109,24 @@ func TestInvoiceWorkflow(t *testing.T) {
if !dbInvoice2.Terms.Settled {
t.Fatalf("invoice should now be settled but isn't")
}
if dbInvoice2.SettleDate.IsZero() {
t.Fatalf("invoice should have non-zero SettledDate but isn't")
}
// Our 2x payment should be reflected, and also the settle index of 1
// should also have been committed for this index.
if dbInvoice2.AmtPaid != payAmt {
t.Fatalf("wrong amt paid: expected %v, got %v", payAmt,
dbInvoice2.AmtPaid)
}
if dbInvoice2.SettleIndex != 1 {
t.Fatalf("wrong settle index: expected %v, got %v", 1,
dbInvoice2.SettleIndex)
}
// Attempt to insert generated above again, this should fail as
// duplicates are rejected by the processing logic.
if err := db.AddInvoice(fakeInvoice); err != ErrDuplicateInvoice {
if _, err := db.AddInvoice(fakeInvoice); err != ErrDuplicateInvoice {
t.Fatalf("invoice insertion should fail due to duplication, "+
"instead %v", err)
}
@ -119,18 +138,18 @@ func TestInvoiceWorkflow(t *testing.T) {
t.Fatalf("lookup should have failed, instead %v", err)
}
// Add 100 random invoices.
// Add 10 random invoices.
const numInvoices = 10
amt := lnwire.NewMSatFromSatoshis(1000)
invoices := make([]*Invoice, numInvoices+1)
invoices[0] = dbInvoice2
invoices[0] = &dbInvoice2
for i := 1; i < len(invoices)-1; i++ {
invoice, err := randInvoice(amt)
if err != nil {
t.Fatalf("unable to create invoice: %v", err)
}
if err := db.AddInvoice(invoice); err != nil {
if _, err := db.AddInvoice(invoice); err != nil {
t.Fatalf("unable to add invoice %v", err)
}
@ -148,10 +167,150 @@ func TestInvoiceWorkflow(t *testing.T) {
// order (and the primary key should be incremented with each
// insertion).
for i := 0; i < len(invoices)-1; i++ {
if !reflect.DeepEqual(invoices[i], dbInvoices[i]) {
if !reflect.DeepEqual(*invoices[i], dbInvoices[i]) {
t.Fatalf("retrieved invoices don't match %v vs %v",
spew.Sdump(invoices[i]),
spew.Sdump(dbInvoices[i]))
}
}
}
// TestInvoiceTimeSeries tests that newly added invoices invoices, as well as
// settled invoices are added to the database are properly placed in the add
// add or settle index which serves as an event time series.
func TestInvoiceAddTimeSeries(t *testing.T) {
t.Parallel()
db, cleanUp, err := makeTestDB()
defer cleanUp()
if err != nil {
t.Fatalf("unable to make test db: %v", err)
}
// We'll start off by creating 20 random invoices, and inserting them
// into the database.
const numInvoices = 20
amt := lnwire.NewMSatFromSatoshis(1000)
invoices := make([]Invoice, numInvoices)
for i := 0; i < len(invoices); i++ {
invoice, err := randInvoice(amt)
if err != nil {
t.Fatalf("unable to create invoice: %v", err)
}
if _, err := db.AddInvoice(invoice); err != nil {
t.Fatalf("unable to add invoice %v", err)
}
invoices[i] = *invoice
}
// With the invoices constructed, we'll now create a series of queries
// that we'll use to assert expected return values of
// InvoicesAddedSince.
addQueries := []struct {
sinceAddIndex uint64
resp []Invoice
}{
// If we specify a value of zero, we shouldn't get any invoices
// back.
{
sinceAddIndex: 0,
},
// If we specify a value well beyond the number of inserted
// invoices, we shouldn't get any invoices back.
{
sinceAddIndex: 99999999,
},
// Using an index of 1 should result in all values, but the
// first one being returned.
{
sinceAddIndex: 1,
resp: invoices[1:],
},
// If we use an index of 10, then we should retrieve the
// reaming 10 invoices.
{
sinceAddIndex: 10,
resp: invoices[10:],
},
}
for i, query := range addQueries {
resp, err := db.InvoicesAddedSince(query.sinceAddIndex)
if err != nil {
t.Fatalf("unable to query: %v", err)
}
if !reflect.DeepEqual(query.resp, resp) {
t.Fatalf("test #%v: expected %v, got %v", i,
spew.Sdump(query.resp), spew.Sdump(resp))
}
}
// We'll now only settle the latter half of each of those invoices.
for i := 10; i < len(invoices); i++ {
invoice := &invoices[i]
paymentHash := sha256.Sum256(
invoice.Terms.PaymentPreimage[:],
)
_, err := db.SettleInvoice(paymentHash, 0)
if err != nil {
t.Fatalf("unable to settle invoice: %v", err)
}
}
invoices, err = db.FetchAllInvoices(false)
if err != nil {
t.Fatalf("unable to fetch invoices: %v", err)
}
// We'll slice off the first 10 invoices, as we only settled the last
// 10.
invoices = invoices[10:]
// We'll now prepare an additional set of queries to ensure the settle
// time series has properly been maintained in the database.
settleQueries := []struct {
sinceSettleIndex uint64
resp []Invoice
}{
// If we specify a value of zero, we shouldn't get any settled
// invoices back.
{
sinceSettleIndex: 0,
},
// If we specify a value well beyond the number of settled
// invoices, we shouldn't get any invoices back.
{
sinceSettleIndex: 99999999,
},
// Using an index of 1 should result in the final 10 invoices
// being returned, as we only settled those.
{
sinceSettleIndex: 1,
resp: invoices[1:],
},
}
for i, query := range settleQueries {
resp, err := db.InvoicesSettledSince(query.sinceSettleIndex)
if err != nil {
t.Fatalf("unable to query: %v", err)
}
if !reflect.DeepEqual(query.resp, resp) {
t.Fatalf("test #%v: expected %v, got %v", i,
spew.Sdump(query.resp), spew.Sdump(resp))
}
}
}

@ -26,6 +26,8 @@ var (
// index is used to detect duplicates, and also to provide a fast path
// for looking up incoming HTLCs to determine if we're able to settle
// them fully.
//
// maps: payHash => invoiceIndex
invoiceIndexBucket = []byte("paymenthashes")
// numInvoicesKey is the name of key which houses the auto-incrementing
@ -34,6 +36,26 @@ var (
// stored within the invoiceIndexBucket. Within the invoiceBucket
// invoices are uniquely identified by the invoice ID.
numInvoicesKey = []byte("nik")
// addIndexBucket is an index bucket that we'll use to create a
// monotonically increasing set of add indexes. Each time we add a new
// invoice, this sequence number will be incremented and then populated
// within the new invoice.
//
// In addition to this sequence number, we map:
//
// addIndexNo => invoiceIndex
addIndexBucket = []byte("invoice-add-index")
// settleIndexBucket is an index bucket that we'll use to create a
// monotonically increasing integer for tracking a "settle index". Each
// time an invoice is settled, this sequence number will be incremented
// as populate within the newly settled invoice.
//
// In addition to this sequence number, we map:
//
// settleIndexNo => invoiceIndex
settleIndexBucket = []byte("invoice-settle-index")
)
const (
@ -61,8 +83,8 @@ type ContractTerm struct {
// extended.
PaymentPreimage [32]byte
// Value is the expected amount of milli-satoshis to be paid to an
// HTLC which can be satisfied by the above preimage.
// Value is the expected amount of milli-satoshis to be paid to an HTLC
// which can be satisfied by the above preimage.
Value lnwire.MilliSatoshi
// Settled indicates if this particular contract term has been fully
@ -79,8 +101,7 @@ type ContractTerm struct {
// invoices are never deleted from the database, instead a bit is toggled
// denoting the invoice has been fully settled. Within the database, all
// invoices must have a unique payment hash which is generated by taking the
// sha256 of the payment
// preimage.
// sha256 of the payment preimage.
type Invoice struct {
// Memo is an optional memo to be stored along side an invoice. The
// memo may contain further details pertaining to the invoice itself,
@ -103,13 +124,37 @@ type Invoice struct {
// SettleDate is the exact time the invoice was settled.
SettleDate time.Time
// Terms are the contractual payment terms of the invoice. Once
// all the terms have been satisfied by the payer, then the invoice can
// be considered fully fulfilled.
// Terms are the contractual payment terms of the invoice. Once all the
// terms have been satisfied by the payer, then the invoice can be
// considered fully fulfilled.
//
// TODO(roasbeef): later allow for multiple terms to fulfill the final
// invoice: payment fragmentation, etc.
Terms ContractTerm
// AddIndex is an auto-incrementing integer that acts as a
// monotonically increasing sequence number for all invoices created.
// Clients can then use this field as a "checkpoint" of sorts when
// implementing a streaming RPC to notify consumers of instances where
// an invoice has been added before they re-connected.
//
// NOTE: This index starts at 1.
AddIndex uint64
// SettleIndex is an auto-incrementing integer that acts as a
// monotonically increasing sequence number for all settled invoices.
// Clients can then use this field as a "checkpoint" of sorts when
// implementing a streaming RPC to notify consumers of instances where
// an invoice has been settled before they re-connected.
//
// NOTE: This index starts at 1.
SettleIndex uint64
// AmtPaid is the final amount that we ultimately accepted for pay for
// this invoice. We specify this value independently as it's possible
// that the invoice originally didn't specify an amount, or the sender
// overpaid.
AmtPaid lnwire.MilliSatoshi
}
func validateInvoice(i *Invoice) error {
@ -134,24 +179,36 @@ func validateInvoice(i *Invoice) error {
// has *any* payment hashes which already exists within the database, then the
// insertion will be aborted and rejected due to the strict policy banning any
// duplicate payment hashes.
func (d *DB) AddInvoice(i *Invoice) error {
if err := validateInvoice(i); err != nil {
return err
func (d *DB) AddInvoice(newInvoice *Invoice) (uint64, error) {
if err := validateInvoice(newInvoice); err != nil {
return 0, err
}
return d.Update(func(tx *bolt.Tx) error {
var invoiceAddIndex uint64
err := d.Update(func(tx *bolt.Tx) error {
invoices, err := tx.CreateBucketIfNotExists(invoiceBucket)
if err != nil {
return err
}
invoiceIndex, err := invoices.CreateBucketIfNotExists(invoiceIndexBucket)
invoiceIndex, err := invoices.CreateBucketIfNotExists(
invoiceIndexBucket,
)
if err != nil {
return err
}
addIndex, err := invoices.CreateBucketIfNotExists(
addIndexBucket,
)
if err != nil {
return err
}
// Ensure that an invoice an identical payment hash doesn't
// already exist within the index.
paymentHash := sha256.Sum256(i.Terms.PaymentPreimage[:])
paymentHash := sha256.Sum256(
newInvoice.Terms.PaymentPreimage[:],
)
if invoiceIndex.Get(paymentHash[:]) != nil {
return ErrDuplicateInvoice
}
@ -163,15 +220,96 @@ func (d *DB) AddInvoice(i *Invoice) error {
if invoiceCounter == nil {
var scratch [4]byte
byteOrder.PutUint32(scratch[:], invoiceNum)
if err := invoiceIndex.Put(numInvoicesKey, scratch[:]); err != nil {
err := invoiceIndex.Put(numInvoicesKey, scratch[:])
if err != nil {
return nil
}
} else {
invoiceNum = byteOrder.Uint32(invoiceCounter)
}
return putInvoice(invoices, invoiceIndex, i, invoiceNum)
newIndex, err := putInvoice(
invoices, invoiceIndex, addIndex, newInvoice, invoiceNum,
)
if err != nil {
return err
}
invoiceAddIndex = newIndex
return nil
})
if err != nil {
return 0, err
}
return invoiceAddIndex, err
}
// InvoicesAddedSince can be used by callers to seek into the event time series
// of all the invoices added in the database. The specified sinceAddIndex
// should be the highest add index that the caller knows of. This method will
// return all invoices with an add index greater than the specified
// sinceAddIndex.
//
// NOTE: The index starts from 1, as a result. We enforce that specifying a
// value below the starting index value is a noop.
func (d *DB) InvoicesAddedSince(sinceAddIndex uint64) ([]Invoice, error) {
var newInvoices []Invoice
// If an index of zero was specified, then in order to maintain
// backwards compat, we won't send out any new invoices.
if sinceAddIndex == 0 {
return newInvoices, nil
}
var startIndex [8]byte
byteOrder.PutUint64(startIndex[:], sinceAddIndex)
err := d.DB.View(func(tx *bolt.Tx) error {
invoices := tx.Bucket(invoiceBucket)
if invoices == nil {
return ErrNoInvoicesCreated
}
addIndex := invoices.Bucket(addIndexBucket)
if addIndex == nil {
return ErrNoInvoicesCreated
}
// We'll now run through each entry in the add index starting
// at our starting index. We'll continue until we reach the
// very end of the current key space.
invoiceCursor := addIndex.Cursor()
// We'll seek to the starting index, then manually advance the
// cursor in order to skip the entry with the since add index.
invoiceCursor.Seek(startIndex[:])
addSeqNo, invoiceKey := invoiceCursor.Next()
for ; addSeqNo != nil && bytes.Compare(addSeqNo, startIndex[:]) > 0; addSeqNo, invoiceKey = invoiceCursor.Next() {
// For each key found, we'll look up the actual
// invoice, then accumulate it into our return value.
invoice, err := fetchInvoice(invoiceKey, invoices)
if err != nil {
return err
}
newInvoices = append(newInvoices, invoice)
}
return nil
})
switch {
// If no invoices have been created, then we'll return the empty set of
// invoices.
case err == ErrNoInvoicesCreated:
case err != nil:
return nil, err
}
return newInvoices, nil
}
// LookupInvoice attempts to look up an invoice according to its 32 byte
@ -180,8 +318,8 @@ func (d *DB) AddInvoice(i *Invoice) error {
// full invoice is returned. Before setting the incoming HTLC, the values
// SHOULD be checked to ensure the payer meets the agreed upon contractual
// terms of the payment.
func (d *DB) LookupInvoice(paymentHash [32]byte) (*Invoice, error) {
var invoice *Invoice
func (d *DB) LookupInvoice(paymentHash [32]byte) (Invoice, error) {
var invoice Invoice
err := d.View(func(tx *bolt.Tx) error {
invoices := tx.Bucket(invoiceBucket)
if invoices == nil {
@ -210,7 +348,7 @@ func (d *DB) LookupInvoice(paymentHash [32]byte) (*Invoice, error) {
return nil
})
if err != nil {
return nil, err
return invoice, err
}
return invoice, nil
@ -219,8 +357,8 @@ func (d *DB) LookupInvoice(paymentHash [32]byte) (*Invoice, error) {
// FetchAllInvoices returns all invoices currently stored within the database.
// If the pendingOnly param is true, then only unsettled invoices will be
// returned, skipping all invoices that are fully settled.
func (d *DB) FetchAllInvoices(pendingOnly bool) ([]*Invoice, error) {
var invoices []*Invoice
func (d *DB) FetchAllInvoices(pendingOnly bool) ([]Invoice, error) {
var invoices []Invoice
err := d.View(func(tx *bolt.Tx) error {
invoiceB := tx.Bucket(invoiceBucket)
@ -262,13 +400,24 @@ func (d *DB) FetchAllInvoices(pendingOnly bool) ([]*Invoice, error) {
// payment hash as fully settled. If an invoice matching the passed payment
// hash doesn't existing within the database, then the action will fail with a
// "not found" error.
func (d *DB) SettleInvoice(paymentHash [32]byte) error {
return d.Update(func(tx *bolt.Tx) error {
func (d *DB) SettleInvoice(paymentHash [32]byte,
amtPaid lnwire.MilliSatoshi) (*Invoice, error) {
var settledInvoice *Invoice
err := d.Update(func(tx *bolt.Tx) error {
invoices, err := tx.CreateBucketIfNotExists(invoiceBucket)
if err != nil {
return err
}
invoiceIndex, err := invoices.CreateBucketIfNotExists(invoiceIndexBucket)
invoiceIndex, err := invoices.CreateBucketIfNotExists(
invoiceIndexBucket,
)
if err != nil {
return err
}
settleIndex, err := invoices.CreateBucketIfNotExists(
settleIndexBucket,
)
if err != nil {
return err
}
@ -280,12 +429,86 @@ func (d *DB) SettleInvoice(paymentHash [32]byte) error {
return ErrInvoiceNotFound
}
return settleInvoice(invoices, invoiceNum)
invoice, err := settleInvoice(
invoices, settleIndex, invoiceNum, amtPaid,
)
if err != nil {
return err
}
settledInvoice = invoice
return nil
})
if err != nil {
return nil, err
}
return settledInvoice, nil
}
func putInvoice(invoices *bolt.Bucket, invoiceIndex *bolt.Bucket,
i *Invoice, invoiceNum uint32) error {
// InvoicesSettledSince can be used by callers to catch up any settled invoices
// they missed within the settled invoice time series. We'll return all known
// settled invoice that have a settle index higher than the passed
// sinceSettleIndex.
//
// NOTE: The index starts from 1, as a result. We enforce that specifying a
// value below the starting index value is a noop.
func (d *DB) InvoicesSettledSince(sinceSettleIndex uint64) ([]Invoice, error) {
var settledInvoices []Invoice
// If an index of zero was specified, then in order to maintain
// backwards compat, we won't send out any new invoices.
if sinceSettleIndex == 0 {
return settledInvoices, nil
}
var startIndex [8]byte
byteOrder.PutUint64(startIndex[:], sinceSettleIndex)
err := d.DB.View(func(tx *bolt.Tx) error {
invoices := tx.Bucket(invoiceBucket)
if invoices == nil {
return ErrNoInvoicesCreated
}
settleIndex := invoices.Bucket(settleIndexBucket)
if settleIndex == nil {
return ErrNoInvoicesCreated
}
// We'll now run through each entry in the add index starting
// at our starting index. We'll continue until we reach the
// very end of the current key space.
invoiceCursor := settleIndex.Cursor()
// We'll seek to the starting index, then manually advance the
// cursor in order to skip the entry with the since add index.
invoiceCursor.Seek(startIndex[:])
seqNo, invoiceKey := invoiceCursor.Next()
for ; seqNo != nil && bytes.Compare(seqNo, startIndex[:]) > 0; seqNo, invoiceKey = invoiceCursor.Next() {
// For each key found, we'll look up the actual
// invoice, then accumulate it into our return value.
invoice, err := fetchInvoice(invoiceKey, invoices)
if err != nil {
return err
}
settledInvoices = append(settledInvoices, invoice)
}
return nil
})
if err != nil {
return nil, err
}
return settledInvoices, nil
}
func putInvoice(invoices, invoiceIndex, addIndex *bolt.Bucket,
i *Invoice, invoiceNum uint32) (uint64, error) {
// Create the invoice key which is just the big-endian representation
// of the invoice number.
@ -298,24 +521,48 @@ func putInvoice(invoices *bolt.Bucket, invoiceIndex *bolt.Bucket,
invoiceCounter := invoiceNum + 1
byteOrder.PutUint32(scratch[:], invoiceCounter)
if err := invoiceIndex.Put(numInvoicesKey, scratch[:]); err != nil {
return err
return 0, err
}
// Add the payment hash to the invoice index. This will let us quickly
// identify if we can settle an incoming payment, and also to possibly
// allow a single invoice to have multiple payment installations.
paymentHash := sha256.Sum256(i.Terms.PaymentPreimage[:])
if err := invoiceIndex.Put(paymentHash[:], invoiceKey[:]); err != nil {
return err
err := invoiceIndex.Put(paymentHash[:], invoiceKey[:])
if err != nil {
return 0, err
}
// Next, we'll obtain the next add invoice index (sequence
// number), so we can properly place this invoice within this
// event stream.
nextAddSeqNo, err := addIndex.NextSequence()
if err != nil {
return 0, err
}
// With the next sequence obtained, we'll updating the event series in
// the add index bucket to map this current add counter to the index of
// this new invoice.
var seqNoBytes [8]byte
byteOrder.PutUint64(seqNoBytes[:], nextAddSeqNo)
if err := addIndex.Put(seqNoBytes[:], invoiceKey[:]); err != nil {
return 0, err
}
i.AddIndex = nextAddSeqNo
// Finally, serialize the invoice itself to be written to the disk.
var buf bytes.Buffer
if err := serializeInvoice(&buf, i); err != nil {
return nil
return 0, nil
}
return invoices.Put(invoiceKey[:], buf.Bytes())
if err := invoices.Put(invoiceKey[:], buf.Bytes()); err != nil {
return 0, err
}
return nextAddSeqNo, nil
}
func serializeInvoice(w io.Writer, i *Invoice) error {
@ -361,13 +608,23 @@ func serializeInvoice(w io.Writer, i *Invoice) error {
return err
}
if err := binary.Write(w, byteOrder, i.AddIndex); err != nil {
return err
}
if err := binary.Write(w, byteOrder, i.SettleIndex); err != nil {
return err
}
if err := binary.Write(w, byteOrder, int64(i.AmtPaid)); err != nil {
return err
}
return nil
}
func fetchInvoice(invoiceNum []byte, invoices *bolt.Bucket) (*Invoice, error) {
func fetchInvoice(invoiceNum []byte, invoices *bolt.Bucket) (Invoice, error) {
invoiceBytes := invoices.Get(invoiceNum)
if invoiceBytes == nil {
return nil, ErrInvoiceNotFound
return Invoice{}, ErrInvoiceNotFound
}
invoiceReader := bytes.NewReader(invoiceBytes)
@ -375,76 +632,108 @@ func fetchInvoice(invoiceNum []byte, invoices *bolt.Bucket) (*Invoice, error) {
return deserializeInvoice(invoiceReader)
}
func deserializeInvoice(r io.Reader) (*Invoice, error) {
func deserializeInvoice(r io.Reader) (Invoice, error) {
var err error
invoice := &Invoice{}
invoice := Invoice{}
// TODO(roasbeef): use read full everywhere
invoice.Memo, err = wire.ReadVarBytes(r, 0, MaxMemoSize, "")
if err != nil {
return nil, err
return invoice, err
}
invoice.Receipt, err = wire.ReadVarBytes(r, 0, MaxReceiptSize, "")
if err != nil {
return nil, err
return invoice, err
}
invoice.PaymentRequest, err = wire.ReadVarBytes(r, 0, MaxPaymentRequestSize, "")
if err != nil {
return nil, err
return invoice, err
}
birthBytes, err := wire.ReadVarBytes(r, 0, 300, "birth")
if err != nil {
return nil, err
return invoice, err
}
if err := invoice.CreationDate.UnmarshalBinary(birthBytes); err != nil {
return nil, err
return invoice, err
}
settledBytes, err := wire.ReadVarBytes(r, 0, 300, "settled")
if err != nil {
return nil, err
return invoice, err
}
if err := invoice.SettleDate.UnmarshalBinary(settledBytes); err != nil {
return nil, err
return invoice, err
}
if _, err := io.ReadFull(r, invoice.Terms.PaymentPreimage[:]); err != nil {
return nil, err
return invoice, err
}
var scratch [8]byte
if _, err := io.ReadFull(r, scratch[:]); err != nil {
return nil, err
return invoice, err
}
invoice.Terms.Value = lnwire.MilliSatoshi(byteOrder.Uint64(scratch[:]))
if err := binary.Read(r, byteOrder, &invoice.Terms.Settled); err != nil {
return nil, err
return invoice, err
}
if err := binary.Read(r, byteOrder, &invoice.AddIndex); err != nil {
return invoice, err
}
if err := binary.Read(r, byteOrder, &invoice.SettleIndex); err != nil {
return invoice, err
}
if err := binary.Read(r, byteOrder, &invoice.AmtPaid); err != nil {
return invoice, err
}
return invoice, nil
}
func settleInvoice(invoices *bolt.Bucket, invoiceNum []byte) error {
func settleInvoice(invoices, settleIndex *bolt.Bucket, invoiceNum []byte,
amtPaid lnwire.MilliSatoshi) (*Invoice, error) {
invoice, err := fetchInvoice(invoiceNum, invoices)
if err != nil {
return err
return nil, err
}
// Add idempotency to duplicate settles, return here to avoid
// overwriting the previous info.
if invoice.Terms.Settled {
return nil
return nil, nil
}
// Now that we know the invoice hasn't already been settled, we'll
// update the settle index so we can place this settle event in the
// proper location within our time series.
nextSettleSeqNo, err := settleIndex.NextSequence()
if err != nil {
return nil, err
}
var seqNoBytes [8]byte
byteOrder.PutUint64(seqNoBytes[:], nextSettleSeqNo)
if err := settleIndex.Put(seqNoBytes[:], invoiceNum); err != nil {
return nil, err
}
invoice.AmtPaid = amtPaid
invoice.Terms.Settled = true
invoice.SettleDate = time.Now()
invoice.SettleIndex = nextSettleSeqNo
var buf bytes.Buffer
if err := serializeInvoice(&buf, invoice); err != nil {
return nil
if err := serializeInvoice(&buf, &invoice); err != nil {
return nil, err
}
return invoices.Put(invoiceNum[:], buf.Bytes())
if err := invoices.Put(invoiceNum[:], buf.Bytes()); err != nil {
return nil, err
}
return &invoice, nil
}

@ -112,3 +112,122 @@ func migrateNodeAndEdgeUpdateIndex(tx *bolt.Tx) error {
return nil
}
// migrateInvoiceTimeSeries is a database migration that assigns all existing
// invoices an index in the add and/or the settle index. Additionally, all
// existing invoices will have their bytes padded out in order to encode the
// add+settle index as well as the amount paid.
func migrateInvoiceTimeSeries(tx *bolt.Tx) error {
invoices, err := tx.CreateBucketIfNotExists(invoiceBucket)
if err != nil {
return err
}
addIndex, err := invoices.CreateBucketIfNotExists(
addIndexBucket,
)
if err != nil {
return err
}
settleIndex, err := invoices.CreateBucketIfNotExists(
settleIndexBucket,
)
if err != nil {
return err
}
log.Infof("Migrating invoice database to new time series format")
// Now that we have all the buckets we need, we'll run through each
// invoice in the database, and update it to reflect the new format
// expected post migration.
err = invoices.ForEach(func(invoiceNum, invoiceBytes []byte) error {
// If this is a sub bucket, then we'll skip it.
if invoiceBytes == nil {
return nil
}
// First, we'll make a copy of the encoded invoice bytes.
invoiceBytesCopy := make([]byte, len(invoiceBytes))
copy(invoiceBytesCopy, invoiceBytes)
// With the bytes copied over, we'll append 24 additional
// bytes. We do this so we can decode the invoice under the new
// serialization format.
padding := bytes.Repeat([]byte{0}, 24)
invoiceBytesCopy = append(invoiceBytesCopy, padding...)
invoiceReader := bytes.NewReader(invoiceBytesCopy)
invoice, err := deserializeInvoice(invoiceReader)
if err != nil {
return fmt.Errorf("unable to decode invoice: %v", err)
}
// Now that we have the fully decoded invoice, we can update
// the various indexes that we're added, and finally the
// invoice itself before re-inserting it.
// First, we'll get the new sequence in the addIndex in order
// to create the proper mapping.
nextAddSeqNo, err := addIndex.NextSequence()
if err != nil {
return err
}
var seqNoBytes [8]byte
byteOrder.PutUint64(seqNoBytes[:], nextAddSeqNo)
err = addIndex.Put(seqNoBytes[:], invoiceNum[:])
if err != nil {
return err
}
log.Tracef("Adding invoice (preimage=%v, add_index=%v) to add "+
"time series", invoice.Terms.PaymentPreimage[:],
nextAddSeqNo)
// Next, we'll check if the invoice has been settled or not. If
// so, then we'll also add it to the settle index.
var nextSettleSeqNo uint64
if invoice.Terms.Settled {
nextSettleSeqNo, err = settleIndex.NextSequence()
if err != nil {
return err
}
var seqNoBytes [8]byte
byteOrder.PutUint64(seqNoBytes[:], nextSettleSeqNo)
err := settleIndex.Put(seqNoBytes[:], invoiceNum)
if err != nil {
return err
}
invoice.AmtPaid = invoice.Terms.Value
log.Tracef("Adding invoice (preimage=%v, "+
"settle_index=%v) to add time series",
invoice.Terms.PaymentPreimage[:],
nextSettleSeqNo)
}
// Finally, we'll update the invoice itself with the new
// indexing information as well as the amount paid if it has
// been settled or not.
invoice.AddIndex = nextAddSeqNo
invoice.SettleIndex = nextSettleSeqNo
// We've fully migrated an invoice, so we'll now update the
// invoice in-place.
var b bytes.Buffer
if err := serializeInvoice(&b, &invoice); err != nil {
return err
}
return invoices.Put(invoiceNum, b.Bytes())
})
if err != nil {
return err
}
log.Infof("Migration to invoice time series index complete!")
return nil
}

@ -177,7 +177,7 @@ func deserializeOutgoingPayment(r io.Reader) (*OutgoingPayment, error) {
if err != nil {
return nil, err
}
p.Invoice = *inv
p.Invoice = inv
if _, err := r.Read(scratch[:]); err != nil {
return nil, err

@ -2195,11 +2195,13 @@ func addInvoice(ctx *cli.Context) error {
}
printJSON(struct {
RHash string `json:"r_hash"`
PayReq string `json:"pay_req"`
RHash string `json:"r_hash"`
PayReq string `json:"pay_req"`
AddIndex uint64 `json:"add_index"`
}{
RHash: hex.EncodeToString(resp.RHash),
PayReq: resp.PaymentRequest,
RHash: hex.EncodeToString(resp.RHash),
PayReq: resp.PaymentRequest,
AddIndex: resp.AddIndex,
})
return nil

@ -18,7 +18,7 @@ type InvoiceDatabase interface {
// SettleInvoice attempts to mark an invoice corresponding to the
// passed payment hash as fully settled.
SettleInvoice(chainhash.Hash) error
SettleInvoice(payHash chainhash.Hash, paidAmount lnwire.MilliSatoshi) error
}
// ChannelLink is an interface which represents the subsystem for managing the

@ -2298,8 +2298,9 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
}
preimage := invoice.Terms.PaymentPreimage
err = l.channel.SettleHTLC(preimage,
pd.HtlcIndex, pd.SourceRef, nil, nil)
err = l.channel.SettleHTLC(
preimage, pd.HtlcIndex, pd.SourceRef, nil, nil,
)
if err != nil {
l.fail(LinkFailureError{code: ErrInternalError},
"unable to settle htlc: %v", err)
@ -2307,8 +2308,11 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
}
// Notify the invoiceRegistry of the invoices we just
// settled with this latest commitment update.
err = l.cfg.Registry.SettleInvoice(invoiceHash)
// settled (with the amount accepted at settle time)
// with this latest commitment update.
err = l.cfg.Registry.SettleInvoice(
invoiceHash, pd.Amount,
)
if err != nil {
l.fail(LinkFailureError{code: ErrInternalError},
"unable to settle invoice: %v", err)

@ -3657,6 +3657,13 @@ func TestChannelLinkAcceptOverpay(t *testing.T) {
t.Fatalf("channel bandwidth incorrect: expected %v, got %v",
expectedCarolBandwidth, n.carolChannelLink.Bandwidth())
}
// Finally, we'll ensure that the amount we paid is properly reflected
// in the stored invoice.
if invoice.AmtPaid != amount {
t.Fatalf("expected amt paid to be %v, is instead %v", amount,
invoice.AmtPaid)
}
}
// chanRestoreFunc is a method signature for functions that can reload both

@ -673,7 +673,9 @@ func (i *mockInvoiceRegistry) LookupInvoice(rHash chainhash.Hash) (channeldb.Inv
return invoice, i.finalDelta, nil
}
func (i *mockInvoiceRegistry) SettleInvoice(rhash chainhash.Hash) error {
func (i *mockInvoiceRegistry) SettleInvoice(rhash chainhash.Hash,
amt lnwire.MilliSatoshi) error {
i.Lock()
defer i.Unlock()
@ -687,6 +689,7 @@ func (i *mockInvoiceRegistry) SettleInvoice(rhash chainhash.Hash) error {
}
invoice.Terms.Settled = true
invoice.AmtPaid = amt
i.invoices[rhash] = invoice
return nil

@ -3,10 +3,13 @@ package main
import (
"bytes"
"crypto/sha256"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/zpay32"
@ -37,10 +40,17 @@ type invoiceRegistry struct {
nextClientID uint32
notificationClients map[uint32]*invoiceSubscription
newSubscriptions chan *invoiceSubscription
subscriptionCancels chan uint32
invoiceEvents chan *invoiceEvent
// debugInvoices is a map which stores special "debug" invoices which
// should be only created/used when manual tests require an invoice
// that *all* nodes are able to fully settle.
debugInvoices map[chainhash.Hash]*channeldb.Invoice
wg sync.WaitGroup
quit chan struct{}
}
// newInvoiceRegistry creates a new invoice registry. The invoice registry
@ -52,9 +62,194 @@ func newInvoiceRegistry(cdb *channeldb.DB) *invoiceRegistry {
cdb: cdb,
debugInvoices: make(map[chainhash.Hash]*channeldb.Invoice),
notificationClients: make(map[uint32]*invoiceSubscription),
newSubscriptions: make(chan *invoiceSubscription),
subscriptionCancels: make(chan uint32),
invoiceEvents: make(chan *invoiceEvent),
quit: make(chan struct{}),
}
}
// Start starts the registry and all goroutines it needs to carry out its task.
func (i *invoiceRegistry) Start() error {
i.wg.Add(1)
go i.invoiceEventNotifier()
return nil
}
// Stop signals the registry for a graceful shutdown.
func (i *invoiceRegistry) Stop() {
close(i.quit)
i.wg.Wait()
}
// invoiceEvent represents a new event that has modified on invoice on disk.
// Only two event types are currently supported: newly created invoices, and
// instance where invoices are settled.
type invoiceEvent struct {
isSettle bool
invoice *channeldb.Invoice
}
// invoiceEventNotifier is the dedicated goroutine responsible for accepting
// new notification subscriptions, cancelling old subscriptions, and
// dispatching new invoice events.
func (i *invoiceRegistry) invoiceEventNotifier() {
defer i.wg.Done()
for {
select {
// A new invoice subscription has just arrived! We'll query for
// any backlog notifications, then add it to the set of
// clients.
case newClient := <-i.newSubscriptions:
// Before we add the client to our set of active
// clients, we'll first attempt to deliver any backlog
// invoice events.
err := i.deliverBacklogEvents(newClient)
if err != nil {
ltndLog.Errorf("unable to deliver backlog invoice "+
"notifications: %v", err)
}
ltndLog.Infof("New invoice subscription "+
"client: id=%v", newClient.id)
// With the backlog notifications delivered (if any),
// we'll add this to our active subscriptions and
// continue.
i.notificationClients[newClient.id] = newClient
// A client no longer wishes to receive invoice notifications.
// So we'll remove them from the set of active clients.
case clientID := <-i.subscriptionCancels:
ltndLog.Infof("Cancelling invoice subscription for "+
"client=%v", clientID)
delete(i.notificationClients, clientID)
// A sub-systems has just modified the invoice state, so we'll
// dispatch notifications to all registered clients.
case event := <-i.invoiceEvents:
for clientID, client := range i.notificationClients {
// Before we dispatch this event, we'll check
// to ensure that this client hasn't already
// received this notification in order to
// ensure we don't duplicate any events.
invoice := event.invoice
switch {
// If we've already sent this settle event to
// the client, then we can skip this.
case event.isSettle &&
client.settleIndex >= invoice.SettleIndex:
continue
// Similarly, if we've already sent this add to
// the client then we can skip this one.
case !event.isSettle &&
client.addIndex >= invoice.AddIndex:
continue
// These two states should never happen, but we
// log them just in case so we can detect this
// instance.
case !event.isSettle &&
client.addIndex+1 != invoice.AddIndex:
ltndLog.Warnf("client=%v for invoice "+
"notifications missed an update, "+
"add_index=%v, new add event index=%v",
clientID, client.addIndex,
invoice.AddIndex)
case event.isSettle &&
client.settleIndex+1 != invoice.SettleIndex:
ltndLog.Warnf("client=%v for invoice "+
"notifications missed an update, "+
"settle_index=%v, new settle event index=%v",
clientID, client.settleIndex,
invoice.SettleIndex)
}
select {
case client.ntfnQueue.ChanIn() <- &invoiceEvent{
isSettle: event.isSettle,
invoice: invoice,
}:
case <-i.quit:
return
}
// Each time we send a notification to a
// client, we'll record the latest add/settle
// index it has. We'll use this to ensure we
// don't send a notification twice, which can
// happen if a new event is added while we're
// catching up a new client.
if event.isSettle {
client.settleIndex = invoice.SettleIndex
} else {
client.addIndex = invoice.AddIndex
}
}
case <-i.quit:
return
}
}
}
// deliverBacklogEvents will attempts to query the invoice database for any
// notifications that the client has missed since it reconnected last.
func (i *invoiceRegistry) deliverBacklogEvents(client *invoiceSubscription) error {
// First, we'll query the database to see if based on the provided
// addIndex and settledIndex we need to deliver any backlog
// notifications.
addEvents, err := i.cdb.InvoicesAddedSince(client.addIndex)
if err != nil {
return err
}
settleEvents, err := i.cdb.InvoicesSettledSince(client.settleIndex)
if err != nil {
return err
}
// If we have any to deliver, then we'll append them to the end of the
// notification queue in order to catch up the client before delivering
// any new notifications.
for _, addEvent := range addEvents {
// We re-bind the loop variable to ensure we don't hold onto
// the loop reference causing is to point to the same item.
addEvent := addEvent
select {
case client.ntfnQueue.ChanIn() <- &invoiceEvent{
isSettle: false,
invoice: &addEvent,
}:
case <-i.quit:
return fmt.Errorf("registry shutting down")
}
}
for _, settleEvent := range settleEvents {
// We re-bind the loop variable to ensure we don't hold onto
// the loop reference causing is to point to the same item.
settleEvent := settleEvent
select {
case client.ntfnQueue.ChanIn() <- &invoiceEvent{
isSettle: true,
invoice: &settleEvent,
}:
case <-i.quit:
return fmt.Errorf("registry shutting down")
}
}
return nil
}
// AddDebugInvoice adds a debug invoice for the specified amount, identified
// by the passed preimage. Once this invoice is added, subsystems within the
// daemon add/forward HTLCs that are able to obtain the proper preimage
@ -82,18 +277,28 @@ func (i *invoiceRegistry) AddDebugInvoice(amt btcutil.Amount, preimage chainhash
// AddInvoice adds a regular invoice for the specified amount, identified by
// the passed preimage. Additionally, any memo or receipt data provided will
// also be stored on-disk. Once this invoice is added, subsystems within the
// daemon add/forward HTLCs are able to obtain the proper preimage required
// for redemption in the case that we're the final destination.
func (i *invoiceRegistry) AddInvoice(invoice *channeldb.Invoice) error {
// daemon add/forward HTLCs are able to obtain the proper preimage required for
// redemption in the case that we're the final destination. We also return the
// addIndex of the newly created invoice which monotonically increases for each
// new invoice added.
func (i *invoiceRegistry) AddInvoice(invoice *channeldb.Invoice) (uint64, error) {
i.Lock()
defer i.Unlock()
ltndLog.Debugf("Adding invoice %v", newLogClosure(func() string {
return spew.Sdump(invoice)
}))
// TODO(roasbeef): also check in memory for quick lookups/settles?
return i.cdb.AddInvoice(invoice)
addIndex, err := i.cdb.AddInvoice(invoice)
if err != nil {
return 0, err
}
// TODO(roasbeef): re-enable?
//go i.notifyClients(invoice, false)
// Now that we've added the invoice, we'll send dispatch a message to
// notify the clients of this new invoice.
i.notifyClients(invoice, false)
return addIndex, nil
}
// LookupInvoice looks up an invoice by its payment hash (R-Hash), if found
@ -107,12 +312,12 @@ func (i *invoiceRegistry) LookupInvoice(rHash chainhash.Hash) (channeldb.Invoice
// First check the in-memory debug invoice index to see if this is an
// existing invoice added for debugging.
i.RLock()
invoice, ok := i.debugInvoices[rHash]
debugInv, ok := i.debugInvoices[rHash]
i.RUnlock()
// If found, then simply return the invoice directly.
if ok {
return *invoice, 0, nil
return *debugInv, 0, nil
}
// Otherwise, we'll check the database to see if there's an existing
@ -129,46 +334,38 @@ func (i *invoiceRegistry) LookupInvoice(rHash chainhash.Hash) (channeldb.Invoice
return channeldb.Invoice{}, 0, err
}
return *invoice, uint32(payReq.MinFinalCLTVExpiry()), nil
return invoice, uint32(payReq.MinFinalCLTVExpiry()), nil
}
// SettleInvoice attempts to mark an invoice as settled. If the invoice is a
// debug invoice, then this method is a noop as debug invoices are never fully
// settled.
func (i *invoiceRegistry) SettleInvoice(rHash chainhash.Hash) error {
func (i *invoiceRegistry) SettleInvoice(rHash chainhash.Hash,
amtPaid lnwire.MilliSatoshi) error {
i.Lock()
defer i.Unlock()
ltndLog.Debugf("Settling invoice %x", rHash[:])
// First check the in-memory debug invoice index to see if this is an
// existing invoice added for debugging.
i.RLock()
if _, ok := i.debugInvoices[rHash]; ok {
// Debug invoices are never fully settled, so we simply return
// immediately in this case.
i.RUnlock()
return nil
}
i.RUnlock()
// If this isn't a debug invoice, then we'll attempt to settle an
// invoice matching this rHash on disk (if one exists).
if err := i.cdb.SettleInvoice(rHash); err != nil {
invoice, err := i.cdb.SettleInvoice(rHash, amtPaid)
if err != nil {
return err
}
// Launch a new goroutine to notify any/all registered invoice
// notification clients.
go func() {
invoice, err := i.cdb.LookupInvoice(rHash)
if err != nil {
ltndLog.Errorf("unable to find invoice: %v", err)
return
}
ltndLog.Infof("Payment received: %v", spew.Sdump(invoice))
ltndLog.Infof("Payment received: %v", spew.Sdump(invoice))
i.notifyClients(invoice, true)
}()
i.notifyClients(invoice, true)
return nil
}
@ -176,20 +373,14 @@ func (i *invoiceRegistry) SettleInvoice(rHash chainhash.Hash) error {
// notifyClients notifies all currently registered invoice notification clients
// of a newly added/settled invoice.
func (i *invoiceRegistry) notifyClients(invoice *channeldb.Invoice, settle bool) {
i.clientMtx.Lock()
defer i.clientMtx.Unlock()
event := &invoiceEvent{
isSettle: settle,
invoice: invoice,
}
for _, client := range i.notificationClients {
var eventChan chan *channeldb.Invoice
if settle {
eventChan = client.SettledInvoices
} else {
eventChan = client.NewInvoices
}
go func() {
eventChan <- invoice
}()
select {
case i.invoiceEvents <- event:
case <-i.quit:
}
}
@ -199,36 +390,127 @@ func (i *invoiceRegistry) notifyClients(invoice *channeldb.Invoice, settle bool)
// invoice, a copy of the invoice will be sent over the SettledInvoices
// channel.
type invoiceSubscription struct {
NewInvoices chan *channeldb.Invoice
cancelled uint32 // To be used atomically.
// NewInvoices is a channel that we'll use to send all newly created
// invoices with an invoice index greater than the specified
// StartingInvoiceIndex field.
NewInvoices chan *channeldb.Invoice
// SettledInvoices is a channel that we'll use to send all setted
// invoices with an invoices index greater than the specified
// StartingInvoiceIndex field.
SettledInvoices chan *channeldb.Invoice
// addIndex is the highest add index the caller knows of. We'll use
// this information to send out an event backlog to the notifications
// subscriber. Any new add events with an index greater than this will
// be dispatched before any new notifications are sent out.
addIndex uint64
// settleIndex is the highest settle index the caller knows of. We'll
// use this information to send out an event backlog to the
// notifications subscriber. Any new settle events with an index
// greater than this will be dispatched before any new notifications
// are sent out.
settleIndex uint64
ntfnQueue *chainntnfs.ConcurrentQueue
id uint32
inv *invoiceRegistry
id uint32
cancelChan chan struct{}
wg sync.WaitGroup
}
// Cancel unregisters the invoiceSubscription, freeing any previously allocated
// resources.
func (i *invoiceSubscription) Cancel() {
i.inv.clientMtx.Lock()
delete(i.inv.notificationClients, i.id)
i.inv.clientMtx.Unlock()
if !atomic.CompareAndSwapUint32(&i.cancelled, 0, 1) {
return
}
select {
case i.inv.subscriptionCancels <- i.id:
case <-i.inv.quit:
}
i.ntfnQueue.Stop()
close(i.cancelChan)
i.wg.Wait()
}
// SubscribeNotifications returns an invoiceSubscription which allows the
// caller to receive async notifications when any invoices are settled or
// added.
func (i *invoiceRegistry) SubscribeNotifications() *invoiceSubscription {
// added. The invoiceIndex parameter is a streaming "checkpoint". We'll start
// by first sending out all new events with an invoice index _greater_ than
// this value. Afterwards, we'll send out real-time notifications.
func (i *invoiceRegistry) SubscribeNotifications(addIndex, settleIndex uint64) *invoiceSubscription {
client := &invoiceSubscription{
NewInvoices: make(chan *channeldb.Invoice),
SettledInvoices: make(chan *channeldb.Invoice),
addIndex: addIndex,
settleIndex: settleIndex,
inv: i,
ntfnQueue: chainntnfs.NewConcurrentQueue(20),
cancelChan: make(chan struct{}),
}
client.ntfnQueue.Start()
i.clientMtx.Lock()
i.notificationClients[i.nextClientID] = client
client.id = i.nextClientID
i.nextClientID++
i.clientMtx.Unlock()
// Before we register this new invoice subscription, we'll launch a new
// goroutine that will proxy all notifications appended to the end of
// the concurrent queue to the two client-side channels the caller will
// feed off of.
i.wg.Add(1)
go func() {
defer i.wg.Done()
for {
select {
// A new invoice event has been sent by the
// invoiceRegistry! We'll figure out if this is an add
// event or a settle event, then dispatch the event to
// the client.
case ntfn := <-client.ntfnQueue.ChanOut():
invoiceEvent := ntfn.(*invoiceEvent)
targetChan := client.NewInvoices
if invoiceEvent.isSettle {
targetChan = client.SettledInvoices
}
select {
case targetChan <- invoiceEvent.invoice:
case <-client.cancelChan:
return
case <-i.quit:
return
}
case <-client.cancelChan:
return
case <-i.quit:
return
}
}
}()
select {
case i.newSubscriptions <- client:
case <-i.quit:
}
return client
}

@ -19,6 +19,7 @@ import (
"reflect"
"crypto/rand"
"crypto/sha256"
prand "math/rand"
"github.com/btcsuite/btclog"
@ -3452,10 +3453,11 @@ func testSendToRouteErrorPropagation(net *lntest.NetworkHarness, t *harnessTest)
t.Fatalf("alice didn't advertise her channel: %v", err)
}
// Create a new nodes (Carol and Charlie), load her with some funds, then establish
// a connection between Carol and Charlie with a channel that has
// identical capacity to the one created above.Then we will get route via queryroutes call
// which will be fake route for Alice -> Bob graph.
// Create a new nodes (Carol and Charlie), load her with some funds,
// then establish a connection between Carol and Charlie with a channel
// that has identical capacity to the one created above.Then we will
// get route via queryroutes call which will be fake route for Alice ->
// Bob graph.
//
// The network topology should now look like: Alice -> Bob; Carol -> Charlie.
carol, err := net.NewNode("Carol", nil)
@ -4298,15 +4300,18 @@ func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) {
if err != nil {
t.Fatalf("unable to add invoice: %v", err)
}
lastAddIndex := invoiceResp.AddIndex
// Create a new invoice subscription client for Bob, the notification
// should be dispatched shortly below.
req := &lnrpc.InvoiceSubscription{}
bobInvoiceSubscription, err := net.Bob.SubscribeInvoices(ctxb, req)
ctx, cancelInvoiceSubscription := context.WithCancel(context.Background())
bobInvoiceSubscription, err := net.Bob.SubscribeInvoices(ctx, req)
if err != nil {
t.Fatalf("unable to subscribe to bob's invoice updates: %v", err)
}
var settleIndex uint64
quit := make(chan struct{})
updateSent := make(chan struct{})
go func() {
@ -4336,6 +4341,12 @@ func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) {
invoice.RPreimage, invoiceUpdate.RPreimage)
}
if invoiceUpdate.SettleIndex == 0 {
t.Fatalf("invoice should have settle index")
}
settleIndex = invoiceUpdate.SettleIndex
close(updateSent)
}()
@ -4373,6 +4384,126 @@ func testInvoiceSubscriptions(net *lntest.NetworkHarness, t *harnessTest) {
case <-updateSent: // Fall through on success
}
// With the base case working, we'll now cancel Bob's current
// subscription in order to exercise the backlog fill behavior.
cancelInvoiceSubscription()
// We'll now add 3 more invoices to Bob's invoice registry.
const numInvoices = 3
newInvoices := make([]*lnrpc.Invoice, numInvoices)
payReqs := make([]string, numInvoices)
for i := 0; i < numInvoices; i++ {
preimage := bytes.Repeat([]byte{byte(90 + 1 + i)}, 32)
invoice := &lnrpc.Invoice{
Memo: "testing",
RPreimage: preimage,
Value: paymentAmt,
}
resp, err := net.Bob.AddInvoice(ctxb, invoice)
if err != nil {
t.Fatalf("unable to add invoice: %v", err)
}
newInvoices[i] = invoice
payReqs[i] = resp.PaymentRequest
}
// Now that the set of invoices has been added, we'll re-register for
// streaming invoice notifications for Bob, this time specifying the
// add invoice of the last prior invoice.
req = &lnrpc.InvoiceSubscription{
AddIndex: lastAddIndex,
}
ctx, cancelInvoiceSubscription = context.WithCancel(context.Background())
bobInvoiceSubscription, err = net.Bob.SubscribeInvoices(ctx, req)
if err != nil {
t.Fatalf("unable to subscribe to bob's invoice updates: %v", err)
}
// Since we specified a value of the prior add index above, we should
// now immediately get the invoices we just added as we should get the
// backlog of notifications.
for i := 0; i < numInvoices; i++ {
invoiceUpdate, err := bobInvoiceSubscription.Recv()
if err != nil {
t.Fatalf("unable to receive subscription")
}
// We should now get the ith invoice we added, as they should
// be returned in order.
if invoiceUpdate.Settled {
t.Fatalf("should have only received add events")
}
originalInvoice := newInvoices[i]
rHash := sha256.Sum256(originalInvoice.RPreimage[:])
if !bytes.Equal(invoiceUpdate.RHash, rHash[:]) {
t.Fatalf("invoices have mismatched payment hashes: "+
"expected %x, got %x", rHash[:],
invoiceUpdate.RHash)
}
}
cancelInvoiceSubscription()
// We'll now have Bob settle out the remainder of these invoices so we
// can test that all settled invoices are properly notified.
ctxt, _ = context.WithTimeout(ctxb, timeout)
err = completePaymentRequests(
ctxt, net.Alice, payReqs, true,
)
if err != nil {
t.Fatalf("unable to send payment: %v", err)
}
// With the set of invoices paid, we'll now cancel the old
// subscription, and create a new one for Bob, this time using the
// settle index to obtain the backlog of settled invoices.
req = &lnrpc.InvoiceSubscription{
SettleIndex: settleIndex,
}
ctx, cancelInvoiceSubscription = context.WithCancel(context.Background())
bobInvoiceSubscription, err = net.Bob.SubscribeInvoices(ctx, req)
if err != nil {
t.Fatalf("unable to subscribe to bob's invoice updates: %v", err)
}
defer cancelInvoiceSubscription()
// As we specified the index of the past settle index, we should now
// receive notifications for the three HTLCs that we just settled. As
// the order that the HTLCs will be settled in is partially randomized,
// we'll use a map to assert that the proper set has been settled.
settledInvoices := make(map[[32]byte]struct{})
for _, invoice := range newInvoices {
rHash := sha256.Sum256(invoice.RPreimage[:])
settledInvoices[rHash] = struct{}{}
}
for i := 0; i < numInvoices; i++ {
invoiceUpdate, err := bobInvoiceSubscription.Recv()
if err != nil {
t.Fatalf("unable to receive subscription")
}
// We should now get the ith invoice we added, as they should
// be returned in order.
if !invoiceUpdate.Settled {
t.Fatalf("should have only received settle events")
}
var rHash [32]byte
copy(rHash[:], invoiceUpdate.RHash)
if _, ok := settledInvoices[rHash]; !ok {
t.Fatalf("unknown invoice settled: %x", rHash)
}
delete(settledInvoices, rHash)
}
// At this point, all the invoices should be fully settled.
if len(settledInvoices) != 0 {
t.Fatalf("not all invoices settled")
}
ctxt, _ = context.WithTimeout(ctxb, timeout)
closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false)
}
@ -5986,7 +6117,8 @@ func subscribeGraphNotifications(t *harnessTest, ctxb context.Context,
// We'll first start by establishing a notification client which will
// send us notifications upon detected changes in the channel graph.
req := &lnrpc.GraphTopologySubscription{}
topologyClient, err := node.SubscribeChannelGraph(ctxb, req)
ctx, cancelFunc := context.WithCancel(context.Background())
topologyClient, err := node.SubscribeChannelGraph(ctx, req)
if err != nil {
t.Fatalf("unable to create topology client: %v", err)
}
@ -5997,6 +6129,8 @@ func subscribeGraphNotifications(t *harnessTest, ctxb context.Context,
graphUpdates := make(chan *lnrpc.GraphTopologyUpdate, 20)
go func() {
for {
defer cancelFunc()
select {
case <-quit:
return

@ -518,7 +518,9 @@ func (m *FeeLimit) String() string { return proto.CompactTextString(m
func (*FeeLimit) ProtoMessage() {}
func (*FeeLimit) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
type isFeeLimit_Limit interface{ isFeeLimit_Limit() }
type isFeeLimit_Limit interface {
isFeeLimit_Limit()
}
type FeeLimit_Fixed struct {
Fixed int64 `protobuf:"varint,1,opt,name=fixed,oneof"`
@ -785,7 +787,9 @@ func (m *ChannelPoint) String() string { return proto.CompactTextStri
func (*ChannelPoint) ProtoMessage() {}
func (*ChannelPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} }
type isChannelPoint_FundingTxid interface{ isChannelPoint_FundingTxid() }
type isChannelPoint_FundingTxid interface {
isChannelPoint_FundingTxid()
}
type ChannelPoint_FundingTxidBytes struct {
FundingTxidBytes []byte `protobuf:"bytes,1,opt,name=funding_txid_bytes,proto3,oneof"`
@ -2034,7 +2038,9 @@ func (m *CloseStatusUpdate) String() string { return proto.CompactTex
func (*CloseStatusUpdate) ProtoMessage() {}
func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{48} }
type isCloseStatusUpdate_Update interface{ isCloseStatusUpdate_Update() }
type isCloseStatusUpdate_Update interface {
isCloseStatusUpdate_Update()
}
type CloseStatusUpdate_ClosePending struct {
ClosePending *PendingUpdate `protobuf:"bytes,1,opt,name=close_pending,oneof"`
@ -2297,7 +2303,9 @@ func (m *OpenStatusUpdate) String() string { return proto.CompactText
func (*OpenStatusUpdate) ProtoMessage() {}
func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{51} }
type isOpenStatusUpdate_Update interface{ isOpenStatusUpdate_Update() }
type isOpenStatusUpdate_Update interface {
isOpenStatusUpdate_Update()
}
type OpenStatusUpdate_ChanPending struct {
ChanPending *PendingUpdate `protobuf:"bytes,1,opt,name=chan_pending,oneof"`
@ -3834,6 +3842,26 @@ type Invoice struct {
RouteHints []*RouteHint `protobuf:"bytes,14,rep,name=route_hints" json:"route_hints,omitempty"`
// / Whether this invoice should include routing hints for private channels.
Private bool `protobuf:"varint,15,opt,name=private" json:"private,omitempty"`
// *
// The "add" index of this invoice. Each newly created invoice will increment
// this index making it monotonically increasing. Callers to the
// SubscribeInvoices call can use this to instantly get notified of all added
// invoices with an add_index greater than this one.
AddIndex uint64 `protobuf:"varint,16,opt,name=add_index" json:"add_index,omitempty"`
// *
// The "settle" index of this invoice. Each newly settled invoice will
// increment this index making it monotonically increasing. Callers to the
// SubscribeInvoices call can use this to instantly get notified of all
// settled invoices with an settle_index greater than this one.
SettleIndex uint64 `protobuf:"varint,17,opt,name=settle_index" json:"settle_index,omitempty"`
// *
// The amount that was accepted for this invoice. This will ONLY be set if
// this invoice has been settled. We provide this field as if the invoice was
// created with a zero value, then we need to record what amount was
// ultimately accepted. Additionally, it's possible that the sender paid MORE
// that was specified in the original invoice. So we'll record that here as
// well.
AmtPaid int64 `protobuf:"varint,18,opt,name=amt_paid" json:"amt_paid,omitempty"`
}
func (m *Invoice) Reset() { *m = Invoice{} }
@ -3946,6 +3974,27 @@ func (m *Invoice) GetPrivate() bool {
return false
}
func (m *Invoice) GetAddIndex() uint64 {
if m != nil {
return m.AddIndex
}
return 0
}
func (m *Invoice) GetSettleIndex() uint64 {
if m != nil {
return m.SettleIndex
}
return 0
}
func (m *Invoice) GetAmtPaid() int64 {
if m != nil {
return m.AmtPaid
}
return 0
}
type AddInvoiceResponse struct {
RHash []byte `protobuf:"bytes,1,opt,name=r_hash,proto3" json:"r_hash,omitempty"`
// *
@ -3953,6 +4002,12 @@ type AddInvoiceResponse struct {
// details of the invoice, the sender has all the data necessary to send a
// payment to the recipient.
PaymentRequest string `protobuf:"bytes,2,opt,name=payment_request" json:"payment_request,omitempty"`
// *
// The "add" index of this invoice. Each newly created invoice will increment
// this index making it monotonically increasing. Callers to the
// SubscribeInvoices call can use this to instantly get notified of all added
// invoices with an add_index greater than this one.
AddIndex uint64 `protobuf:"varint,16,opt,name=add_index" json:"add_index,omitempty"`
}
func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} }
@ -3974,6 +4029,13 @@ func (m *AddInvoiceResponse) GetPaymentRequest() string {
return ""
}
func (m *AddInvoiceResponse) GetAddIndex() uint64 {
if m != nil {
return m.AddIndex
}
return 0
}
type PaymentHash struct {
// *
// The hex-encoded payment hash of the invoice to be looked up. The passed
@ -4036,6 +4098,18 @@ func (m *ListInvoiceResponse) GetInvoices() []*Invoice {
}
type InvoiceSubscription struct {
// *
// If specified (non-zero), then we'll first start by sending out
// notifications for all added indexes with an add_index greater than this
// value. This allows callers to catch up on any events they missed while they
// weren't connected to the streaming RPC.
AddIndex uint64 `protobuf:"varint,1,opt,name=add_index" json:"add_index,omitempty"`
// *
// If specified (non-zero), then we'll first start by sending out
// notifications for all settled indexes with an settle_index greater than
// this value. This allows callers to catch up on any events they missed while
// they weren't connected to the streaming RPC.
SettleIndex uint64 `protobuf:"varint,2,opt,name=settle_index" json:"settle_index,omitempty"`
}
func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} }
@ -4043,6 +4117,20 @@ func (m *InvoiceSubscription) String() string { return proto.CompactT
func (*InvoiceSubscription) ProtoMessage() {}
func (*InvoiceSubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{88} }
func (m *InvoiceSubscription) GetAddIndex() uint64 {
if m != nil {
return m.AddIndex
}
return 0
}
func (m *InvoiceSubscription) GetSettleIndex() uint64 {
if m != nil {
return m.SettleIndex
}
return 0
}
type Payment struct {
// / The payment hash
PaymentHash string `protobuf:"bytes,1,opt,name=payment_hash" json:"payment_hash,omitempty"`
@ -4405,7 +4493,9 @@ func (m *PolicyUpdateRequest) String() string { return proto.CompactT
func (*PolicyUpdateRequest) ProtoMessage() {}
func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{101} }
type isPolicyUpdateRequest_Scope interface{ isPolicyUpdateRequest_Scope() }
type isPolicyUpdateRequest_Scope interface {
isPolicyUpdateRequest_Scope()
}
type PolicyUpdateRequest_Global struct {
Global bool `protobuf:"varint,1,opt,name=global,oneof"`
@ -5158,7 +5248,14 @@ type LightningClient interface {
LookupInvoice(ctx context.Context, in *PaymentHash, opts ...grpc.CallOption) (*Invoice, error)
// *
// SubscribeInvoices returns a uni-directional stream (sever -> client) for
// notifying the client of newly added/settled invoices.
// notifying the client of newly added/settled invoices. The caller can
// optionally specify the add_index and/or the settle_index. If the add_index
// is specified, then we'll first start by sending add invoice events for all
// invoices with an add_index greater than the specified value. If the
// settle_index is specified, the next, we'll send out all settle events for
// invoices with a settle_index greater than the specified value. One or both
// of these fields can be set. If no fields are set, then we'll only send out
// the latest add/settle events.
SubscribeInvoices(ctx context.Context, in *InvoiceSubscription, opts ...grpc.CallOption) (Lightning_SubscribeInvoicesClient, error)
// * lncli: `decodepayreq`
// DecodePayReq takes an encoded payment request string and attempts to decode
@ -5928,7 +6025,14 @@ type LightningServer interface {
LookupInvoice(context.Context, *PaymentHash) (*Invoice, error)
// *
// SubscribeInvoices returns a uni-directional stream (sever -> client) for
// notifying the client of newly added/settled invoices.
// notifying the client of newly added/settled invoices. The caller can
// optionally specify the add_index and/or the settle_index. If the add_index
// is specified, then we'll first start by sending add invoice events for all
// invoices with an add_index greater than the specified value. If the
// settle_index is specified, the next, we'll send out all settle events for
// invoices with a settle_index greater than the specified value. One or both
// of these fields can be set. If no fields are set, then we'll only send out
// the latest add/settle events.
SubscribeInvoices(*InvoiceSubscription, Lightning_SubscribeInvoicesServer) error
// * lncli: `decodepayreq`
// DecodePayReq takes an encoded payment request string and attempts to decode
@ -6991,391 +7095,394 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 6171 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5c, 0x4f, 0x8c, 0x1c, 0xd9,
0x59, 0x77, 0x75, 0xf7, 0xfc, 0xe9, 0xaf, 0x7b, 0x7a, 0x7a, 0xde, 0x8c, 0xc7, 0xed, 0xde, 0x5d,
0xaf, 0xb7, 0x62, 0xad, 0x9d, 0x61, 0xb1, 0xbd, 0x93, 0x64, 0xd9, 0xec, 0x42, 0x82, 0x3d, 0x1e,
0x7b, 0x9c, 0xcc, 0xda, 0x93, 0x1a, 0x3b, 0x86, 0x04, 0xd4, 0xa9, 0xe9, 0x7e, 0xd3, 0x53, 0x71,
0x77, 0x55, 0xa7, 0xaa, 0x7a, 0xc6, 0x9d, 0xc5, 0x52, 0xf8, 0x23, 0x4e, 0x44, 0x08, 0xc1, 0x25,
0x48, 0x08, 0x29, 0x48, 0x28, 0x1c, 0x38, 0xc2, 0x25, 0x20, 0x71, 0xe0, 0x84, 0x84, 0x38, 0xe4,
0x14, 0x71, 0x04, 0x0e, 0x10, 0x71, 0x41, 0xe2, 0x8a, 0xd0, 0xf7, 0xbd, 0x3f, 0xf5, 0x5e, 0x55,
0xb5, 0xed, 0xfc, 0x81, 0x5b, 0xbf, 0xdf, 0xfb, 0xea, 0xfd, 0xfd, 0xfe, 0xbd, 0xef, 0x7d, 0xaf,
0xa1, 0x1e, 0x4f, 0xfa, 0xd7, 0x27, 0x71, 0x94, 0x46, 0x6c, 0x61, 0x14, 0xc6, 0x93, 0x7e, 0xf7,
0xf5, 0x61, 0x14, 0x0d, 0x47, 0xfc, 0x86, 0x3f, 0x09, 0x6e, 0xf8, 0x61, 0x18, 0xa5, 0x7e, 0x1a,
0x44, 0x61, 0x22, 0x88, 0xdc, 0xaf, 0x41, 0xeb, 0x1e, 0x0f, 0x0f, 0x39, 0x1f, 0x78, 0xfc, 0x1b,
0x53, 0x9e, 0xa4, 0xec, 0xe7, 0x60, 0xcd, 0xe7, 0xdf, 0xe4, 0x7c, 0xd0, 0x9b, 0xf8, 0x49, 0x32,
0x39, 0x89, 0xfd, 0x84, 0x77, 0x9c, 0xcb, 0xce, 0xb5, 0xa6, 0xd7, 0x16, 0x15, 0x07, 0x1a, 0x67,
0x6f, 0x41, 0x33, 0x41, 0x52, 0x1e, 0xa6, 0x71, 0x34, 0x99, 0x75, 0x2a, 0x44, 0xd7, 0x40, 0x6c,
0x57, 0x40, 0xee, 0x08, 0x56, 0x75, 0x0f, 0xc9, 0x24, 0x0a, 0x13, 0xce, 0x6e, 0xc2, 0x46, 0x3f,
0x98, 0x9c, 0xf0, 0xb8, 0x47, 0x1f, 0x8f, 0x43, 0x3e, 0x8e, 0xc2, 0xa0, 0xdf, 0x71, 0x2e, 0x57,
0xaf, 0xd5, 0x3d, 0x26, 0xea, 0xf0, 0x8b, 0x8f, 0x64, 0x0d, 0xbb, 0x0a, 0xab, 0x3c, 0x14, 0x38,
0x1f, 0xd0, 0x57, 0xb2, 0xab, 0x56, 0x06, 0xe3, 0x07, 0xee, 0xdf, 0x3b, 0xb0, 0x76, 0x3f, 0x0c,
0xd2, 0x27, 0xfe, 0x68, 0xc4, 0x53, 0x35, 0xa7, 0xab, 0xb0, 0x7a, 0x46, 0x00, 0xcd, 0xe9, 0x2c,
0x8a, 0x07, 0x72, 0x46, 0x2d, 0x01, 0x1f, 0x48, 0x74, 0xee, 0xc8, 0x2a, 0x73, 0x47, 0x56, 0xba,
0x5c, 0xd5, 0x39, 0xcb, 0x75, 0x15, 0x56, 0x63, 0xde, 0x8f, 0x4e, 0x79, 0x3c, 0xeb, 0x9d, 0x05,
0xe1, 0x20, 0x3a, 0xeb, 0xd4, 0x2e, 0x3b, 0xd7, 0x16, 0xbc, 0x96, 0x82, 0x9f, 0x10, 0xea, 0x6e,
0x00, 0x33, 0x67, 0x21, 0xd6, 0xcd, 0x1d, 0xc2, 0xfa, 0xe3, 0x70, 0x14, 0xf5, 0x9f, 0xfe, 0x84,
0xb3, 0x2b, 0xe9, 0xbe, 0x52, 0xda, 0xfd, 0x26, 0x6c, 0xd8, 0x1d, 0xc9, 0x01, 0x70, 0x38, 0xbf,
0x73, 0xe2, 0x87, 0x43, 0xae, 0x9a, 0x54, 0x43, 0xf8, 0x24, 0xb4, 0xfb, 0xd3, 0x38, 0xe6, 0x61,
0x61, 0x0c, 0xab, 0x12, 0xd7, 0x83, 0x78, 0x0b, 0x9a, 0x21, 0x3f, 0xcb, 0xc8, 0x24, 0xcb, 0x84,
0xfc, 0x4c, 0x91, 0xb8, 0x1d, 0xd8, 0xcc, 0x77, 0x23, 0x07, 0xf0, 0x9d, 0x0a, 0x34, 0x1e, 0xc5,
0x7e, 0x98, 0xf8, 0x7d, 0xe4, 0x62, 0xd6, 0x81, 0xa5, 0xf4, 0x59, 0xef, 0xc4, 0x4f, 0x4e, 0xa8,
0xbb, 0xba, 0xa7, 0x8a, 0x6c, 0x13, 0x16, 0xfd, 0x71, 0x34, 0x0d, 0x53, 0xea, 0xa0, 0xea, 0xc9,
0x12, 0x7b, 0x07, 0xd6, 0xc2, 0xe9, 0xb8, 0xd7, 0x8f, 0xc2, 0xe3, 0x20, 0x1e, 0x0b, 0x59, 0xa0,
0xfd, 0x5a, 0xf0, 0x8a, 0x15, 0xec, 0x12, 0xc0, 0x11, 0xae, 0x83, 0xe8, 0xa2, 0x46, 0x5d, 0x18,
0x08, 0x73, 0xa1, 0x29, 0x4b, 0x3c, 0x18, 0x9e, 0xa4, 0x9d, 0x05, 0x6a, 0xc8, 0xc2, 0xb0, 0x8d,
0x34, 0x18, 0xf3, 0x5e, 0x92, 0xfa, 0xe3, 0x49, 0x67, 0x91, 0x46, 0x63, 0x20, 0x54, 0x1f, 0xa5,
0xfe, 0xa8, 0x77, 0xcc, 0x79, 0xd2, 0x59, 0x92, 0xf5, 0x1a, 0x61, 0x6f, 0x43, 0x6b, 0xc0, 0x93,
0xb4, 0xe7, 0x0f, 0x06, 0x31, 0x4f, 0x12, 0x9e, 0x74, 0x96, 0x89, 0x1b, 0x73, 0x28, 0xae, 0xda,
0x3d, 0x9e, 0x1a, 0xab, 0x93, 0xc8, 0xdd, 0x71, 0xf7, 0x81, 0x19, 0xf0, 0x1d, 0x9e, 0xfa, 0xc1,
0x28, 0x61, 0xef, 0x41, 0x33, 0x35, 0x88, 0x49, 0xfa, 0x1a, 0xdb, 0xec, 0x3a, 0xa9, 0x8d, 0xeb,
0xc6, 0x07, 0x9e, 0x45, 0xe7, 0xde, 0x83, 0xe5, 0xbb, 0x9c, 0xef, 0x07, 0xe3, 0x20, 0x65, 0x9b,
0xb0, 0x70, 0x1c, 0x3c, 0xe3, 0x62, 0xb3, 0xab, 0x7b, 0xe7, 0x3c, 0x51, 0x64, 0x5d, 0x58, 0x9a,
0xf0, 0xb8, 0xcf, 0xd5, 0xf2, 0xef, 0x9d, 0xf3, 0x14, 0x70, 0x7b, 0x09, 0x16, 0x46, 0xf8, 0xb1,
0xfb, 0xbd, 0x0a, 0x34, 0x0e, 0x79, 0xa8, 0x99, 0x88, 0x41, 0x0d, 0xa7, 0x24, 0x19, 0x87, 0x7e,
0xb3, 0x37, 0xa1, 0x41, 0xd3, 0x4c, 0xd2, 0x38, 0x08, 0x87, 0xd4, 0x58, 0xdd, 0x03, 0x84, 0x0e,
0x09, 0x61, 0x6d, 0xa8, 0xfa, 0xe3, 0x94, 0x76, 0xb0, 0xea, 0xe1, 0x4f, 0x64, 0xb0, 0x89, 0x3f,
0x1b, 0x23, 0x2f, 0xea, 0x5d, 0x6b, 0x7a, 0x0d, 0x89, 0xed, 0xe1, 0xb6, 0x5d, 0x87, 0x75, 0x93,
0x44, 0xb5, 0xbe, 0x40, 0xad, 0xaf, 0x19, 0x94, 0xb2, 0x93, 0xab, 0xb0, 0xaa, 0xe8, 0x63, 0x31,
0x58, 0xda, 0xc7, 0xba, 0xd7, 0x92, 0xb0, 0x9a, 0xc2, 0x35, 0x68, 0x1f, 0x07, 0xa1, 0x3f, 0xea,
0xf5, 0x47, 0xe9, 0x69, 0x6f, 0xc0, 0x47, 0xa9, 0x4f, 0x3b, 0xba, 0xe0, 0xb5, 0x08, 0xdf, 0x19,
0xa5, 0xa7, 0x77, 0x10, 0x65, 0xef, 0x40, 0xfd, 0x98, 0xf3, 0x1e, 0xad, 0x44, 0x67, 0xf9, 0xb2,
0x73, 0xad, 0xb1, 0xbd, 0x2a, 0x97, 0x5e, 0xad, 0xae, 0xb7, 0x7c, 0x2c, 0x7f, 0xb9, 0x7f, 0xe4,
0x40, 0x53, 0x2c, 0x95, 0x54, 0xa1, 0x57, 0x60, 0x45, 0x8d, 0x88, 0xc7, 0x71, 0x14, 0x4b, 0xf6,
0xb7, 0x41, 0xb6, 0x05, 0x6d, 0x05, 0x4c, 0x62, 0x1e, 0x8c, 0xfd, 0x21, 0x97, 0xf2, 0x56, 0xc0,
0xd9, 0x76, 0xd6, 0x62, 0x1c, 0x4d, 0x53, 0xa1, 0xc4, 0x1a, 0xdb, 0x4d, 0x39, 0x28, 0x0f, 0x31,
0xcf, 0x26, 0x71, 0xbf, 0xed, 0x00, 0xc3, 0x61, 0x3d, 0x8a, 0x44, 0xb5, 0x5c, 0x85, 0xfc, 0x0e,
0x38, 0xaf, 0xbc, 0x03, 0x95, 0x79, 0x3b, 0x70, 0x05, 0x16, 0xa9, 0x4b, 0x94, 0xd5, 0x6a, 0x61,
0x58, 0xb2, 0xce, 0xfd, 0xae, 0x03, 0x4d, 0xd4, 0x1c, 0x21, 0x1f, 0x1d, 0x44, 0x41, 0x98, 0xb2,
0x9b, 0xc0, 0x8e, 0xa7, 0xe1, 0x20, 0x08, 0x87, 0xbd, 0xf4, 0x59, 0x30, 0xe8, 0x1d, 0xcd, 0xb0,
0x09, 0x1a, 0xcf, 0xde, 0x39, 0xaf, 0xa4, 0x8e, 0xbd, 0x03, 0x6d, 0x0b, 0x4d, 0xd2, 0x58, 0x8c,
0x6a, 0xef, 0x9c, 0x57, 0xa8, 0x41, 0xf9, 0x8f, 0xa6, 0xe9, 0x64, 0x9a, 0xf6, 0x82, 0x70, 0xc0,
0x9f, 0xd1, 0x9a, 0xad, 0x78, 0x16, 0x76, 0xbb, 0x05, 0x4d, 0xf3, 0x3b, 0xf7, 0x73, 0xd0, 0xde,
0x47, 0xc5, 0x10, 0x06, 0xe1, 0xf0, 0x96, 0x90, 0x5e, 0xd4, 0x56, 0x93, 0xe9, 0xd1, 0x53, 0x3e,
0x93, 0xfb, 0x28, 0x4b, 0x28, 0x12, 0x27, 0x51, 0x92, 0xca, 0x75, 0xa1, 0xdf, 0xee, 0xbf, 0x38,
0xb0, 0x8a, 0x8b, 0xfe, 0x91, 0x1f, 0xce, 0xd4, 0x8a, 0xef, 0x43, 0x13, 0x9b, 0x7a, 0x14, 0xdd,
0x12, 0x3a, 0x4f, 0xc8, 0xf2, 0x35, 0xb9, 0x48, 0x39, 0xea, 0xeb, 0x26, 0x29, 0x9a, 0xe9, 0x99,
0x67, 0x7d, 0x8d, 0x42, 0x97, 0xfa, 0xf1, 0x90, 0xa7, 0xa4, 0x0d, 0xa5, 0x76, 0x04, 0x01, 0xed,
0x44, 0xe1, 0x31, 0xbb, 0x0c, 0xcd, 0xc4, 0x4f, 0x7b, 0x13, 0x1e, 0xd3, 0xaa, 0x91, 0xe0, 0x54,
0x3d, 0x48, 0xfc, 0xf4, 0x80, 0xc7, 0xb7, 0x67, 0x29, 0xef, 0x7e, 0x1e, 0xd6, 0x0a, 0xbd, 0xa0,
0xac, 0x66, 0x53, 0xc4, 0x9f, 0x6c, 0x03, 0x16, 0x4e, 0xfd, 0xd1, 0x94, 0x4b, 0x25, 0x2d, 0x0a,
0x1f, 0x54, 0xde, 0x77, 0xdc, 0xb7, 0xa1, 0x9d, 0x0d, 0x5b, 0x32, 0x3d, 0x83, 0x1a, 0xae, 0xa0,
0x6c, 0x80, 0x7e, 0xbb, 0xbf, 0xe9, 0x08, 0xc2, 0x9d, 0x28, 0xd0, 0x0a, 0x0f, 0x09, 0x51, 0x2f,
0x2a, 0x42, 0xfc, 0x3d, 0xd7, 0x20, 0xfc, 0xf4, 0x93, 0x75, 0xaf, 0xc2, 0x9a, 0x31, 0x84, 0x17,
0x0c, 0xf6, 0xdb, 0x0e, 0xac, 0x3d, 0xe0, 0x67, 0x72, 0xd7, 0xd5, 0x68, 0xdf, 0x87, 0x5a, 0x3a,
0x9b, 0x08, 0x27, 0xab, 0xb5, 0x7d, 0x45, 0x6e, 0x5a, 0x81, 0xee, 0xba, 0x2c, 0x3e, 0x9a, 0x4d,
0xb8, 0x47, 0x5f, 0xb8, 0x9f, 0x83, 0x86, 0x01, 0xb2, 0x0b, 0xb0, 0xfe, 0xe4, 0xfe, 0xa3, 0x07,
0xbb, 0x87, 0x87, 0xbd, 0x83, 0xc7, 0xb7, 0xbf, 0xb8, 0xfb, 0xab, 0xbd, 0xbd, 0x5b, 0x87, 0x7b,
0xed, 0x73, 0x6c, 0x13, 0xd8, 0x83, 0xdd, 0xc3, 0x47, 0xbb, 0x77, 0x2c, 0xdc, 0x71, 0xbb, 0xd0,
0x79, 0xc0, 0xcf, 0x9e, 0x04, 0x69, 0xc8, 0x93, 0xc4, 0xee, 0xcd, 0xbd, 0x0e, 0xcc, 0x1c, 0x82,
0x9c, 0x55, 0x07, 0x96, 0xa4, 0xc5, 0x51, 0x06, 0x57, 0x16, 0xdd, 0xb7, 0x81, 0x1d, 0x06, 0xc3,
0xf0, 0x23, 0x9e, 0x24, 0xfe, 0x50, 0xab, 0x82, 0x36, 0x54, 0xc7, 0xc9, 0x50, 0x6a, 0x00, 0xfc,
0xe9, 0x7e, 0x0a, 0xd6, 0x2d, 0x3a, 0xd9, 0xf0, 0xeb, 0x50, 0x4f, 0x82, 0x61, 0xe8, 0xa7, 0xd3,
0x98, 0xcb, 0xa6, 0x33, 0xc0, 0xbd, 0x0b, 0x1b, 0x5f, 0xe6, 0x71, 0x70, 0x3c, 0x7b, 0x59, 0xf3,
0x76, 0x3b, 0x95, 0x7c, 0x3b, 0xbb, 0x70, 0x3e, 0xd7, 0x8e, 0xec, 0x5e, 0x30, 0xa2, 0xdc, 0xae,
0x65, 0x4f, 0x14, 0x0c, 0xb1, 0xac, 0x98, 0x62, 0xe9, 0x3e, 0x06, 0xb6, 0x13, 0x85, 0x21, 0xef,
0xa7, 0x07, 0x9c, 0xc7, 0x99, 0xe7, 0x9c, 0x71, 0x5d, 0x63, 0xfb, 0x82, 0xdc, 0xc7, 0xbc, 0xac,
0x4b, 0x76, 0x64, 0x50, 0x9b, 0xf0, 0x78, 0x4c, 0x0d, 0x2f, 0x7b, 0xf4, 0xdb, 0x3d, 0x0f, 0xeb,
0x56, 0xb3, 0xd2, 0xe9, 0x79, 0x17, 0xce, 0xdf, 0x09, 0x92, 0x7e, 0xb1, 0xc3, 0x0e, 0x2c, 0x4d,
0xa6, 0x47, 0xbd, 0x4c, 0xa6, 0x54, 0x11, 0x7d, 0x81, 0xfc, 0x27, 0xb2, 0xb1, 0xdf, 0x75, 0xa0,
0xb6, 0xf7, 0x68, 0x7f, 0x87, 0x75, 0x61, 0x39, 0x08, 0xfb, 0xd1, 0x18, 0xd5, 0xae, 0x98, 0xb4,
0x2e, 0xcf, 0x95, 0x95, 0xd7, 0xa1, 0x4e, 0xda, 0x1a, 0xdd, 0x1b, 0xe9, 0xe4, 0x66, 0x00, 0xba,
0x56, 0xfc, 0xd9, 0x24, 0x88, 0xc9, 0x77, 0x52, 0x1e, 0x51, 0x8d, 0x34, 0x62, 0xb1, 0xc2, 0xfd,
0x9f, 0x1a, 0x2c, 0x49, 0x5d, 0x4d, 0xfd, 0xf5, 0xd3, 0xe0, 0x94, 0xcb, 0x91, 0xc8, 0x12, 0x5a,
0xb9, 0x98, 0x8f, 0xa3, 0x94, 0xf7, 0xac, 0x6d, 0xb0, 0x41, 0xa4, 0xea, 0x8b, 0x86, 0x7a, 0x13,
0xd4, 0xfa, 0x34, 0xb2, 0xba, 0x67, 0x83, 0xb8, 0x58, 0x08, 0xf4, 0x82, 0x01, 0x8d, 0xa9, 0xe6,
0xa9, 0x22, 0xae, 0x44, 0xdf, 0x9f, 0xf8, 0xfd, 0x20, 0x9d, 0x49, 0xe1, 0xd6, 0x65, 0x6c, 0x7b,
0x14, 0xf5, 0xfd, 0x51, 0xef, 0xc8, 0x1f, 0xf9, 0x61, 0x9f, 0x4b, 0xff, 0xcd, 0x06, 0xd1, 0x45,
0x93, 0x43, 0x52, 0x64, 0xc2, 0x8d, 0xcb, 0xa1, 0xe8, 0xea, 0xf5, 0xa3, 0xf1, 0x38, 0x48, 0xd1,
0xb3, 0x23, 0xab, 0x5f, 0xf5, 0x0c, 0x84, 0x66, 0x22, 0x4a, 0x67, 0x62, 0xf5, 0xea, 0xa2, 0x37,
0x0b, 0xc4, 0x56, 0xd0, 0x75, 0x40, 0x85, 0xf4, 0xf4, 0xac, 0x03, 0xa2, 0x95, 0x0c, 0xc1, 0x7d,
0x98, 0x86, 0x09, 0x4f, 0xd3, 0x11, 0x1f, 0xe8, 0x01, 0x35, 0x88, 0xac, 0x58, 0xc1, 0x6e, 0xc2,
0xba, 0x70, 0x36, 0x13, 0x3f, 0x8d, 0x92, 0x93, 0x20, 0xe9, 0x25, 0xe8, 0xb6, 0x35, 0x89, 0xbe,
0xac, 0x8a, 0xbd, 0x0f, 0x17, 0x72, 0x70, 0xcc, 0xfb, 0x3c, 0x38, 0xe5, 0x83, 0xce, 0x0a, 0x7d,
0x35, 0xaf, 0x9a, 0x5d, 0x86, 0x06, 0xfa, 0xd8, 0xd3, 0xc9, 0xc0, 0x47, 0x3b, 0xdc, 0xa2, 0x7d,
0x30, 0x21, 0xf6, 0x2e, 0xac, 0x4c, 0xb8, 0x30, 0x96, 0x27, 0xe9, 0xa8, 0x9f, 0x74, 0x56, 0xc9,
0x92, 0x35, 0xa4, 0x30, 0x21, 0xe7, 0x7a, 0x36, 0x05, 0x32, 0x65, 0x3f, 0x21, 0x67, 0xcb, 0x9f,
0x75, 0xda, 0xc4, 0x6e, 0x19, 0x40, 0x32, 0x12, 0x07, 0xa7, 0x7e, 0xca, 0x3b, 0x6b, 0xc4, 0x5b,
0xaa, 0xe8, 0xfe, 0xa9, 0x03, 0xeb, 0xfb, 0x41, 0x92, 0x4a, 0x26, 0xd4, 0xea, 0xf8, 0x4d, 0x68,
0x08, 0xf6, 0xeb, 0x45, 0xe1, 0x68, 0x26, 0x39, 0x12, 0x04, 0xf4, 0x30, 0x1c, 0xcd, 0xd8, 0x27,
0x60, 0x25, 0x08, 0x4d, 0x12, 0x21, 0xc3, 0x4d, 0x05, 0x12, 0xd1, 0x9b, 0xd0, 0x98, 0x4c, 0x8f,
0x46, 0x41, 0x5f, 0x90, 0x54, 0x45, 0x2b, 0x02, 0x22, 0x02, 0x74, 0x92, 0xc4, 0x48, 0x04, 0x45,
0x8d, 0x28, 0x1a, 0x12, 0x43, 0x12, 0xf7, 0x36, 0x6c, 0xd8, 0x03, 0x94, 0xca, 0x6a, 0x0b, 0x96,
0x25, 0x6f, 0x27, 0x9d, 0x06, 0xad, 0x4f, 0x4b, 0xae, 0x8f, 0x24, 0xf5, 0x74, 0xbd, 0xfb, 0xe7,
0x35, 0x58, 0x97, 0xe8, 0xce, 0x28, 0x4a, 0xf8, 0xe1, 0x74, 0x3c, 0xf6, 0xe3, 0x12, 0xa1, 0x71,
0x5e, 0x22, 0x34, 0x15, 0x5b, 0x68, 0x90, 0x95, 0x4f, 0xfc, 0x20, 0x14, 0x1e, 0x9e, 0x90, 0x38,
0x03, 0x61, 0xd7, 0x60, 0xb5, 0x3f, 0x8a, 0x12, 0xe1, 0xf5, 0x98, 0xc7, 0xa7, 0x3c, 0x5c, 0x14,
0xf2, 0x85, 0x32, 0x21, 0x37, 0x85, 0x74, 0x31, 0x27, 0xa4, 0x2e, 0x34, 0xb1, 0x51, 0xae, 0x74,
0xce, 0x92, 0xf0, 0xc2, 0x4c, 0x0c, 0xc7, 0x93, 0x17, 0x09, 0x21, 0x7f, 0xab, 0x65, 0x02, 0x81,
0xa7, 0x33, 0xd4, 0x69, 0x06, 0x75, 0x5d, 0x0a, 0x44, 0xb1, 0x8a, 0xdd, 0x05, 0x10, 0x7d, 0x91,
0x19, 0x07, 0x32, 0xe3, 0x6f, 0xdb, 0x3b, 0x62, 0xae, 0xfd, 0x75, 0x2c, 0x4c, 0x63, 0x4e, 0x86,
0xdc, 0xf8, 0xd2, 0xfd, 0x18, 0x1a, 0x46, 0x15, 0x3b, 0x0f, 0x6b, 0x3b, 0x0f, 0x1f, 0x1e, 0xec,
0x7a, 0xb7, 0x1e, 0xdd, 0xff, 0xf2, 0x6e, 0x6f, 0x67, 0xff, 0xe1, 0xe1, 0x6e, 0xfb, 0x1c, 0xc2,
0xfb, 0x0f, 0x77, 0x6e, 0xed, 0xf7, 0xee, 0x3e, 0xf4, 0x76, 0x14, 0xec, 0xa0, 0x8d, 0xf7, 0x76,
0x3f, 0x7a, 0xf8, 0x68, 0xd7, 0xc2, 0x2b, 0xac, 0x0d, 0xcd, 0xdb, 0xde, 0xee, 0xad, 0x9d, 0x3d,
0x89, 0x54, 0xd9, 0x06, 0xb4, 0xef, 0x3e, 0x7e, 0x70, 0xe7, 0xfe, 0x83, 0x7b, 0xbd, 0x9d, 0x5b,
0x0f, 0x76, 0x76, 0xf7, 0x77, 0xef, 0xb4, 0x6b, 0xee, 0xdf, 0x39, 0x70, 0x9e, 0x46, 0x39, 0xc8,
0x0b, 0xc4, 0x65, 0x68, 0xf4, 0xa3, 0x68, 0xc2, 0x51, 0x7f, 0x6b, 0x15, 0x6d, 0x42, 0xc8, 0xec,
0x42, 0x21, 0x1e, 0x47, 0x71, 0x9f, 0x4b, 0x79, 0x00, 0x82, 0xee, 0x22, 0x82, 0xcc, 0x2e, 0xb7,
0x53, 0x50, 0x08, 0x71, 0x68, 0x08, 0x4c, 0x90, 0x6c, 0xc2, 0xe2, 0x51, 0xcc, 0xfd, 0xfe, 0x89,
0x94, 0x04, 0x59, 0x62, 0x9f, 0xcc, 0x1c, 0xf2, 0x3e, 0xae, 0xf6, 0x88, 0x0f, 0x88, 0x43, 0x96,
0xbd, 0x55, 0x89, 0xef, 0x48, 0xd8, 0x3d, 0x80, 0xcd, 0xfc, 0x0c, 0xa4, 0xc4, 0xbc, 0x67, 0x48,
0x8c, 0xf0, 0x8d, 0xbb, 0xf3, 0xf7, 0xc7, 0x90, 0x9e, 0xff, 0x70, 0xa0, 0x86, 0xe6, 0x73, 0xbe,
0xa9, 0x35, 0x3d, 0xa2, 0xaa, 0xe5, 0x11, 0x51, 0xf0, 0x00, 0xcf, 0x14, 0x42, 0xa1, 0x0a, 0xa3,
0x63, 0x20, 0x59, 0x7d, 0xcc, 0xfb, 0xa7, 0x34, 0x27, 0x5d, 0x8f, 0x08, 0xb2, 0x3c, 0x3a, 0x9e,
0xf4, 0xb5, 0x64, 0x79, 0x55, 0x56, 0x75, 0xf4, 0xe5, 0x52, 0x56, 0x47, 0xdf, 0x75, 0x60, 0x29,
0x08, 0x8f, 0xa2, 0x69, 0x38, 0x20, 0x16, 0x5f, 0xf6, 0x54, 0x11, 0x55, 0xe5, 0x84, 0x44, 0x2f,
0x18, 0x2b, 0x86, 0xce, 0x00, 0x97, 0xe1, 0xc1, 0x24, 0x21, 0x77, 0x41, 0x7b, 0x81, 0xef, 0xc1,
0x9a, 0x81, 0xc9, 0xd5, 0x7c, 0x0b, 0x16, 0x26, 0x08, 0xc8, 0xa5, 0x54, 0xca, 0x99, 0xfc, 0x0c,
0x51, 0xe3, 0xb6, 0xa1, 0x75, 0x8f, 0xa7, 0xf7, 0xc3, 0xe3, 0x48, 0xb5, 0xf4, 0xc3, 0x2a, 0xac,
0x6a, 0x48, 0x36, 0x74, 0x0d, 0x56, 0x83, 0x01, 0x0f, 0xd3, 0x20, 0x9d, 0xf5, 0xac, 0xf3, 0x4f,
0x1e, 0x46, 0xff, 0xcc, 0x1f, 0x05, 0x7e, 0x22, 0x3d, 0x00, 0x51, 0x60, 0xdb, 0xb0, 0x81, 0xc6,
0x43, 0xd9, 0x03, 0xbd, 0xc5, 0xe2, 0x18, 0x56, 0x5a, 0x87, 0xe2, 0x8d, 0xb8, 0xd4, 0xdf, 0xfa,
0x13, 0xe1, 0xa7, 0x94, 0x55, 0xe1, 0xaa, 0x89, 0x96, 0x70, 0xca, 0x0b, 0xc2, 0xc0, 0x68, 0xa0,
0x10, 0x02, 0x5a, 0x14, 0xca, 0x27, 0x1f, 0x02, 0x32, 0xc2, 0x48, 0xcb, 0x85, 0x30, 0x12, 0x2a,
0xa7, 0x59, 0xd8, 0xe7, 0x83, 0x5e, 0x1a, 0xf5, 0x48, 0x89, 0xd2, 0xee, 0x2c, 0x7b, 0x79, 0x98,
0x02, 0x5e, 0x3c, 0x49, 0x43, 0x9e, 0x92, 0x9e, 0x59, 0xf6, 0x54, 0x11, 0xe5, 0x87, 0x48, 0x84,
0x49, 0xa8, 0x7b, 0xb2, 0x84, 0x8e, 0xe6, 0x34, 0x0e, 0x92, 0x4e, 0x93, 0x50, 0xfa, 0xcd, 0x3e,
0x0d, 0xe7, 0x8f, 0x78, 0x92, 0xf6, 0x4e, 0xb8, 0x3f, 0xe0, 0x31, 0xed, 0xbe, 0x88, 0x4e, 0x09,
0xfb, 0x5d, 0x5e, 0x89, 0x7d, 0x9f, 0xf2, 0x38, 0x09, 0xa2, 0x90, 0x2c, 0x77, 0xdd, 0x53, 0x45,
0xf7, 0x9b, 0xe4, 0x0f, 0xeb, 0xb8, 0xd9, 0x63, 0x32, 0xe6, 0xec, 0x35, 0xa8, 0x8b, 0x39, 0x26,
0x27, 0xbe, 0x74, 0xd1, 0x97, 0x09, 0x38, 0x3c, 0xf1, 0x51, 0x23, 0x58, 0xcb, 0x26, 0x02, 0x91,
0x0d, 0xc2, 0xf6, 0xc4, 0xaa, 0x5d, 0x81, 0x96, 0x8a, 0xc8, 0x25, 0xbd, 0x11, 0x3f, 0x4e, 0xd5,
0xf1, 0x3a, 0x9c, 0x8e, 0xb1, 0xbb, 0x64, 0x9f, 0x1f, 0xa7, 0xee, 0x03, 0x58, 0x93, 0x32, 0xfc,
0x70, 0xc2, 0x55, 0xd7, 0x9f, 0x2d, 0xb3, 0x6e, 0x8d, 0xed, 0x75, 0x5b, 0xe8, 0x29, 0x46, 0x90,
0x33, 0x79, 0xae, 0x07, 0xcc, 0xd4, 0x09, 0xb2, 0x41, 0x69, 0x62, 0xd4, 0x21, 0x5e, 0x4e, 0xc7,
0xc2, 0x70, 0x7d, 0x92, 0x69, 0xbf, 0x8f, 0x9a, 0x40, 0x68, 0x40, 0x55, 0x74, 0xbf, 0xe7, 0xc0,
0x3a, 0xb5, 0xa6, 0xec, 0xb3, 0x3e, 0xf9, 0xbd, 0xfa, 0x30, 0x9b, 0x7d, 0x33, 0xb0, 0xb1, 0x01,
0x0b, 0xa6, 0xae, 0x15, 0x85, 0x1f, 0xff, 0x2c, 0x5b, 0x2b, 0x9c, 0x65, 0x7f, 0xe8, 0xc0, 0x9a,
0x50, 0x86, 0xa9, 0x9f, 0x4e, 0x13, 0x39, 0xfd, 0x5f, 0x84, 0x15, 0x61, 0xa7, 0xa4, 0x38, 0xc9,
0x81, 0x6e, 0x68, 0xc9, 0x27, 0x54, 0x10, 0xef, 0x9d, 0xf3, 0x6c, 0x62, 0xf6, 0x79, 0x68, 0x9a,
0x61, 0x55, 0x1a, 0x73, 0x63, 0xfb, 0xa2, 0x9a, 0x65, 0x81, 0x73, 0xf6, 0xce, 0x79, 0xd6, 0x07,
0xec, 0x43, 0x72, 0x36, 0xc2, 0x1e, 0x35, 0x2b, 0x03, 0x53, 0x17, 0x4b, 0x14, 0xb8, 0xfe, 0xdc,
0x20, 0xbf, 0xbd, 0x0c, 0x8b, 0xc2, 0xbb, 0x74, 0xef, 0xc1, 0x8a, 0x35, 0x52, 0xeb, 0x8c, 0xde,
0x14, 0x67, 0xf4, 0x42, 0x48, 0xa7, 0x52, 0x0c, 0xe9, 0xb8, 0xff, 0x56, 0x01, 0x86, 0xdc, 0x96,
0xdb, 0x4e, 0x74, 0x6f, 0xa3, 0x81, 0x75, 0x58, 0x69, 0x7a, 0x26, 0xc4, 0xae, 0x03, 0x33, 0x8a,
0x2a, 0xea, 0x25, 0xec, 0x46, 0x49, 0x0d, 0x2a, 0x38, 0x69, 0x58, 0xa5, 0x09, 0x94, 0xc7, 0x32,
0xb1, 0x6f, 0xa5, 0x75, 0x68, 0x1a, 0x26, 0xd3, 0xe4, 0x04, 0xdd, 0x6f, 0x75, 0x9c, 0x51, 0xe5,
0x3c, 0x83, 0x2c, 0xbe, 0x94, 0x41, 0x96, 0xf2, 0x0c, 0x62, 0x3a, 0xd4, 0xcb, 0x96, 0x43, 0x8d,
0x8e, 0xdc, 0x18, 0xdd, 0xbf, 0x74, 0xd4, 0xef, 0x8d, 0xb1, 0x77, 0x79, 0x7a, 0xb1, 0x40, 0xb6,
0x05, 0x6d, 0xe9, 0x0a, 0x64, 0x5e, 0x3b, 0xd0, 0x1a, 0x17, 0x70, 0xf7, 0x07, 0x0e, 0xb4, 0x71,
0x9d, 0x2d, 0x5e, 0xfc, 0x00, 0x48, 0x14, 0x5e, 0x91, 0x15, 0x2d, 0xda, 0x9f, 0x9e, 0x13, 0xdf,
0x87, 0x3a, 0x35, 0x18, 0x4d, 0x78, 0x28, 0x19, 0xb1, 0x63, 0x33, 0x62, 0xa6, 0x85, 0xf6, 0xce,
0x79, 0x19, 0xb1, 0xc1, 0x86, 0xff, 0xe4, 0x40, 0x43, 0x0e, 0xf3, 0x27, 0x3e, 0x89, 0x77, 0x61,
0x19, 0x39, 0xd2, 0x38, 0xee, 0xea, 0x32, 0x5a, 0x93, 0xb1, 0x9f, 0x4e, 0x63, 0x34, 0x9f, 0xd6,
0x29, 0x3c, 0x0f, 0xa3, 0x2d, 0x24, 0x85, 0x9b, 0xf4, 0xd2, 0x60, 0xd4, 0x53, 0xb5, 0xf2, 0x16,
0xa3, 0xac, 0x0a, 0xf5, 0x4e, 0x92, 0xfa, 0x43, 0x2e, 0xcd, 0x9c, 0x28, 0xb8, 0x1d, 0xd8, 0x94,
0x13, 0xca, 0xf9, 0x8e, 0xee, 0xdf, 0x36, 0xe1, 0x42, 0xa1, 0x4a, 0x5f, 0x03, 0xca, 0xe3, 0xe5,
0x28, 0x18, 0x1f, 0x45, 0xda, 0xd1, 0x76, 0xcc, 0x93, 0xa7, 0x55, 0xc5, 0x86, 0x70, 0x5e, 0xd9,
0x73, 0x5c, 0xd3, 0xcc, 0x7a, 0x57, 0xc8, 0x11, 0x79, 0xd7, 0xe6, 0x81, 0x7c, 0x87, 0x0a, 0x37,
0x25, 0xb7, 0xbc, 0x3d, 0x76, 0x02, 0x1d, 0xed, 0x38, 0x48, 0x15, 0x6f, 0x38, 0x17, 0xd8, 0xd7,
0x3b, 0x2f, 0xe9, 0xcb, 0x72, 0x44, 0xbd, 0xb9, 0xad, 0xb1, 0x19, 0x5c, 0x52, 0x75, 0xa4, 0xc3,
0x8b, 0xfd, 0xd5, 0x5e, 0x69, 0x6e, 0xe4, 0x44, 0xdb, 0x9d, 0xbe, 0xa4, 0x61, 0xf6, 0x75, 0xd8,
0x3c, 0xf3, 0x83, 0x54, 0x0d, 0xcb, 0x70, 0x86, 0x16, 0xa8, 0xcb, 0xed, 0x97, 0x74, 0xf9, 0x44,
0x7c, 0x6c, 0x19, 0xb6, 0x39, 0x2d, 0x76, 0xff, 0xc1, 0x81, 0x96, 0xdd, 0x0e, 0xb2, 0xa9, 0x14,
0x78, 0xa5, 0xf8, 0x94, 0xf3, 0x97, 0x83, 0x8b, 0x67, 0xd5, 0x4a, 0xd9, 0x59, 0xd5, 0x3c, 0x21,
0x56, 0x5f, 0x16, 0xc6, 0xa9, 0xbd, 0x5a, 0x18, 0x67, 0xa1, 0x2c, 0x8c, 0xd3, 0xfd, 0x6f, 0x07,
0x58, 0x91, 0x97, 0xd8, 0x3d, 0x71, 0x58, 0x0e, 0xf9, 0x48, 0xea, 0xa4, 0x9f, 0x7f, 0x35, 0x7e,
0x54, 0x6b, 0xa7, 0xbe, 0x46, 0xc1, 0x30, 0x95, 0x8e, 0xe9, 0x22, 0xad, 0x78, 0x65, 0x55, 0xb9,
0xc0, 0x52, 0xed, 0xe5, 0x81, 0xa5, 0x85, 0x97, 0x07, 0x96, 0x16, 0xf3, 0x81, 0xa5, 0xee, 0xef,
0x38, 0xb0, 0x5e, 0xb2, 0xe9, 0x3f, 0xbb, 0x89, 0xe3, 0x36, 0x59, 0xba, 0xa0, 0x22, 0xb7, 0xc9,
0x04, 0xbb, 0xbf, 0x01, 0x2b, 0x16, 0xa3, 0xff, 0xec, 0xfa, 0xcf, 0x7b, 0x79, 0x82, 0xcf, 0x2c,
0xac, 0xfb, 0xa3, 0x0a, 0xb0, 0xa2, 0xb0, 0xfd, 0xbf, 0x8e, 0xa1, 0xb8, 0x4e, 0xd5, 0x92, 0x75,
0xfa, 0x3f, 0xb5, 0x03, 0xef, 0xc0, 0x9a, 0xcc, 0x19, 0x30, 0x42, 0x24, 0x82, 0x63, 0x8a, 0x15,
0xe8, 0xe7, 0xda, 0x51, 0xbd, 0x65, 0xeb, 0xae, 0xd9, 0x30, 0x86, 0xb9, 0xe0, 0x9e, 0xbb, 0x09,
0x1b, 0x22, 0x07, 0xe1, 0xb6, 0x68, 0x4a, 0xd9, 0x95, 0x3f, 0x71, 0xe0, 0x7c, 0xae, 0x22, 0xbb,
0x19, 0x15, 0xa6, 0xc3, 0xb6, 0x27, 0x36, 0x88, 0xe3, 0x97, 0x72, 0x64, 0x8c, 0x5f, 0x70, 0x5b,
0xb1, 0x02, 0xd7, 0x67, 0x1a, 0x16, 0xe9, 0xc5, 0xaa, 0x97, 0x55, 0xb9, 0x17, 0x44, 0xa6, 0x44,
0xc8, 0x47, 0xb9, 0x81, 0x1f, 0x8b, 0xdc, 0x06, 0xb3, 0x22, 0xbb, 0x5a, 0xb1, 0x87, 0xac, 0x8a,
0xe8, 0x05, 0x5a, 0x66, 0xca, 0x1e, 0x6f, 0x69, 0x9d, 0xfb, 0xd7, 0x0e, 0xb0, 0x2f, 0x4d, 0x79,
0x3c, 0xa3, 0x1b, 0x52, 0x1d, 0xcb, 0xb9, 0x90, 0x8f, 0x63, 0x2c, 0x4e, 0xa6, 0x47, 0x5f, 0xe4,
0x33, 0x75, 0x8f, 0x5e, 0xc9, 0xee, 0xd1, 0xdf, 0x00, 0xc0, 0xe3, 0x97, 0xbe, 0x76, 0x45, 0x5e,
0xc0, 0x73, 0xaf, 0x68, 0xb0, 0xf4, 0xaa, 0xbb, 0xf6, 0xf2, 0xab, 0xee, 0x85, 0x97, 0x5d, 0x75,
0x7f, 0x08, 0xeb, 0xd6, 0xb8, 0xf5, 0xb6, 0xaa, 0x0b, 0x60, 0xe7, 0x05, 0x17, 0xc0, 0xff, 0xe9,
0x40, 0x75, 0x2f, 0x9a, 0x98, 0x71, 0x4b, 0xc7, 0x8e, 0x5b, 0x4a, 0x5b, 0xd2, 0xd3, 0xa6, 0x42,
0xaa, 0x18, 0x0b, 0x64, 0x5b, 0xd0, 0xf2, 0xc7, 0x29, 0x1e, 0xbb, 0x8f, 0xa3, 0xf8, 0xcc, 0x8f,
0x07, 0x62, 0xaf, 0x6f, 0x57, 0x3a, 0x8e, 0x97, 0xab, 0x61, 0x1b, 0x50, 0xd5, 0x4a, 0x97, 0x08,
0xb0, 0x88, 0x8e, 0x1b, 0xdd, 0x79, 0xcc, 0x64, 0xc4, 0x40, 0x96, 0x90, 0x95, 0xec, 0xef, 0x85,
0xab, 0x2c, 0x44, 0xa7, 0xac, 0x0a, 0xed, 0x1a, 0x2e, 0x1f, 0x91, 0xc9, 0x50, 0x8f, 0x2a, 0xbb,
0xff, 0xee, 0xc0, 0x02, 0xad, 0x00, 0x0a, 0xbb, 0xe0, 0x70, 0x1d, 0xa0, 0xa4, 0x99, 0xaf, 0x78,
0x79, 0x98, 0xb9, 0x56, 0xbe, 0x49, 0x45, 0x0f, 0xdb, 0xcc, 0x39, 0xb9, 0x0c, 0x75, 0x51, 0xd2,
0xb9, 0x15, 0x44, 0x92, 0x81, 0xec, 0x12, 0xd4, 0x4e, 0xa2, 0x89, 0xf2, 0x4e, 0x40, 0xc5, 0xe7,
0xa3, 0x89, 0x47, 0x78, 0x36, 0x1e, 0x6c, 0x4f, 0x0c, 0x5e, 0xd8, 0x9c, 0x3c, 0x8c, 0x56, 0x57,
0x37, 0x6b, 0x2e, 0x46, 0x0e, 0x75, 0xb7, 0x60, 0xf5, 0x41, 0x34, 0xe0, 0x46, 0x4c, 0x69, 0x2e,
0x37, 0xbb, 0xdf, 0x72, 0x60, 0x59, 0x11, 0xb3, 0x6b, 0x50, 0x43, 0x57, 0x22, 0x77, 0x50, 0xd0,
0xf7, 0x72, 0x48, 0xe7, 0x11, 0x05, 0xea, 0x5e, 0x8a, 0x38, 0x64, 0x6e, 0xa5, 0x8a, 0x37, 0x64,
0x5e, 0x93, 0x1e, 0x6e, 0xce, 0xd9, 0xc8, 0xa1, 0xee, 0x5f, 0x38, 0xb0, 0x62, 0xf5, 0x81, 0xc7,
0xc3, 0x91, 0x9f, 0xa4, 0xf2, 0xae, 0x43, 0x6e, 0x8f, 0x09, 0x99, 0x51, 0xc6, 0x8a, 0x1d, 0x65,
0xd4, 0xf1, 0xaf, 0xaa, 0x19, 0xff, 0xba, 0x09, 0xf5, 0x2c, 0x2b, 0xa8, 0x66, 0xe9, 0x54, 0xec,
0x51, 0xdd, 0x38, 0x66, 0x44, 0xd8, 0x4e, 0x3f, 0x1a, 0x45, 0xb1, 0x0c, 0xb2, 0x8b, 0x82, 0xfb,
0x21, 0x34, 0x0c, 0x7a, 0x1c, 0x46, 0xc8, 0xd3, 0xb3, 0x28, 0x7e, 0xaa, 0x82, 0x9d, 0xb2, 0xa8,
0x2f, 0xd6, 0x2b, 0xd9, 0xc5, 0xba, 0xfb, 0x97, 0x0e, 0xac, 0x20, 0x0f, 0x06, 0xe1, 0xf0, 0x20,
0x1a, 0x05, 0xfd, 0x19, 0xed, 0xbd, 0x62, 0x37, 0xa9, 0x19, 0x14, 0x2f, 0xda, 0x30, 0xf2, 0xb6,
0x3a, 0x1d, 0x4a, 0x41, 0xd4, 0x65, 0x94, 0x54, 0xe4, 0xf3, 0x23, 0x3f, 0x91, 0xcc, 0x2f, 0x8d,
0x9c, 0x05, 0xa2, 0x3c, 0x21, 0x10, 0xfb, 0x29, 0xef, 0x8d, 0x83, 0xd1, 0x28, 0x10, 0xb4, 0xc2,
0x05, 0x2a, 0xab, 0x72, 0xbf, 0x5f, 0x81, 0x86, 0x54, 0xc1, 0xbb, 0x83, 0x21, 0x97, 0x37, 0x19,
0xe4, 0x48, 0x6a, 0x75, 0x61, 0x20, 0xaa, 0xde, 0x72, 0x3d, 0x0d, 0x24, 0xbf, 0xad, 0xd5, 0xe2,
0xb6, 0xbe, 0x0e, 0x75, 0x64, 0xaf, 0x77, 0xc9, 0xc7, 0x15, 0xb7, 0x20, 0x19, 0xa0, 0x6a, 0xb7,
0xa9, 0x76, 0x21, 0xab, 0x25, 0xe0, 0x85, 0xf7, 0x1e, 0xef, 0x43, 0x53, 0x36, 0x43, 0xeb, 0x4e,
0xda, 0x21, 0x63, 0x70, 0x6b, 0x4f, 0x3c, 0x8b, 0x52, 0x7d, 0xb9, 0xad, 0xbe, 0x5c, 0x7e, 0xd9,
0x97, 0x8a, 0x92, 0xee, 0xa8, 0xc5, 0xda, 0xdc, 0x8b, 0xfd, 0xc9, 0x89, 0x32, 0x6b, 0x03, 0x9d,
0x78, 0x43, 0x30, 0xdb, 0x82, 0x05, 0xfc, 0x4c, 0x69, 0xeb, 0x72, 0xa1, 0x13, 0x24, 0xec, 0x1a,
0x2c, 0xf0, 0xc1, 0x90, 0xab, 0x53, 0x1c, 0xb3, 0xcf, 0xd3, 0xb8, 0x47, 0x9e, 0x20, 0x40, 0x15,
0x80, 0x68, 0x4e, 0x05, 0xd8, 0x9a, 0x7e, 0x11, 0x8b, 0xf7, 0x07, 0xee, 0x06, 0xb0, 0x07, 0x82,
0x6b, 0xcd, 0x28, 0xf4, 0x6f, 0x57, 0xa1, 0x61, 0xc0, 0x28, 0xcd, 0x43, 0x1c, 0x70, 0x6f, 0x10,
0xf8, 0x63, 0x9e, 0xf2, 0x58, 0x72, 0x6a, 0x0e, 0x45, 0x3a, 0xff, 0x74, 0xd8, 0x8b, 0xa6, 0x69,
0x6f, 0xc0, 0x87, 0x31, 0x17, 0xc6, 0x17, 0x8d, 0x81, 0x85, 0x22, 0xdd, 0xd8, 0x7f, 0x66, 0xd2,
0x09, 0x7e, 0xc8, 0xa1, 0x2a, 0xa6, 0x2c, 0xd6, 0xa8, 0x96, 0xc5, 0x94, 0xc5, 0x8a, 0xe4, 0xf5,
0xd0, 0x42, 0x89, 0x1e, 0x7a, 0x0f, 0x36, 0x85, 0xc6, 0x91, 0xb2, 0xd9, 0xcb, 0xb1, 0xc9, 0x9c,
0x5a, 0xb6, 0x05, 0x6d, 0x1c, 0xb3, 0x62, 0xf0, 0x24, 0xf8, 0xa6, 0x88, 0xf2, 0x38, 0x5e, 0x01,
0x47, 0x5a, 0x14, 0x47, 0x8b, 0x56, 0xdc, 0x9a, 0x15, 0x70, 0xa2, 0xf5, 0x9f, 0xd9, 0xb4, 0x75,
0x49, 0x9b, 0xc3, 0xdd, 0x15, 0x68, 0x1c, 0xa6, 0xd1, 0x44, 0x6d, 0x4a, 0x0b, 0x9a, 0xa2, 0x28,
0x73, 0x14, 0x5e, 0x83, 0x8b, 0xc4, 0x45, 0x8f, 0xa2, 0x49, 0x34, 0x8a, 0x86, 0xb3, 0xc3, 0xe9,
0x51, 0xd2, 0x8f, 0x83, 0x09, 0x9e, 0x78, 0xdc, 0x7f, 0x74, 0x60, 0xdd, 0xaa, 0x95, 0x61, 0xa1,
0x4f, 0x0b, 0x96, 0xd6, 0x97, 0xcb, 0x82, 0xf1, 0xd6, 0x0c, 0x75, 0x28, 0x08, 0x45, 0x40, 0xee,
0xb1, 0xbc, 0x6f, 0xbe, 0x05, 0xab, 0x6a, 0x64, 0xea, 0x43, 0xc1, 0x85, 0x9d, 0x22, 0x17, 0xca,
0xef, 0x5b, 0xf2, 0x03, 0xd5, 0xc4, 0x2f, 0xc9, 0xdb, 0xc7, 0x01, 0xcd, 0x51, 0xc5, 0x07, 0xf4,
0xfd, 0x92, 0x79, 0x4a, 0x50, 0x23, 0xe8, 0x6b, 0x30, 0x71, 0x7f, 0xcf, 0x01, 0xc8, 0x46, 0x87,
0x8c, 0x91, 0xa9, 0x74, 0x91, 0x10, 0x6d, 0xa8, 0xef, 0xb7, 0xa0, 0xa9, 0x6f, 0x46, 0x32, 0x2b,
0xd1, 0x50, 0x18, 0x3a, 0x72, 0x57, 0x61, 0x75, 0x38, 0x8a, 0x8e, 0xc8, 0xc4, 0x52, 0xd2, 0x4b,
0x22, 0x33, 0x35, 0x5a, 0x02, 0xbe, 0x2b, 0xd1, 0xcc, 0xa4, 0xd4, 0x0c, 0x93, 0xe2, 0x7e, 0xbb,
0xa2, 0xe3, 0xe9, 0xd9, 0x9c, 0xe7, 0x4a, 0x19, 0xdb, 0x2e, 0x28, 0xc7, 0x39, 0xe1, 0x6b, 0x8a,
0x84, 0x1d, 0xbc, 0xf4, 0xa0, 0xfe, 0x21, 0xb4, 0x62, 0xa1, 0x7d, 0x94, 0x6a, 0xaa, 0xbd, 0x40,
0x35, 0xad, 0xc4, 0x96, 0xdd, 0xf9, 0x24, 0xb4, 0xfd, 0xc1, 0x29, 0x8f, 0xd3, 0x80, 0x8e, 0x4a,
0x64, 0xf4, 0x85, 0x42, 0x5d, 0x35, 0x70, 0xb2, 0xc5, 0x57, 0x61, 0x55, 0x66, 0xc7, 0x68, 0x4a,
0x99, 0xd1, 0x99, 0xc1, 0x48, 0xe8, 0xfe, 0x99, 0x0a, 0xdd, 0xdb, 0x7b, 0x38, 0x7f, 0x45, 0xcc,
0xd9, 0x55, 0x72, 0xb3, 0xfb, 0x84, 0x0c, 0xa3, 0x0f, 0xd4, 0x79, 0xac, 0x6a, 0xdc, 0x54, 0x0f,
0xe4, 0xb5, 0x87, 0xbd, 0xa4, 0xb5, 0x57, 0x59, 0x52, 0xf7, 0x07, 0x0e, 0x2c, 0xed, 0x45, 0x93,
0x3d, 0x79, 0x67, 0x4f, 0x82, 0xa0, 0x73, 0xcf, 0x54, 0xf1, 0x05, 0xb7, 0xf9, 0xa5, 0xb6, 0x76,
0x25, 0x6f, 0x6b, 0x7f, 0x19, 0x5e, 0xa3, 0x68, 0x40, 0x1c, 0x4d, 0xa2, 0x18, 0x85, 0xd1, 0x1f,
0x09, 0xc3, 0x1a, 0x85, 0xe9, 0x89, 0x52, 0x63, 0x2f, 0x22, 0xa1, 0x63, 0x17, 0x1e, 0x17, 0x84,
0x33, 0x2c, 0x7d, 0x03, 0xa1, 0xdd, 0x8a, 0x15, 0xee, 0x67, 0xa1, 0x4e, 0xce, 0x2d, 0x4d, 0xeb,
0x1d, 0xa8, 0x9f, 0x44, 0x93, 0xde, 0x49, 0x10, 0xa6, 0x4a, 0xb8, 0x5b, 0x99, 0xd7, 0xb9, 0x47,
0x0b, 0xa2, 0x09, 0xdc, 0x1f, 0x55, 0x61, 0xe9, 0x7e, 0x78, 0x1a, 0x05, 0x7d, 0x8a, 0xf2, 0x8f,
0xf9, 0x38, 0x52, 0x99, 0x78, 0xf8, 0x1b, 0x97, 0x82, 0xb2, 0x52, 0x26, 0xa9, 0x0c, 0xd3, 0xab,
0x22, 0x9a, 0xfb, 0x38, 0xcb, 0x96, 0x15, 0xa2, 0x63, 0x20, 0xe8, 0xd8, 0xc7, 0x66, 0x62, 0xb1,
0x2c, 0x65, 0xa9, 0x8c, 0x0b, 0x46, 0x2a, 0x23, 0xdd, 0x09, 0x89, 0xfc, 0x02, 0xe2, 0xaf, 0x65,
0x4f, 0x15, 0xe9, 0x20, 0x12, 0x73, 0x11, 0xc5, 0x21, 0xc7, 0x61, 0x49, 0x1e, 0x44, 0x4c, 0x10,
0x9d, 0x0b, 0xf1, 0x81, 0xa0, 0x11, 0xca, 0xd7, 0x84, 0xd0, 0xd9, 0xca, 0xe7, 0x26, 0xd7, 0x05,
0xcf, 0xe7, 0x60, 0xd4, 0xd0, 0x03, 0xae, 0x15, 0xa9, 0x98, 0x03, 0x88, 0x6c, 0xe0, 0x3c, 0x6e,
0x1c, 0x5f, 0x44, 0xe2, 0x90, 0x3a, 0xbe, 0x20, 0xa3, 0xf8, 0xa3, 0xd1, 0x91, 0xdf, 0x7f, 0x4a,
0xa9, 0xe7, 0x94, 0x27, 0x54, 0xf7, 0x6c, 0x90, 0x32, 0x06, 0xb2, 0xdd, 0xa4, 0x5b, 0xc5, 0x9a,
0x67, 0x42, 0x6c, 0x1b, 0x1a, 0x74, 0x64, 0x93, 0xfb, 0xd9, 0xa2, 0xfd, 0x6c, 0x9b, 0x67, 0x3a,
0xda, 0x51, 0x93, 0xc8, 0xbc, 0x79, 0x58, 0xb5, 0x53, 0x79, 0xbe, 0x0c, 0xec, 0xd6, 0x60, 0x20,
0xf7, 0x5b, 0x1f, 0x19, 0xb3, 0x9d, 0x72, 0xac, 0x9d, 0x2a, 0x59, 0xb1, 0x4a, 0xe9, 0x8a, 0xb9,
0xbb, 0xd0, 0x38, 0x30, 0x92, 0x96, 0x89, 0x35, 0x54, 0xba, 0xb2, 0x64, 0x27, 0x03, 0x31, 0x3a,
0xac, 0x98, 0x1d, 0xba, 0xbf, 0x00, 0x6c, 0x3f, 0x48, 0x52, 0x3d, 0xbe, 0x2c, 0x4b, 0x5a, 0x9d,
0xdc, 0xb3, 0x44, 0xa3, 0x86, 0xc4, 0x28, 0x01, 0xe8, 0x96, 0xc8, 0x50, 0xca, 0x4f, 0x6c, 0x0b,
0x96, 0x03, 0x01, 0xe5, 0x25, 0x41, 0x51, 0xea, 0x7a, 0xf4, 0xd7, 0x24, 0x68, 0x59, 0xd1, 0xef,
0x3b, 0xb0, 0x24, 0xa7, 0x86, 0xde, 0x46, 0x21, 0x5d, 0xbb, 0xee, 0x59, 0x58, 0x79, 0xa2, 0x6e,
0x91, 0x87, 0xab, 0x65, 0x3c, 0xcc, 0xa0, 0x36, 0xf1, 0xd3, 0x13, 0x3a, 0xa0, 0xd4, 0x3d, 0xfa,
0xcd, 0xda, 0xe2, 0xd0, 0x2c, 0x64, 0x85, 0x0e, 0xcc, 0x65, 0xb9, 0xea, 0x42, 0x25, 0x17, 0x70,
0x9c, 0x14, 0x65, 0x25, 0x08, 0x5c, 0x5f, 0x36, 0xc8, 0x7c, 0xa9, 0x0c, 0xce, 0xd6, 0x4b, 0x36,
0x91, 0x5f, 0x2f, 0x49, 0xea, 0xe9, 0x7a, 0xb7, 0x0b, 0x9d, 0x3b, 0x7c, 0xc4, 0x53, 0x7e, 0x6b,
0x34, 0xca, 0xb7, 0xff, 0x1a, 0x5c, 0x2c, 0xa9, 0x93, 0x4e, 0xcb, 0x5d, 0x58, 0xbb, 0xc3, 0x8f,
0xa6, 0xc3, 0x7d, 0x7e, 0x9a, 0xdd, 0x08, 0x32, 0xa8, 0x25, 0x27, 0xd1, 0x99, 0xdc, 0x5b, 0xfa,
0xcd, 0xde, 0x00, 0x18, 0x21, 0x4d, 0x2f, 0x99, 0xf0, 0xbe, 0x4a, 0x51, 0x25, 0xe4, 0x70, 0xc2,
0xfb, 0xee, 0x7b, 0xc0, 0xcc, 0x76, 0xe4, 0x14, 0x50, 0x0f, 0x4c, 0x8f, 0x7a, 0xc9, 0x2c, 0x49,
0xf9, 0x58, 0xe5, 0xde, 0x9a, 0x90, 0x7b, 0x15, 0x9a, 0x07, 0xfe, 0xcc, 0xe3, 0xdf, 0x90, 0x19,
0xf3, 0x78, 0x36, 0xf6, 0x67, 0xc8, 0xca, 0xfa, 0x6c, 0x4c, 0xd5, 0xee, 0x7f, 0x55, 0x60, 0x51,
0x50, 0x62, 0xab, 0x03, 0x9e, 0xa4, 0x41, 0x28, 0x6e, 0xc3, 0x64, 0xab, 0x06, 0x54, 0xe0, 0x8d,
0x4a, 0x09, 0x6f, 0x48, 0x6f, 0x55, 0xa5, 0xfb, 0x49, 0x26, 0xb0, 0x30, 0x74, 0x6b, 0xb2, 0x2c,
0x03, 0x71, 0x38, 0xcb, 0x80, 0x5c, 0xb0, 0x24, 0xd3, 0x36, 0x62, 0x7c, 0x8a, 0x69, 0x25, 0x3b,
0x98, 0x50, 0xa9, 0x4e, 0x5b, 0x12, 0x5c, 0x53, 0xd0, 0x69, 0x05, 0xdd, 0xb5, 0xfc, 0x0a, 0xba,
0x4b, 0xb8, 0xb0, 0x2f, 0xd2, 0x5d, 0xf0, 0x0a, 0xba, 0xcb, 0x65, 0xd0, 0xbe, 0xcb, 0xb9, 0xc7,
0xd1, 0x2a, 0x2a, 0x76, 0xfa, 0x8e, 0x03, 0x6d, 0x69, 0xd0, 0x75, 0x1d, 0x7b, 0xcb, 0xb2, 0xfe,
0xa5, 0x49, 0x79, 0x57, 0x60, 0x85, 0x6c, 0xb2, 0x8e, 0x0a, 0xc9, 0x10, 0x96, 0x05, 0xe2, 0x3c,
0x54, 0xe8, 0x7e, 0x1c, 0x8c, 0xe4, 0xa6, 0x98, 0x90, 0x0a, 0x2c, 0xe1, 0xf9, 0x98, 0xb6, 0xc4,
0xf1, 0x74, 0xd9, 0xfd, 0x1b, 0x07, 0xd6, 0x8c, 0x01, 0x4b, 0x2e, 0xfc, 0x10, 0x54, 0x16, 0x82,
0x08, 0x1e, 0x09, 0x61, 0xba, 0x60, 0x3b, 0x27, 0xd9, 0x67, 0x16, 0x31, 0x6d, 0xa6, 0x3f, 0xa3,
0x01, 0x26, 0xd3, 0xb1, 0xf4, 0x40, 0x4c, 0x08, 0x19, 0xe9, 0x8c, 0xf3, 0xa7, 0x9a, 0xa4, 0x4a,
0x24, 0x16, 0x46, 0x97, 0xcc, 0xe8, 0x4b, 0x68, 0x22, 0x91, 0x57, 0x65, 0x83, 0xee, 0x3f, 0x3b,
0xb0, 0x2e, 0x9c, 0x42, 0xe9, 0x72, 0xeb, 0x8c, 0xe9, 0x45, 0xe1, 0x05, 0x0b, 0x89, 0xdc, 0x3b,
0xe7, 0xc9, 0x32, 0xfb, 0xcc, 0x2b, 0x3a, 0xb2, 0x3a, 0xb9, 0x60, 0xce, 0x5e, 0x54, 0xcb, 0xf6,
0xe2, 0x05, 0x2b, 0x5d, 0x16, 0x2c, 0x59, 0x28, 0x0d, 0x96, 0xdc, 0x5e, 0x82, 0x85, 0xa4, 0x1f,
0x4d, 0xb8, 0xbb, 0x09, 0x1b, 0xf6, 0xe4, 0xa4, 0x0a, 0xfa, 0xae, 0x03, 0x9d, 0xbb, 0x22, 0x74,
0x18, 0x84, 0xc3, 0xbd, 0x20, 0x49, 0xa3, 0x58, 0x3f, 0x11, 0xb9, 0x04, 0x90, 0xa4, 0x7e, 0x9c,
0x8a, 0xe4, 0x2f, 0x19, 0xe6, 0xc8, 0x10, 0x1c, 0x23, 0x0f, 0x07, 0xa2, 0x56, 0xec, 0x8d, 0x2e,
0xe3, 0xc6, 0x50, 0xe2, 0x43, 0x2f, 0x3a, 0x3e, 0x4e, 0xb8, 0x76, 0x5b, 0x4d, 0x0c, 0x4f, 0xbe,
0x28, 0xf1, 0x78, 0xd6, 0xe3, 0xa7, 0xa4, 0x6a, 0x85, 0x3f, 0x98, 0x43, 0xdd, 0xbf, 0x72, 0x60,
0x35, 0x1b, 0xe4, 0x2e, 0x82, 0xb6, 0x76, 0x10, 0x43, 0x33, 0xb4, 0x83, 0x0a, 0xc0, 0x04, 0x83,
0x5e, 0x10, 0xca, 0xb1, 0x19, 0x08, 0x49, 0xac, 0x2c, 0x45, 0x53, 0x95, 0x68, 0x67, 0x42, 0xe2,
0x16, 0x3d, 0xc5, 0xaf, 0x45, 0x96, 0x9d, 0x2c, 0x51, 0xee, 0xde, 0x38, 0xa5, 0xaf, 0x16, 0x85,
0x43, 0x2c, 0x8b, 0xca, 0x3e, 0x2d, 0x11, 0x8a, 0x3f, 0xdd, 0xdf, 0x77, 0xe0, 0x62, 0xc9, 0xe2,
0x4a, 0xc9, 0xb8, 0x03, 0x6b, 0xc7, 0xba, 0x52, 0x2d, 0x80, 0x10, 0x8f, 0x4d, 0x15, 0xeb, 0xb6,
0x27, 0xed, 0x15, 0x3f, 0x40, 0xf7, 0x98, 0xe2, 0x46, 0x62, 0x49, 0xad, 0x04, 0x94, 0x62, 0xc5,
0xf6, 0x1f, 0x54, 0xa1, 0x25, 0xee, 0x40, 0xc4, 0x63, 0x4d, 0x1e, 0xb3, 0x8f, 0x60, 0x49, 0x3e,
0xb6, 0x65, 0xe7, 0x65, 0xb7, 0xf6, 0xf3, 0xde, 0xee, 0x66, 0x1e, 0x96, 0xbc, 0xb3, 0xfe, 0x5b,
0x3f, 0xf8, 0xd7, 0x3f, 0xac, 0xac, 0xb0, 0xc6, 0x8d, 0xd3, 0x77, 0x6f, 0x0c, 0x79, 0x98, 0x60,
0x1b, 0xbf, 0x06, 0x90, 0x3d, 0x43, 0x65, 0x1d, 0xed, 0x64, 0xe4, 0xde, 0xd7, 0x76, 0x2f, 0x96,
0xd4, 0xc8, 0x76, 0x2f, 0x52, 0xbb, 0xeb, 0x6e, 0x0b, 0xdb, 0x0d, 0xc2, 0x20, 0x15, 0x6f, 0x52,
0x3f, 0x70, 0xb6, 0xd8, 0x00, 0x9a, 0xe6, 0x2b, 0x53, 0xa6, 0x8e, 0xcc, 0x25, 0x6f, 0x5c, 0xbb,
0xaf, 0x95, 0xd6, 0xa9, 0x78, 0x01, 0xf5, 0x71, 0xde, 0x6d, 0x63, 0x1f, 0x53, 0xa2, 0xc8, 0x7a,
0x19, 0x41, 0xcb, 0x7e, 0x4c, 0xca, 0x5e, 0x37, 0xc4, 0xba, 0xf0, 0x94, 0xb5, 0xfb, 0xc6, 0x9c,
0x5a, 0xd9, 0xd7, 0x1b, 0xd4, 0xd7, 0x05, 0x97, 0x61, 0x5f, 0x7d, 0xa2, 0x51, 0x4f, 0x59, 0x3f,
0x70, 0xb6, 0xb6, 0xbf, 0x75, 0x09, 0xea, 0x3a, 0xc8, 0xc5, 0xbe, 0x0e, 0x2b, 0xd6, 0x25, 0x15,
0x53, 0xd3, 0x28, 0xbb, 0xd3, 0xea, 0xbe, 0x5e, 0x5e, 0x29, 0x3b, 0xbe, 0x44, 0x1d, 0x77, 0xd8,
0x26, 0x76, 0x2c, 0x6f, 0x79, 0x6e, 0xd0, 0xd5, 0x9c, 0xc8, 0x0c, 0x7c, 0x2a, 0xe6, 0x99, 0x5d,
0x2c, 0x59, 0xf3, 0x2c, 0x5c, 0x44, 0x59, 0xf3, 0x2c, 0xde, 0x46, 0xb9, 0xaf, 0x53, 0x77, 0x9b,
0x6c, 0xc3, 0xec, 0x4e, 0x07, 0x9f, 0x38, 0xe5, 0x72, 0x9a, 0x6f, 0x4d, 0xd9, 0x1b, 0x9a, 0xb1,
0xca, 0xde, 0xa0, 0x6a, 0x16, 0x29, 0x3e, 0x44, 0x75, 0x3b, 0xd4, 0x15, 0x63, 0xb4, 0x7d, 0xe6,
0x53, 0x53, 0xf6, 0x55, 0xa8, 0xeb, 0x87, 0x55, 0xec, 0x82, 0xf1, 0x9a, 0xcd, 0x7c, 0xed, 0xd5,
0xed, 0x14, 0x2b, 0xca, 0x18, 0xc3, 0x6c, 0x19, 0x19, 0x63, 0x1f, 0xce, 0x4b, 0x97, 0xf8, 0x88,
0xff, 0x38, 0x33, 0x29, 0x79, 0x21, 0x7b, 0xd3, 0x61, 0x1f, 0xc2, 0xb2, 0x7a, 0xaf, 0xc6, 0x36,
0xcb, 0xdf, 0xdd, 0x75, 0x2f, 0x14, 0x70, 0xa9, 0x3d, 0x6e, 0x01, 0x64, 0x6f, 0xad, 0xb4, 0x9c,
0x15, 0x5e, 0x80, 0xe9, 0x45, 0x2c, 0x79, 0x98, 0x35, 0xa4, 0x97, 0x65, 0xf6, 0x53, 0x2e, 0xf6,
0x66, 0x46, 0x5f, 0xfa, 0xc8, 0xeb, 0x05, 0x0d, 0xba, 0x9b, 0xb4, 0x76, 0x6d, 0x46, 0x82, 0x1b,
0xf2, 0x33, 0x95, 0xd5, 0x7c, 0x07, 0x1a, 0xc6, 0xfb, 0x2d, 0xa6, 0x5a, 0x28, 0xbe, 0xfd, 0xea,
0x76, 0xcb, 0xaa, 0xe4, 0x70, 0xbf, 0x00, 0x2b, 0xd6, 0x43, 0x2c, 0x2d, 0x19, 0x65, 0xcf, 0xbc,
0xb4, 0x64, 0x94, 0xbf, 0xdd, 0xfa, 0x0a, 0x34, 0x8c, 0x67, 0x53, 0xcc, 0xc8, 0xe6, 0xca, 0x3d,
0x98, 0xd2, 0x23, 0x2a, 0x7b, 0x65, 0xb5, 0x41, 0xf3, 0x6d, 0xb9, 0x75, 0x9c, 0x2f, 0xa5, 0xf6,
0x22, 0x93, 0x7c, 0x1d, 0x5a, 0xf6, 0x43, 0x2a, 0x2d, 0x55, 0xa5, 0x4f, 0xb2, 0xb4, 0x54, 0xcd,
0x79, 0x7d, 0x25, 0x19, 0x72, 0x6b, 0x5d, 0x77, 0x72, 0xe3, 0x63, 0x79, 0xc5, 0xf3, 0x9c, 0x7d,
0x09, 0x55, 0x87, 0xcc, 0xb5, 0x66, 0xd9, 0xf3, 0x31, 0x3b, 0x23, 0x5b, 0x73, 0x7b, 0x21, 0x2d,
0xdb, 0x5d, 0xa3, 0xc6, 0x1b, 0x2c, 0x9b, 0x81, 0xb0, 0x07, 0x94, 0x73, 0x6d, 0xd8, 0x03, 0x33,
0x2d, 0xdb, 0xb0, 0x07, 0x56, 0x6a, 0x76, 0xde, 0x1e, 0xa4, 0x01, 0xb6, 0x11, 0xc2, 0x6a, 0x2e,
0x9d, 0x41, 0x0b, 0x4b, 0x79, 0xfe, 0x57, 0xf7, 0xd2, 0x8b, 0xb3, 0x20, 0x6c, 0x35, 0xa3, 0xd4,
0xcb, 0x0d, 0x95, 0xae, 0xf7, 0xeb, 0xd0, 0x34, 0x1f, 0xc0, 0x68, 0x0b, 0x51, 0xf2, 0x6c, 0x47,
0x5b, 0x88, 0xb2, 0x17, 0x33, 0x6a, 0x73, 0x59, 0xd3, 0xec, 0x06, 0x37, 0xd7, 0x7e, 0x2f, 0x90,
0xa9, 0xcc, 0xb2, 0x87, 0x10, 0x99, 0xca, 0x2c, 0x7d, 0x64, 0xa0, 0x36, 0x97, 0xad, 0x5b, 0x73,
0x11, 0xb1, 0x3d, 0xf6, 0x15, 0x58, 0x35, 0x72, 0x85, 0x0e, 0x67, 0x61, 0x5f, 0x33, 0x6a, 0x31,
0x93, 0xb4, 0x5b, 0xe6, 0x79, 0xba, 0x17, 0xa8, 0xfd, 0x35, 0xd7, 0x9a, 0x04, 0x32, 0xe9, 0x0e,
0x34, 0xcc, 0x3c, 0xa4, 0x17, 0xb4, 0x7b, 0xc1, 0xa8, 0x32, 0x93, 0x2a, 0x6f, 0x3a, 0xec, 0x8f,
0x1d, 0x68, 0x5a, 0x59, 0x3d, 0x56, 0x04, 0x3b, 0xd7, 0x4e, 0xc7, 0xac, 0x33, 0x1b, 0x72, 0x3d,
0x1a, 0xe4, 0xfe, 0xd6, 0x17, 0xac, 0x45, 0xf8, 0xd8, 0x3a, 0xc1, 0x5c, 0xcf, 0xbf, 0xa3, 0x7e,
0x9e, 0x27, 0x30, 0xb3, 0x6d, 0x9f, 0xdf, 0x74, 0xd8, 0x07, 0xe2, 0x9f, 0x02, 0x54, 0xc4, 0x82,
0x19, 0x8a, 0x34, 0xbf, 0x64, 0xe6, 0x33, 0xf9, 0x6b, 0xce, 0x4d, 0x87, 0x7d, 0x4d, 0x3c, 0x97,
0x96, 0xdf, 0xd2, 0xca, 0xbf, 0xea, 0xf7, 0xee, 0x15, 0x9a, 0xcd, 0x25, 0xf7, 0xa2, 0x35, 0x9b,
0xbc, 0x25, 0xb9, 0x25, 0x46, 0x27, 0x5f, 0xc1, 0x67, 0x2a, 0xb1, 0xf0, 0x32, 0x7e, 0xfe, 0x20,
0xc7, 0x62, 0x90, 0x92, 0xdc, 0x62, 0x8f, 0x57, 0x6c, 0xc6, 0xdd, 0xa2, 0xb1, 0x5e, 0x71, 0xdf,
0x9c, 0x3b, 0xd6, 0x1b, 0x74, 0x22, 0xc5, 0x11, 0x1f, 0x00, 0x64, 0x01, 0x33, 0x96, 0x8b, 0x1e,
0x69, 0xab, 0x50, 0x8c, 0xa9, 0xd9, 0x3c, 0xa8, 0x82, 0x4c, 0xd8, 0xe2, 0x57, 0x85, 0xa8, 0x4a,
0xfa, 0x44, 0x8f, 0xbe, 0x18, 0xf8, 0xea, 0x76, 0xcb, 0xaa, 0xca, 0x04, 0x55, 0xb5, 0xcf, 0x1e,
0xc3, 0xca, 0x7e, 0x14, 0x3d, 0x9d, 0x4e, 0x74, 0x48, 0xd7, 0x8e, 0xdf, 0xec, 0xf9, 0xc9, 0x49,
0x37, 0x37, 0x0b, 0xf7, 0x32, 0x35, 0xd5, 0x65, 0x1d, 0xa3, 0xa9, 0x1b, 0x1f, 0x67, 0xe1, 0xba,
0xe7, 0xcc, 0x87, 0x35, 0xed, 0x01, 0xe8, 0x81, 0x77, 0xed, 0x66, 0xcc, 0xa8, 0x59, 0xa1, 0x0b,
0xcb, 0x27, 0x53, 0xa3, 0xbd, 0x91, 0xa8, 0x36, 0x6f, 0x3a, 0xec, 0x00, 0x9a, 0x77, 0x78, 0x3f,
0x1a, 0x70, 0x19, 0x71, 0x59, 0xcf, 0x06, 0xae, 0x43, 0x35, 0xdd, 0x15, 0x0b, 0xb4, 0x75, 0xe2,
0xc4, 0x9f, 0xc5, 0xfc, 0x1b, 0x37, 0x3e, 0x96, 0xb1, 0x9c, 0xe7, 0x4a, 0x27, 0xaa, 0xf8, 0x93,
0xa5, 0x13, 0x73, 0x01, 0x2b, 0x4b, 0x27, 0x16, 0x02, 0x56, 0xd6, 0x52, 0xab, 0xf8, 0x17, 0x1b,
0xc1, 0x5a, 0x21, 0xc6, 0xa5, 0xfd, 0x88, 0x79, 0x91, 0xb1, 0xee, 0xe5, 0xf9, 0x04, 0x76, 0x6f,
0x5b, 0x76, 0x6f, 0x87, 0xb0, 0x72, 0x87, 0x8b, 0xc5, 0x12, 0xf7, 0xc6, 0xb9, 0x67, 0x59, 0xe6,
0x1d, 0x73, 0x5e, 0x29, 0x52, 0x9d, 0x6d, 0xf4, 0xe8, 0xd2, 0x96, 0x7d, 0x15, 0x1a, 0xf7, 0x78,
0xaa, 0x2e, 0x8a, 0xb5, 0x37, 0x96, 0xbb, 0x39, 0xee, 0x96, 0xdc, 0x33, 0xdb, 0x3c, 0x43, 0xad,
0xdd, 0xe0, 0x83, 0x21, 0x17, 0xea, 0xa9, 0x17, 0x0c, 0x9e, 0xb3, 0x5f, 0xa1, 0xc6, 0x75, 0x6e,
0xc9, 0xa6, 0x71, 0xbf, 0x68, 0x36, 0xbe, 0x9a, 0xc3, 0xcb, 0x5a, 0x0e, 0xa3, 0x01, 0x37, 0xcc,
0x7f, 0x08, 0x0d, 0x23, 0xf1, 0x49, 0x0b, 0x50, 0x31, 0x89, 0x4b, 0x0b, 0x50, 0x49, 0x9e, 0x94,
0x7b, 0x8d, 0xfa, 0x71, 0xd9, 0xe5, 0xac, 0x1f, 0x91, 0x1b, 0x95, 0xf5, 0x74, 0xe3, 0x63, 0x7f,
0x9c, 0x3e, 0x67, 0x4f, 0xe8, 0x89, 0x96, 0x79, 0x19, 0x9e, 0x79, 0x83, 0xf9, 0x7b, 0x73, 0xbd,
0x58, 0x46, 0x95, 0xed, 0x21, 0x8a, 0xae, 0xc8, 0x4b, 0xf8, 0x0c, 0xc0, 0x61, 0x1a, 0x4d, 0xee,
0xf8, 0x7c, 0x1c, 0x85, 0x99, 0xae, 0xcd, 0x2e, 0x7c, 0x33, 0xfd, 0x65, 0xdc, 0xfa, 0xb2, 0x27,
0x86, 0x3f, 0x6e, 0xe5, 0x12, 0x28, 0xe6, 0x9a, 0x7b, 0x27, 0xac, 0x17, 0xa4, 0xe4, 0x5e, 0xf8,
0xa6, 0x83, 0xde, 0x75, 0x16, 0x51, 0xd5, 0xde, 0x75, 0x21, 0x58, 0xab, 0xd5, 0x5e, 0x49, 0xf8,
0xf5, 0x00, 0xea, 0x59, 0x88, 0xee, 0x42, 0x96, 0xbc, 0x66, 0x05, 0xf4, 0xb4, 0x55, 0x2c, 0x04,
0xce, 0xdc, 0x36, 0x2d, 0x15, 0xb0, 0x65, 0x5c, 0x2a, 0x8a, 0x86, 0x05, 0xb0, 0x2e, 0x06, 0xa8,
0x4d, 0x3c, 0x5d, 0x61, 0xaa, 0x99, 0x94, 0x04, 0xaf, 0xb4, 0x34, 0x97, 0xc6, 0x7e, 0xac, 0x73,
0x36, 0x72, 0xab, 0xb8, 0x3e, 0x45, 0xd5, 0x3c, 0x86, 0xb5, 0x42, 0xe0, 0x42, 0x8b, 0xf4, 0xbc,
0x78, 0x91, 0x16, 0xe9, 0xb9, 0x31, 0x0f, 0xf7, 0x3c, 0x75, 0xb9, 0xea, 0x02, 0x76, 0x99, 0x9c,
0x05, 0x69, 0xff, 0xe4, 0x03, 0x67, 0xeb, 0x68, 0x91, 0xfe, 0x59, 0xec, 0x53, 0xff, 0x1b, 0x00,
0x00, 0xff, 0xff, 0x49, 0x74, 0xd2, 0x22, 0x8b, 0x4c, 0x00, 0x00,
// 6217 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5c, 0x4d, 0x6c, 0x1c, 0xc9,
0x75, 0x56, 0x0f, 0x87, 0x3f, 0xf3, 0x66, 0x48, 0x0e, 0x8b, 0x14, 0x35, 0x9a, 0xdd, 0xd5, 0x6a,
0xdb, 0xc2, 0x4a, 0x66, 0x36, 0x92, 0x96, 0xb6, 0x37, 0xeb, 0xdd, 0xc4, 0x8e, 0x44, 0x52, 0xa2,
0x6c, 0xae, 0x44, 0x37, 0x25, 0x2b, 0xb1, 0x13, 0x8c, 0x9b, 0x33, 0xc5, 0x61, 0x5b, 0x33, 0xdd,
0xed, 0xee, 0x1e, 0x52, 0xe3, 0x8d, 0x00, 0xe7, 0x07, 0x39, 0xc5, 0x08, 0x82, 0xe4, 0xe2, 0x00,
0x41, 0x00, 0x07, 0x08, 0x9c, 0x43, 0x8e, 0xc9, 0xc5, 0x09, 0x90, 0x43, 0x2e, 0x09, 0x10, 0xe4,
0xe0, 0x93, 0x91, 0x63, 0x92, 0x43, 0x12, 0xe4, 0x12, 0x20, 0xd7, 0x20, 0x78, 0xaf, 0x7e, 0xba,
0xaa, 0xbb, 0x29, 0xca, 0x3f, 0xc9, 0x6d, 0xea, 0xab, 0xd7, 0xf5, 0xfb, 0xfe, 0xea, 0xd5, 0xab,
0x81, 0x46, 0x12, 0xf7, 0x6f, 0xc6, 0x49, 0x94, 0x45, 0x6c, 0x76, 0x14, 0x26, 0x71, 0xbf, 0xfb,
0xfa, 0x30, 0x8a, 0x86, 0x23, 0x7e, 0xcb, 0x8f, 0x83, 0x5b, 0x7e, 0x18, 0x46, 0x99, 0x9f, 0x05,
0x51, 0x98, 0x0a, 0x22, 0xf7, 0x6b, 0xb0, 0x74, 0x9f, 0x87, 0x07, 0x9c, 0x0f, 0x3c, 0xfe, 0x8d,
0x09, 0x4f, 0x33, 0xf6, 0x33, 0xb0, 0xe2, 0xf3, 0x6f, 0x72, 0x3e, 0xe8, 0xc5, 0x7e, 0x9a, 0xc6,
0xc7, 0x89, 0x9f, 0xf2, 0x8e, 0x73, 0xd5, 0xb9, 0xd1, 0xf2, 0xda, 0xa2, 0x62, 0x5f, 0xe3, 0xec,
0x2d, 0x68, 0xa5, 0x48, 0xca, 0xc3, 0x2c, 0x89, 0xe2, 0x69, 0xa7, 0x46, 0x74, 0x4d, 0xc4, 0x76,
0x04, 0xe4, 0x8e, 0x60, 0x59, 0xf7, 0x90, 0xc6, 0x51, 0x98, 0x72, 0x76, 0x1b, 0xd6, 0xfa, 0x41,
0x7c, 0xcc, 0x93, 0x1e, 0x7d, 0x3c, 0x0e, 0xf9, 0x38, 0x0a, 0x83, 0x7e, 0xc7, 0xb9, 0x3a, 0x73,
0xa3, 0xe1, 0x31, 0x51, 0x87, 0x5f, 0x7c, 0x24, 0x6b, 0xd8, 0x75, 0x58, 0xe6, 0xa1, 0xc0, 0xf9,
0x80, 0xbe, 0x92, 0x5d, 0x2d, 0xe5, 0x30, 0x7e, 0xe0, 0xfe, 0xad, 0x03, 0x2b, 0x0f, 0xc2, 0x20,
0x7b, 0xea, 0x8f, 0x46, 0x3c, 0x53, 0x73, 0xba, 0x0e, 0xcb, 0xa7, 0x04, 0xd0, 0x9c, 0x4e, 0xa3,
0x64, 0x20, 0x67, 0xb4, 0x24, 0xe0, 0x7d, 0x89, 0x9e, 0x39, 0xb2, 0xda, 0x99, 0x23, 0xab, 0x5c,
0xae, 0x99, 0x33, 0x96, 0xeb, 0x3a, 0x2c, 0x27, 0xbc, 0x1f, 0x9d, 0xf0, 0x64, 0xda, 0x3b, 0x0d,
0xc2, 0x41, 0x74, 0xda, 0xa9, 0x5f, 0x75, 0x6e, 0xcc, 0x7a, 0x4b, 0x0a, 0x7e, 0x4a, 0xa8, 0xbb,
0x06, 0xcc, 0x9c, 0x85, 0x58, 0x37, 0x77, 0x08, 0xab, 0x4f, 0xc2, 0x51, 0xd4, 0x7f, 0xf6, 0x63,
0xce, 0xae, 0xa2, 0xfb, 0x5a, 0x65, 0xf7, 0xeb, 0xb0, 0x66, 0x77, 0x24, 0x07, 0xc0, 0xe1, 0xe2,
0xd6, 0xb1, 0x1f, 0x0e, 0xb9, 0x6a, 0x52, 0x0d, 0xe1, 0x93, 0xd0, 0xee, 0x4f, 0x92, 0x84, 0x87,
0xa5, 0x31, 0x2c, 0x4b, 0x5c, 0x0f, 0xe2, 0x2d, 0x68, 0x85, 0xfc, 0x34, 0x27, 0x93, 0x2c, 0x13,
0xf2, 0x53, 0x45, 0xe2, 0x76, 0x60, 0xbd, 0xd8, 0x8d, 0x1c, 0xc0, 0x77, 0x6a, 0xd0, 0x7c, 0x9c,
0xf8, 0x61, 0xea, 0xf7, 0x91, 0x8b, 0x59, 0x07, 0xe6, 0xb3, 0xe7, 0xbd, 0x63, 0x3f, 0x3d, 0xa6,
0xee, 0x1a, 0x9e, 0x2a, 0xb2, 0x75, 0x98, 0xf3, 0xc7, 0xd1, 0x24, 0xcc, 0xa8, 0x83, 0x19, 0x4f,
0x96, 0xd8, 0x3b, 0xb0, 0x12, 0x4e, 0xc6, 0xbd, 0x7e, 0x14, 0x1e, 0x05, 0xc9, 0x58, 0xc8, 0x02,
0xed, 0xd7, 0xac, 0x57, 0xae, 0x60, 0x57, 0x00, 0x0e, 0x71, 0x1d, 0x44, 0x17, 0x75, 0xea, 0xc2,
0x40, 0x98, 0x0b, 0x2d, 0x59, 0xe2, 0xc1, 0xf0, 0x38, 0xeb, 0xcc, 0x52, 0x43, 0x16, 0x86, 0x6d,
0x64, 0xc1, 0x98, 0xf7, 0xd2, 0xcc, 0x1f, 0xc7, 0x9d, 0x39, 0x1a, 0x8d, 0x81, 0x50, 0x7d, 0x94,
0xf9, 0xa3, 0xde, 0x11, 0xe7, 0x69, 0x67, 0x5e, 0xd6, 0x6b, 0x84, 0xbd, 0x0d, 0x4b, 0x03, 0x9e,
0x66, 0x3d, 0x7f, 0x30, 0x48, 0x78, 0x9a, 0xf2, 0xb4, 0xb3, 0x40, 0xdc, 0x58, 0x40, 0x71, 0xd5,
0xee, 0xf3, 0xcc, 0x58, 0x9d, 0x54, 0xee, 0x8e, 0xbb, 0x07, 0xcc, 0x80, 0xb7, 0x79, 0xe6, 0x07,
0xa3, 0x94, 0xbd, 0x07, 0xad, 0xcc, 0x20, 0x26, 0xe9, 0x6b, 0x6e, 0xb2, 0x9b, 0xa4, 0x36, 0x6e,
0x1a, 0x1f, 0x78, 0x16, 0x9d, 0x7b, 0x1f, 0x16, 0xee, 0x71, 0xbe, 0x17, 0x8c, 0x83, 0x8c, 0xad,
0xc3, 0xec, 0x51, 0xf0, 0x9c, 0x8b, 0xcd, 0x9e, 0xd9, 0xbd, 0xe0, 0x89, 0x22, 0xeb, 0xc2, 0x7c,
0xcc, 0x93, 0x3e, 0x57, 0xcb, 0xbf, 0x7b, 0xc1, 0x53, 0xc0, 0xdd, 0x79, 0x98, 0x1d, 0xe1, 0xc7,
0xee, 0xf7, 0x6a, 0xd0, 0x3c, 0xe0, 0xa1, 0x66, 0x22, 0x06, 0x75, 0x9c, 0x92, 0x64, 0x1c, 0xfa,
0xcd, 0xde, 0x84, 0x26, 0x4d, 0x33, 0xcd, 0x92, 0x20, 0x1c, 0x52, 0x63, 0x0d, 0x0f, 0x10, 0x3a,
0x20, 0x84, 0xb5, 0x61, 0xc6, 0x1f, 0x67, 0xb4, 0x83, 0x33, 0x1e, 0xfe, 0x44, 0x06, 0x8b, 0xfd,
0xe9, 0x18, 0x79, 0x51, 0xef, 0x5a, 0xcb, 0x6b, 0x4a, 0x6c, 0x17, 0xb7, 0xed, 0x26, 0xac, 0x9a,
0x24, 0xaa, 0xf5, 0x59, 0x6a, 0x7d, 0xc5, 0xa0, 0x94, 0x9d, 0x5c, 0x87, 0x65, 0x45, 0x9f, 0x88,
0xc1, 0xd2, 0x3e, 0x36, 0xbc, 0x25, 0x09, 0xab, 0x29, 0xdc, 0x80, 0xf6, 0x51, 0x10, 0xfa, 0xa3,
0x5e, 0x7f, 0x94, 0x9d, 0xf4, 0x06, 0x7c, 0x94, 0xf9, 0xb4, 0xa3, 0xb3, 0xde, 0x12, 0xe1, 0x5b,
0xa3, 0xec, 0x64, 0x1b, 0x51, 0xf6, 0x0e, 0x34, 0x8e, 0x38, 0xef, 0xd1, 0x4a, 0x74, 0x16, 0xae,
0x3a, 0x37, 0x9a, 0x9b, 0xcb, 0x72, 0xe9, 0xd5, 0xea, 0x7a, 0x0b, 0x47, 0xf2, 0x97, 0xfb, 0x07,
0x0e, 0xb4, 0xc4, 0x52, 0x49, 0x15, 0x7a, 0x0d, 0x16, 0xd5, 0x88, 0x78, 0x92, 0x44, 0x89, 0x64,
0x7f, 0x1b, 0x64, 0x1b, 0xd0, 0x56, 0x40, 0x9c, 0xf0, 0x60, 0xec, 0x0f, 0xb9, 0x94, 0xb7, 0x12,
0xce, 0x36, 0xf3, 0x16, 0x93, 0x68, 0x92, 0x09, 0x25, 0xd6, 0xdc, 0x6c, 0xc9, 0x41, 0x79, 0x88,
0x79, 0x36, 0x89, 0xfb, 0x6d, 0x07, 0x18, 0x0e, 0xeb, 0x71, 0x24, 0xaa, 0xe5, 0x2a, 0x14, 0x77,
0xc0, 0x79, 0xe5, 0x1d, 0xa8, 0x9d, 0xb5, 0x03, 0xd7, 0x60, 0x8e, 0xba, 0x44, 0x59, 0x9d, 0x29,
0x0d, 0x4b, 0xd6, 0xb9, 0xdf, 0x75, 0xa0, 0x85, 0x9a, 0x23, 0xe4, 0xa3, 0xfd, 0x28, 0x08, 0x33,
0x76, 0x1b, 0xd8, 0xd1, 0x24, 0x1c, 0x04, 0xe1, 0xb0, 0x97, 0x3d, 0x0f, 0x06, 0xbd, 0xc3, 0x29,
0x36, 0x41, 0xe3, 0xd9, 0xbd, 0xe0, 0x55, 0xd4, 0xb1, 0x77, 0xa0, 0x6d, 0xa1, 0x69, 0x96, 0x88,
0x51, 0xed, 0x5e, 0xf0, 0x4a, 0x35, 0x28, 0xff, 0xd1, 0x24, 0x8b, 0x27, 0x59, 0x2f, 0x08, 0x07,
0xfc, 0x39, 0xad, 0xd9, 0xa2, 0x67, 0x61, 0x77, 0x97, 0xa0, 0x65, 0x7e, 0xe7, 0x7e, 0x0e, 0xda,
0x7b, 0xa8, 0x18, 0xc2, 0x20, 0x1c, 0xde, 0x11, 0xd2, 0x8b, 0xda, 0x2a, 0x9e, 0x1c, 0x3e, 0xe3,
0x53, 0xb9, 0x8f, 0xb2, 0x84, 0x22, 0x71, 0x1c, 0xa5, 0x99, 0x5c, 0x17, 0xfa, 0xed, 0xfe, 0xb3,
0x03, 0xcb, 0xb8, 0xe8, 0x1f, 0xf9, 0xe1, 0x54, 0xad, 0xf8, 0x1e, 0xb4, 0xb0, 0xa9, 0xc7, 0xd1,
0x1d, 0xa1, 0xf3, 0x84, 0x2c, 0xdf, 0x90, 0x8b, 0x54, 0xa0, 0xbe, 0x69, 0x92, 0xa2, 0x99, 0x9e,
0x7a, 0xd6, 0xd7, 0x28, 0x74, 0x99, 0x9f, 0x0c, 0x79, 0x46, 0xda, 0x50, 0x6a, 0x47, 0x10, 0xd0,
0x56, 0x14, 0x1e, 0xb1, 0xab, 0xd0, 0x4a, 0xfd, 0xac, 0x17, 0xf3, 0x84, 0x56, 0x8d, 0x04, 0x67,
0xc6, 0x83, 0xd4, 0xcf, 0xf6, 0x79, 0x72, 0x77, 0x9a, 0xf1, 0xee, 0xe7, 0x61, 0xa5, 0xd4, 0x0b,
0xca, 0x6a, 0x3e, 0x45, 0xfc, 0xc9, 0xd6, 0x60, 0xf6, 0xc4, 0x1f, 0x4d, 0xb8, 0x54, 0xd2, 0xa2,
0xf0, 0x41, 0xed, 0x7d, 0xc7, 0x7d, 0x1b, 0xda, 0xf9, 0xb0, 0x25, 0xd3, 0x33, 0xa8, 0xe3, 0x0a,
0xca, 0x06, 0xe8, 0xb7, 0xfb, 0xeb, 0x8e, 0x20, 0xdc, 0x8a, 0x02, 0xad, 0xf0, 0x90, 0x10, 0xf5,
0xa2, 0x22, 0xc4, 0xdf, 0x67, 0x1a, 0x84, 0x9f, 0x7c, 0xb2, 0xee, 0x75, 0x58, 0x31, 0x86, 0xf0,
0x92, 0xc1, 0x7e, 0xdb, 0x81, 0x95, 0x87, 0xfc, 0x54, 0xee, 0xba, 0x1a, 0xed, 0xfb, 0x50, 0xcf,
0xa6, 0xb1, 0x70, 0xb2, 0x96, 0x36, 0xaf, 0xc9, 0x4d, 0x2b, 0xd1, 0xdd, 0x94, 0xc5, 0xc7, 0xd3,
0x98, 0x7b, 0xf4, 0x85, 0xfb, 0x39, 0x68, 0x1a, 0x20, 0xbb, 0x04, 0xab, 0x4f, 0x1f, 0x3c, 0x7e,
0xb8, 0x73, 0x70, 0xd0, 0xdb, 0x7f, 0x72, 0xf7, 0x8b, 0x3b, 0xbf, 0xdc, 0xdb, 0xbd, 0x73, 0xb0,
0xdb, 0xbe, 0xc0, 0xd6, 0x81, 0x3d, 0xdc, 0x39, 0x78, 0xbc, 0xb3, 0x6d, 0xe1, 0x8e, 0xdb, 0x85,
0xce, 0x43, 0x7e, 0xfa, 0x34, 0xc8, 0x42, 0x9e, 0xa6, 0x76, 0x6f, 0xee, 0x4d, 0x60, 0xe6, 0x10,
0xe4, 0xac, 0x3a, 0x30, 0x2f, 0x2d, 0x8e, 0x32, 0xb8, 0xb2, 0xe8, 0xbe, 0x0d, 0xec, 0x20, 0x18,
0x86, 0x1f, 0xf1, 0x34, 0xf5, 0x87, 0x5a, 0x15, 0xb4, 0x61, 0x66, 0x9c, 0x0e, 0xa5, 0x06, 0xc0,
0x9f, 0xee, 0xa7, 0x60, 0xd5, 0xa2, 0x93, 0x0d, 0xbf, 0x0e, 0x8d, 0x34, 0x18, 0x86, 0x7e, 0x36,
0x49, 0xb8, 0x6c, 0x3a, 0x07, 0xdc, 0x7b, 0xb0, 0xf6, 0x65, 0x9e, 0x04, 0x47, 0xd3, 0xf3, 0x9a,
0xb7, 0xdb, 0xa9, 0x15, 0xdb, 0xd9, 0x81, 0x8b, 0x85, 0x76, 0x64, 0xf7, 0x82, 0x11, 0xe5, 0x76,
0x2d, 0x78, 0xa2, 0x60, 0x88, 0x65, 0xcd, 0x14, 0x4b, 0xf7, 0x09, 0xb0, 0xad, 0x28, 0x0c, 0x79,
0x3f, 0xdb, 0xe7, 0x3c, 0xc9, 0x3d, 0xe7, 0x9c, 0xeb, 0x9a, 0x9b, 0x97, 0xe4, 0x3e, 0x16, 0x65,
0x5d, 0xb2, 0x23, 0x83, 0x7a, 0xcc, 0x93, 0x31, 0x35, 0xbc, 0xe0, 0xd1, 0x6f, 0xf7, 0x22, 0xac,
0x5a, 0xcd, 0x4a, 0xa7, 0xe7, 0x5d, 0xb8, 0xb8, 0x1d, 0xa4, 0xfd, 0x72, 0x87, 0x1d, 0x98, 0x8f,
0x27, 0x87, 0xbd, 0x5c, 0xa6, 0x54, 0x11, 0x7d, 0x81, 0xe2, 0x27, 0xb2, 0xb1, 0xdf, 0x76, 0xa0,
0xbe, 0xfb, 0x78, 0x6f, 0x8b, 0x75, 0x61, 0x21, 0x08, 0xfb, 0xd1, 0x18, 0xd5, 0xae, 0x98, 0xb4,
0x2e, 0x9f, 0x29, 0x2b, 0xaf, 0x43, 0x83, 0xb4, 0x35, 0xba, 0x37, 0xd2, 0xc9, 0xcd, 0x01, 0x74,
0xad, 0xf8, 0xf3, 0x38, 0x48, 0xc8, 0x77, 0x52, 0x1e, 0x51, 0x9d, 0x34, 0x62, 0xb9, 0xc2, 0xfd,
0x9f, 0x3a, 0xcc, 0x4b, 0x5d, 0x4d, 0xfd, 0xf5, 0xb3, 0xe0, 0x84, 0xcb, 0x91, 0xc8, 0x12, 0x5a,
0xb9, 0x84, 0x8f, 0xa3, 0x8c, 0xf7, 0xac, 0x6d, 0xb0, 0x41, 0xa4, 0xea, 0x8b, 0x86, 0x7a, 0x31,
0x6a, 0x7d, 0x1a, 0x59, 0xc3, 0xb3, 0x41, 0x5c, 0x2c, 0x04, 0x7a, 0xc1, 0x80, 0xc6, 0x54, 0xf7,
0x54, 0x11, 0x57, 0xa2, 0xef, 0xc7, 0x7e, 0x3f, 0xc8, 0xa6, 0x52, 0xb8, 0x75, 0x19, 0xdb, 0x1e,
0x45, 0x7d, 0x7f, 0xd4, 0x3b, 0xf4, 0x47, 0x7e, 0xd8, 0xe7, 0xd2, 0x7f, 0xb3, 0x41, 0x74, 0xd1,
0xe4, 0x90, 0x14, 0x99, 0x70, 0xe3, 0x0a, 0x28, 0xba, 0x7a, 0xfd, 0x68, 0x3c, 0x0e, 0x32, 0xf4,
0xec, 0xc8, 0xea, 0xcf, 0x78, 0x06, 0x42, 0x33, 0x11, 0xa5, 0x53, 0xb1, 0x7a, 0x0d, 0xd1, 0x9b,
0x05, 0x62, 0x2b, 0xe8, 0x3a, 0xa0, 0x42, 0x7a, 0x76, 0xda, 0x01, 0xd1, 0x4a, 0x8e, 0xe0, 0x3e,
0x4c, 0xc2, 0x94, 0x67, 0xd9, 0x88, 0x0f, 0xf4, 0x80, 0x9a, 0x44, 0x56, 0xae, 0x60, 0xb7, 0x61,
0x55, 0x38, 0x9b, 0xa9, 0x9f, 0x45, 0xe9, 0x71, 0x90, 0xf6, 0x52, 0x74, 0xdb, 0x5a, 0x44, 0x5f,
0x55, 0xc5, 0xde, 0x87, 0x4b, 0x05, 0x38, 0xe1, 0x7d, 0x1e, 0x9c, 0xf0, 0x41, 0x67, 0x91, 0xbe,
0x3a, 0xab, 0x9a, 0x5d, 0x85, 0x26, 0xfa, 0xd8, 0x93, 0x78, 0xe0, 0xa3, 0x1d, 0x5e, 0xa2, 0x7d,
0x30, 0x21, 0xf6, 0x2e, 0x2c, 0xc6, 0x5c, 0x18, 0xcb, 0xe3, 0x6c, 0xd4, 0x4f, 0x3b, 0xcb, 0x64,
0xc9, 0x9a, 0x52, 0x98, 0x90, 0x73, 0x3d, 0x9b, 0x02, 0x99, 0xb2, 0x9f, 0x92, 0xb3, 0xe5, 0x4f,
0x3b, 0x6d, 0x62, 0xb7, 0x1c, 0x20, 0x19, 0x49, 0x82, 0x13, 0x3f, 0xe3, 0x9d, 0x15, 0xe2, 0x2d,
0x55, 0x74, 0xff, 0xd8, 0x81, 0xd5, 0xbd, 0x20, 0xcd, 0x24, 0x13, 0x6a, 0x75, 0xfc, 0x26, 0x34,
0x05, 0xfb, 0xf5, 0xa2, 0x70, 0x34, 0x95, 0x1c, 0x09, 0x02, 0x7a, 0x14, 0x8e, 0xa6, 0xec, 0x13,
0xb0, 0x18, 0x84, 0x26, 0x89, 0x90, 0xe1, 0x96, 0x02, 0x89, 0xe8, 0x4d, 0x68, 0xc6, 0x93, 0xc3,
0x51, 0xd0, 0x17, 0x24, 0x33, 0xa2, 0x15, 0x01, 0x11, 0x01, 0x3a, 0x49, 0x62, 0x24, 0x82, 0xa2,
0x4e, 0x14, 0x4d, 0x89, 0x21, 0x89, 0x7b, 0x17, 0xd6, 0xec, 0x01, 0x4a, 0x65, 0xb5, 0x01, 0x0b,
0x92, 0xb7, 0xd3, 0x4e, 0x93, 0xd6, 0x67, 0x49, 0xae, 0x8f, 0x24, 0xf5, 0x74, 0xbd, 0xfb, 0xa7,
0x75, 0x58, 0x95, 0xe8, 0xd6, 0x28, 0x4a, 0xf9, 0xc1, 0x64, 0x3c, 0xf6, 0x93, 0x0a, 0xa1, 0x71,
0xce, 0x11, 0x9a, 0x9a, 0x2d, 0x34, 0xc8, 0xca, 0xc7, 0x7e, 0x10, 0x0a, 0x0f, 0x4f, 0x48, 0x9c,
0x81, 0xb0, 0x1b, 0xb0, 0xdc, 0x1f, 0x45, 0xa9, 0xf0, 0x7a, 0xcc, 0xe3, 0x53, 0x11, 0x2e, 0x0b,
0xf9, 0x6c, 0x95, 0x90, 0x9b, 0x42, 0x3a, 0x57, 0x10, 0x52, 0x17, 0x5a, 0xd8, 0x28, 0x57, 0x3a,
0x67, 0x5e, 0x78, 0x61, 0x26, 0x86, 0xe3, 0x29, 0x8a, 0x84, 0x90, 0xbf, 0xe5, 0x2a, 0x81, 0xc0,
0xd3, 0x19, 0xea, 0x34, 0x83, 0xba, 0x21, 0x05, 0xa2, 0x5c, 0xc5, 0xee, 0x01, 0x88, 0xbe, 0xc8,
0x8c, 0x03, 0x99, 0xf1, 0xb7, 0xed, 0x1d, 0x31, 0xd7, 0xfe, 0x26, 0x16, 0x26, 0x09, 0x27, 0x43,
0x6e, 0x7c, 0xe9, 0x7e, 0x0c, 0x4d, 0xa3, 0x8a, 0x5d, 0x84, 0x95, 0xad, 0x47, 0x8f, 0xf6, 0x77,
0xbc, 0x3b, 0x8f, 0x1f, 0x7c, 0x79, 0xa7, 0xb7, 0xb5, 0xf7, 0xe8, 0x60, 0xa7, 0x7d, 0x01, 0xe1,
0xbd, 0x47, 0x5b, 0x77, 0xf6, 0x7a, 0xf7, 0x1e, 0x79, 0x5b, 0x0a, 0x76, 0xd0, 0xc6, 0x7b, 0x3b,
0x1f, 0x3d, 0x7a, 0xbc, 0x63, 0xe1, 0x35, 0xd6, 0x86, 0xd6, 0x5d, 0x6f, 0xe7, 0xce, 0xd6, 0xae,
0x44, 0x66, 0xd8, 0x1a, 0xb4, 0xef, 0x3d, 0x79, 0xb8, 0xfd, 0xe0, 0xe1, 0xfd, 0xde, 0xd6, 0x9d,
0x87, 0x5b, 0x3b, 0x7b, 0x3b, 0xdb, 0xed, 0xba, 0xfb, 0x37, 0x0e, 0x5c, 0xa4, 0x51, 0x0e, 0x8a,
0x02, 0x71, 0x15, 0x9a, 0xfd, 0x28, 0x8a, 0x39, 0xea, 0x6f, 0xad, 0xa2, 0x4d, 0x08, 0x99, 0x5d,
0x28, 0xc4, 0xa3, 0x28, 0xe9, 0x73, 0x29, 0x0f, 0x40, 0xd0, 0x3d, 0x44, 0x90, 0xd9, 0xe5, 0x76,
0x0a, 0x0a, 0x21, 0x0e, 0x4d, 0x81, 0x09, 0x92, 0x75, 0x98, 0x3b, 0x4c, 0xb8, 0xdf, 0x3f, 0x96,
0x92, 0x20, 0x4b, 0xec, 0x93, 0xb9, 0x43, 0xde, 0xc7, 0xd5, 0x1e, 0xf1, 0x01, 0x71, 0xc8, 0x82,
0xb7, 0x2c, 0xf1, 0x2d, 0x09, 0xbb, 0xfb, 0xb0, 0x5e, 0x9c, 0x81, 0x94, 0x98, 0xf7, 0x0c, 0x89,
0x11, 0xbe, 0x71, 0xf7, 0xec, 0xfd, 0x31, 0xa4, 0xe7, 0xdf, 0x1d, 0xa8, 0xa3, 0xf9, 0x3c, 0xdb,
0xd4, 0x9a, 0x1e, 0xd1, 0x8c, 0xe5, 0x11, 0x51, 0xf0, 0x00, 0xcf, 0x14, 0x42, 0xa1, 0x0a, 0xa3,
0x63, 0x20, 0x79, 0x7d, 0xc2, 0xfb, 0x27, 0x34, 0x27, 0x5d, 0x8f, 0x08, 0xb2, 0x3c, 0x3a, 0x9e,
0xf4, 0xb5, 0x64, 0x79, 0x55, 0x56, 0x75, 0xf4, 0xe5, 0x7c, 0x5e, 0x47, 0xdf, 0x75, 0x60, 0x3e,
0x08, 0x0f, 0xa3, 0x49, 0x38, 0x20, 0x16, 0x5f, 0xf0, 0x54, 0x11, 0x55, 0x65, 0x4c, 0xa2, 0x17,
0x8c, 0x15, 0x43, 0xe7, 0x80, 0xcb, 0xf0, 0x60, 0x92, 0x92, 0xbb, 0xa0, 0xbd, 0xc0, 0xf7, 0x60,
0xc5, 0xc0, 0xe4, 0x6a, 0xbe, 0x05, 0xb3, 0x31, 0x02, 0x72, 0x29, 0x95, 0x72, 0x26, 0x3f, 0x43,
0xd4, 0xb8, 0x6d, 0x58, 0xba, 0xcf, 0xb3, 0x07, 0xe1, 0x51, 0xa4, 0x5a, 0xfa, 0xe1, 0x0c, 0x2c,
0x6b, 0x48, 0x36, 0x74, 0x03, 0x96, 0x83, 0x01, 0x0f, 0xb3, 0x20, 0x9b, 0xf6, 0xac, 0xf3, 0x4f,
0x11, 0x46, 0xff, 0xcc, 0x1f, 0x05, 0x7e, 0x2a, 0x3d, 0x00, 0x51, 0x60, 0x9b, 0xb0, 0x86, 0xc6,
0x43, 0xd9, 0x03, 0xbd, 0xc5, 0xe2, 0x18, 0x56, 0x59, 0x87, 0xe2, 0x8d, 0xb8, 0xd4, 0xdf, 0xfa,
0x13, 0xe1, 0xa7, 0x54, 0x55, 0xe1, 0xaa, 0x89, 0x96, 0x70, 0xca, 0xb3, 0xc2, 0xc0, 0x68, 0xa0,
0x14, 0x02, 0x9a, 0x13, 0xca, 0xa7, 0x18, 0x02, 0x32, 0xc2, 0x48, 0x0b, 0xa5, 0x30, 0x12, 0x2a,
0xa7, 0x69, 0xd8, 0xe7, 0x83, 0x5e, 0x16, 0xf5, 0x48, 0x89, 0xd2, 0xee, 0x2c, 0x78, 0x45, 0x98,
0x02, 0x5e, 0x3c, 0xcd, 0x42, 0x9e, 0x91, 0x9e, 0x59, 0xf0, 0x54, 0x11, 0xe5, 0x87, 0x48, 0x84,
0x49, 0x68, 0x78, 0xb2, 0x84, 0x8e, 0xe6, 0x24, 0x09, 0xd2, 0x4e, 0x8b, 0x50, 0xfa, 0xcd, 0x3e,
0x0d, 0x17, 0x0f, 0x79, 0x9a, 0xf5, 0x8e, 0xb9, 0x3f, 0xe0, 0x09, 0xed, 0xbe, 0x88, 0x4e, 0x09,
0xfb, 0x5d, 0x5d, 0x89, 0x7d, 0x9f, 0xf0, 0x24, 0x0d, 0xa2, 0x90, 0x2c, 0x77, 0xc3, 0x53, 0x45,
0xf7, 0x9b, 0xe4, 0x0f, 0xeb, 0xb8, 0xd9, 0x13, 0x32, 0xe6, 0xec, 0x35, 0x68, 0x88, 0x39, 0xa6,
0xc7, 0xbe, 0x74, 0xd1, 0x17, 0x08, 0x38, 0x38, 0xf6, 0x51, 0x23, 0x58, 0xcb, 0x26, 0x02, 0x91,
0x4d, 0xc2, 0x76, 0xc5, 0xaa, 0x5d, 0x83, 0x25, 0x15, 0x91, 0x4b, 0x7b, 0x23, 0x7e, 0x94, 0xa9,
0xe3, 0x75, 0x38, 0x19, 0x63, 0x77, 0xe9, 0x1e, 0x3f, 0xca, 0xdc, 0x87, 0xb0, 0x22, 0x65, 0xf8,
0x51, 0xcc, 0x55, 0xd7, 0x9f, 0xad, 0xb2, 0x6e, 0xcd, 0xcd, 0x55, 0x5b, 0xe8, 0x29, 0x46, 0x50,
0x30, 0x79, 0xae, 0x07, 0xcc, 0xd4, 0x09, 0xb2, 0x41, 0x69, 0x62, 0xd4, 0x21, 0x5e, 0x4e, 0xc7,
0xc2, 0x70, 0x7d, 0xd2, 0x49, 0xbf, 0x8f, 0x9a, 0x40, 0x68, 0x40, 0x55, 0x74, 0xbf, 0xe7, 0xc0,
0x2a, 0xb5, 0xa6, 0xec, 0xb3, 0x3e, 0xf9, 0xbd, 0xfa, 0x30, 0x5b, 0x7d, 0x33, 0xb0, 0xb1, 0x06,
0xb3, 0xa6, 0xae, 0x15, 0x85, 0x1f, 0xfd, 0x2c, 0x5b, 0x2f, 0x9d, 0x65, 0x7f, 0xe8, 0xc0, 0x8a,
0x50, 0x86, 0x99, 0x9f, 0x4d, 0x52, 0x39, 0xfd, 0x9f, 0x87, 0x45, 0x61, 0xa7, 0xa4, 0x38, 0xc9,
0x81, 0xae, 0x69, 0xc9, 0x27, 0x54, 0x10, 0xef, 0x5e, 0xf0, 0x6c, 0x62, 0xf6, 0x79, 0x68, 0x99,
0x61, 0x55, 0x1a, 0x73, 0x73, 0xf3, 0xb2, 0x9a, 0x65, 0x89, 0x73, 0x76, 0x2f, 0x78, 0xd6, 0x07,
0xec, 0x43, 0x72, 0x36, 0xc2, 0x1e, 0x35, 0x2b, 0x03, 0x53, 0x97, 0x2b, 0x14, 0xb8, 0xfe, 0xdc,
0x20, 0xbf, 0xbb, 0x00, 0x73, 0xc2, 0xbb, 0x74, 0xef, 0xc3, 0xa2, 0x35, 0x52, 0xeb, 0x8c, 0xde,
0x12, 0x67, 0xf4, 0x52, 0x48, 0xa7, 0x56, 0x0e, 0xe9, 0xb8, 0xff, 0x5a, 0x03, 0x86, 0xdc, 0x56,
0xd8, 0x4e, 0x74, 0x6f, 0xa3, 0x81, 0x75, 0x58, 0x69, 0x79, 0x26, 0xc4, 0x6e, 0x02, 0x33, 0x8a,
0x2a, 0xea, 0x25, 0xec, 0x46, 0x45, 0x0d, 0x2a, 0x38, 0x69, 0x58, 0xa5, 0x09, 0x94, 0xc7, 0x32,
0xb1, 0x6f, 0x95, 0x75, 0x68, 0x1a, 0xe2, 0x49, 0x7a, 0x8c, 0xee, 0xb7, 0x3a, 0xce, 0xa8, 0x72,
0x91, 0x41, 0xe6, 0xce, 0x65, 0x90, 0xf9, 0x22, 0x83, 0x98, 0x0e, 0xf5, 0x82, 0xe5, 0x50, 0xa3,
0x23, 0x37, 0x46, 0xf7, 0x2f, 0x1b, 0xf5, 0x7b, 0x63, 0xec, 0x5d, 0x9e, 0x5e, 0x2c, 0x90, 0x6d,
0x40, 0x5b, 0xba, 0x02, 0xb9, 0xd7, 0x0e, 0xb4, 0xc6, 0x25, 0xdc, 0xfd, 0x81, 0x03, 0x6d, 0x5c,
0x67, 0x8b, 0x17, 0x3f, 0x00, 0x12, 0x85, 0x57, 0x64, 0x45, 0x8b, 0xf6, 0x27, 0xe7, 0xc4, 0xf7,
0xa1, 0x41, 0x0d, 0x46, 0x31, 0x0f, 0x25, 0x23, 0x76, 0x6c, 0x46, 0xcc, 0xb5, 0xd0, 0xee, 0x05,
0x2f, 0x27, 0x36, 0xd8, 0xf0, 0x1f, 0x1d, 0x68, 0xca, 0x61, 0xfe, 0xd8, 0x27, 0xf1, 0x2e, 0x2c,
0x20, 0x47, 0x1a, 0xc7, 0x5d, 0x5d, 0x46, 0x6b, 0x32, 0xf6, 0xb3, 0x49, 0x82, 0xe6, 0xd3, 0x3a,
0x85, 0x17, 0x61, 0xb4, 0x85, 0xa4, 0x70, 0xd3, 0x5e, 0x16, 0x8c, 0x7a, 0xaa, 0x56, 0xde, 0x62,
0x54, 0x55, 0xa1, 0xde, 0x49, 0x33, 0x7f, 0xc8, 0xa5, 0x99, 0x13, 0x05, 0xb7, 0x03, 0xeb, 0x72,
0x42, 0x05, 0xdf, 0xd1, 0xfd, 0xeb, 0x16, 0x5c, 0x2a, 0x55, 0xe9, 0x6b, 0x40, 0x79, 0xbc, 0x1c,
0x05, 0xe3, 0xc3, 0x48, 0x3b, 0xda, 0x8e, 0x79, 0xf2, 0xb4, 0xaa, 0xd8, 0x10, 0x2e, 0x2a, 0x7b,
0x8e, 0x6b, 0x9a, 0x5b, 0xef, 0x1a, 0x39, 0x22, 0xef, 0xda, 0x3c, 0x50, 0xec, 0x50, 0xe1, 0xa6,
0xe4, 0x56, 0xb7, 0xc7, 0x8e, 0xa1, 0xa3, 0x1d, 0x07, 0xa9, 0xe2, 0x0d, 0xe7, 0x02, 0xfb, 0x7a,
0xe7, 0x9c, 0xbe, 0x2c, 0x47, 0xd4, 0x3b, 0xb3, 0x35, 0x36, 0x85, 0x2b, 0xaa, 0x8e, 0x74, 0x78,
0xb9, 0xbf, 0xfa, 0x2b, 0xcd, 0x8d, 0x9c, 0x68, 0xbb, 0xd3, 0x73, 0x1a, 0x66, 0x5f, 0x87, 0xf5,
0x53, 0x3f, 0xc8, 0xd4, 0xb0, 0x0c, 0x67, 0x68, 0x96, 0xba, 0xdc, 0x3c, 0xa7, 0xcb, 0xa7, 0xe2,
0x63, 0xcb, 0xb0, 0x9d, 0xd1, 0x62, 0xf7, 0xef, 0x1d, 0x58, 0xb2, 0xdb, 0x41, 0x36, 0x95, 0x02,
0xaf, 0x14, 0x9f, 0x72, 0xfe, 0x0a, 0x70, 0xf9, 0xac, 0x5a, 0xab, 0x3a, 0xab, 0x9a, 0x27, 0xc4,
0x99, 0xf3, 0xc2, 0x38, 0xf5, 0x57, 0x0b, 0xe3, 0xcc, 0x56, 0x85, 0x71, 0xba, 0xff, 0xed, 0x00,
0x2b, 0xf3, 0x12, 0xbb, 0x2f, 0x0e, 0xcb, 0x21, 0x1f, 0x49, 0x9d, 0xf4, 0xb3, 0xaf, 0xc6, 0x8f,
0x6a, 0xed, 0xd4, 0xd7, 0x28, 0x18, 0xa6, 0xd2, 0x31, 0x5d, 0xa4, 0x45, 0xaf, 0xaa, 0xaa, 0x10,
0x58, 0xaa, 0x9f, 0x1f, 0x58, 0x9a, 0x3d, 0x3f, 0xb0, 0x34, 0x57, 0x0c, 0x2c, 0x75, 0x7f, 0xcb,
0x81, 0xd5, 0x8a, 0x4d, 0xff, 0xe9, 0x4d, 0x1c, 0xb7, 0xc9, 0xd2, 0x05, 0x35, 0xb9, 0x4d, 0x26,
0xd8, 0xfd, 0x35, 0x58, 0xb4, 0x18, 0xfd, 0xa7, 0xd7, 0x7f, 0xd1, 0xcb, 0x13, 0x7c, 0x66, 0x61,
0xdd, 0xff, 0xa8, 0x01, 0x2b, 0x0b, 0xdb, 0xff, 0xeb, 0x18, 0xca, 0xeb, 0x34, 0x53, 0xb1, 0x4e,
0xff, 0xa7, 0x76, 0xe0, 0x1d, 0x58, 0x91, 0x39, 0x03, 0x46, 0x88, 0x44, 0x70, 0x4c, 0xb9, 0x02,
0xfd, 0x5c, 0x3b, 0xaa, 0xb7, 0x60, 0xdd, 0x35, 0x1b, 0xc6, 0xb0, 0x10, 0xdc, 0x73, 0xd7, 0x61,
0x4d, 0xe4, 0x20, 0xdc, 0x15, 0x4d, 0x29, 0xbb, 0xf2, 0x47, 0x0e, 0x5c, 0x2c, 0x54, 0xe4, 0x37,
0xa3, 0xc2, 0x74, 0xd8, 0xf6, 0xc4, 0x06, 0x71, 0xfc, 0x52, 0x8e, 0x8c, 0xf1, 0x0b, 0x6e, 0x2b,
0x57, 0xe0, 0xfa, 0x4c, 0xc2, 0x32, 0xbd, 0x58, 0xf5, 0xaa, 0x2a, 0xf7, 0x92, 0xc8, 0x94, 0x08,
0xf9, 0xa8, 0x30, 0xf0, 0x23, 0x91, 0xdb, 0x60, 0x56, 0xe4, 0x57, 0x2b, 0xf6, 0x90, 0x55, 0x11,
0xbd, 0x40, 0xcb, 0x4c, 0xd9, 0xe3, 0xad, 0xac, 0x73, 0xff, 0xd2, 0x01, 0xf6, 0xa5, 0x09, 0x4f,
0xa6, 0x74, 0x43, 0xaa, 0x63, 0x39, 0x97, 0x8a, 0x71, 0x8c, 0xb9, 0x78, 0x72, 0xf8, 0x45, 0x3e,
0x55, 0xf7, 0xe8, 0xb5, 0xfc, 0x1e, 0xfd, 0x0d, 0x00, 0x3c, 0x7e, 0xe9, 0x6b, 0x57, 0xe4, 0x05,
0x3c, 0xf7, 0x8a, 0x06, 0x2b, 0xaf, 0xba, 0xeb, 0xe7, 0x5f, 0x75, 0xcf, 0x9e, 0x77, 0xd5, 0xfd,
0x21, 0xac, 0x5a, 0xe3, 0xd6, 0xdb, 0xaa, 0x2e, 0x80, 0x9d, 0x97, 0x5c, 0x00, 0xff, 0xa7, 0x03,
0x33, 0xbb, 0x51, 0x6c, 0xc6, 0x2d, 0x1d, 0x3b, 0x6e, 0x29, 0x6d, 0x49, 0x4f, 0x9b, 0x0a, 0xa9,
0x62, 0x2c, 0x90, 0x6d, 0xc0, 0x92, 0x3f, 0xce, 0xf0, 0xd8, 0x7d, 0x14, 0x25, 0xa7, 0x7e, 0x32,
0x10, 0x7b, 0x7d, 0xb7, 0xd6, 0x71, 0xbc, 0x42, 0x0d, 0x5b, 0x83, 0x19, 0xad, 0x74, 0x89, 0x00,
0x8b, 0xe8, 0xb8, 0xd1, 0x9d, 0xc7, 0x54, 0x46, 0x0c, 0x64, 0x09, 0x59, 0xc9, 0xfe, 0x5e, 0xb8,
0xca, 0x42, 0x74, 0xaa, 0xaa, 0xd0, 0xae, 0xe1, 0xf2, 0x11, 0x99, 0x0c, 0xf5, 0xa8, 0xb2, 0xfb,
0x6f, 0x0e, 0xcc, 0xd2, 0x0a, 0xa0, 0xb0, 0x0b, 0x0e, 0xd7, 0x01, 0x4a, 0x9a, 0xf9, 0xa2, 0x57,
0x84, 0x99, 0x6b, 0xe5, 0x9b, 0xd4, 0xf4, 0xb0, 0xcd, 0x9c, 0x93, 0xab, 0xd0, 0x10, 0x25, 0x9d,
0x5b, 0x41, 0x24, 0x39, 0xc8, 0xae, 0x40, 0xfd, 0x38, 0x8a, 0x95, 0x77, 0x02, 0x2a, 0x3e, 0x1f,
0xc5, 0x1e, 0xe1, 0xf9, 0x78, 0xb0, 0x3d, 0x31, 0x78, 0x61, 0x73, 0x8a, 0x30, 0x5a, 0x5d, 0xdd,
0xac, 0xb9, 0x18, 0x05, 0xd4, 0xdd, 0x80, 0xe5, 0x87, 0xd1, 0x80, 0x1b, 0x31, 0xa5, 0x33, 0xb9,
0xd9, 0xfd, 0x96, 0x03, 0x0b, 0x8a, 0x98, 0xdd, 0x80, 0x3a, 0xba, 0x12, 0x85, 0x83, 0x82, 0xbe,
0x97, 0x43, 0x3a, 0x8f, 0x28, 0x50, 0xf7, 0x52, 0xc4, 0x21, 0x77, 0x2b, 0x55, 0xbc, 0x21, 0xf7,
0x9a, 0xf4, 0x70, 0x0b, 0xce, 0x46, 0x01, 0x75, 0xff, 0xcc, 0x81, 0x45, 0xab, 0x0f, 0x3c, 0x1e,
0x8e, 0xfc, 0x34, 0x93, 0x77, 0x1d, 0x72, 0x7b, 0x4c, 0xc8, 0x8c, 0x32, 0xd6, 0xec, 0x28, 0xa3,
0x8e, 0x7f, 0xcd, 0x98, 0xf1, 0xaf, 0xdb, 0xd0, 0xc8, 0xb3, 0x82, 0xea, 0x96, 0x4e, 0xc5, 0x1e,
0xd5, 0x8d, 0x63, 0x4e, 0x84, 0xed, 0xf4, 0xa3, 0x51, 0x94, 0xc8, 0x20, 0xbb, 0x28, 0xb8, 0x1f,
0x42, 0xd3, 0xa0, 0xc7, 0x61, 0x84, 0x3c, 0x3b, 0x8d, 0x92, 0x67, 0x2a, 0xd8, 0x29, 0x8b, 0xfa,
0x62, 0xbd, 0x96, 0x5f, 0xac, 0xbb, 0x7f, 0xee, 0xc0, 0x22, 0xf2, 0x60, 0x10, 0x0e, 0xf7, 0xa3,
0x51, 0xd0, 0x9f, 0xd2, 0xde, 0x2b, 0x76, 0x93, 0x9a, 0x41, 0xf1, 0xa2, 0x0d, 0x23, 0x6f, 0xab,
0xd3, 0xa1, 0x14, 0x44, 0x5d, 0x46, 0x49, 0x45, 0x3e, 0x3f, 0xf4, 0x53, 0xc9, 0xfc, 0xd2, 0xc8,
0x59, 0x20, 0xca, 0x13, 0x02, 0x89, 0x9f, 0xf1, 0xde, 0x38, 0x18, 0x8d, 0x02, 0x41, 0x2b, 0x5c,
0xa0, 0xaa, 0x2a, 0xf7, 0xfb, 0x35, 0x68, 0x4a, 0x15, 0xbc, 0x33, 0x18, 0x72, 0x79, 0x93, 0x41,
0x8e, 0xa4, 0x56, 0x17, 0x06, 0xa2, 0xea, 0x2d, 0xd7, 0xd3, 0x40, 0x8a, 0xdb, 0x3a, 0x53, 0xde,
0xd6, 0xd7, 0xa1, 0x81, 0xec, 0xf5, 0x2e, 0xf9, 0xb8, 0xe2, 0x16, 0x24, 0x07, 0x54, 0xed, 0x26,
0xd5, 0xce, 0xe6, 0xb5, 0x04, 0xbc, 0xf4, 0xde, 0xe3, 0x7d, 0x68, 0xc9, 0x66, 0x68, 0xdd, 0x49,
0x3b, 0xe4, 0x0c, 0x6e, 0xed, 0x89, 0x67, 0x51, 0xaa, 0x2f, 0x37, 0xd5, 0x97, 0x0b, 0xe7, 0x7d,
0xa9, 0x28, 0xe9, 0x8e, 0x5a, 0xac, 0xcd, 0xfd, 0xc4, 0x8f, 0x8f, 0x95, 0x59, 0x1b, 0xe8, 0xc4,
0x1b, 0x82, 0xd9, 0x06, 0xcc, 0xe2, 0x67, 0x4a, 0x5b, 0x57, 0x0b, 0x9d, 0x20, 0x61, 0x37, 0x60,
0x96, 0x0f, 0x86, 0x5c, 0x9d, 0xe2, 0x98, 0x7d, 0x9e, 0xc6, 0x3d, 0xf2, 0x04, 0x01, 0xaa, 0x00,
0x44, 0x0b, 0x2a, 0xc0, 0xd6, 0xf4, 0x73, 0x58, 0x7c, 0x30, 0x70, 0xd7, 0x80, 0x3d, 0x14, 0x5c,
0x6b, 0x46, 0xa1, 0x7f, 0x73, 0x06, 0x9a, 0x06, 0x8c, 0xd2, 0x3c, 0xc4, 0x01, 0xf7, 0x06, 0x81,
0x3f, 0xe6, 0x19, 0x4f, 0x24, 0xa7, 0x16, 0x50, 0xa4, 0xf3, 0x4f, 0x86, 0xbd, 0x68, 0x92, 0xf5,
0x06, 0x7c, 0x98, 0x70, 0x61, 0x7c, 0xd1, 0x18, 0x58, 0x28, 0xd2, 0x8d, 0xfd, 0xe7, 0x26, 0x9d,
0xe0, 0x87, 0x02, 0xaa, 0x62, 0xca, 0x62, 0x8d, 0xea, 0x79, 0x4c, 0x59, 0xac, 0x48, 0x51, 0x0f,
0xcd, 0x56, 0xe8, 0xa1, 0xf7, 0x60, 0x5d, 0x68, 0x1c, 0x29, 0x9b, 0xbd, 0x02, 0x9b, 0x9c, 0x51,
0xcb, 0x36, 0xa0, 0x8d, 0x63, 0x56, 0x0c, 0x9e, 0x06, 0xdf, 0x14, 0x51, 0x1e, 0xc7, 0x2b, 0xe1,
0x48, 0x8b, 0xe2, 0x68, 0xd1, 0x8a, 0x5b, 0xb3, 0x12, 0x4e, 0xb4, 0xfe, 0x73, 0x9b, 0xb6, 0x21,
0x69, 0x0b, 0xb8, 0xbb, 0x08, 0xcd, 0x83, 0x2c, 0x8a, 0xd5, 0xa6, 0x2c, 0x41, 0x4b, 0x14, 0x65,
0x8e, 0xc2, 0x6b, 0x70, 0x99, 0xb8, 0xe8, 0x71, 0x14, 0x47, 0xa3, 0x68, 0x38, 0x3d, 0x98, 0x1c,
0xa6, 0xfd, 0x24, 0x88, 0xf1, 0xc4, 0xe3, 0xfe, 0x83, 0x03, 0xab, 0x56, 0xad, 0x0c, 0x0b, 0x7d,
0x5a, 0xb0, 0xb4, 0xbe, 0x5c, 0x16, 0x8c, 0xb7, 0x62, 0xa8, 0x43, 0x41, 0x28, 0x02, 0x72, 0x4f,
0xe4, 0x7d, 0xf3, 0x1d, 0x58, 0x56, 0x23, 0x53, 0x1f, 0x0a, 0x2e, 0xec, 0x94, 0xb9, 0x50, 0x7e,
0xbf, 0x24, 0x3f, 0x50, 0x4d, 0xfc, 0x82, 0xbc, 0x7d, 0x1c, 0xd0, 0x1c, 0x55, 0x7c, 0x40, 0xdf,
0x2f, 0x99, 0xa7, 0x04, 0x35, 0x82, 0xbe, 0x06, 0x53, 0xf7, 0x77, 0x1c, 0x80, 0x7c, 0x74, 0xc8,
0x18, 0xb9, 0x4a, 0x17, 0x09, 0xd1, 0x86, 0xfa, 0x7e, 0x0b, 0x5a, 0xfa, 0x66, 0x24, 0xb7, 0x12,
0x4d, 0x85, 0xa1, 0x23, 0x77, 0x1d, 0x96, 0x87, 0xa3, 0xe8, 0x90, 0x4c, 0x2c, 0x25, 0xbd, 0xa4,
0x32, 0x53, 0x63, 0x49, 0xc0, 0xf7, 0x24, 0x9a, 0x9b, 0x94, 0xba, 0x61, 0x52, 0xdc, 0x6f, 0xd7,
0x74, 0x3c, 0x3d, 0x9f, 0xf3, 0x99, 0x52, 0xc6, 0x36, 0x4b, 0xca, 0xf1, 0x8c, 0xf0, 0x35, 0x45,
0xc2, 0xf6, 0xcf, 0x3d, 0xa8, 0x7f, 0x08, 0x4b, 0x89, 0xd0, 0x3e, 0x4a, 0x35, 0xd5, 0x5f, 0xa2,
0x9a, 0x16, 0x13, 0xcb, 0xee, 0x7c, 0x12, 0xda, 0xfe, 0xe0, 0x84, 0x27, 0x59, 0x40, 0x47, 0x25,
0x32, 0xfa, 0x42, 0xa1, 0x2e, 0x1b, 0x38, 0xd9, 0xe2, 0xeb, 0xb0, 0x2c, 0xb3, 0x63, 0x34, 0xa5,
0xcc, 0xe8, 0xcc, 0x61, 0x24, 0x74, 0xff, 0x44, 0x85, 0xee, 0xed, 0x3d, 0x3c, 0x7b, 0x45, 0xcc,
0xd9, 0xd5, 0x0a, 0xb3, 0xfb, 0x84, 0x0c, 0xa3, 0x0f, 0xd4, 0x79, 0x6c, 0xc6, 0xb8, 0xa9, 0x1e,
0xc8, 0x6b, 0x0f, 0x7b, 0x49, 0xeb, 0xaf, 0xb2, 0xa4, 0xee, 0x0f, 0x1c, 0x98, 0xdf, 0x8d, 0xe2,
0x5d, 0x79, 0x67, 0x4f, 0x82, 0xa0, 0x73, 0xcf, 0x54, 0xf1, 0x25, 0xb7, 0xf9, 0x95, 0xb6, 0x76,
0xb1, 0x68, 0x6b, 0x7f, 0x11, 0x5e, 0xa3, 0x68, 0x40, 0x12, 0xc5, 0x51, 0x82, 0xc2, 0xe8, 0x8f,
0x84, 0x61, 0x8d, 0xc2, 0xec, 0x58, 0xa9, 0xb1, 0x97, 0x91, 0xd0, 0xb1, 0x0b, 0x8f, 0x0b, 0xc2,
0x19, 0x96, 0xbe, 0x81, 0xd0, 0x6e, 0xe5, 0x0a, 0xf7, 0xb3, 0xd0, 0x20, 0xe7, 0x96, 0xa6, 0xf5,
0x0e, 0x34, 0x8e, 0xa3, 0xb8, 0x77, 0x1c, 0x84, 0x99, 0x12, 0xee, 0xa5, 0xdc, 0xeb, 0xdc, 0xa5,
0x05, 0xd1, 0x04, 0xee, 0xdf, 0xd5, 0x61, 0xfe, 0x41, 0x78, 0x12, 0x05, 0x7d, 0x8a, 0xf2, 0x8f,
0xf9, 0x38, 0x52, 0x99, 0x78, 0xf8, 0x1b, 0x97, 0x82, 0xb2, 0x52, 0xe2, 0x4c, 0x86, 0xe9, 0x55,
0x11, 0xcd, 0x7d, 0x92, 0x67, 0xcb, 0x0a, 0xd1, 0x31, 0x10, 0x74, 0xec, 0x13, 0x33, 0xb1, 0x58,
0x96, 0xf2, 0x54, 0xc6, 0x59, 0x23, 0x95, 0x91, 0xee, 0x84, 0x44, 0x7e, 0x01, 0xf1, 0xd7, 0x82,
0xa7, 0x8a, 0x74, 0x10, 0x49, 0xb8, 0x88, 0xe2, 0x90, 0xe3, 0x30, 0x2f, 0x0f, 0x22, 0x26, 0x88,
0xce, 0x85, 0xf8, 0x40, 0xd0, 0x08, 0xe5, 0x6b, 0x42, 0xe8, 0x6c, 0x15, 0x73, 0x93, 0x1b, 0x82,
0xe7, 0x0b, 0x30, 0x6a, 0xe8, 0x01, 0xd7, 0x8a, 0x54, 0xcc, 0x01, 0x44, 0x36, 0x70, 0x11, 0x37,
0x8e, 0x2f, 0x22, 0x71, 0x48, 0x1d, 0x5f, 0x90, 0x51, 0xfc, 0xd1, 0xe8, 0xd0, 0xef, 0x3f, 0xa3,
0xd4, 0x73, 0xca, 0x13, 0x6a, 0x78, 0x36, 0x48, 0x19, 0x03, 0xf9, 0x6e, 0xd2, 0xad, 0x62, 0xdd,
0x33, 0x21, 0xb6, 0x09, 0x4d, 0x3a, 0xb2, 0xc9, 0xfd, 0x5c, 0xa2, 0xfd, 0x6c, 0x9b, 0x67, 0x3a,
0xda, 0x51, 0x93, 0xc8, 0xbc, 0x79, 0x58, 0xb6, 0x6f, 0x1e, 0x84, 0xd2, 0x94, 0x17, 0x36, 0x6d,
0xea, 0x2d, 0x07, 0xd0, 0x9a, 0xca, 0x05, 0x13, 0x04, 0x2b, 0x44, 0x60, 0x61, 0x28, 0xb5, 0x78,
0xd0, 0x88, 0xfd, 0x60, 0xd0, 0x61, 0x42, 0x6a, 0x55, 0xd9, 0xcd, 0x80, 0xdd, 0x19, 0x0c, 0x24,
0x37, 0xe9, 0x03, 0x69, 0xce, 0x07, 0x8e, 0xc5, 0x07, 0x15, 0xfb, 0x51, 0xab, 0xde, 0x8f, 0x97,
0x8e, 0xda, 0xdd, 0x81, 0xe6, 0xbe, 0x91, 0x30, 0x4d, 0x6c, 0xa9, 0x52, 0xa5, 0x25, 0x2b, 0x1b,
0x88, 0x31, 0x9c, 0x9a, 0x39, 0x1c, 0xf7, 0xe7, 0x80, 0xed, 0x05, 0x69, 0xa6, 0x47, 0x9f, 0x67,
0x68, 0xab, 0xa8, 0x41, 0x9e, 0xe4, 0xd4, 0x94, 0x18, 0x25, 0x1f, 0xdd, 0x11, 0xd9, 0x51, 0xc5,
0x69, 0x6f, 0xc0, 0x42, 0x20, 0xa0, 0xa2, 0x14, 0x2a, 0x4a, 0x5d, 0xef, 0x3e, 0x85, 0x55, 0x09,
0x9a, 0x16, 0xdc, 0x9e, 0xb7, 0x73, 0xde, 0x6e, 0xd5, 0xca, 0xbb, 0xe5, 0x7e, 0xdf, 0x81, 0x79,
0xb9, 0x38, 0x48, 0x5f, 0x4a, 0x36, 0x6f, 0x78, 0x16, 0x56, 0x9d, 0x66, 0x5c, 0x96, 0xc0, 0x99,
0x2a, 0x09, 0x64, 0x50, 0x8f, 0xfd, 0xec, 0x98, 0x8e, 0x57, 0x0d, 0x8f, 0x7e, 0xb3, 0xb6, 0x38,
0xf2, 0x0b, 0x49, 0xa7, 0xe3, 0x7e, 0x55, 0xa6, 0xbd, 0x30, 0x28, 0x25, 0x1c, 0x5d, 0x68, 0xca,
0xa9, 0x10, 0xb8, 0xbe, 0x2a, 0x91, 0xd9, 0x5e, 0x39, 0x9c, 0xaf, 0xb8, 0x6c, 0xa2, 0xb8, 0xe2,
0x92, 0xd4, 0xd3, 0xf5, 0x6e, 0x17, 0x3a, 0xdb, 0x7c, 0xc4, 0x33, 0x7e, 0x67, 0x34, 0x2a, 0xb6,
0xff, 0x1a, 0x5c, 0xae, 0xa8, 0x93, 0x2e, 0xd7, 0x3d, 0x58, 0xd9, 0xe6, 0x87, 0x93, 0xe1, 0x1e,
0x3f, 0xc9, 0xef, 0x33, 0x19, 0xd4, 0xd3, 0xe3, 0xe8, 0x54, 0x72, 0x07, 0xfd, 0x66, 0x6f, 0x00,
0x8c, 0x90, 0xa6, 0x97, 0xc6, 0xbc, 0xaf, 0x12, 0x6c, 0x09, 0x39, 0x88, 0x79, 0xdf, 0x7d, 0x0f,
0x98, 0xd9, 0x8e, 0x9c, 0x02, 0x6a, 0xb1, 0xc9, 0x61, 0x2f, 0x9d, 0xa6, 0x19, 0x1f, 0xab, 0xcc,
0x61, 0x13, 0x72, 0xaf, 0x43, 0x6b, 0xdf, 0x9f, 0x7a, 0xfc, 0x1b, 0x32, 0xdf, 0x1f, 0x4f, 0xf6,
0xfe, 0x14, 0x45, 0x45, 0x9f, 0xec, 0xa9, 0xda, 0xfd, 0xaf, 0x1a, 0xcc, 0x09, 0x4a, 0x6c, 0x75,
0xc0, 0xd3, 0x2c, 0x08, 0xc5, 0x5d, 0x9e, 0x6c, 0xd5, 0x80, 0x4a, 0xbc, 0x51, 0xab, 0xe0, 0x0d,
0xe9, 0x6b, 0xab, 0x64, 0x45, 0xc9, 0x04, 0x16, 0x86, 0x1c, 0x9b, 0xe7, 0x48, 0x88, 0xa3, 0x65,
0x0e, 0x14, 0x42, 0x3d, 0xb9, 0xae, 0x14, 0xe3, 0x53, 0x6c, 0x2f, 0xd9, 0xc1, 0x84, 0x2a, 0x35,
0xf2, 0xbc, 0xe0, 0x9a, 0x92, 0x46, 0x2e, 0x69, 0xde, 0x85, 0x57, 0xd0, 0xbc, 0xc2, 0x01, 0x7f,
0x99, 0xe6, 0x85, 0x57, 0xd0, 0xbc, 0x2e, 0x83, 0xf6, 0x3d, 0xce, 0x3d, 0x8e, 0x36, 0x5d, 0xb1,
0xd3, 0x77, 0x1c, 0x68, 0x4b, 0x77, 0x44, 0xd7, 0xb1, 0xb7, 0x2c, 0xdf, 0xa5, 0x32, 0xa5, 0xf0,
0x1a, 0x2c, 0x92, 0x47, 0xa1, 0x63, 0x5a, 0x32, 0x00, 0x67, 0x81, 0x38, 0x0f, 0x75, 0xf1, 0x30,
0x0e, 0x46, 0x72, 0x53, 0x4c, 0x48, 0x85, 0xc5, 0xf0, 0x74, 0x4f, 0x5b, 0xe2, 0x78, 0xba, 0xec,
0xfe, 0x95, 0x03, 0x2b, 0xc6, 0x80, 0x25, 0x17, 0x7e, 0x08, 0x2a, 0x87, 0x42, 0x84, 0xbe, 0x84,
0x30, 0x5d, 0xb2, 0x5d, 0xab, 0xfc, 0x33, 0x8b, 0x98, 0x36, 0xd3, 0x9f, 0xd2, 0x00, 0xd3, 0xc9,
0x58, 0x6a, 0x25, 0x13, 0x42, 0x46, 0x3a, 0xe5, 0xfc, 0x99, 0x26, 0x99, 0x11, 0x8a, 0xcb, 0xc4,
0xe8, 0x8a, 0x1c, 0x3d, 0x21, 0x4d, 0x24, 0xb2, 0xc2, 0x6c, 0xd0, 0xfd, 0x27, 0x07, 0x56, 0x85,
0x4b, 0x2b, 0x0f, 0x0c, 0x3a, 0xdf, 0x7b, 0x4e, 0xf8, 0xf0, 0x42, 0x22, 0x77, 0x2f, 0x78, 0xb2,
0xcc, 0x3e, 0xf3, 0x8a, 0x6e, 0xb8, 0x4e, 0x8d, 0x38, 0x63, 0x2f, 0x66, 0xaa, 0xf6, 0xe2, 0x25,
0x2b, 0x5d, 0x15, 0xea, 0x99, 0xad, 0x0c, 0xf5, 0xdc, 0x9d, 0x87, 0xd9, 0xb4, 0x1f, 0xc5, 0xdc,
0x5d, 0x87, 0x35, 0x7b, 0x72, 0x52, 0x05, 0x7d, 0xd7, 0x81, 0xce, 0x3d, 0x11, 0xf8, 0x0c, 0xc2,
0xe1, 0x6e, 0x90, 0x66, 0x51, 0xa2, 0x1f, 0xb8, 0x5c, 0x01, 0x48, 0x33, 0x3f, 0xc9, 0x44, 0xea,
0x9a, 0x0c, 0xd2, 0xe4, 0x08, 0x8e, 0x91, 0x87, 0x03, 0x51, 0x2b, 0xf6, 0x46, 0x97, 0x71, 0x63,
0xc8, 0x6c, 0xf4, 0xa2, 0xa3, 0xa3, 0x94, 0x6b, 0xa7, 0xdb, 0xc4, 0xf0, 0xdc, 0x8e, 0x12, 0x8f,
0x27, 0x55, 0x7e, 0x42, 0xaa, 0x56, 0x78, 0xb3, 0x05, 0xd4, 0xfd, 0x0b, 0x07, 0x96, 0xf3, 0x41,
0xee, 0x20, 0x68, 0x6b, 0x07, 0x69, 0xcf, 0x72, 0xed, 0xa0, 0xc2, 0x47, 0x01, 0x1a, 0x38, 0x39,
0x36, 0x03, 0x21, 0x89, 0x95, 0xa5, 0x68, 0xa2, 0xd2, 0x04, 0x4d, 0x48, 0xe4, 0x00, 0x64, 0xf8,
0xb5, 0xc8, 0x11, 0x94, 0x25, 0xca, 0x3c, 0x1c, 0x67, 0xf4, 0xd5, 0x9c, 0x70, 0xe7, 0x65, 0x51,
0xd9, 0xa7, 0x79, 0x42, 0xf1, 0xa7, 0xfb, 0xbb, 0x0e, 0x5c, 0xae, 0x58, 0x5c, 0x29, 0x19, 0xdb,
0xb0, 0x72, 0xa4, 0x2b, 0xd5, 0x02, 0x08, 0xf1, 0x58, 0x57, 0x91, 0x7a, 0x7b, 0xd2, 0x5e, 0xf9,
0x03, 0x74, 0xee, 0x29, 0xea, 0x25, 0x96, 0xd4, 0x4a, 0x9f, 0x29, 0x57, 0x6c, 0xfe, 0xde, 0x0c,
0x2c, 0x89, 0x1b, 0x1c, 0xf1, 0xd4, 0x94, 0x27, 0xec, 0x23, 0x98, 0x97, 0x4f, 0x85, 0xd9, 0x45,
0xd9, 0xad, 0xfd, 0x38, 0xb9, 0xbb, 0x5e, 0x84, 0x25, 0xef, 0xac, 0xfe, 0xc6, 0x0f, 0xfe, 0xe5,
0xf7, 0x6b, 0x8b, 0xac, 0x79, 0xeb, 0xe4, 0xdd, 0x5b, 0x43, 0x1e, 0xa6, 0xd8, 0xc6, 0xaf, 0x00,
0xe4, 0x8f, 0x68, 0x59, 0x47, 0xbb, 0x29, 0x85, 0xd7, 0xc1, 0xdd, 0xcb, 0x15, 0x35, 0xb2, 0xdd,
0xcb, 0xd4, 0xee, 0xaa, 0xbb, 0x84, 0xed, 0x06, 0x61, 0x90, 0x89, 0x17, 0xb5, 0x1f, 0x38, 0x1b,
0x6c, 0x00, 0x2d, 0xf3, 0x8d, 0x2c, 0x53, 0x07, 0xfe, 0x8a, 0x17, 0xba, 0xdd, 0xd7, 0x2a, 0xeb,
0x54, 0xb4, 0x83, 0xfa, 0xb8, 0xe8, 0xb6, 0xb1, 0x8f, 0x09, 0x51, 0xe4, 0xbd, 0x8c, 0x60, 0xc9,
0x7e, 0x0a, 0xcb, 0x5e, 0x37, 0xc4, 0xba, 0xf4, 0x10, 0xb7, 0xfb, 0xc6, 0x19, 0xb5, 0xb2, 0xaf,
0x37, 0xa8, 0xaf, 0x4b, 0x2e, 0xc3, 0xbe, 0xfa, 0x44, 0xa3, 0x1e, 0xe2, 0x7e, 0xe0, 0x6c, 0x6c,
0x7e, 0xeb, 0x0a, 0x34, 0x74, 0x88, 0x8e, 0x7d, 0x1d, 0x16, 0xad, 0x2b, 0x36, 0xa6, 0xa6, 0x51,
0x75, 0x23, 0xd7, 0x7d, 0xbd, 0xba, 0x52, 0x76, 0x7c, 0x85, 0x3a, 0xee, 0xb0, 0x75, 0xec, 0x58,
0xde, 0x51, 0xdd, 0xa2, 0x8b, 0x45, 0x91, 0xd7, 0xf8, 0x4c, 0xcc, 0x33, 0xbf, 0x16, 0xb3, 0xe6,
0x59, 0xba, 0x46, 0xb3, 0xe6, 0x59, 0xbe, 0x4b, 0x73, 0x5f, 0xa7, 0xee, 0xd6, 0xd9, 0x9a, 0xd9,
0x9d, 0x0e, 0x9d, 0x71, 0xca, 0x44, 0x35, 0x5f, 0xca, 0xb2, 0x37, 0x34, 0x63, 0x55, 0xbd, 0xa0,
0xd5, 0x2c, 0x52, 0x7e, 0x46, 0xeb, 0x76, 0xa8, 0x2b, 0xc6, 0x68, 0xfb, 0xcc, 0x87, 0xb2, 0xec,
0xab, 0xd0, 0xd0, 0xcf, 0xc2, 0xd8, 0x25, 0xe3, 0x2d, 0x9e, 0xf9, 0x56, 0xad, 0xdb, 0x29, 0x57,
0x54, 0x31, 0x86, 0xd9, 0x32, 0x32, 0xc6, 0x1e, 0x5c, 0x94, 0x4e, 0xf5, 0x21, 0xff, 0x51, 0x66,
0x52, 0xf1, 0xbe, 0xf7, 0xb6, 0xc3, 0x3e, 0x84, 0x05, 0xf5, 0xda, 0x8e, 0xad, 0x57, 0xbf, 0x1a,
0xec, 0x5e, 0x2a, 0xe1, 0x52, 0x7b, 0xdc, 0x01, 0xc8, 0x5f, 0x8a, 0x69, 0x39, 0x2b, 0xbd, 0x5f,
0xd3, 0x8b, 0x58, 0xf1, 0xac, 0x6c, 0x48, 0xef, 0xe2, 0xec, 0x87, 0x68, 0xec, 0xcd, 0x9c, 0xbe,
0xf2, 0x89, 0xda, 0x4b, 0x1a, 0x74, 0xd7, 0x69, 0xed, 0xda, 0x8c, 0x04, 0x37, 0xe4, 0xa7, 0x2a,
0x27, 0x7b, 0x1b, 0x9a, 0xc6, 0xeb, 0x33, 0xa6, 0x5a, 0x28, 0xbf, 0x5c, 0xeb, 0x76, 0xab, 0xaa,
0xe4, 0x70, 0xbf, 0x00, 0x8b, 0xd6, 0x33, 0x32, 0x2d, 0x19, 0x55, 0x8f, 0xd4, 0xb4, 0x64, 0x54,
0xbf, 0x3c, 0xfb, 0x0a, 0x34, 0x8d, 0x47, 0x5f, 0xcc, 0xc8, 0x45, 0x2b, 0x3c, 0xf7, 0xd2, 0x23,
0xaa, 0x7a, 0x23, 0xb6, 0x46, 0xf3, 0x5d, 0x72, 0x1b, 0x38, 0x5f, 0x4a, 0x4c, 0x46, 0x26, 0xf9,
0x3a, 0x2c, 0xd9, 0xcf, 0xc0, 0xb4, 0x54, 0x55, 0x3e, 0x28, 0xd3, 0x52, 0x75, 0xc6, 0xdb, 0x31,
0xc9, 0x90, 0x1b, 0xab, 0xba, 0x93, 0x5b, 0x1f, 0xcb, 0x0b, 0xaa, 0x17, 0xec, 0x4b, 0xa8, 0x3a,
0x64, 0xa6, 0x38, 0xcb, 0x1f, 0xbf, 0xd9, 0xf9, 0xe4, 0x9a, 0xdb, 0x4b, 0x49, 0xe5, 0xee, 0x0a,
0x35, 0xde, 0x64, 0xf9, 0x0c, 0x84, 0x3d, 0xa0, 0x8c, 0x71, 0xc3, 0x1e, 0x98, 0x49, 0xe5, 0x86,
0x3d, 0xb0, 0x12, 0xcb, 0x8b, 0xf6, 0x20, 0x0b, 0xb0, 0x8d, 0x10, 0x96, 0x0b, 0xc9, 0x18, 0x5a,
0x58, 0xaa, 0xb3, 0xd7, 0xba, 0x57, 0x5e, 0x9e, 0xc3, 0x61, 0xab, 0x19, 0xa5, 0x5e, 0x6e, 0xa9,
0x64, 0xc3, 0x5f, 0x85, 0x96, 0xf9, 0x7c, 0x47, 0x5b, 0x88, 0x8a, 0x47, 0x47, 0xda, 0x42, 0x54,
0xbd, 0xf7, 0x51, 0x9b, 0xcb, 0x5a, 0x66, 0x37, 0xb8, 0xb9, 0xf6, 0x6b, 0x87, 0x5c, 0x65, 0x56,
0x3d, 0xe3, 0xc8, 0x55, 0x66, 0xe5, 0x13, 0x09, 0xb5, 0xb9, 0x6c, 0xd5, 0x9a, 0x8b, 0x88, 0x4c,
0xb2, 0xaf, 0xc0, 0xb2, 0x91, 0xe9, 0x74, 0x30, 0x0d, 0xfb, 0x9a, 0x51, 0xcb, 0x79, 0xb0, 0xdd,
0x2a, 0xcf, 0xd3, 0xbd, 0x44, 0xed, 0xaf, 0xb8, 0xd6, 0x24, 0x90, 0x49, 0xb7, 0xa0, 0x69, 0x66,
0x51, 0xbd, 0xa4, 0xdd, 0x4b, 0x46, 0x95, 0x99, 0x12, 0x7a, 0xdb, 0x61, 0x7f, 0xe8, 0x40, 0xcb,
0xca, 0x49, 0xb2, 0xe2, 0xef, 0x85, 0x76, 0x3a, 0x66, 0x9d, 0xd9, 0x90, 0xeb, 0xd1, 0x20, 0xf7,
0x36, 0xbe, 0x60, 0x2d, 0xc2, 0xc7, 0xd6, 0x09, 0xe6, 0x66, 0xf1, 0x15, 0xf8, 0x8b, 0x22, 0x81,
0x99, 0x2b, 0xfc, 0xe2, 0xb6, 0xc3, 0x3e, 0x10, 0xff, 0x73, 0xa0, 0x22, 0x16, 0xcc, 0x50, 0xa4,
0xc5, 0x25, 0x33, 0x1f, 0xf9, 0xdf, 0x70, 0x6e, 0x3b, 0xec, 0x6b, 0xe2, 0xb1, 0xb7, 0xfc, 0x96,
0x56, 0xfe, 0x55, 0xbf, 0x77, 0xaf, 0xd1, 0x6c, 0xae, 0xb8, 0x97, 0xad, 0xd9, 0x14, 0x2d, 0xc9,
0x1d, 0x31, 0x3a, 0xf9, 0x86, 0x3f, 0x57, 0x89, 0xa5, 0x77, 0xfd, 0x67, 0x0f, 0x72, 0x2c, 0x06,
0x29, 0xc9, 0x2d, 0xf6, 0x78, 0xc5, 0x66, 0xdc, 0x0d, 0x1a, 0xeb, 0x35, 0xf7, 0xcd, 0x33, 0xc7,
0x7a, 0x8b, 0x4e, 0xa4, 0x38, 0xe2, 0x7d, 0x80, 0x3c, 0x20, 0xc7, 0x0a, 0xf1, 0x27, 0x6d, 0x15,
0xca, 0x31, 0x3b, 0x9b, 0x07, 0x55, 0x98, 0x0a, 0x5b, 0xfc, 0xaa, 0x10, 0x55, 0x49, 0x9f, 0xea,
0xd1, 0x97, 0x43, 0x67, 0xdd, 0x6e, 0x55, 0x55, 0x95, 0xa0, 0xaa, 0xf6, 0xd9, 0x13, 0x58, 0xdc,
0x8b, 0xa2, 0x67, 0x93, 0x58, 0x07, 0xa4, 0xed, 0xf8, 0xcd, 0xae, 0x9f, 0x1e, 0x77, 0x0b, 0xb3,
0x70, 0xaf, 0x52, 0x53, 0x5d, 0xd6, 0x31, 0x9a, 0xba, 0xf5, 0x71, 0x1e, 0xf0, 0x7b, 0xc1, 0x7c,
0x58, 0xd1, 0x1e, 0x80, 0x1e, 0x78, 0xd7, 0x6e, 0xc6, 0x8c, 0xbb, 0x95, 0xba, 0xb0, 0x7c, 0x32,
0x35, 0xda, 0x5b, 0xa9, 0x6a, 0xf3, 0xb6, 0xc3, 0xf6, 0xa1, 0xb5, 0xcd, 0xfb, 0xd1, 0x80, 0xcb,
0x88, 0xcb, 0x6a, 0x3e, 0x70, 0x1d, 0xaa, 0xe9, 0x2e, 0x5a, 0xa0, 0xad, 0x13, 0x63, 0x7f, 0x9a,
0xf0, 0x6f, 0xdc, 0xfa, 0x58, 0xc6, 0x72, 0x5e, 0x28, 0x9d, 0xa8, 0xe2, 0x4f, 0x96, 0x4e, 0x2c,
0x04, 0xac, 0x2c, 0x9d, 0x58, 0x0a, 0x58, 0x59, 0x4b, 0xad, 0xe2, 0x5f, 0x6c, 0x04, 0x2b, 0xa5,
0x18, 0x97, 0xf6, 0x23, 0xce, 0x8a, 0x8c, 0x75, 0xaf, 0x9e, 0x4d, 0x60, 0xf7, 0xb6, 0x61, 0xf7,
0x76, 0x00, 0x8b, 0xdb, 0x5c, 0x2c, 0x96, 0xb8, 0xf5, 0x2e, 0x3c, 0x2a, 0x33, 0x6f, 0xc8, 0x8b,
0x4a, 0x91, 0xea, 0x6c, 0xa3, 0x47, 0x57, 0xce, 0xec, 0xab, 0xd0, 0xbc, 0xcf, 0x33, 0x75, 0xcd,
0xad, 0xbd, 0xb1, 0xc2, 0xbd, 0x77, 0xb7, 0xe2, 0x96, 0xdc, 0xe6, 0x19, 0x6a, 0xed, 0x16, 0x1f,
0x0c, 0xb9, 0x50, 0x4f, 0xbd, 0x60, 0xf0, 0x82, 0xfd, 0x12, 0x35, 0xae, 0x33, 0x63, 0xd6, 0x8d,
0xdb, 0x51, 0xb3, 0xf1, 0xe5, 0x02, 0x5e, 0xd5, 0x72, 0x18, 0x0d, 0xb8, 0x61, 0xfe, 0x43, 0x68,
0x1a, 0x69, 0x5b, 0x5a, 0x80, 0xca, 0x29, 0x68, 0x5a, 0x80, 0x2a, 0xb2, 0xbc, 0xdc, 0x1b, 0xd4,
0x8f, 0xcb, 0xae, 0xe6, 0xfd, 0x88, 0xcc, 0xae, 0xbc, 0xa7, 0x5b, 0x1f, 0xfb, 0xe3, 0xec, 0x05,
0x7b, 0x4a, 0x0f, 0xcc, 0xcc, 0xab, 0xfc, 0xdc, 0x1b, 0x2c, 0xde, 0xfa, 0xeb, 0xc5, 0x32, 0xaa,
0x6c, 0x0f, 0x51, 0x74, 0x45, 0x5e, 0xc2, 0x67, 0x00, 0x0e, 0xb2, 0x28, 0xde, 0xf6, 0xf9, 0x38,
0x0a, 0x73, 0x5d, 0x9b, 0x5f, 0x57, 0xe7, 0xfa, 0xcb, 0xb8, 0xb3, 0x66, 0x4f, 0x0d, 0x7f, 0xdc,
0xca, 0x84, 0x50, 0xcc, 0x75, 0xe6, 0x8d, 0xb6, 0x5e, 0x90, 0x8a, 0x5b, 0xed, 0xdb, 0x0e, 0x7a,
0xd7, 0x79, 0x44, 0x55, 0x7b, 0xd7, 0xa5, 0x60, 0xad, 0x56, 0x7b, 0x15, 0xe1, 0xd7, 0x7d, 0x68,
0xe4, 0x21, 0xba, 0x4b, 0x79, 0xea, 0x9d, 0x15, 0xd0, 0xd3, 0x56, 0xb1, 0x14, 0x38, 0x73, 0xdb,
0xb4, 0x54, 0xc0, 0x16, 0x70, 0xa9, 0x28, 0x1a, 0x16, 0xc0, 0xaa, 0x18, 0xa0, 0x36, 0xf1, 0x74,
0x01, 0xab, 0x66, 0x52, 0x11, 0xbc, 0xd2, 0xd2, 0x5c, 0x19, 0xfb, 0xb1, 0xce, 0xd9, 0xc8, 0xad,
0xe2, 0xf2, 0x17, 0x55, 0xf3, 0x18, 0x56, 0x4a, 0x81, 0x0b, 0x2d, 0xd2, 0x67, 0xc5, 0x8b, 0xb4,
0x48, 0x9f, 0x19, 0xf3, 0x70, 0x2f, 0x52, 0x97, 0xcb, 0x2e, 0x60, 0x97, 0xe9, 0x69, 0x90, 0xf5,
0x8f, 0x3f, 0x70, 0x36, 0x0e, 0xe7, 0xe8, 0x7f, 0xd1, 0x3e, 0xf5, 0xbf, 0x01, 0x00, 0x00, 0xff,
0xff, 0xb6, 0xb3, 0x40, 0xb7, 0x49, 0x4d, 0x00, 0x00,
}

@ -392,10 +392,18 @@ func request_Lightning_LookupInvoice_0(ctx context.Context, marshaler runtime.Ma
}
var (
filter_Lightning_SubscribeInvoices_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Lightning_SubscribeInvoices_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (Lightning_SubscribeInvoicesClient, runtime.ServerMetadata, error) {
var protoReq InvoiceSubscription
var metadata runtime.ServerMetadata
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Lightning_SubscribeInvoices_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
stream, err := client.SubscribeInvoices(ctx, &protoReq)
if err != nil {
return nil, metadata, err

@ -464,7 +464,14 @@ service Lightning {
/**
SubscribeInvoices returns a uni-directional stream (sever -> client) for
notifying the client of newly added/settled invoices.
notifying the client of newly added/settled invoices. The caller can
optionally specify the add_index and/or the settle_index. If the add_index
is specified, then we'll first start by sending add invoice events for all
invoices with an add_index greater than the specified value. If the
settle_index is specified, the next, we'll send out all settle events for
invoices with a settle_index greater than the specified value. One or both
of these fields can be set. If no fields are set, then we'll only send out
the latest add/settle events.
*/
rpc SubscribeInvoices (InvoiceSubscription) returns (stream Invoice) {
option (google.api.http) = {
@ -1642,6 +1649,32 @@ message Invoice {
/// Whether this invoice should include routing hints for private channels.
bool private = 15 [json_name = "private"];
/**
The "add" index of this invoice. Each newly created invoice will increment
this index making it monotonically increasing. Callers to the
SubscribeInvoices call can use this to instantly get notified of all added
invoices with an add_index greater than this one.
*/
uint64 add_index = 16 [json_name = "add_index"];
/**
The "settle" index of this invoice. Each newly settled invoice will
increment this index making it monotonically increasing. Callers to the
SubscribeInvoices call can use this to instantly get notified of all
settled invoices with an settle_index greater than this one.
*/
uint64 settle_index = 17 [json_name = "settle_index"];
/**
The amount that was accepted for this invoice. This will ONLY be set if
this invoice has been settled. We provide this field as if the invoice was
created with a zero value, then we need to record what amount was
ultimately accepted. Additionally, it's possible that the sender paid MORE
that was specified in the original invoice. So we'll record that here as
well.
*/
int64 amt_paid = 18 [json_name = "amt_paid"];
}
message AddInvoiceResponse {
bytes r_hash = 1 [json_name = "r_hash"];
@ -1652,6 +1685,14 @@ message AddInvoiceResponse {
payment to the recipient.
*/
string payment_request = 2 [json_name = "payment_request"];
/**
The "add" index of this invoice. Each newly created invoice will increment
this index making it monotonically increasing. Callers to the
SubscribeInvoices call can use this to instantly get notified of all added
invoices with an add_index greater than this one.
*/
uint64 add_index = 16 [json_name = "add_index"];
}
message PaymentHash {
/**
@ -1672,6 +1713,21 @@ message ListInvoiceResponse {
}
message InvoiceSubscription {
/**
If specified (non-zero), then we'll first start by sending out
notifications for all added indexes with an add_index greater than this
value. This allows callers to catch up on any events they missed while they
weren't connected to the streaming RPC.
*/
uint64 add_index = 1 [json_name = "add_index"];
/**
If specified (non-zero), then we'll first start by sending out
notifications for all settled indexes with an settle_index greater than
this value. This allows callers to catch up on any events they missed while
they weren't connected to the streaming RPC.
*/
uint64 settle_index = 2 [json_name = "settle_index"];
}

@ -666,7 +666,7 @@
},
"/v1/invoices/subscribe": {
"get": {
"summary": "*\nSubscribeInvoices returns a uni-directional stream (sever -\u003e client) for\nnotifying the client of newly added/settled invoices.",
"summary": "*\nSubscribeInvoices returns a uni-directional stream (sever -\u003e client) for\nnotifying the client of newly added/settled invoices. The caller can\noptionally specify the add_index and/or the settle_index. If the add_index\nis specified, then we'll first start by sending add invoice events for all\ninvoices with an add_index greater than the specified value. If the\nsettle_index is specified, the next, we'll send out all settle events for\ninvoices with a settle_index greater than the specified value. One or both\nof these fields can be set. If no fields are set, then we'll only send out\nthe latest add/settle events.",
"operationId": "SubscribeInvoices",
"responses": {
"200": {
@ -676,6 +676,24 @@
}
}
},
"parameters": [
{
"name": "add_index",
"description": "*\nIf specified (non-zero), then we'll first start by sending out\nnotifications for all added indexes with an add_index greater than this\nvalue. This allows callers to catch up on any events they missed while they\nweren't connected to the streaming RPC.",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
},
{
"name": "settle_index",
"description": "*\nIf specified (non-zero), then we'll first start by sending out\nnotifications for all settled indexes with an settle_index greater than\nthis value. This allows callers to catch up on any events they missed while\nthey weren't connected to the streaming RPC.",
"in": "query",
"required": false,
"type": "string",
"format": "uint64"
}
],
"tags": [
"Lightning"
]
@ -1060,6 +1078,11 @@
"payment_request": {
"type": "string",
"description": "*\nA bare-bones invoice for a payment within the Lightning Network. With the\ndetails of the invoice, the sender has all the data necessary to send a\npayment to the recipient."
},
"add_index": {
"type": "string",
"format": "uint64",
"description": "*\nThe \"add\" index of this invoice. Each newly created invoice will increment\nthis index making it monotonically increasing. Callers to the\nSubscribeInvoices call can use this to instantly get notified of all added\ninvoices with an add_index greater than this one."
}
}
},
@ -1893,6 +1916,21 @@
"type": "boolean",
"format": "boolean",
"description": "/ Whether this invoice should include routing hints for private channels."
},
"add_index": {
"type": "string",
"format": "uint64",
"description": "*\nThe \"add\" index of this invoice. Each newly created invoice will increment\nthis index making it monotonically increasing. Callers to the\nSubscribeInvoices call can use this to instantly get notified of all added\ninvoices with an add_index greater than this one."
},
"settle_index": {
"type": "string",
"format": "uint64",
"description": "*\nThe \"settle\" index of this invoice. Each newly settled invoice will\nincrement this index making it monotonically increasing. Callers to the\nSubscribeInvoices call can use this to instantly get notified of all\nsettled invoices with an settle_index greater than this one."
},
"amt_paid": {
"type": "string",
"format": "int64",
"description": "*\nThe amount that was accepted for this invoice. This will ONLY be set if\nthis invoice has been settled. We provide this field as if the invoice was\ncreated with a zero value, then we need to record what amount was\nultimately accepted. Additionally, it's possible that the sender paid MORE\nthat was specified in the original invoice. So we'll record that here as\nwell."
}
}
},

@ -639,9 +639,9 @@ func (hn *HarnessNode) lightningNetworkWatcher() {
go func() {
defer hn.wg.Done()
ctxb := context.Background()
req := &lnrpc.GraphTopologySubscription{}
topologyClient, err := hn.SubscribeChannelGraph(ctxb, req)
ctx, cancelFunc := context.WithCancel(context.Background())
topologyClient, err := hn.SubscribeChannelGraph(ctx, req)
if err != nil {
// We panic here in case of an error as failure to
// create the topology client will cause all subsequent
@ -650,6 +650,8 @@ func (hn *HarnessNode) lightningNetworkWatcher() {
"client: %v", err))
}
defer cancelFunc()
for {
update, err := topologyClient.Recv()
if err == io.EOF {

@ -2657,7 +2657,7 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
return nil, err
}
i := &channeldb.Invoice{
newInvoice := &channeldb.Invoice{
CreationDate: creationDate,
Memo: []byte(invoice.Memo),
Receipt: invoice.Receipt,
@ -2666,22 +2666,24 @@ func (r *rpcServer) AddInvoice(ctx context.Context,
Value: amtMSat,
},
}
copy(i.Terms.PaymentPreimage[:], paymentPreimage[:])
copy(newInvoice.Terms.PaymentPreimage[:], paymentPreimage[:])
rpcsLog.Tracef("[addinvoice] adding new invoice %v",
newLogClosure(func() string {
return spew.Sdump(i)
return spew.Sdump(newInvoice)
}),
)
// With all sanity checks passed, write the invoice to the database.
if err := r.server.invoices.AddInvoice(i); err != nil {
addIndex, err := r.server.invoices.AddInvoice(newInvoice)
if err != nil {
return nil, err
}
return &lnrpc.AddInvoiceResponse{
RHash: rHash[:],
PaymentRequest: payReqString,
AddIndex: addIndex,
}, nil
}
@ -2737,6 +2739,9 @@ func createRPCInvoice(invoice *channeldb.Invoice) (*lnrpc.Invoice, error) {
CltvExpiry: cltvExpiry,
FallbackAddr: fallbackAddr,
RouteHints: routeHints,
AddIndex: invoice.AddIndex,
SettleIndex: invoice.SettleIndex,
AmtPaid: int64(invoice.AmtPaid),
}, nil
}
@ -2833,7 +2838,7 @@ func (r *rpcServer) ListInvoices(ctx context.Context,
invoices := make([]*lnrpc.Invoice, len(dbInvoices))
for i, dbInvoice := range dbInvoices {
rpcInvoice, err := createRPCInvoice(dbInvoice)
rpcInvoice, err := createRPCInvoice(&dbInvoice)
if err != nil {
return nil, err
}
@ -2851,14 +2856,24 @@ func (r *rpcServer) ListInvoices(ctx context.Context,
func (r *rpcServer) SubscribeInvoices(req *lnrpc.InvoiceSubscription,
updateStream lnrpc.Lightning_SubscribeInvoicesServer) error {
invoiceClient := r.server.invoices.SubscribeNotifications()
invoiceClient := r.server.invoices.SubscribeNotifications(
req.AddIndex, req.SettleIndex,
)
defer invoiceClient.Cancel()
for {
select {
// TODO(roasbeef): include newly added invoices?
case settledInvoice := <-invoiceClient.SettledInvoices:
case newInvoice := <-invoiceClient.NewInvoices:
rpcInvoice, err := createRPCInvoice(newInvoice)
if err != nil {
return err
}
if err := updateStream.Send(rpcInvoice); err != nil {
return err
}
case settledInvoice := <-invoiceClient.SettledInvoices:
rpcInvoice, err := createRPCInvoice(settledInvoice)
if err != nil {
return err
@ -2867,6 +2882,7 @@ func (r *rpcServer) SubscribeInvoices(req *lnrpc.InvoiceSubscription,
if err := updateStream.Send(rpcInvoice); err != nil {
return err
}
case <-r.quit:
return nil
}
@ -2899,6 +2915,7 @@ func (r *rpcServer) SubscribeTransactions(req *lnrpc.GetTransactionsRequest,
if err := updateStream.Send(detail); err != nil {
return err
}
case tx := <-txClient.UnconfirmedTransactions():
detail := &lnrpc.Transaction{
TxHash: tx.Hash.String(),
@ -2909,6 +2926,7 @@ func (r *rpcServer) SubscribeTransactions(req *lnrpc.GetTransactionsRequest,
if err := updateStream.Send(detail); err != nil {
return err
}
case <-r.quit:
return nil
}

@ -753,6 +753,10 @@ func (s *server) Start() error {
}
s.connMgr.Start()
if err := s.invoices.Start(); err != nil {
return err
}
// With all the relevant sub-systems started, we'll now attempt to
// establish persistent connections to our direct channel collaborators
// within the network.
@ -809,6 +813,7 @@ func (s *server) Stop() error {
s.cc.chainView.Stop()
s.connMgr.Stop()
s.cc.feeEstimator.Stop()
s.invoices.Stop()
// Disconnect from each active peers to ensure that
// peerTerminationWatchers signal completion to each peer.