Merge pull request #3362 from Roasbeef/tlv-onion-payload

multi: update the switch+router to be aware of the new TLV EOB format
This commit is contained in:
Olaoluwa Osuntokun 2019-08-22 19:10:19 -07:00 committed by GitHub
commit 64c7a0faa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 2357 additions and 783 deletions

@ -103,6 +103,13 @@ var (
number: 9,
migration: migrateOutgoingPayments,
},
{
// The DB version where we started to store legacy
// payload information for all routes, as well as the
// optional TLV records.
number: 10,
migration: migrateRouteSerialization,
},
}
// Big endian is the preferred byte order, due to cursor scans over

@ -0,0 +1,236 @@
package channeldb
import (
"bytes"
"io"
"github.com/coreos/bbolt"
"github.com/lightningnetwork/lnd/routing/route"
)
// migrateRouteSerialization migrates the way we serialize routes across the
// entire database. At the time of writing of this migration, this includes our
// payment attempts, as well as the payment results in mission control.
func migrateRouteSerialization(tx *bbolt.Tx) error {
// First, we'll do all the payment attempts.
rootPaymentBucket := tx.Bucket(paymentsRootBucket)
if rootPaymentBucket == nil {
return nil
}
// As we can't mutate a bucket while we're iterating over it with
// ForEach, we'll need to collect all the known payment hashes in
// memory first.
var payHashes [][]byte
err := rootPaymentBucket.ForEach(func(k, v []byte) error {
if v != nil {
return nil
}
payHashes = append(payHashes, k)
return nil
})
if err != nil {
return err
}
// Now that we have all the payment hashes, we can carry out the
// migration itself.
for _, payHash := range payHashes {
payHashBucket := rootPaymentBucket.Bucket(payHash)
// First, we'll migrate the main (non duplicate) payment to
// this hash.
err := migrateAttemptEncoding(tx, payHashBucket)
if err != nil {
return err
}
// Now that we've migrated the main payment, we'll also check
// for any duplicate payments to the same payment hash.
dupBucket := payHashBucket.Bucket(paymentDuplicateBucket)
// If there's no dup bucket, then we can move on to the next
// payment.
if dupBucket == nil {
continue
}
// Otherwise, we'll now iterate through all the duplicate pay
// hashes and migrate those.
var dupSeqNos [][]byte
err = dupBucket.ForEach(func(k, v []byte) error {
dupSeqNos = append(dupSeqNos, k)
return nil
})
if err != nil {
return err
}
// Now in this second pass, we'll re-serialize their duplicate
// payment attempts under the new encoding.
for _, seqNo := range dupSeqNos {
dupPayHashBucket := dupBucket.Bucket(seqNo)
err := migrateAttemptEncoding(tx, dupPayHashBucket)
if err != nil {
return err
}
}
}
log.Infof("Migration of route/hop serialization complete!")
log.Infof("Migrating to new mission control store by clearing " +
"existing data")
resultsKey := []byte("missioncontrol-results")
err = tx.DeleteBucket(resultsKey)
if err != nil && err != bbolt.ErrBucketNotFound {
return err
}
log.Infof("Migration to new mission control completed!")
return nil
}
// migrateAttemptEncoding migrates payment attempts using the legacy format to
// the new format.
func migrateAttemptEncoding(tx *bbolt.Tx, payHashBucket *bbolt.Bucket) error {
payAttemptBytes := payHashBucket.Get(paymentAttemptInfoKey)
if payAttemptBytes == nil {
return nil
}
// For our migration, we'll first read out the existing payment attempt
// using the legacy serialization of the attempt.
payAttemptReader := bytes.NewReader(payAttemptBytes)
payAttempt, err := deserializePaymentAttemptInfoLegacy(
payAttemptReader,
)
if err != nil {
return err
}
// Now that we have the old attempts, we'll explicitly mark this as
// needing a legacy payload, since after this migration, the modern
// payload will be the default if signalled.
for _, hop := range payAttempt.Route.Hops {
hop.LegacyPayload = true
}
// Finally, we'll write out the payment attempt using the new encoding.
var b bytes.Buffer
err = serializePaymentAttemptInfo(&b, payAttempt)
if err != nil {
return err
}
return payHashBucket.Put(paymentAttemptInfoKey, b.Bytes())
}
func deserializePaymentAttemptInfoLegacy(r io.Reader) (*PaymentAttemptInfo, error) {
a := &PaymentAttemptInfo{}
err := ReadElements(r, &a.PaymentID, &a.SessionKey)
if err != nil {
return nil, err
}
a.Route, err = deserializeRouteLegacy(r)
if err != nil {
return nil, err
}
return a, nil
}
func serializePaymentAttemptInfoLegacy(w io.Writer, a *PaymentAttemptInfo) error {
if err := WriteElements(w, a.PaymentID, a.SessionKey); err != nil {
return err
}
if err := serializeRouteLegacy(w, a.Route); err != nil {
return err
}
return nil
}
func deserializeHopLegacy(r io.Reader) (*route.Hop, error) {
h := &route.Hop{}
var pub []byte
if err := ReadElements(r, &pub); err != nil {
return nil, err
}
copy(h.PubKeyBytes[:], pub)
if err := ReadElements(r,
&h.ChannelID, &h.OutgoingTimeLock, &h.AmtToForward,
); err != nil {
return nil, err
}
return h, nil
}
func serializeHopLegacy(w io.Writer, h *route.Hop) error {
if err := WriteElements(w,
h.PubKeyBytes[:], h.ChannelID, h.OutgoingTimeLock,
h.AmtToForward,
); err != nil {
return err
}
return nil
}
func deserializeRouteLegacy(r io.Reader) (route.Route, error) {
rt := route.Route{}
if err := ReadElements(r,
&rt.TotalTimeLock, &rt.TotalAmount,
); err != nil {
return rt, err
}
var pub []byte
if err := ReadElements(r, &pub); err != nil {
return rt, err
}
copy(rt.SourcePubKey[:], pub)
var numHops uint32
if err := ReadElements(r, &numHops); err != nil {
return rt, err
}
var hops []*route.Hop
for i := uint32(0); i < numHops; i++ {
hop, err := deserializeHopLegacy(r)
if err != nil {
return rt, err
}
hops = append(hops, hop)
}
rt.Hops = hops
return rt, nil
}
func serializeRouteLegacy(w io.Writer, r route.Route) error {
if err := WriteElements(w,
r.TotalTimeLock, r.TotalAmount, r.SourcePubKey[:],
); err != nil {
return err
}
if err := WriteElements(w, uint32(len(r.Hops))); err != nil {
return err
}
for _, h := range r.Hops {
if err := serializeHopLegacy(w, h); err != nil {
return err
}
}
return nil
}

@ -5,14 +5,18 @@ import (
"crypto/sha256"
"encoding/binary"
"fmt"
"math/rand"
"reflect"
"testing"
"time"
"github.com/btcsuite/btcutil"
"github.com/coreos/bbolt"
"github.com/davecgh/go-spew/spew"
"github.com/go-errors/errors"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
)
// TestPaymentStatusesMigration checks that already completed payments will have
@ -723,3 +727,223 @@ func TestOutgoingPaymentsMigration(t *testing.T) {
migrateOutgoingPayments,
false)
}
func makeRandPaymentCreationInfo() (*PaymentCreationInfo, error) {
var payHash lntypes.Hash
if _, err := rand.Read(payHash[:]); err != nil {
return nil, err
}
return &PaymentCreationInfo{
PaymentHash: payHash,
Value: lnwire.MilliSatoshi(rand.Int63()),
CreationDate: time.Now(),
PaymentRequest: []byte("test"),
}, nil
}
// TestPaymentRouteSerialization tests that we're able to properly migrate
// existing payments on disk that contain the traversed routes to the new
// routing format which supports the TLV payloads. We also test that the
// migration is able to handle duplicate payment attempts.
func TestPaymentRouteSerialization(t *testing.T) {
t.Parallel()
legacyHop1 := &route.Hop{
PubKeyBytes: route.NewVertex(pub),
ChannelID: 12345,
OutgoingTimeLock: 111,
LegacyPayload: true,
AmtToForward: 555,
}
legacyHop2 := &route.Hop{
PubKeyBytes: route.NewVertex(pub),
ChannelID: 12345,
OutgoingTimeLock: 111,
LegacyPayload: true,
AmtToForward: 555,
}
legacyRoute := route.Route{
TotalTimeLock: 123,
TotalAmount: 1234567,
SourcePubKey: route.NewVertex(pub),
Hops: []*route.Hop{legacyHop1, legacyHop2},
}
const numPayments = 4
var oldPayments []*Payment
sharedPayAttempt := PaymentAttemptInfo{
PaymentID: 1,
SessionKey: priv,
Route: legacyRoute,
}
// We'll first add a series of fake payments, using the existing legacy
// serialization format.
beforeMigrationFunc := func(d *DB) {
err := d.Update(func(tx *bbolt.Tx) error {
paymentsBucket, err := tx.CreateBucket(
paymentsRootBucket,
)
if err != nil {
t.Fatalf("unable to create new payments "+
"bucket: %v", err)
}
for i := 0; i < numPayments; i++ {
var seqNum [8]byte
byteOrder.PutUint64(seqNum[:], uint64(i))
// All payments will be randomly generated,
// other than the final payment. We'll force
// the final payment to re-use an existing
// payment hash so we can insert it into the
// duplicate payment hash bucket.
var payInfo *PaymentCreationInfo
if i < numPayments-1 {
payInfo, err = makeRandPaymentCreationInfo()
if err != nil {
t.Fatalf("unable to create "+
"payment: %v", err)
}
} else {
payInfo = oldPayments[0].Info
}
// Next, legacy encoded when needed, we'll
// serialize the info and the attempt.
var payInfoBytes bytes.Buffer
err = serializePaymentCreationInfo(
&payInfoBytes, payInfo,
)
if err != nil {
t.Fatalf("unable to encode pay "+
"info: %v", err)
}
var payAttemptBytes bytes.Buffer
err = serializePaymentAttemptInfoLegacy(
&payAttemptBytes, &sharedPayAttempt,
)
if err != nil {
t.Fatalf("unable to encode payment attempt: "+
"%v", err)
}
// Before we write to disk, we'll need to fetch
// the proper bucket. If this is the duplicate
// payment, then we'll grab the dup bucket,
// otherwise, we'll use the top level bucket.
var payHashBucket *bbolt.Bucket
if i < numPayments-1 {
payHashBucket, err = paymentsBucket.CreateBucket(
payInfo.PaymentHash[:],
)
} else {
payHashBucket = paymentsBucket.Bucket(
payInfo.PaymentHash[:],
)
dupPayBucket, err := payHashBucket.CreateBucket(
paymentDuplicateBucket,
)
if err != nil {
t.Fatalf("unable to create "+
"dup hash bucket: %v", err)
}
payHashBucket, err = dupPayBucket.CreateBucket(
seqNum[:],
)
if err != nil {
t.Fatalf("unable to make dup "+
"bucket: %v", err)
}
}
err = payHashBucket.Put(paymentSequenceKey, seqNum[:])
if err != nil {
t.Fatalf("unable to write seqno: %v", err)
}
err = payHashBucket.Put(
paymentCreationInfoKey, payInfoBytes.Bytes(),
)
if err != nil {
t.Fatalf("unable to write creation "+
"info: %v", err)
}
err = payHashBucket.Put(
paymentAttemptInfoKey, payAttemptBytes.Bytes(),
)
if err != nil {
t.Fatalf("unable to write attempt "+
"info: %v", err)
}
oldPayments = append(oldPayments, &Payment{
Info: payInfo,
Attempt: &sharedPayAttempt,
})
}
return nil
})
if err != nil {
t.Fatalf("unable to create test payments: %v", err)
}
}
afterMigrationFunc := func(d *DB) {
newPayments, err := d.FetchPayments()
if err != nil {
t.Fatalf("unable to fetch new payments: %v", err)
}
if len(newPayments) != numPayments {
t.Fatalf("expected %d payments, got %d", numPayments,
len(newPayments))
}
for i, p := range newPayments {
// Order of payments should be be preserved.
old := oldPayments[i]
if p.Attempt.PaymentID != old.Attempt.PaymentID {
t.Fatalf("wrong pay ID: expected %v, got %v",
p.Attempt.PaymentID,
old.Attempt.PaymentID)
}
if p.Attempt.Route.TotalFees() != old.Attempt.Route.TotalFees() {
t.Fatalf("Fee mismatch")
}
if p.Attempt.Route.TotalAmount != old.Attempt.Route.TotalAmount {
t.Fatalf("Total amount mismatch")
}
if p.Attempt.Route.TotalTimeLock != old.Attempt.Route.TotalTimeLock {
t.Fatalf("timelock mismatch")
}
if p.Attempt.Route.SourcePubKey != old.Attempt.Route.SourcePubKey {
t.Fatalf("source mismatch: %x vs %x",
p.Attempt.Route.SourcePubKey[:],
old.Attempt.Route.SourcePubKey[:])
}
for i, hop := range p.Attempt.Route.Hops {
if !reflect.DeepEqual(hop, legacyRoute.Hops[i]) {
t.Fatalf("hop mismatch")
}
}
}
}
applyMigration(t,
beforeMigrationFunc,
afterMigrationFunc,
migrateRouteSerialization,
false)
}

@ -15,6 +15,7 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/tlv"
)
func initDB() (*DB, error) {
@ -137,8 +138,37 @@ func TestPaymentControlSwitchFail(t *testing.T) {
if err != nil {
t.Fatalf("error shouldn't have been received, got: %v", err)
}
err = assertRouteHopRecordsEqual(route, &attempt.Route)
if err != nil {
t.Fatalf("route tlv records not equal: %v", err)
}
for i := 0; i < len(route.Hops); i++ {
for j := 0; j < len(route.Hops[i].TLVRecords); j++ {
expectedRecord := route.Hops[i].TLVRecords[j]
newRecord := attempt.Route.Hops[i].TLVRecords[j]
err := assertHopRecordsEqual(expectedRecord, newRecord)
if err != nil {
t.Fatalf("route record mismatch: %v", err)
}
}
}
for i := 0; i < len(route.Hops); i++ {
// reflect.DeepEqual can't assert that two function closures
// are equal. The underlying tlv.Record uses function closures
// internally, so after we verify that the records match above
// manually, we unset these so we can use reflect.DeepEqual
// below.
route.Hops[i].TLVRecords = nil
attempt.Route.Hops[i].TLVRecords = nil
}
if !reflect.DeepEqual(*route, attempt.Route) {
t.Fatalf("unexpected route returned")
t.Fatalf("unexpected route returned: %v vs %v",
spew.Sdump(attempt.Route), spew.Sdump(*route))
}
assertPaymentStatus(t, db, info.PaymentHash, StatusSucceeded)
@ -427,7 +457,6 @@ func checkPaymentCreationInfo(bucket *bbolt.Bucket, c *PaymentCreationInfo) erro
r := bytes.NewReader(b)
c2, err := deserializePaymentCreationInfo(r)
if err != nil {
fmt.Println("creation info err: ", err)
return err
}
if !reflect.DeepEqual(c, c2) {
@ -454,11 +483,34 @@ func checkPaymentAttemptInfo(bucket *bbolt.Bucket, a *PaymentAttemptInfo) error
if err != nil {
return err
}
err = assertRouteHopRecordsEqual(&a.Route, &a2.Route)
if err != nil {
return err
}
recordCache := make(map[int][]tlv.Record)
for i := 0; i < len(a.Route.Hops); i++ {
recordCache[i] = a.Route.Hops[i].TLVRecords
// reflect.DeepEqual can't assert that two function closures
// are equal. The underlying tlv.Record uses function closures
// internally, so after we verify that the records match above
// manually, we unset these so we can use reflect.DeepEqual
// below.
a.Route.Hops[i].TLVRecords = nil
a2.Route.Hops[i].TLVRecords = nil
}
if !reflect.DeepEqual(a, a2) {
return fmt.Errorf("PaymentAttemptInfos don't match: %v vs %v",
spew.Sdump(a), spew.Sdump(a2))
}
for index, records := range recordCache {
a.Route.Hops[index].TLVRecords = records
}
return nil
}

@ -10,10 +10,12 @@ import (
"time"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire"
"github.com/coreos/bbolt"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/tlv"
)
var (
@ -512,9 +514,47 @@ func serializeHop(w io.Writer, h *route.Hop) error {
return err
}
if err := binary.Write(w, byteOrder, h.LegacyPayload); err != nil {
return err
}
// For legacy payloads, we don't need to write any TLV records, so
// we'll write a zero indicating the our serialized TLV map has no
// records.
if h.LegacyPayload {
return WriteElements(w, uint32(0))
}
// Otherwise, we'll transform our slice of records into a map of the
// raw bytes, then serialize them in-line with a length (number of
// elements) prefix.
mapRecords, err := tlv.RecordsToMap(h.TLVRecords)
if err != nil {
return err
}
numRecords := uint32(len(mapRecords))
if err := WriteElements(w, numRecords); err != nil {
return err
}
for recordType, rawBytes := range mapRecords {
if err := WriteElements(w, recordType); err != nil {
return err
}
if err := wire.WriteVarBytes(w, 0, rawBytes); err != nil {
return err
}
}
return nil
}
// maxOnionPayloadSize is the largest Sphinx payload possible, so we don't need
// to read/write a TLV stream larger than this.
const maxOnionPayloadSize = 1300
func deserializeHop(r io.Reader) (*route.Hop, error) {
h := &route.Hop{}
@ -530,6 +570,47 @@ func deserializeHop(r io.Reader) (*route.Hop, error) {
return nil, err
}
// TODO(roasbeef): change field to allow LegacyPayload false to be the
// legacy default?
err := binary.Read(r, byteOrder, &h.LegacyPayload)
if err != nil {
return nil, err
}
var numElements uint32
if err := ReadElements(r, &numElements); err != nil {
return nil, err
}
// If there're no elements, then we can return early.
if numElements == 0 {
return h, nil
}
tlvMap := make(map[uint64][]byte)
for i := uint32(0); i < numElements; i++ {
var tlvType uint64
if err := ReadElements(r, &tlvType); err != nil {
return nil, err
}
rawRecordBytes, err := wire.ReadVarBytes(
r, 0, maxOnionPayloadSize, "tlv",
)
if err != nil {
return nil, err
}
tlvMap[tlvType] = rawRecordBytes
}
tlvRecords, err := tlv.MapToRecords(tlvMap)
if err != nil {
return nil, err
}
h.TLVRecords = tlvRecords
return h, nil
}

@ -13,17 +13,32 @@ import (
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/tlv"
)
var (
priv, _ = btcec.NewPrivateKey(btcec.S256())
pub = priv.PubKey()
testHop = &route.Hop{
tlvBytes = []byte{1, 2, 3}
tlvEncoder = tlv.StubEncoder(tlvBytes)
testHop1 = &route.Hop{
PubKeyBytes: route.NewVertex(pub),
ChannelID: 12345,
OutgoingTimeLock: 111,
AmtToForward: 555,
TLVRecords: []tlv.Record{
tlv.MakeStaticRecord(1, nil, 3, tlvEncoder, nil),
tlv.MakeStaticRecord(2, nil, 3, tlvEncoder, nil),
},
}
testHop2 = &route.Hop{
PubKeyBytes: route.NewVertex(pub),
ChannelID: 12345,
OutgoingTimeLock: 111,
AmtToForward: 555,
LegacyPayload: true,
}
testRoute = route.Route{
@ -31,8 +46,8 @@ var (
TotalAmount: 1234567,
SourcePubKey: route.NewVertex(pub),
Hops: []*route.Hop{
testHop,
testHop,
testHop1,
testHop2,
},
}
)
@ -191,6 +206,8 @@ func TestSentPaymentSerialization(t *testing.T) {
}
if !reflect.DeepEqual(s, newAttemptInfo) {
s.SessionKey.Curve = nil
newAttemptInfo.SessionKey.Curve = nil
t.Fatalf("Payments do not match after "+
"serialization/deserialization %v vs %v",
spew.Sdump(s), spew.Sdump(newAttemptInfo),
@ -199,6 +216,46 @@ func TestSentPaymentSerialization(t *testing.T) {
}
func assertRouteHopRecordsEqual(r1, r2 *route.Route) error {
for i := 0; i < len(r1.Hops); i++ {
for j := 0; j < len(r1.Hops[i].TLVRecords); j++ {
expectedRecord := r1.Hops[i].TLVRecords[j]
newRecord := r2.Hops[i].TLVRecords[j]
err := assertHopRecordsEqual(expectedRecord, newRecord)
if err != nil {
return fmt.Errorf("route record mismatch: %v", err)
}
}
}
return nil
}
func assertHopRecordsEqual(h1, h2 tlv.Record) error {
if h1.Type() != h2.Type() {
return fmt.Errorf("wrong type: expected %v, got %v", h1.Type(),
h2.Type())
}
var b bytes.Buffer
if err := h2.Encode(&b); err != nil {
return fmt.Errorf("unable to encode record: %v", err)
}
if !bytes.Equal(b.Bytes(), tlvBytes) {
return fmt.Errorf("wrong raw record: expected %x, got %x",
tlvBytes, b.Bytes())
}
if h1.Size() != h2.Size() {
return fmt.Errorf("wrong size: expected %v, "+
"got %v", h1.Size(), h2.Size())
}
return nil
}
func TestRouteSerialization(t *testing.T) {
t.Parallel()
@ -213,9 +270,23 @@ func TestRouteSerialization(t *testing.T) {
t.Fatal(err)
}
// First we verify all the records match up porperly, as they aren't
// able to be properly compared using reflect.DeepEqual.
err = assertRouteHopRecordsEqual(&testRoute, &route2)
if err != nil {
t.Fatalf("route tlv records don't match: %v", err)
}
// Now that we know the records match up, we'll examine the remainder
// of the route without the TLV records attached as reflect.DeepEqual
// can't properly assert their equality.
testRoute.Hops[0].TLVRecords = nil
testRoute.Hops[1].TLVRecords = nil
route2.Hops[0].TLVRecords = nil
route2.Hops[1].TLVRecords = nil
if !reflect.DeepEqual(testRoute, route2) {
t.Fatalf("routes not equal: \n%v vs \n%v",
spew.Sdump(testRoute), spew.Sdump(route2))
}
}

@ -328,6 +328,8 @@ type config struct {
WtClient *lncfg.WtClient `group:"wtclient" namespace:"wtclient"`
Watchtower *lncfg.Watchtower `group:"watchtower" namespace:"watchtower"`
LegacyProtocol *lncfg.LegacyProtocol `group:"legacyprotocol" namespace:"legacyprotocol"`
}
// loadConfig initializes and parses the config using a config file and command

@ -166,7 +166,7 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) {
// identical to HTLC resolution in the link.
event, err := h.Registry.NotifyExitHopHtlc(
h.payHash, h.htlcAmt, h.htlcExpiry, currentHeight,
hodlChan,
hodlChan, nil,
)
switch err {
case channeldb.ErrInvoiceNotFound:

@ -22,7 +22,8 @@ type Registry interface {
// the resolution is sent on the passed in hodlChan later.
NotifyExitHopHtlc(payHash lntypes.Hash, paidAmount lnwire.MilliSatoshi,
expiry uint32, currentHeight int32,
hodlChan chan<- interface{}) (*invoices.HodlEvent, error)
hodlChan chan<- interface{},
eob []byte) (*invoices.HodlEvent, error)
// HodlUnsubscribeAll unsubscribes from all hodl events.
HodlUnsubscribeAll(subscriber chan<- interface{})

@ -23,7 +23,7 @@ type mockRegistry struct {
func (r *mockRegistry) NotifyExitHopHtlc(payHash lntypes.Hash,
paidAmount lnwire.MilliSatoshi, expiry uint32, currentHeight int32,
hodlChan chan<- interface{}) (*invoices.HodlEvent, error) {
hodlChan chan<- interface{}, eob []byte) (*invoices.HodlEvent, error) {
r.notifyChan <- notifyExitHopData{
hodlChan: hodlChan,

21
go.mod

@ -1,8 +1,7 @@
module github.com/lightningnetwork/lnd
require (
git.schwanenlied.me/yawning/bsaes.git v0.0.0-20180720073208-c0276d75487e // indirect
github.com/NebulousLabs/fastrand v0.0.0-20180208210444-3cf7173006a0 // indirect
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e // indirect
github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82
github.com/Yawning/aez v0.0.0-20180114000226-4dad034d9db2
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8
@ -21,22 +20,19 @@ require (
github.com/jackpal/go-nat-pmp v0.0.0-20170405195558-28a68d0c24ad
github.com/jessevdk/go-flags v1.4.0
github.com/jrick/logrotate v1.0.0
github.com/juju/clock v0.0.0-20180808021310-bab88fc67299 // indirect
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 // indirect
github.com/juju/loggo v0.0.0-20180524022052-584905176618 // indirect
github.com/juju/retry v0.0.0-20180821225755-9058e192b216 // indirect
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 // indirect
github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d // indirect
github.com/juju/version v0.0.0-20180108022336-b64dbd566305 // indirect
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c // indirect
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d // indirect
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect
github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2 // indirect
github.com/kkdai/bstream v0.0.0-20181106074824-b3251f7901ec
github.com/lightninglabs/neutrino v0.0.0-20190725230401-ddf667a8b5c4
github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9
github.com/lightningnetwork/lightning-onion v0.0.0-20190808221659-0c0c9dbf17ea
github.com/lightningnetwork/lnd/queue v1.0.1
github.com/lightningnetwork/lnd/ticker v1.0.0
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796
github.com/miekg/dns v0.0.0-20171125082028-79bfde677fa8
github.com/prometheus/client_golang v0.9.3
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af // indirect
github.com/rogpeppe/fastuuid v1.2.0 // indirect
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02
github.com/urfave/cli v1.18.0
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67
@ -44,10 +40,9 @@ require (
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922
google.golang.org/grpc v1.18.0
gopkg.in/errgo.v1 v1.0.0 // indirect
gopkg.in/errgo.v1 v1.0.1 // indirect
gopkg.in/macaroon-bakery.v2 v2.0.1
gopkg.in/macaroon.v2 v2.0.0
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce // indirect
)
replace github.com/lightningnetwork/lnd/ticker => ./ticker

45
go.sum

@ -1,6 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/NebulousLabs/fastrand v0.0.0-20180208210444-3cf7173006a0 h1:g/ETZwHx5wN2fqKWS3gCUrEU7dLko+DvVs3hakQCfyE=
github.com/NebulousLabs/fastrand v0.0.0-20180208210444-3cf7173006a0/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ=
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e h1:n+DcnTNkQnHlwpsrHoQtkrJIO7CBx029fw6oR4vIob4=
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ=
github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82 h1:MG93+PZYs9PyEsj/n5/haQu2gK0h4tUtSy9ejtMwWa0=
github.com/NebulousLabs/go-upnp v0.0.0-20180202185039-29b680b06c82/go.mod h1:GbuBk21JqF+driLX3XtJYNZjGa45YDoa9IqCTzNSfEc=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -20,18 +21,14 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/btcsuite/btcd v0.0.0-20180823030728-d81d8877b8f3/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
github.com/btcsuite/btcd v0.0.0-20181130015935-7d2daa5bfef2/go.mod h1:Jr9bmNVGZ7TH2Ux1QuP0ec+yGgh0gE9FIlkzQiI5bR0=
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32 h1:qkOC5Gd33k54tobS36cXdAzJbeHaduLtnLQQwNoIi78=
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c h1:aEbSeNALREWXk0G7UdNhR3ayBV7tZ4M2PNmnrCAph6Q=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50 h1:4i3KsuVA0o0KoBxAC5x+MY7RbteiMK1V7gf/G08NGIQ=
github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8 h1:mOg8/RgDSHTQ1R0IR+LMDuW4TDShPv+JzYHuR4GLoNA=
github.com/btcsuite/btcd v0.0.0-20190629003639-c26ffa870fd8/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803 h1:j3AgPKKZtZStM2nyhrDSLSYgT7YHrZKdSkq1OYeLjvM=
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
@ -46,11 +43,9 @@ github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd h1:R/opQEbFEy9JG
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8 h1:nOsAWScwueMVk/VLm/dvQQD7DuanyvAUb6B3P3eT274=
github.com/btcsuite/golangcrypto v0.0.0-20150304025918-53f62d9b43e8/go.mod h1:tYvUd8KLhm/oXvUeSEs2VlLghFjQt9+ZaF9ghH0JNjc=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd h1:qdGvebPBDuYDPGi1WCPjy1tGyMpmDK8IEapSsszn7HE=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
github.com/btcsuite/goleveldb v1.0.0 h1:Tvd0BfvqX9o823q1j2UZ/epQo09eJh6dTcRp79ilIN4=
github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723 h1:ZA/jbKoGcVAnER6pCHPEkGdZOV7U1oLUedErBHCUMs0=
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/snappy-go v1.0.0 h1:ZxaA6lo2EpxGddsA8JwWOcxlzRybb444sgmeJQMJGQE=
github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
@ -60,7 +55,6 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v0.0.0-20180223184059-7ee3ded59d4835e10f3e7d0f7603c42aa5e83820/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY=
github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@ -68,6 +62,8 @@ github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY=
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
@ -82,10 +78,11 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v0.0.0-20180821051752-b27b920f9e71/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42 h1:q3pnF5JFBNRz8sRD+IRj7Y6DMyYGTNqnZ9axTbSfoNI=
github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
@ -103,16 +100,20 @@ github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGAR
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/juju/clock v0.0.0-20180808021310-bab88fc67299 h1:K9nBHQ3UNqg/HhZkQnGG2AE4YxDyNmGS9FFT2gGegLQ=
github.com/juju/clock v0.0.0-20180808021310-bab88fc67299/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c h1:3UvYABOQRhJAApj9MdCN+Ydv841ETSoy6xLzdmmr/9A=
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618 h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8=
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d h1:hJXjZMxj0SWlMoQkzeZDLi2cmeiWKa7y1B8Rg+qaoEc=
github.com/juju/errors v0.0.0-20190806202954-0232dcc7464d/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 h1:UUHMLvzt/31azWTN/ifGWef4WUqvXk0iRqdhdy/2uzI=
github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/retry v0.0.0-20180821225755-9058e192b216 h1:/eQL7EJQKFHByJe3DeE8Z36yqManj9UY5zppDoQi4FU=
github.com/juju/retry v0.0.0-20180821225755-9058e192b216/go.mod h1:OohPQGsr4pnxwD5YljhQ+TZnuVRYpa5irjugL1Yuif4=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 h1:WQM1NildKThwdP7qWrNAFGzp4ijNLw8RlgENkaI4MJs=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2 h1:Pp8RxiF4rSoXP9SED26WCfNB28/dwTDpPXS8XMJR8rc=
github.com/juju/testing v0.0.0-20190723135506-ce30eb24acd2/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d h1:irPlN9z5VCe6BTsqVsxheCZH99OFSmqSVyTigW4mEoY=
github.com/juju/utils v0.0.0-20180820210520-bf9cc5bdd62d/go.mod h1:6/KLg8Wz/y2KVGWEpkK9vMNGkOnu4k/cqs8Z1fKjTOk=
github.com/juju/version v0.0.0-20180108022336-b64dbd566305 h1:lQxPJ1URr2fjsKnJRt/BxiIxjLt9IKGvS+0injMHbag=
@ -134,12 +135,13 @@ github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d h1:tt8hwvxl6fk
github.com/lightninglabs/gozmq v0.0.0-20190710231225-cea2a031735d/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk=
github.com/lightninglabs/neutrino v0.0.0-20181017011010-4d6069299130/go.mod h1:KJq43Fu9ceitbJsSXMILcT4mGDNI/crKmPIkDOZXFyM=
github.com/lightninglabs/neutrino v0.0.0-20190213031021-ae4583a89cfb/go.mod h1:g6cMQd+hfAU8pQTJAdjm6/EQREhupyd22f+CL0qYFOE=
github.com/lightninglabs/neutrino v0.0.0-20190313035638-e1ad4c33fb18 h1:lxD7RgKYrjRRht6Cn1AiBPn4Rjgr5pkKSRxTs++EgaI=
github.com/lightninglabs/neutrino v0.0.0-20190313035638-e1ad4c33fb18/go.mod h1:v6tz6jbuAubTrRpX8ke2KH9sJxml8KlPQTKgo9mAp1Q=
github.com/lightninglabs/neutrino v0.0.0-20190725230401-ddf667a8b5c4 h1:Yq3usMeTtJyRHFRJQsVqmr5oJTFm6uhZdKL2/YhoVrA=
github.com/lightninglabs/neutrino v0.0.0-20190725230401-ddf667a8b5c4/go.mod h1:vzLU75ll8qbRJIzW5dvK/UXtR9c2FecJ6VNOM8chyVM=
github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9 h1:u6dbtgPtilk/HWg9GwA8GniHqzCW/7an3ZSpZARfHx4=
github.com/lightningnetwork/lightning-onion v0.0.0-20190703000913-ecc936dc56c9/go.mod h1:Sooe/CoCqa85JxqHV+IBR2HW+6t2Cv+36awSmoccswM=
github.com/lightningnetwork/lightning-onion v0.0.0-20190808221659-0c0c9dbf17ea h1:ER+s5SmDJZeVp2WG6NFg9HuDzaMaEna5I3iQwMU9SEk=
github.com/lightningnetwork/lightning-onion v0.0.0-20190808221659-0c0c9dbf17ea/go.mod h1:kuepZyHzr5O4sYQ/Y5yLYXWz+GoHZm3N+M+Jri9Hb64=
github.com/lightningnetwork/lnd v0.7.1-beta.0.20190807225126-ea77ff91c221/go.mod h1:F6I/YZmW3e+kVRgQtCLqvLzBFl+tRCyoT8nolFeqQOo=
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw=
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1sNPI5H8P3NkTFF4LuwMdPl2DodF60qAKqY=
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
@ -171,8 +173,9 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af h1:gu+uRPtBe88sKxUCEXRoeCvVG90TJmwhiqRpvdhQFng=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -183,7 +186,6 @@ github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02/go.mod h1:tHlrkM198S0
github.com/urfave/cli v1.18.0 h1:m9MfmZWX7bwr9kUcs/Asr95j0IVXzGNNc+/5ku2m26Q=
github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
go.etcd.io/bbolt v1.3.0/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
@ -199,16 +201,13 @@ golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180821023952-922f4815f713/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953 h1:LuZIitY8waaxUfNIdtajyE/YzA/zyf0YxXG27VpLrkg=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 h1:bfLnR+k0tq5Lqt6dflRLcZiz6UaXCMt3vhYJ1l4FQ80=
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180821140842-3b58ed4ad339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -219,7 +218,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503 h1:5SvYFrOM3W8Mexn9/oA44Ji7vhXAZQ9hiP+1Q/DMrWg=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -231,7 +229,6 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922 h1:mBVYJnbrXLA/ZCBTCe7PtEgAUP+1bg92qTaFoPHdz+8=
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0 h1:dz5IJGuC2BB7qXR5AyHNwAUBhZscK2xVez7mznh72sY=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@ -239,8 +236,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v1 v1.0.0 h1:n+7XfCyygBFb8sEjg6692xjC6Us50TFRO54+xYUEwjE=
gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk=
gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso=
gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/macaroon-bakery.v2 v2.0.1 h1:0N1TlEdfLP4HXNCg7MQUMp5XwvOoxk+oe9Owr2cpvsc=
@ -251,7 +249,6 @@ gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

@ -23,10 +23,13 @@ type InvoiceDatabase interface {
// invoice is a debug invoice, then this method is a noop as debug
// invoices are never fully settled. The return value describes how the
// htlc should be resolved. If the htlc cannot be resolved immediately,
// the resolution is sent on the passed in hodlChan later.
// the resolution is sent on the passed in hodlChan later. The eob
// field passes the entire onion hop payload into the invoice registry
// for decoding purposes.
NotifyExitHopHtlc(payHash lntypes.Hash, paidAmount lnwire.MilliSatoshi,
expiry uint32, currentHeight int32,
hodlChan chan<- interface{}) (*invoices.HodlEvent, error)
hodlChan chan<- interface{},
eob []byte) (*invoices.HodlEvent, error)
// CancelInvoice attempts to cancel the invoice corresponding to the
// passed payment hash.

@ -1,12 +1,15 @@
package htlcswitch
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"github.com/btcsuite/btcd/btcec"
"github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
)
// NetworkHop indicates the blockchain network that is intended to be the next
@ -85,7 +88,10 @@ type HopIterator interface {
// Additionally, the information encoded within the returned
// ForwardingInfo is to be used by each hop to authenticate the
// information given to it by the prior hop.
ForwardingInstructions() ForwardingInfo
ForwardingInstructions() (ForwardingInfo, error)
// ExtraOnionBlob returns the additional EOB data (if available).
ExtraOnionBlob() []byte
// EncodeNextHop encodes the onion packet destined for the next hop
// into the passed io.Writer.
@ -139,24 +145,79 @@ func (r *sphinxHopIterator) EncodeNextHop(w io.Writer) error {
// hop to authenticate the information given to it by the prior hop.
//
// NOTE: Part of the HopIterator interface.
func (r *sphinxHopIterator) ForwardingInstructions() ForwardingInfo {
fwdInst := r.processedPacket.ForwardingInstructions
func (r *sphinxHopIterator) ForwardingInstructions() (ForwardingInfo, error) {
var (
nextHop lnwire.ShortChannelID
amt uint64
cltv uint32
)
var nextHop lnwire.ShortChannelID
switch r.processedPacket.Action {
case sphinx.ExitNode:
nextHop = exitHop
case sphinx.MoreHops:
s := binary.BigEndian.Uint64(fwdInst.NextAddress[:])
nextHop = lnwire.NewShortChanIDFromInt(s)
switch r.processedPacket.Payload.Type {
// If this is the legacy payload, then we'll extract the information
// directly from the pre-populated ForwardingInstructions field.
case sphinx.PayloadLegacy:
fwdInst := r.processedPacket.ForwardingInstructions
switch r.processedPacket.Action {
case sphinx.ExitNode:
nextHop = exitHop
case sphinx.MoreHops:
s := binary.BigEndian.Uint64(fwdInst.NextAddress[:])
nextHop = lnwire.NewShortChanIDFromInt(s)
}
amt = fwdInst.ForwardAmount
cltv = fwdInst.OutgoingCltv
// Otherwise, if this is the TLV payload, then we'll make a new stream
// to decode only what we need to make routing decisions.
case sphinx.PayloadTLV:
var cid uint64
tlvStream, err := tlv.NewStream(
tlv.MakeDynamicRecord(
tlv.AmtOnionType, &amt, nil,
tlv.ETUint64, tlv.DTUint64,
),
tlv.MakeDynamicRecord(
tlv.LockTimeOnionType, &cltv, nil,
tlv.ETUint32, tlv.DTUint32,
),
tlv.MakePrimitiveRecord(tlv.NextHopOnionType, &cid),
)
if err != nil {
return ForwardingInfo{}, err
}
err = tlvStream.Decode(bytes.NewReader(
r.processedPacket.Payload.Payload,
))
if err != nil {
return ForwardingInfo{}, err
}
nextHop = lnwire.NewShortChanIDFromInt(cid)
default:
return ForwardingInfo{}, fmt.Errorf("unknown sphinx payload "+
"type: %v", r.processedPacket.Payload.Type)
}
return ForwardingInfo{
Network: BitcoinHop,
NextHop: nextHop,
AmountToForward: lnwire.MilliSatoshi(fwdInst.ForwardAmount),
OutgoingCTLV: fwdInst.OutgoingCltv,
AmountToForward: lnwire.MilliSatoshi(amt),
OutgoingCTLV: cltv,
}, nil
}
// ExtraOnionBlob returns the additional EOB data (if available).
func (r *sphinxHopIterator) ExtraOnionBlob() []byte {
if r.processedPacket.Payload.Type == sphinx.PayloadLegacy {
return nil
}
return r.processedPacket.Payload.Payload
}
// ExtractErrorEncrypter decodes and returns the ErrorEncrypter for this hop,

109
htlcswitch/iterator_test.go Normal file

@ -0,0 +1,109 @@
package htlcswitch
import (
"bytes"
"encoding/binary"
"testing"
"github.com/davecgh/go-spew/spew"
sphinx "github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
)
// TestSphinxHopIteratorForwardingInstructions tests that we're able to
// properly decode an onion payload, no matter the payload type, into the
// original set of forwarding instructions.
func TestSphinxHopIteratorForwardingInstructions(t *testing.T) {
t.Parallel()
// First, we'll make the hop data that the sender would create to send
// an HTLC through our imaginary route.
hopData := sphinx.HopData{
ForwardAmount: 100000,
OutgoingCltv: 4343,
}
copy(hopData.NextAddress[:], bytes.Repeat([]byte("a"), 8))
// Next, we'll make the hop forwarding information that we should
// extract each type, no matter the payload type.
nextAddrInt := binary.BigEndian.Uint64(hopData.NextAddress[:])
expectedFwdInfo := ForwardingInfo{
NextHop: lnwire.NewShortChanIDFromInt(nextAddrInt),
AmountToForward: lnwire.MilliSatoshi(hopData.ForwardAmount),
OutgoingCTLV: hopData.OutgoingCltv,
}
// For our TLV payload, we'll serialize the hop into into a TLV stream
// as we would normally in the routing network.
var b bytes.Buffer
tlvRecords := []tlv.Record{
tlv.MakeDynamicRecord(
tlv.AmtOnionType, &hopData.ForwardAmount, func() uint64 {
return tlv.SizeTUint64(hopData.ForwardAmount)
},
tlv.ETUint64, tlv.DTUint64,
),
tlv.MakeDynamicRecord(
tlv.LockTimeOnionType, &hopData.OutgoingCltv, func() uint64 {
return tlv.SizeTUint32(hopData.OutgoingCltv)
},
tlv.ETUint32, tlv.DTUint32,
),
tlv.MakePrimitiveRecord(tlv.NextHopOnionType, &nextAddrInt),
}
tlvStream, err := tlv.NewStream(tlvRecords...)
if err != nil {
t.Fatalf("unable to create stream: %v", err)
}
if err := tlvStream.Encode(&b); err != nil {
t.Fatalf("unable to encode stream: %v", err)
}
var testCases = []struct {
sphinxPacket *sphinx.ProcessedPacket
expectedFwdInfo ForwardingInfo
}{
// A regular legacy payload that signals more hops.
{
sphinxPacket: &sphinx.ProcessedPacket{
Payload: sphinx.HopPayload{
Type: sphinx.PayloadLegacy,
},
Action: sphinx.MoreHops,
ForwardingInstructions: &hopData,
},
expectedFwdInfo: expectedFwdInfo,
},
// A TLV payload, we can leave off the action as we'll always
// read the cid encoded.
{
sphinxPacket: &sphinx.ProcessedPacket{
Payload: sphinx.HopPayload{
Type: sphinx.PayloadTLV,
Payload: b.Bytes(),
},
},
expectedFwdInfo: expectedFwdInfo,
},
}
// Finally, we'll test that we get the same set of
// ForwardingInstructions for each payload type.
iterator := sphinxHopIterator{}
for i, testCase := range testCases {
iterator.processedPacket = testCase.sphinxPacket
fwdInfo, err := iterator.ForwardingInstructions()
if err != nil {
t.Fatalf("#%v: unable to extract forwarding "+
"instructions: %v", i, err)
}
if fwdInfo != testCase.expectedFwdInfo {
t.Fatalf("#%v: wrong fwding info: expected %v, got %v",
i, spew.Sdump(testCase.expectedFwdInfo),
spew.Sdump(fwdInfo))
}
}
}

@ -2627,8 +2627,9 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
// If we're unable to process the onion blob than we
// should send the malformed htlc error to payment
// sender.
l.sendMalformedHTLCError(pd.HtlcIndex, failureCode,
onionBlob[:], pd.SourceRef)
l.sendMalformedHTLCError(
pd.HtlcIndex, failureCode, onionBlob[:], pd.SourceRef,
)
needUpdate = true
log.Errorf("unable to decode onion "+
@ -2638,11 +2639,29 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
heightNow := l.cfg.Switch.BestHeight()
fwdInfo := chanIterator.ForwardingInstructions()
fwdInfo, err := chanIterator.ForwardingInstructions()
if err != nil {
// If we're unable to process the onion payload, or we
// we received malformed TLV stream, then we should
// send an error back to the caller so the HTLC can be
// cancelled.
l.sendHTLCError(
pd.HtlcIndex,
lnwire.NewInvalidOnionVersion(onionBlob[:]),
obfuscator, pd.SourceRef,
)
needUpdate = true
log.Errorf("Unable to decode forwarding "+
"instructions: %v", err)
continue
}
switch fwdInfo.NextHop {
case exitHop:
updated, err := l.processExitHop(
pd, obfuscator, fwdInfo, heightNow,
chanIterator.ExtraOnionBlob(),
)
if err != nil {
l.fail(LinkFailureError{code: ErrInternalError},
@ -2814,8 +2833,8 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg,
// processExitHop handles an htlc for which this link is the exit hop. It
// returns a boolean indicating whether the commitment tx needs an update.
func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor,
obfuscator ErrorEncrypter, fwdInfo ForwardingInfo, heightNow uint32) (
bool, error) {
obfuscator ErrorEncrypter, fwdInfo ForwardingInfo,
heightNow uint32, eob []byte) (bool, error) {
// If hodl.ExitSettle is requested, we will not validate the final hop's
// ADD, nor will we settle the corresponding invoice or respond with the
@ -2861,7 +2880,7 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor,
event, err := l.cfg.Registry.NotifyExitHopHtlc(
invoiceHash, pd.Amount, pd.Timeout, int32(heightNow),
l.hodlQueue.ChanIn(),
l.hodlQueue.ChanIn(), eob,
)
switch err {

@ -275,10 +275,14 @@ func newMockHopIterator(hops ...ForwardingInfo) HopIterator {
return &mockHopIterator{hops: hops}
}
func (r *mockHopIterator) ForwardingInstructions() ForwardingInfo {
func (r *mockHopIterator) ForwardingInstructions() (ForwardingInfo, error) {
h := r.hops[0]
r.hops = r.hops[1:]
return h
return h, nil
}
func (r *mockHopIterator) ExtraOnionBlob() []byte {
return nil
}
func (r *mockHopIterator) ExtractErrorEncrypter(
@ -789,10 +793,10 @@ func (i *mockInvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error
func (i *mockInvoiceRegistry) NotifyExitHopHtlc(rhash lntypes.Hash,
amt lnwire.MilliSatoshi, expiry uint32, currentHeight int32,
hodlChan chan<- interface{}) (*invoices.HodlEvent, error) {
hodlChan chan<- interface{}, eob []byte) (*invoices.HodlEvent, error) {
event, err := i.registry.NotifyExitHopHtlc(
rhash, amt, expiry, currentHeight, hodlChan,
rhash, amt, expiry, currentHeight, hodlChan, eob,
)
if err != nil {
return nil, err

@ -489,7 +489,7 @@ func (i *InvoiceRegistry) checkHtlcParameters(invoice *channeldb.Invoice,
// prevent deadlock.
func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash,
amtPaid lnwire.MilliSatoshi, expiry uint32, currentHeight int32,
hodlChan chan<- interface{}) (*HodlEvent, error) {
hodlChan chan<- interface{}, eob []byte) (*HodlEvent, error) {
i.Lock()
defer i.Unlock()

@ -119,7 +119,7 @@ func TestSettleInvoice(t *testing.T) {
// Settle invoice with a slightly higher amount.
amtPaid := lnwire.MilliSatoshi(100500)
_, err = registry.NotifyExitHopHtlc(
hash, amtPaid, testInvoiceExpiry, 0, hodlChan,
hash, amtPaid, testInvoiceExpiry, 0, hodlChan, nil,
)
if err != nil {
t.Fatal(err)
@ -155,6 +155,7 @@ func TestSettleInvoice(t *testing.T) {
// restart.
event, err := registry.NotifyExitHopHtlc(
hash, amtPaid, testInvoiceExpiry, testCurrentHeight, hodlChan,
nil,
)
if err != nil {
t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
@ -168,7 +169,7 @@ func TestSettleInvoice(t *testing.T) {
// same. New HTLCs with a different amount should be rejected.
event, err = registry.NotifyExitHopHtlc(
hash, amtPaid+600, testInvoiceExpiry, testCurrentHeight,
hodlChan,
hodlChan, nil,
)
if err != nil {
t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
@ -181,7 +182,7 @@ func TestSettleInvoice(t *testing.T) {
// behaviour as settling with a higher amount.
event, err = registry.NotifyExitHopHtlc(
hash, amtPaid-600, testInvoiceExpiry, testCurrentHeight,
hodlChan,
hodlChan, nil,
)
if err != nil {
t.Fatalf("unexpected NotifyExitHopHtlc error: %v", err)
@ -304,7 +305,7 @@ func TestCancelInvoice(t *testing.T) {
// succeed.
hodlChan := make(chan interface{})
event, err := registry.NotifyExitHopHtlc(
hash, amt, testInvoiceExpiry, testCurrentHeight, hodlChan,
hash, amt, testInvoiceExpiry, testCurrentHeight, hodlChan, nil,
)
if err != nil {
t.Fatal("expected settlement of a canceled invoice to succeed")
@ -381,6 +382,7 @@ func TestHoldInvoice(t *testing.T) {
// should be possible.
event, err := registry.NotifyExitHopHtlc(
hash, amtPaid, testInvoiceExpiry, testCurrentHeight, hodlChan,
nil,
)
if err != nil {
t.Fatalf("expected settle to succeed but got %v", err)
@ -392,6 +394,7 @@ func TestHoldInvoice(t *testing.T) {
// Test idempotency.
event, err = registry.NotifyExitHopHtlc(
hash, amtPaid, testInvoiceExpiry, testCurrentHeight, hodlChan,
nil,
)
if err != nil {
t.Fatalf("expected settle to succeed but got %v", err)
@ -487,7 +490,7 @@ func TestUnknownInvoice(t *testing.T) {
hodlChan := make(chan interface{})
amt := lnwire.MilliSatoshi(100000)
_, err := registry.NotifyExitHopHtlc(
hash, amt, testInvoiceExpiry, testCurrentHeight, hodlChan,
hash, amt, testInvoiceExpiry, testCurrentHeight, hodlChan, nil,
)
if err != channeldb.ErrInvoiceNotFound {
t.Fatal("expected invoice not found error")

@ -0,0 +1,16 @@
// +build !dev
package lncfg
// LegacyProtocol is a struct that we use to be able to test backwards
// compatibility of protocol additions, while defaulting to the latest within
// lnd.
type LegacyProtocol struct {
}
// LegacyOnion returns true if the old legacy onion format should be used when
// we're an intermediate or final hop. This controls if we set the
// TLVOnionPayloadOptional bit or not.
func (l *LegacyProtocol) LegacyOnion() bool {
return false
}

@ -0,0 +1,20 @@
// +build dev
package lncfg
// LegacyProtocol is a struct that we use to be able to test backwards
// compatibility of protocol additions, while defaulting to the latest within
// lnd.
type LegacyProtocol struct {
// Onion if set to true, then we won't signal TLVOnionPayloadOptional.
// As a result, nodes that include us in the route won't use the new
// modern onion framing.
Onion bool `long:"onion" description:"force node to not advertise the new modern TLV onion format"`
}
// LegacyOnion returns true if the old legacy onion format should be used when
// we're an intermediate or final hop. This controls if we set the
// TLVOnionPayloadOptional bit or not.
func (l *LegacyProtocol) LegacyOnion() bool {
return l.Onion
}

@ -214,10 +214,15 @@ type SendPaymentRequest struct {
CltvLimit int32 `protobuf:"varint,9,opt,name=cltv_limit,json=cltvLimit,proto3" json:"cltv_limit,omitempty"`
//*
//Optional route hints to reach the destination through private channels.
RouteHints []*lnrpc.RouteHint `protobuf:"bytes,10,rep,name=route_hints,proto3" json:"route_hints,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
RouteHints []*lnrpc.RouteHint `protobuf:"bytes,10,rep,name=route_hints,proto3" json:"route_hints,omitempty"`
//*
//An optional field that can be used to pass an arbitrary set of TLV records
//to a peer which understands the new records. This can be used to pass
//application specific data during the payment attempt.
DestTlv map[uint64][]byte `protobuf:"bytes,11,rep,name=dest_tlv,json=destTlv,proto3" json:"dest_tlv,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SendPaymentRequest) Reset() { *m = SendPaymentRequest{} }
@ -315,6 +320,13 @@ func (m *SendPaymentRequest) GetRouteHints() []*lnrpc.RouteHint {
return nil
}
func (m *SendPaymentRequest) GetDestTlv() map[uint64][]byte {
if m != nil {
return m.DestTlv
}
return nil
}
type TrackPaymentRequest struct {
/// The hash of the payment to look up.
PaymentHash []byte `protobuf:"bytes,1,opt,name=payment_hash,json=paymentHash,proto3" json:"payment_hash,omitempty"`
@ -1171,6 +1183,7 @@ func init() {
proto.RegisterEnum("routerrpc.PaymentState", PaymentState_name, PaymentState_value)
proto.RegisterEnum("routerrpc.Failure_FailureCode", Failure_FailureCode_name, Failure_FailureCode_value)
proto.RegisterType((*SendPaymentRequest)(nil), "routerrpc.SendPaymentRequest")
proto.RegisterMapType((map[uint64][]byte)(nil), "routerrpc.SendPaymentRequest.DestTlvEntry")
proto.RegisterType((*TrackPaymentRequest)(nil), "routerrpc.TrackPaymentRequest")
proto.RegisterType((*PaymentStatus)(nil), "routerrpc.PaymentStatus")
proto.RegisterType((*RouteFeeRequest)(nil), "routerrpc.RouteFeeRequest")
@ -1190,112 +1203,116 @@ func init() {
func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) }
var fileDescriptor_7a0613f69d37b0a5 = []byte{
// 1677 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0x4f, 0x77, 0x22, 0xc7,
0x11, 0x37, 0x02, 0x84, 0x28, 0xfe, 0xcd, 0xb6, 0xb4, 0xda, 0x59, 0xb4, 0xb2, 0xe5, 0xb1, 0xb3,
0xd6, 0xdb, 0xe7, 0x48, 0x0e, 0x79, 0xf6, 0xcb, 0x29, 0x79, 0x2c, 0x34, 0xd6, 0xec, 0xc2, 0x8c,
0xdc, 0xc0, 0xda, 0x9b, 0x1c, 0xfa, 0xb5, 0xa0, 0x05, 0xf3, 0x04, 0x33, 0x78, 0xa6, 0x71, 0x56,
0x39, 0xe4, 0x92, 0x97, 0x63, 0xee, 0xf9, 0x16, 0xf9, 0x14, 0x39, 0xe4, 0x8b, 0x24, 0xdf, 0x21,
0xa7, 0xbc, 0xee, 0x9e, 0x81, 0x01, 0xb1, 0x1b, 0x9f, 0x98, 0xfe, 0xd5, 0xaf, 0xab, 0xaa, 0xab,
0xba, 0xaa, 0x0b, 0x38, 0x0e, 0x83, 0xa5, 0xe0, 0x61, 0xb8, 0x18, 0x5d, 0xea, 0xaf, 0x8b, 0x45,
0x18, 0x88, 0x00, 0x15, 0x57, 0x78, 0xbd, 0x18, 0x2e, 0x46, 0x1a, 0xb5, 0xfe, 0xbb, 0x07, 0xa8,
0xcf, 0xfd, 0xf1, 0x35, 0xbb, 0x9f, 0x73, 0x5f, 0x10, 0xfe, 0xe3, 0x92, 0x47, 0x02, 0x21, 0xc8,
0x8d, 0x79, 0x24, 0xcc, 0xcc, 0x59, 0xe6, 0xbc, 0x4c, 0xd4, 0x37, 0x32, 0x20, 0xcb, 0xe6, 0xc2,
0xdc, 0x3b, 0xcb, 0x9c, 0x67, 0x89, 0xfc, 0x44, 0x9f, 0x42, 0x79, 0xa1, 0xf7, 0xd1, 0x29, 0x8b,
0xa6, 0x66, 0x56, 0xb1, 0x4b, 0x31, 0x76, 0xc5, 0xa2, 0x29, 0x3a, 0x07, 0xe3, 0xd6, 0xf3, 0xd9,
0x8c, 0x8e, 0x66, 0xe2, 0x27, 0x3a, 0xe6, 0x33, 0xc1, 0xcc, 0xdc, 0x59, 0xe6, 0x3c, 0x4f, 0xaa,
0x0a, 0x6f, 0xcd, 0xc4, 0x4f, 0x6d, 0x89, 0xa2, 0x2f, 0xa0, 0x96, 0x28, 0x0b, 0xb5, 0x17, 0x66,
0xfe, 0x2c, 0x73, 0x5e, 0x24, 0xd5, 0xc5, 0xa6, 0x6f, 0x5f, 0x40, 0x4d, 0x78, 0x73, 0x1e, 0x2c,
0x05, 0x8d, 0xf8, 0x28, 0xf0, 0xc7, 0x91, 0xb9, 0xaf, 0x35, 0xc6, 0x70, 0x5f, 0xa3, 0xc8, 0x82,
0xca, 0x2d, 0xe7, 0x74, 0xe6, 0xcd, 0x3d, 0x41, 0x23, 0x26, 0xcc, 0x82, 0x72, 0xbd, 0x74, 0xcb,
0x79, 0x57, 0x62, 0x7d, 0x26, 0xa4, 0x7f, 0xc1, 0x52, 0x4c, 0x02, 0xcf, 0x9f, 0xd0, 0xd1, 0x94,
0xf9, 0xd4, 0x1b, 0x9b, 0x07, 0x67, 0x99, 0xf3, 0x1c, 0xa9, 0x26, 0x78, 0x6b, 0xca, 0x7c, 0x7b,
0x8c, 0x4e, 0x01, 0xd4, 0x19, 0x94, 0x3a, 0xb3, 0xa8, 0x2c, 0x16, 0x25, 0xa2, 0x74, 0xa1, 0x06,
0x94, 0x54, 0x80, 0xe9, 0xd4, 0xf3, 0x45, 0x64, 0xc2, 0x59, 0xf6, 0xbc, 0xd4, 0x30, 0x2e, 0x66,
0xbe, 0x8c, 0x35, 0x91, 0x92, 0x2b, 0xcf, 0x17, 0x24, 0x4d, 0xb2, 0x7e, 0x03, 0x87, 0x83, 0x90,
0x8d, 0xee, 0xb6, 0x82, 0xbf, 0x1d, 0xd6, 0xcc, 0x83, 0xb0, 0x5a, 0x7f, 0x86, 0x4a, 0xbc, 0xa9,
0x2f, 0x98, 0x58, 0x46, 0xe8, 0x97, 0x90, 0x8f, 0x04, 0x13, 0x5c, 0x91, 0xab, 0x8d, 0x27, 0x17,
0xab, 0x6c, 0x5f, 0xa4, 0x88, 0x9c, 0x68, 0x16, 0xaa, 0xc3, 0xc1, 0x22, 0xe4, 0xde, 0x9c, 0x4d,
0xb8, 0x4a, 0x68, 0x99, 0xac, 0xd6, 0xc8, 0x82, 0xbc, 0xda, 0xac, 0xd2, 0x59, 0x6a, 0x94, 0xd3,
0x67, 0x20, 0x5a, 0x64, 0xfd, 0x16, 0x6a, 0x6a, 0xdd, 0xe1, 0xfc, 0x43, 0x57, 0xe6, 0x09, 0x14,
0xd8, 0x5c, 0xc7, 0x5e, 0x5f, 0x9b, 0x7d, 0x36, 0x97, 0x61, 0xb7, 0xc6, 0x60, 0xac, 0xf7, 0x47,
0x8b, 0xc0, 0x8f, 0xb8, 0x4c, 0x85, 0x54, 0x2e, 0x33, 0x21, 0xd3, 0x36, 0x97, 0xbb, 0x32, 0x6a,
0x57, 0x35, 0xc6, 0x3b, 0x9c, 0xf7, 0x22, 0x26, 0xd0, 0x73, 0x7d, 0x03, 0xe8, 0x2c, 0x18, 0xdd,
0xc9, 0x3b, 0xc5, 0xee, 0x63, 0xf5, 0x15, 0x09, 0x77, 0x83, 0xd1, 0x5d, 0x5b, 0x82, 0xd6, 0x1f,
0xf4, 0xdd, 0x1e, 0x04, 0xda, 0xf7, 0x9f, 0x1d, 0xde, 0x75, 0x08, 0xf6, 0xde, 0x1f, 0x02, 0x0a,
0x87, 0x1b, 0xca, 0xe3, 0x53, 0xa4, 0x23, 0x9b, 0xd9, 0x8a, 0xec, 0x97, 0x50, 0xb8, 0x65, 0xde,
0x6c, 0x19, 0x26, 0x8a, 0x51, 0x2a, 0x4d, 0x1d, 0x2d, 0x21, 0x09, 0xc5, 0xfa, 0x57, 0x01, 0x0a,
0x31, 0x88, 0x1a, 0x90, 0x1b, 0x05, 0xe3, 0x24, 0xbb, 0x1f, 0x3f, 0xdc, 0x96, 0xfc, 0xb6, 0x82,
0x31, 0x27, 0x8a, 0x8b, 0x7e, 0x07, 0x55, 0x79, 0xa3, 0x7d, 0x3e, 0xa3, 0xcb, 0xc5, 0x98, 0xad,
0x12, 0x6a, 0xa6, 0x76, 0xb7, 0x34, 0x61, 0xa8, 0xe4, 0xa4, 0x32, 0x4a, 0x2f, 0xd1, 0x09, 0x14,
0xa7, 0x62, 0x36, 0xd2, 0x99, 0xc8, 0xa9, 0xa2, 0x38, 0x90, 0x80, 0xca, 0x81, 0x05, 0x95, 0xc0,
0xf7, 0x02, 0x9f, 0x46, 0x53, 0x46, 0x1b, 0x5f, 0x7f, 0xa3, 0x8a, 0xb5, 0x4c, 0x4a, 0x0a, 0xec,
0x4f, 0x59, 0xe3, 0xeb, 0x6f, 0xd0, 0x27, 0x50, 0x52, 0x25, 0xc3, 0xdf, 0x2d, 0xbc, 0xf0, 0x5e,
0x55, 0x69, 0x85, 0xa8, 0x2a, 0xc2, 0x0a, 0x41, 0x47, 0x90, 0xbf, 0x9d, 0xb1, 0x49, 0xa4, 0x2a,
0xb3, 0x42, 0xf4, 0x02, 0x7d, 0x05, 0x47, 0x71, 0x0c, 0x68, 0x14, 0x2c, 0xc3, 0x11, 0xa7, 0x9e,
0x3f, 0xe6, 0xef, 0x54, 0x5d, 0x56, 0x08, 0x8a, 0x65, 0x7d, 0x25, 0xb2, 0xa5, 0xc4, 0xfa, 0x7b,
0x1e, 0x4a, 0xa9, 0x00, 0xa0, 0x32, 0x1c, 0x10, 0xdc, 0xc7, 0xe4, 0x0d, 0x6e, 0x1b, 0x1f, 0xa1,
0x73, 0xf8, 0xdc, 0x76, 0x5a, 0x2e, 0x21, 0xb8, 0x35, 0xa0, 0x2e, 0xa1, 0x43, 0xe7, 0xb5, 0xe3,
0x7e, 0xef, 0xd0, 0xeb, 0xe6, 0xdb, 0x1e, 0x76, 0x06, 0xb4, 0x8d, 0x07, 0x4d, 0xbb, 0xdb, 0x37,
0x32, 0xe8, 0x19, 0x98, 0x6b, 0x66, 0x22, 0x6e, 0xf6, 0xdc, 0xa1, 0x33, 0x30, 0xf6, 0xd0, 0x27,
0x70, 0xd2, 0xb1, 0x9d, 0x66, 0x97, 0xae, 0x39, 0xad, 0xee, 0xe0, 0x0d, 0xc5, 0x3f, 0x5c, 0xdb,
0xe4, 0xad, 0x91, 0xdd, 0x45, 0xb8, 0x1a, 0x74, 0x5b, 0x89, 0x86, 0x1c, 0x7a, 0x0a, 0x8f, 0x35,
0x41, 0x6f, 0xa1, 0x03, 0xd7, 0xa5, 0x7d, 0xd7, 0x75, 0x8c, 0x3c, 0x7a, 0x04, 0x15, 0xdb, 0x79,
0xd3, 0xec, 0xda, 0x6d, 0x4a, 0x70, 0xb3, 0xdb, 0x33, 0xf6, 0xd1, 0x21, 0xd4, 0xb6, 0x79, 0x05,
0xa9, 0x22, 0xe1, 0xb9, 0x8e, 0xed, 0x3a, 0xf4, 0x0d, 0x26, 0x7d, 0xdb, 0x75, 0x8c, 0x03, 0x74,
0x0c, 0x68, 0x53, 0x74, 0xd5, 0x6b, 0xb6, 0x8c, 0x22, 0x7a, 0x0c, 0x8f, 0x36, 0xf1, 0xd7, 0xf8,
0xad, 0x01, 0xc8, 0x84, 0x23, 0xed, 0x18, 0x7d, 0x89, 0xbb, 0xee, 0xf7, 0xb4, 0x67, 0x3b, 0x76,
0x6f, 0xd8, 0x33, 0x4a, 0xe8, 0x08, 0x8c, 0x0e, 0xc6, 0xd4, 0x76, 0xfa, 0xc3, 0x4e, 0xc7, 0x6e,
0xd9, 0xd8, 0x19, 0x18, 0x65, 0x6d, 0x79, 0xd7, 0xc1, 0x2b, 0x72, 0x43, 0xeb, 0xaa, 0xe9, 0x38,
0xb8, 0x4b, 0xdb, 0x76, 0xbf, 0xf9, 0xb2, 0x8b, 0xdb, 0x46, 0x15, 0x9d, 0xc2, 0xd3, 0x01, 0xee,
0x5d, 0xbb, 0xa4, 0x49, 0xde, 0xd2, 0x44, 0xde, 0x69, 0xda, 0xdd, 0x21, 0xc1, 0x46, 0x0d, 0x7d,
0x0a, 0xa7, 0x04, 0x7f, 0x37, 0xb4, 0x09, 0x6e, 0x53, 0xc7, 0x6d, 0x63, 0xda, 0xc1, 0xcd, 0xc1,
0x90, 0x60, 0xda, 0xb3, 0xfb, 0x7d, 0xdb, 0xf9, 0xd6, 0x30, 0xd0, 0xe7, 0x70, 0xb6, 0xa2, 0xac,
0x14, 0x6c, 0xb1, 0x1e, 0xc9, 0xf3, 0x25, 0x29, 0x75, 0xf0, 0x0f, 0x03, 0x7a, 0x8d, 0x31, 0x31,
0x10, 0xaa, 0xc3, 0xf1, 0xda, 0xbc, 0x36, 0x10, 0xdb, 0x3e, 0x94, 0xb2, 0x6b, 0x4c, 0x7a, 0x4d,
0x47, 0x26, 0x78, 0x43, 0x76, 0x24, 0xdd, 0x5e, 0xcb, 0xb6, 0xdd, 0x7e, 0x8c, 0x8e, 0xa0, 0x96,
0x58, 0x4b, 0xc0, 0x7f, 0x17, 0xd0, 0x13, 0x40, 0x43, 0x87, 0xe0, 0x66, 0x5b, 0x1e, 0x7e, 0x25,
0xf8, 0x4f, 0xe1, 0x55, 0xee, 0x60, 0xcf, 0xc8, 0x5a, 0xff, 0xc8, 0x42, 0x65, 0xa3, 0xd6, 0xd0,
0x33, 0x28, 0x46, 0xde, 0xc4, 0x67, 0x42, 0x76, 0x03, 0xdd, 0x28, 0xd6, 0x80, 0x7a, 0x6c, 0xa6,
0xcc, 0xf3, 0x75, 0x87, 0xd2, 0x1d, 0xba, 0xa8, 0x10, 0xd5, 0x9f, 0x9e, 0x40, 0x21, 0x79, 0xac,
0xb2, 0xaa, 0x2e, 0xf7, 0x47, 0xfa, 0x91, 0x7a, 0x06, 0x45, 0xd9, 0x02, 0x23, 0xc1, 0xe6, 0x0b,
0x55, 0xb2, 0x15, 0xb2, 0x06, 0xd0, 0x67, 0x50, 0x99, 0xf3, 0x28, 0x62, 0x13, 0x4e, 0x75, 0xd9,
0x81, 0x62, 0x94, 0x63, 0xb0, 0xa3, 0xaa, 0xef, 0x33, 0x48, 0xda, 0x40, 0x4c, 0xca, 0x6b, 0x52,
0x0c, 0x6a, 0xd2, 0x76, 0x07, 0x16, 0x2c, 0xae, 0xee, 0x74, 0x07, 0x16, 0x0c, 0xbd, 0x80, 0x47,
0xba, 0x85, 0x78, 0xbe, 0x37, 0x5f, 0xce, 0x75, 0x2b, 0x29, 0x28, 0x97, 0x6b, 0xaa, 0x95, 0x68,
0x5c, 0x75, 0x94, 0xa7, 0x70, 0x70, 0xc3, 0x22, 0x2e, 0x9b, 0x7f, 0x5c, 0xea, 0x05, 0xb9, 0xee,
0x70, 0x2e, 0x45, 0xf2, 0x49, 0x08, 0x65, 0x13, 0x2b, 0x6a, 0xd1, 0x2d, 0xe7, 0x44, 0xc6, 0x71,
0x65, 0x81, 0xbd, 0x5b, 0x5b, 0x28, 0xa5, 0x2c, 0x68, 0x5c, 0x59, 0x78, 0x01, 0x8f, 0xf8, 0x3b,
0x11, 0x32, 0x1a, 0x2c, 0xd8, 0x8f, 0x4b, 0x4e, 0xc7, 0x4c, 0x30, 0xb3, 0xac, 0x82, 0x5b, 0x53,
0x02, 0x57, 0xe1, 0x6d, 0x26, 0x98, 0xf5, 0x0c, 0xea, 0x84, 0x47, 0x5c, 0xf4, 0xbc, 0x28, 0xf2,
0x02, 0xbf, 0x15, 0xf8, 0x22, 0x0c, 0x66, 0xf1, 0x1b, 0x62, 0x9d, 0xc2, 0xc9, 0x4e, 0xa9, 0x7e,
0x04, 0xe4, 0xe6, 0xef, 0x96, 0x3c, 0xbc, 0xdf, 0xbd, 0xf9, 0x1e, 0x4e, 0x76, 0x4a, 0xe3, 0x17,
0xe4, 0x4b, 0xc8, 0xfb, 0xc1, 0x98, 0x47, 0x66, 0x46, 0xcd, 0x10, 0xc7, 0xa9, 0x76, 0xed, 0x04,
0x63, 0x7e, 0xe5, 0x45, 0x22, 0x08, 0xef, 0x89, 0x26, 0x49, 0xf6, 0x82, 0x79, 0x61, 0x64, 0xee,
0x3d, 0x60, 0x5f, 0x33, 0x2f, 0x5c, 0xb1, 0x15, 0xc9, 0xfa, 0x4b, 0x06, 0x4a, 0x29, 0x25, 0xe8,
0x18, 0xf6, 0x17, 0xcb, 0x9b, 0x3b, 0x7e, 0x1f, 0x5f, 0xc1, 0x78, 0x85, 0x9e, 0x43, 0x75, 0xc6,
0x22, 0x41, 0x65, 0xaf, 0xa5, 0x32, 0xa5, 0xf1, 0x03, 0xbb, 0x85, 0xa2, 0x0b, 0x40, 0x81, 0x98,
0xf2, 0x90, 0x46, 0xcb, 0xd1, 0x88, 0x47, 0x11, 0x5d, 0x84, 0xc1, 0x8d, 0xba, 0x93, 0x7b, 0x64,
0x87, 0xe4, 0x55, 0xee, 0x20, 0x67, 0xe4, 0xad, 0x7f, 0x66, 0xa0, 0x94, 0x72, 0x4e, 0xde, 0x5a,
0x79, 0x18, 0x7a, 0x1b, 0x06, 0xf3, 0xa4, 0x16, 0x56, 0x00, 0x32, 0xa1, 0xa0, 0x16, 0x22, 0x88,
0x0b, 0x21, 0x59, 0xee, 0xf0, 0x32, 0xbb, 0xd3, 0xcb, 0x06, 0x1c, 0xcd, 0x3d, 0x9f, 0x2e, 0xb8,
0xcf, 0x66, 0xde, 0x9f, 0x38, 0x4d, 0x66, 0x92, 0x9c, 0x62, 0xef, 0x94, 0x21, 0x0b, 0xca, 0x1b,
0x67, 0xca, 0xab, 0x33, 0x6d, 0x60, 0x2f, 0xfe, 0x96, 0x81, 0x72, 0x7a, 0xba, 0x42, 0x15, 0x28,
0xda, 0x0e, 0xed, 0x74, 0xed, 0x6f, 0xaf, 0x06, 0xc6, 0x47, 0x72, 0xd9, 0x1f, 0xb6, 0x5a, 0x18,
0xb7, 0x71, 0xdb, 0xc8, 0x20, 0x04, 0x55, 0xd9, 0x18, 0x70, 0x9b, 0x0e, 0xec, 0x1e, 0x76, 0x87,
0xf2, 0x4d, 0x39, 0x84, 0x5a, 0x8c, 0x39, 0x2e, 0x25, 0xee, 0x70, 0x80, 0x8d, 0x2c, 0x32, 0xa0,
0x1c, 0x83, 0x98, 0x10, 0x97, 0x18, 0x39, 0xd9, 0x08, 0x63, 0xe4, 0xe1, 0xfb, 0x94, 0x3c, 0x5f,
0xf9, 0xc6, 0x5f, 0x73, 0xb0, 0xaf, 0xa6, 0x91, 0x10, 0x5d, 0x41, 0x29, 0x35, 0xd6, 0xa3, 0xd3,
0xd4, 0xb5, 0x78, 0x38, 0xee, 0xd7, 0xcd, 0xdd, 0xe3, 0xe2, 0x32, 0xfa, 0x2a, 0x83, 0x5e, 0x41,
0x39, 0x3d, 0xa4, 0xa2, 0xf4, 0xf0, 0xb1, 0x63, 0x7a, 0xfd, 0xa0, 0xae, 0xd7, 0x60, 0xe0, 0x48,
0x78, 0x73, 0x39, 0x6c, 0xc4, 0xe3, 0x1f, 0xaa, 0xa7, 0xf8, 0x5b, 0x33, 0x65, 0xfd, 0x64, 0xa7,
0x2c, 0xae, 0x93, 0xae, 0x3e, 0x62, 0x3c, 0x80, 0x3d, 0x38, 0xe2, 0xe6, 0xd4, 0x57, 0xff, 0xf8,
0x7d, 0xe2, 0x58, 0xdb, 0x18, 0x0e, 0x77, 0x54, 0x34, 0xfa, 0x45, 0xda, 0x83, 0xf7, 0xf6, 0x83,
0xfa, 0xf3, 0xff, 0x47, 0x5b, 0x5b, 0xd9, 0x51, 0xfa, 0x1b, 0x56, 0xde, 0xdf, 0x38, 0x36, 0xac,
0x7c, 0xa0, 0x83, 0xbc, 0xfc, 0xd5, 0xef, 0x2f, 0x27, 0x9e, 0x98, 0x2e, 0x6f, 0x2e, 0x46, 0xc1,
0xfc, 0x72, 0xe6, 0x4d, 0xa6, 0xc2, 0xf7, 0xfc, 0x89, 0xcf, 0xc5, 0x1f, 0x83, 0xf0, 0xee, 0x72,
0xe6, 0x8f, 0x2f, 0xd5, 0x40, 0x7b, 0xb9, 0x52, 0x77, 0xb3, 0xaf, 0xfe, 0x0e, 0xfe, 0xfa, 0x7f,
0x01, 0x00, 0x00, 0xff, 0xff, 0x6d, 0xa6, 0xd9, 0x94, 0x3e, 0x0e, 0x00, 0x00,
// 1736 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0x41, 0x73, 0x22, 0xc7,
0x15, 0x36, 0x02, 0x84, 0x78, 0x80, 0x98, 0x6d, 0x69, 0xb5, 0xb3, 0x68, 0x65, 0xcb, 0xd8, 0x59,
0xab, 0xb6, 0x1c, 0xc9, 0x21, 0x65, 0x97, 0xcb, 0x87, 0xa4, 0x58, 0x68, 0xac, 0xd9, 0x85, 0x19,
0xb9, 0x81, 0xb5, 0x37, 0x39, 0x74, 0xb5, 0xa0, 0x05, 0x53, 0x1a, 0x66, 0xf0, 0x4c, 0xa3, 0xac,
0x72, 0xc8, 0x25, 0x95, 0x63, 0xee, 0xf9, 0x17, 0xf9, 0x15, 0x39, 0xe4, 0x8f, 0x24, 0xbf, 0x22,
0x55, 0xa9, 0xee, 0x9e, 0x81, 0x01, 0xb1, 0x9b, 0x9c, 0x98, 0xfe, 0xde, 0xd7, 0xaf, 0x5f, 0xf7,
0xeb, 0xf7, 0xf5, 0x03, 0x8e, 0xc2, 0x60, 0x21, 0x78, 0x18, 0xce, 0x47, 0x17, 0xfa, 0xeb, 0x7c,
0x1e, 0x06, 0x22, 0x40, 0xc5, 0x25, 0x5e, 0x2b, 0x86, 0xf3, 0x91, 0x46, 0xeb, 0xff, 0xc9, 0x02,
0xea, 0x73, 0x7f, 0x7c, 0xc5, 0xee, 0x67, 0xdc, 0x17, 0x84, 0xff, 0xbc, 0xe0, 0x91, 0x40, 0x08,
0x72, 0x63, 0x1e, 0x09, 0x33, 0x73, 0x9a, 0x39, 0x2b, 0x13, 0xf5, 0x8d, 0x0c, 0xc8, 0xb2, 0x99,
0x30, 0x77, 0x4e, 0x33, 0x67, 0x59, 0x22, 0x3f, 0xd1, 0xa7, 0x50, 0x9e, 0xeb, 0x79, 0x74, 0xca,
0xa2, 0xa9, 0x99, 0x55, 0xec, 0x52, 0x8c, 0x5d, 0xb2, 0x68, 0x8a, 0xce, 0xc0, 0xb8, 0x71, 0x7d,
0xe6, 0xd1, 0x91, 0x27, 0xee, 0xe8, 0x98, 0x7b, 0x82, 0x99, 0xb9, 0xd3, 0xcc, 0x59, 0x9e, 0xec,
0x2b, 0xbc, 0xe5, 0x89, 0xbb, 0xb6, 0x44, 0xd1, 0x17, 0x50, 0x4d, 0x9c, 0x85, 0x3a, 0x0a, 0x33,
0x7f, 0x9a, 0x39, 0x2b, 0x92, 0xfd, 0xf9, 0x7a, 0x6c, 0x5f, 0x40, 0x55, 0xb8, 0x33, 0x1e, 0x2c,
0x04, 0x8d, 0xf8, 0x28, 0xf0, 0xc7, 0x91, 0xb9, 0xab, 0x3d, 0xc6, 0x70, 0x5f, 0xa3, 0xa8, 0x0e,
0x95, 0x1b, 0xce, 0xa9, 0xe7, 0xce, 0x5c, 0x41, 0x23, 0x26, 0xcc, 0x82, 0x0a, 0xbd, 0x74, 0xc3,
0x79, 0x57, 0x62, 0x7d, 0x26, 0x64, 0x7c, 0xc1, 0x42, 0x4c, 0x02, 0xd7, 0x9f, 0xd0, 0xd1, 0x94,
0xf9, 0xd4, 0x1d, 0x9b, 0x7b, 0xa7, 0x99, 0xb3, 0x1c, 0xd9, 0x4f, 0xf0, 0xd6, 0x94, 0xf9, 0xd6,
0x18, 0x9d, 0x00, 0xa8, 0x3d, 0x28, 0x77, 0x66, 0x51, 0xad, 0x58, 0x94, 0x88, 0xf2, 0x85, 0x1a,
0x50, 0x52, 0x07, 0x4c, 0xa7, 0xae, 0x2f, 0x22, 0x13, 0x4e, 0xb3, 0x67, 0xa5, 0x86, 0x71, 0xee,
0xf9, 0xf2, 0xac, 0x89, 0xb4, 0x5c, 0xba, 0xbe, 0x20, 0x69, 0x12, 0xc2, 0xb0, 0x27, 0x4f, 0x96,
0x0a, 0xef, 0xce, 0x2c, 0xa9, 0x09, 0x2f, 0xce, 0x97, 0x59, 0x3a, 0x7f, 0x98, 0x96, 0xf3, 0x36,
0x8f, 0xc4, 0xc0, 0xbb, 0xc3, 0xbe, 0x08, 0xef, 0x49, 0x61, 0xac, 0x47, 0xb5, 0xef, 0xa0, 0x9c,
0x36, 0xc8, 0x44, 0xdd, 0xf2, 0x7b, 0x95, 0xbb, 0x1c, 0x91, 0x9f, 0xe8, 0x10, 0xf2, 0x77, 0xcc,
0x5b, 0x70, 0x95, 0xbc, 0x32, 0xd1, 0x83, 0xef, 0x76, 0xbe, 0xcd, 0xd4, 0xbf, 0x85, 0x83, 0x41,
0xc8, 0x46, 0xb7, 0x1b, 0xf9, 0xdf, 0xcc, 0x6c, 0xe6, 0x41, 0x66, 0xeb, 0x7f, 0x82, 0x4a, 0x3c,
0xa9, 0x2f, 0x98, 0x58, 0x44, 0xe8, 0x97, 0x90, 0x8f, 0x04, 0x13, 0x5c, 0x91, 0xf7, 0x1b, 0x4f,
0x52, 0x5b, 0x49, 0x11, 0x39, 0xd1, 0x2c, 0x54, 0x83, 0xbd, 0x79, 0xc8, 0xdd, 0x19, 0x9b, 0x24,
0x61, 0x2d, 0xc7, 0xa8, 0x0e, 0x79, 0x35, 0x59, 0xdd, 0xa8, 0x52, 0xa3, 0x9c, 0x3e, 0x46, 0xa2,
0x4d, 0xf5, 0xdf, 0x40, 0x55, 0x8d, 0x3b, 0x9c, 0x7f, 0xe8, 0xd6, 0x3e, 0x81, 0x02, 0x9b, 0xe9,
0xf4, 0xeb, 0x9b, 0xbb, 0xcb, 0x66, 0x32, 0xf3, 0xf5, 0x31, 0x18, 0xab, 0xf9, 0xd1, 0x3c, 0xf0,
0x23, 0x2e, 0x6f, 0x83, 0x74, 0x2e, 0x2f, 0x83, 0xbc, 0x39, 0x33, 0x39, 0x2b, 0xa3, 0x66, 0xed,
0xc7, 0x78, 0x87, 0xf3, 0x5e, 0xc4, 0x04, 0x7a, 0xae, 0x2f, 0x21, 0xf5, 0x82, 0xd1, 0xad, 0xbc,
0xd6, 0xec, 0x3e, 0x76, 0x5f, 0x91, 0x70, 0x37, 0x18, 0xdd, 0xb6, 0x25, 0x58, 0xff, 0xbd, 0x2e,
0xaf, 0x41, 0xa0, 0x63, 0xff, 0xbf, 0x8f, 0x77, 0x75, 0x04, 0x3b, 0xef, 0x3f, 0x02, 0x0a, 0x07,
0x6b, 0xce, 0xe3, 0x5d, 0xa4, 0x4f, 0x36, 0xb3, 0x71, 0xb2, 0x5f, 0x42, 0xe1, 0x86, 0xb9, 0xde,
0x22, 0x4c, 0x1c, 0xa3, 0x54, 0x9a, 0x3a, 0xda, 0x42, 0x12, 0x4a, 0xfd, 0x9f, 0x05, 0x28, 0xc4,
0x20, 0x6a, 0x40, 0x6e, 0x14, 0x8c, 0x93, 0xec, 0x7e, 0xfc, 0x70, 0x5a, 0xf2, 0xdb, 0x0a, 0xc6,
0x9c, 0x28, 0x2e, 0xfa, 0x2d, 0xec, 0xcb, 0xa2, 0xf2, 0xb9, 0x47, 0x17, 0xf3, 0x31, 0x5b, 0x26,
0xd4, 0x4c, 0xcd, 0x6e, 0x69, 0xc2, 0x50, 0xd9, 0x49, 0x65, 0x94, 0x1e, 0xa2, 0x63, 0x28, 0x4e,
0x85, 0x37, 0xd2, 0x99, 0xc8, 0xa9, 0x0b, 0xbd, 0x27, 0x01, 0x95, 0x83, 0x3a, 0x54, 0x02, 0xdf,
0x0d, 0x7c, 0x1a, 0x4d, 0x19, 0x6d, 0x7c, 0xfd, 0x8d, 0xd2, 0x8b, 0x32, 0x29, 0x29, 0xb0, 0x3f,
0x65, 0x8d, 0xaf, 0xbf, 0x41, 0x9f, 0x40, 0x49, 0x55, 0x2d, 0x7f, 0x37, 0x77, 0xc3, 0x7b, 0x25,
0x14, 0x15, 0xa2, 0x0a, 0x19, 0x2b, 0x44, 0x96, 0xc6, 0x8d, 0xc7, 0x26, 0x91, 0x12, 0x87, 0x0a,
0xd1, 0x03, 0xf4, 0x15, 0x1c, 0xc6, 0x67, 0x40, 0xa3, 0x60, 0x11, 0x8e, 0x38, 0x75, 0xfd, 0x31,
0x7f, 0xa7, 0xa4, 0xa1, 0x42, 0x50, 0x6c, 0xeb, 0x2b, 0x93, 0x25, 0x2d, 0xf5, 0xbf, 0xe5, 0xa1,
0x94, 0x3a, 0x00, 0x54, 0x86, 0x3d, 0x82, 0xfb, 0x98, 0xbc, 0xc1, 0x6d, 0xe3, 0x23, 0x74, 0x06,
0x9f, 0x5b, 0x76, 0xcb, 0x21, 0x04, 0xb7, 0x06, 0xd4, 0x21, 0x74, 0x68, 0xbf, 0xb6, 0x9d, 0x1f,
0x6d, 0x7a, 0xd5, 0x7c, 0xdb, 0xc3, 0xf6, 0x80, 0xb6, 0xf1, 0xa0, 0x69, 0x75, 0xfb, 0x46, 0x06,
0x3d, 0x03, 0x73, 0xc5, 0x4c, 0xcc, 0xcd, 0x9e, 0x33, 0xb4, 0x07, 0xc6, 0x0e, 0xfa, 0x04, 0x8e,
0x3b, 0x96, 0xdd, 0xec, 0xd2, 0x15, 0xa7, 0xd5, 0x1d, 0xbc, 0xa1, 0xf8, 0xa7, 0x2b, 0x8b, 0xbc,
0x35, 0xb2, 0xdb, 0x08, 0x97, 0x83, 0x6e, 0x2b, 0xf1, 0x90, 0x43, 0x4f, 0xe1, 0xb1, 0x26, 0xe8,
0x29, 0x74, 0xe0, 0x38, 0xb4, 0xef, 0x38, 0xb6, 0x91, 0x47, 0x8f, 0xa0, 0x62, 0xd9, 0x6f, 0x9a,
0x5d, 0xab, 0x4d, 0x09, 0x6e, 0x76, 0x7b, 0xc6, 0x2e, 0x3a, 0x80, 0xea, 0x26, 0xaf, 0x20, 0x5d,
0x24, 0x3c, 0xc7, 0xb6, 0x1c, 0x9b, 0xbe, 0xc1, 0xa4, 0x6f, 0x39, 0xb6, 0xb1, 0x87, 0x8e, 0x00,
0xad, 0x9b, 0x2e, 0x7b, 0xcd, 0x96, 0x51, 0x44, 0x8f, 0xe1, 0xd1, 0x3a, 0xfe, 0x1a, 0xbf, 0x35,
0x00, 0x99, 0x70, 0xa8, 0x03, 0xa3, 0x2f, 0x71, 0xd7, 0xf9, 0x91, 0xf6, 0x2c, 0xdb, 0xea, 0x0d,
0x7b, 0x46, 0x09, 0x1d, 0x82, 0xd1, 0xc1, 0x98, 0x5a, 0x76, 0x7f, 0xd8, 0xe9, 0x58, 0x2d, 0x0b,
0xdb, 0x03, 0xa3, 0xac, 0x57, 0xde, 0xb6, 0xf1, 0x8a, 0x9c, 0xd0, 0xba, 0x6c, 0xda, 0x36, 0xee,
0xd2, 0xb6, 0xd5, 0x6f, 0xbe, 0xec, 0xe2, 0xb6, 0xb1, 0x8f, 0x4e, 0xe0, 0xe9, 0x00, 0xf7, 0xae,
0x1c, 0xd2, 0x24, 0x6f, 0x69, 0x62, 0xef, 0x34, 0xad, 0xee, 0x90, 0x60, 0xa3, 0x8a, 0x3e, 0x85,
0x13, 0x82, 0x7f, 0x18, 0x5a, 0x04, 0xb7, 0xa9, 0xed, 0xb4, 0x31, 0xed, 0xe0, 0xe6, 0x60, 0x48,
0x30, 0xed, 0x59, 0xfd, 0xbe, 0x65, 0x7f, 0x6f, 0x18, 0xe8, 0x73, 0x38, 0x5d, 0x52, 0x96, 0x0e,
0x36, 0x58, 0x8f, 0xe4, 0xfe, 0x92, 0x94, 0xda, 0xf8, 0xa7, 0x01, 0xbd, 0xc2, 0x98, 0x18, 0x08,
0xd5, 0xe0, 0x68, 0xb5, 0xbc, 0x5e, 0x20, 0x5e, 0xfb, 0x40, 0xda, 0xae, 0x30, 0xe9, 0x35, 0x6d,
0x99, 0xe0, 0x35, 0xdb, 0xa1, 0x0c, 0x7b, 0x65, 0xdb, 0x0c, 0xfb, 0x31, 0x3a, 0x84, 0x6a, 0xb2,
0x5a, 0x02, 0xfe, 0xab, 0x80, 0x9e, 0x00, 0x1a, 0xda, 0x04, 0x37, 0xdb, 0x72, 0xf3, 0x4b, 0xc3,
0xbf, 0x0b, 0xaf, 0x72, 0x7b, 0x3b, 0x46, 0xb6, 0xfe, 0xf7, 0x2c, 0x54, 0xd6, 0x6a, 0x0d, 0x3d,
0x83, 0x62, 0xe4, 0x4e, 0x7c, 0x26, 0xa4, 0x1a, 0x68, 0xa1, 0x58, 0x01, 0xea, 0xbd, 0x9b, 0x32,
0xd7, 0xd7, 0x0a, 0xa5, 0x15, 0xba, 0xa8, 0x10, 0xa5, 0x4f, 0x4f, 0xa0, 0x90, 0xbc, 0x97, 0x59,
0x55, 0x97, 0xbb, 0x23, 0xfd, 0x4e, 0x3e, 0x83, 0xa2, 0x94, 0xc0, 0x48, 0xb0, 0xd9, 0x5c, 0x95,
0x6c, 0x85, 0xac, 0x00, 0xf4, 0x19, 0x54, 0x66, 0x3c, 0x8a, 0xd8, 0x84, 0x53, 0x5d, 0x76, 0xa0,
0x18, 0xe5, 0x18, 0xec, 0xa8, 0xea, 0xfb, 0x0c, 0x12, 0x19, 0x88, 0x49, 0x79, 0x4d, 0x8a, 0x41,
0x4d, 0xda, 0x54, 0x60, 0xc1, 0xe2, 0xea, 0x4e, 0x2b, 0xb0, 0x60, 0xe8, 0x05, 0x3c, 0xd2, 0x12,
0xe2, 0xfa, 0xee, 0x6c, 0x31, 0xd3, 0x52, 0x52, 0x50, 0x21, 0x57, 0x95, 0x94, 0x68, 0x5c, 0x29,
0xca, 0x53, 0xd8, 0xbb, 0x66, 0x11, 0x97, 0xe2, 0x1f, 0x97, 0x7a, 0x41, 0x8e, 0x3b, 0x9c, 0x4b,
0x93, 0x7c, 0x12, 0x42, 0x29, 0x62, 0x45, 0x6d, 0xba, 0xe1, 0x9c, 0xc8, 0x73, 0x5c, 0xae, 0xc0,
0xde, 0xad, 0x56, 0x28, 0xa5, 0x56, 0xd0, 0xb8, 0x5a, 0xe1, 0x05, 0x3c, 0xe2, 0xef, 0x44, 0xc8,
0x68, 0x30, 0x67, 0x3f, 0x2f, 0x38, 0x1d, 0x33, 0xc1, 0xcc, 0xb2, 0x3a, 0xdc, 0xaa, 0x32, 0x38,
0x0a, 0x6f, 0x33, 0xc1, 0xea, 0xcf, 0xa0, 0x46, 0x78, 0xc4, 0x45, 0xcf, 0x8d, 0x22, 0x37, 0xf0,
0x5b, 0x81, 0x2f, 0xc2, 0xc0, 0x8b, 0xdf, 0x90, 0xfa, 0x09, 0x1c, 0x6f, 0xb5, 0xea, 0x47, 0x40,
0x4e, 0xfe, 0x61, 0xc1, 0xc3, 0xfb, 0xed, 0x93, 0xef, 0xe1, 0x78, 0xab, 0x35, 0x7e, 0x41, 0xbe,
0x84, 0xbc, 0x1f, 0x8c, 0x79, 0x64, 0x66, 0x54, 0x57, 0x72, 0x94, 0x92, 0x6b, 0x3b, 0x18, 0xf3,
0x4b, 0x37, 0x12, 0x41, 0x78, 0x4f, 0x34, 0x49, 0xb2, 0xe7, 0xcc, 0x0d, 0x23, 0x73, 0xe7, 0x01,
0xfb, 0x8a, 0xb9, 0xe1, 0x92, 0xad, 0x48, 0xf5, 0x3f, 0x67, 0xa0, 0x94, 0x72, 0x82, 0x8e, 0x60,
0x77, 0xbe, 0xb8, 0x4e, 0x1a, 0x96, 0x32, 0x89, 0x47, 0xe8, 0x39, 0xec, 0x7b, 0x2c, 0x12, 0x54,
0x6a, 0x2d, 0x95, 0x29, 0x8d, 0x1f, 0xd8, 0x0d, 0x14, 0x9d, 0x03, 0x0a, 0xc4, 0x94, 0x87, 0x34,
0x5a, 0x8c, 0x46, 0x3c, 0x8a, 0xe8, 0x3c, 0x0c, 0xae, 0xd5, 0x9d, 0xdc, 0x21, 0x5b, 0x2c, 0xaf,
0x72, 0x7b, 0x39, 0x23, 0x5f, 0xff, 0x47, 0x06, 0x4a, 0xa9, 0xe0, 0xe4, 0xad, 0x95, 0x9b, 0xa1,
0x37, 0x61, 0x30, 0x4b, 0x6a, 0x61, 0x09, 0x20, 0x13, 0x0a, 0x6a, 0x20, 0x82, 0xb8, 0x10, 0x92,
0xe1, 0x96, 0x28, 0xb3, 0x5b, 0xa3, 0x6c, 0xc0, 0xe1, 0xcc, 0xf5, 0xe9, 0x9c, 0xfb, 0xcc, 0x73,
0xff, 0xc8, 0x69, 0xd2, 0x93, 0xe4, 0x14, 0x7b, 0xab, 0x0d, 0xd5, 0xa1, 0xbc, 0xb6, 0xa7, 0xbc,
0xda, 0xd3, 0x1a, 0xf6, 0xe2, 0xaf, 0x19, 0x28, 0xa7, 0xbb, 0x2b, 0x54, 0x81, 0xa2, 0x65, 0xd3,
0x4e, 0xd7, 0xfa, 0xfe, 0x72, 0x60, 0x7c, 0x24, 0x87, 0xfd, 0x61, 0xab, 0x85, 0x71, 0x1b, 0xb7,
0x8d, 0x0c, 0x42, 0xb0, 0x2f, 0x85, 0x01, 0xb7, 0xe9, 0xc0, 0xea, 0x61, 0x67, 0x28, 0xdf, 0x94,
0x03, 0xa8, 0xc6, 0x98, 0xed, 0x50, 0xe2, 0x0c, 0x07, 0xd8, 0xc8, 0x22, 0x03, 0xca, 0x31, 0x88,
0x09, 0x71, 0x88, 0x91, 0x93, 0x42, 0x18, 0x23, 0x0f, 0xdf, 0xa7, 0xe4, 0xf9, 0xca, 0x37, 0xfe,
0x92, 0x83, 0x5d, 0xd5, 0x8d, 0x84, 0xe8, 0x12, 0x4a, 0xa9, 0x16, 0x16, 0x9d, 0x7c, 0xb0, 0xb5,
0xad, 0x99, 0xdb, 0xdb, 0xc5, 0x45, 0xf4, 0x55, 0x06, 0xbd, 0x82, 0x72, 0xba, 0x49, 0x45, 0xe9,
0xe6, 0x63, 0x4b, 0xf7, 0xfa, 0x41, 0x5f, 0xaf, 0xc1, 0xc0, 0x91, 0x70, 0x67, 0xb2, 0xd9, 0x88,
0xdb, 0x3f, 0x54, 0x4b, 0xf1, 0x37, 0x7a, 0xca, 0xda, 0xf1, 0x56, 0x5b, 0x5c, 0x27, 0x5d, 0xbd,
0xc5, 0xb8, 0x01, 0x7b, 0xb0, 0xc5, 0xf5, 0xae, 0xaf, 0xf6, 0xf1, 0xfb, 0xcc, 0xb1, 0xb7, 0x31,
0x1c, 0x6c, 0xa9, 0x68, 0xf4, 0x8b, 0x74, 0x04, 0xef, 0xd5, 0x83, 0xda, 0xf3, 0xff, 0x45, 0x5b,
0xad, 0xb2, 0xa5, 0xf4, 0xd7, 0x56, 0x79, 0xbf, 0x70, 0xac, 0xad, 0xf2, 0x01, 0x05, 0x79, 0xf9,
0xab, 0xdf, 0x5d, 0x4c, 0x5c, 0x31, 0x5d, 0x5c, 0x9f, 0x8f, 0x82, 0xd9, 0x85, 0xe7, 0x4e, 0xa6,
0xc2, 0x77, 0xfd, 0x89, 0xcf, 0xc5, 0x1f, 0x82, 0xf0, 0xf6, 0xc2, 0xf3, 0xc7, 0x17, 0xaa, 0xa1,
0xbd, 0x58, 0xba, 0xbb, 0xde, 0x55, 0xff, 0x48, 0x7f, 0xfd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff,
0x54, 0xde, 0xd4, 0xfd, 0xc1, 0x0e, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

@ -63,6 +63,13 @@ message SendPaymentRequest {
Optional route hints to reach the destination through private channels.
*/
repeated lnrpc.RouteHint route_hints = 10 [json_name = "route_hints"];
/**
An optional field that can be used to pass an arbitrary set of TLV records
to a peer which understands the new records. This can be used to pass
application specific data during the payment attempt.
*/
map<uint64, bytes> dest_tlv = 11;
}
message TrackPaymentRequest {

@ -14,6 +14,7 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/tlv"
"github.com/lightningnetwork/lnd/zpay32"
context "golang.org/x/net/context"
)
@ -40,6 +41,7 @@ type RouterBackend struct {
// routes.
FindRoute func(source, target route.Vertex,
amt lnwire.MilliSatoshi, restrictions *routing.RestrictParams,
destTlvRecords []tlv.Record,
finalExpiry ...uint16) (*route.Route, error)
MissionControl MissionControl
@ -188,6 +190,15 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
fromNode, toNode, amt,
)
},
DestPayloadTLV: len(in.DestTlv) != 0,
}
// If we have any TLV records destined for the final hop, then we'll
// attempt to decode them now into a form that the router can more
// easily manipulate.
destTlvRecords, err := tlv.MapToRecords(in.DestTlv)
if err != nil {
return nil, err
}
// Query the channel router for a possible path to the destination that
@ -201,11 +212,12 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
if in.FinalCltvDelta == 0 {
route, findErr = r.FindRoute(
sourcePubKey, targetPubKey, amtMSat, restrictions,
destTlvRecords,
)
} else {
route, findErr = r.FindRoute(
sourcePubKey, targetPubKey, amtMSat, restrictions,
uint16(in.FinalCltvDelta),
destTlvRecords, uint16(in.FinalCltvDelta),
)
}
if findErr != nil {
@ -214,8 +226,10 @@ func (r *RouterBackend) QueryRoutes(ctx context.Context,
// For each valid route, we'll convert the result into the format
// required by the RPC system.
rpcRoute := r.MarshallRoute(route)
rpcRoute, err := r.MarshallRoute(route)
if err != nil {
return nil, err
}
routeResp := &lnrpc.QueryRoutesResponse{
Routes: []*lnrpc.Route{rpcRoute},
@ -266,7 +280,7 @@ func calculateFeeLimit(feeLimit *lnrpc.FeeLimit,
}
// MarshallRoute marshalls an internal route to an rpc route struct.
func (r *RouterBackend) MarshallRoute(route *route.Route) *lnrpc.Route {
func (r *RouterBackend) MarshallRoute(route *route.Route) (*lnrpc.Route, error) {
resp := &lnrpc.Route{
TotalTimeLock: route.TotalTimeLock,
TotalFees: int64(route.TotalFees().ToSatoshis()),
@ -290,6 +304,11 @@ func (r *RouterBackend) MarshallRoute(route *route.Route) *lnrpc.Route {
chanCapacity = incomingAmt.ToSatoshis()
}
tlvMap, err := tlv.RecordsToMap(hop.TLVRecords)
if err != nil {
return nil, err
}
resp.Hops[i] = &lnrpc.Hop{
ChanId: hop.ChannelID,
ChanCapacity: int64(chanCapacity),
@ -301,11 +320,13 @@ func (r *RouterBackend) MarshallRoute(route *route.Route) *lnrpc.Route {
PubKey: hex.EncodeToString(
hop.PubKeyBytes[:],
),
TlvRecords: tlvMap,
TlvPayload: !hop.LegacyPayload,
}
incomingAmt = hop.AmtToForward
}
return resp
return resp, nil
}
// UnmarshallHopByChannelLookup unmarshalls an rpc hop for which the pub key is
@ -331,11 +352,18 @@ func (r *RouterBackend) UnmarshallHopByChannelLookup(hop *lnrpc.Hop,
return nil, fmt.Errorf("channel edge does not match expected node")
}
tlvRecords, err := tlv.MapToRecords(hop.TlvRecords)
if err != nil {
return nil, err
}
return &route.Hop{
OutgoingTimeLock: hop.Expiry,
AmtToForward: lnwire.MilliSatoshi(hop.AmtToForwardMsat),
PubKeyBytes: pubKeyBytes,
ChannelID: hop.ChanId,
TLVRecords: tlvRecords,
LegacyPayload: !hop.TlvPayload,
}, nil
}
@ -351,11 +379,21 @@ func UnmarshallKnownPubkeyHop(hop *lnrpc.Hop) (*route.Hop, error) {
var pubKeyBytes [33]byte
copy(pubKeyBytes[:], pubKey)
var tlvRecords []tlv.Record
if hop.TlvRecords != nil {
tlvRecords, err = tlv.MapToRecords(hop.TlvRecords)
if err != nil {
return nil, err
}
}
return &route.Hop{
OutgoingTimeLock: hop.Expiry,
AmtToForward: lnwire.MilliSatoshi(hop.AmtToForwardMsat),
PubKeyBytes: pubKeyBytes,
ChannelID: hop.ChanId,
TLVRecords: tlvRecords,
LegacyPayload: !hop.TlvPayload,
}, nil
}
@ -435,6 +473,16 @@ func (r *RouterBackend) extractIntentFromSendRequest(
return nil, errors.New("timeout_seconds must be specified")
}
if len(rpcPayReq.DestTlv) != 0 {
var err error
payIntent.FinalDestRecords, err = tlv.MapToRecords(
rpcPayReq.DestTlv,
)
if err != nil {
return nil, err
}
}
payIntent.PayAttemptTimeout = time.Second *
time.Duration(rpcPayReq.TimeoutSeconds)

@ -10,6 +10,7 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/tlv"
"github.com/lightningnetwork/lnd/lnrpc"
)
@ -77,6 +78,7 @@ func testQueryRoutes(t *testing.T, useMissionControl bool) {
findRoute := func(source, target route.Vertex,
amt lnwire.MilliSatoshi, restrictions *routing.RestrictParams,
_ []tlv.Record,
finalExpiry ...uint16) (*route.Route, error) {
if int64(amt) != request.Amt*1000 {

@ -249,7 +249,7 @@ func (s *Server) EstimateRouteFee(ctx context.Context,
s.cfg.RouterBackend.SelfNode, destNode, amtMsat,
&routing.RestrictParams{
FeeLimit: feeLimit,
},
}, nil,
)
if err != nil {
return nil, err
@ -550,9 +550,12 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
status.State = PaymentState_SUCCEEDED
status.Preimage = result.Preimage[:]
status.Route = router.MarshallRoute(
status.Route, err = router.MarshallRoute(
result.Route,
)
if err != nil {
return err
}
} else {
state, err := marshallFailureReason(
result.FailureReason,
@ -562,9 +565,12 @@ func (s *Server) trackPayment(paymentHash lntypes.Hash,
}
status.State = state
if result.Route != nil {
status.Route = router.MarshallRoute(
status.Route, err = router.MarshallRoute(
result.Route,
)
if err != nil {
return err
}
}
}

@ -1026,10 +1026,15 @@ type SendRequest struct {
//*
//An optional maximum total time lock for the route. If zero, there is no
//maximum enforced.
CltvLimit uint32 `protobuf:"varint,10,opt,name=cltv_limit,json=cltvLimit,proto3" json:"cltv_limit,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
CltvLimit uint32 `protobuf:"varint,10,opt,name=cltv_limit,json=cltvLimit,proto3" json:"cltv_limit,omitempty"`
//*
//An optional field that can be used to pass an arbitrary set of TLV records
//to a peer which understands the new records. This can be used to pass
//application specific data during the payment attempt.
DestTlv map[uint64][]byte `protobuf:"bytes,11,rep,name=dest_tlv,json=destTlv,proto3" json:"dest_tlv,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SendRequest) Reset() { *m = SendRequest{} }
@ -1127,6 +1132,13 @@ func (m *SendRequest) GetCltvLimit() uint32 {
return 0
}
func (m *SendRequest) GetDestTlv() map[uint64][]byte {
if m != nil {
return m.DestTlv
}
return nil
}
type SendResponse struct {
PaymentError string `protobuf:"bytes,1,opt,name=payment_error,proto3" json:"payment_error,omitempty"`
PaymentPreimage []byte `protobuf:"bytes,2,opt,name=payment_preimage,proto3" json:"payment_preimage,omitempty"`
@ -4817,10 +4829,16 @@ type QueryRoutesRequest struct {
UseMissionControl bool `protobuf:"varint,9,opt,name=use_mission_control,json=useMissionControl,proto3" json:"use_mission_control,omitempty"`
//*
//A list of directed node pairs that will be ignored during path finding.
IgnoredPairs []*NodePair `protobuf:"bytes,10,rep,name=ignored_pairs,json=ignoredPairs,proto3" json:"ignored_pairs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
IgnoredPairs []*NodePair `protobuf:"bytes,10,rep,name=ignored_pairs,json=ignoredPairs,proto3" json:"ignored_pairs,omitempty"`
//*
//An optional field that can be used to pass an arbitrary set of TLV records
//to a peer which understands the new records. This can be used to pass
//application specific data during the payment attempt. If the destination
//does not support the specified recrods, and error will be returned.
DestTlv map[uint64][]byte `protobuf:"bytes,11,rep,name=dest_tlv,json=destTlv,proto3" json:"dest_tlv,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *QueryRoutesRequest) Reset() { *m = QueryRoutesRequest{} }
@ -4912,6 +4930,13 @@ func (m *QueryRoutesRequest) GetIgnoredPairs() []*NodePair {
return nil
}
func (m *QueryRoutesRequest) GetDestTlv() map[uint64][]byte {
if m != nil {
return m.DestTlv
}
return nil
}
type NodePair struct {
/// The sending node of the pair.
From []byte `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"`
@ -5068,10 +5093,20 @@ type Hop struct {
//*
//An optional public key of the hop. If the public key is given, the payment
//can be executed without relying on a copy of the channel graph.
PubKey string `protobuf:"bytes,8,opt,name=pub_key,proto3" json:"pub_key,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
PubKey string `protobuf:"bytes,8,opt,name=pub_key,proto3" json:"pub_key,omitempty"`
//*
//If set to true, then this hop will be encoded using the new variable length
//TLV format. Note that if any custom tlv_records below are specified, then
//this field MUST be set to true for them to be encoded properly.
TlvPayload bool `protobuf:"varint,9,opt,name=tlv_payload,proto3" json:"tlv_payload,omitempty"`
//*
//An optional set of key-value TLV records. This is useful within the context
//of the SendToRoute call as it allows callers to specify arbitrary K-V pairs
//to drop off at each hop within the onion.
TlvRecords map[uint64][]byte `protobuf:"bytes,10,rep,name=tlv_records,proto3" json:"tlv_records,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Hop) Reset() { *m = Hop{} }
@ -5157,6 +5192,20 @@ func (m *Hop) GetPubKey() string {
return ""
}
func (m *Hop) GetTlvPayload() bool {
if m != nil {
return m.TlvPayload
}
return false
}
func (m *Hop) GetTlvRecords() map[uint64][]byte {
if m != nil {
return m.TlvRecords
}
return nil
}
//*
//A path through the channel graph which runs over one or more channels in
//succession. This struct carries all the information required to craft the
@ -8614,6 +8663,7 @@ func init() {
proto.RegisterType((*TransactionDetails)(nil), "lnrpc.TransactionDetails")
proto.RegisterType((*FeeLimit)(nil), "lnrpc.FeeLimit")
proto.RegisterType((*SendRequest)(nil), "lnrpc.SendRequest")
proto.RegisterMapType((map[uint64][]byte)(nil), "lnrpc.SendRequest.DestTlvEntry")
proto.RegisterType((*SendResponse)(nil), "lnrpc.SendResponse")
proto.RegisterType((*SendToRouteRequest)(nil), "lnrpc.SendToRouteRequest")
proto.RegisterType((*ChannelPoint)(nil), "lnrpc.ChannelPoint")
@ -8675,10 +8725,12 @@ func init() {
proto.RegisterType((*ChannelBalanceRequest)(nil), "lnrpc.ChannelBalanceRequest")
proto.RegisterType((*ChannelBalanceResponse)(nil), "lnrpc.ChannelBalanceResponse")
proto.RegisterType((*QueryRoutesRequest)(nil), "lnrpc.QueryRoutesRequest")
proto.RegisterMapType((map[uint64][]byte)(nil), "lnrpc.QueryRoutesRequest.DestTlvEntry")
proto.RegisterType((*NodePair)(nil), "lnrpc.NodePair")
proto.RegisterType((*EdgeLocator)(nil), "lnrpc.EdgeLocator")
proto.RegisterType((*QueryRoutesResponse)(nil), "lnrpc.QueryRoutesResponse")
proto.RegisterType((*Hop)(nil), "lnrpc.Hop")
proto.RegisterMapType((map[uint64][]byte)(nil), "lnrpc.Hop.TlvRecordsEntry")
proto.RegisterType((*Route)(nil), "lnrpc.Route")
proto.RegisterType((*NodeInfoRequest)(nil), "lnrpc.NodeInfoRequest")
proto.RegisterType((*NodeInfo)(nil), "lnrpc.NodeInfo")
@ -8740,508 +8792,515 @@ func init() {
func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) }
var fileDescriptor_77a6da22d6a3feb1 = []byte{
// 8015 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7d, 0x5d, 0x6c, 0x24, 0x49,
0xd2, 0x90, 0xab, 0x7f, 0xec, 0xee, 0xe8, 0x76, 0xbb, 0x9d, 0xfe, 0xeb, 0xe9, 0x9d, 0x9d, 0xf5,
0xd6, 0xcd, 0x37, 0x33, 0xeb, 0xdd, 0xcf, 0x9e, 0xf5, 0xed, 0x2d, 0xf3, 0xed, 0xf0, 0xf1, 0xe1,
0xbf, 0x19, 0xcf, 0xae, 0xc7, 0xe3, 0x2b, 0xcf, 0xdc, 0xb0, 0x7b, 0x1f, 0xea, 0x2b, 0x77, 0xa7,
0xdb, 0xb5, 0xd3, 0x5d, 0xd5, 0x5b, 0x55, 0x6d, 0x8f, 0x77, 0x19, 0x1e, 0x10, 0x02, 0x04, 0x42,
0x68, 0x41, 0x20, 0x40, 0x20, 0xa4, 0x3b, 0x1e, 0x38, 0xf1, 0x00, 0x3c, 0x80, 0x40, 0x3a, 0x89,
0x47, 0x9e, 0x10, 0x42, 0xf7, 0x88, 0xc4, 0x09, 0x81, 0x84, 0x4e, 0x3c, 0x81, 0xc4, 0x3b, 0xca,
0xc8, 0x9f, 0xca, 0xac, 0xaa, 0x1e, 0xcf, 0xde, 0x1d, 0xdf, 0x93, 0x3b, 0x23, 0xa2, 0xf2, 0x37,
0x22, 0x32, 0x22, 0x32, 0x32, 0x0d, 0xd5, 0x70, 0xd4, 0x5d, 0x1f, 0x85, 0x41, 0x1c, 0x90, 0xf2,
0xc0, 0x0f, 0x47, 0xdd, 0xf6, 0xf5, 0x7e, 0x10, 0xf4, 0x07, 0x74, 0xc3, 0x1d, 0x79, 0x1b, 0xae,
0xef, 0x07, 0xb1, 0x1b, 0x7b, 0x81, 0x1f, 0x71, 0x22, 0xfb, 0x27, 0xd0, 0x78, 0x48, 0xfd, 0x63,
0x4a, 0x7b, 0x0e, 0xfd, 0x6a, 0x4c, 0xa3, 0x98, 0xbc, 0x0f, 0xf3, 0x2e, 0xfd, 0x9a, 0xd2, 0x5e,
0x67, 0xe4, 0x46, 0xd1, 0xe8, 0x2c, 0x74, 0x23, 0xda, 0xb2, 0x56, 0xad, 0x3b, 0x75, 0xa7, 0xc9,
0x11, 0x47, 0x0a, 0x4e, 0xde, 0x85, 0x7a, 0xc4, 0x48, 0xa9, 0x1f, 0x87, 0xc1, 0xe8, 0xb2, 0x55,
0x40, 0xba, 0x1a, 0x83, 0xed, 0x71, 0x90, 0x3d, 0x80, 0x39, 0xd5, 0x42, 0x34, 0x0a, 0xfc, 0x88,
0x92, 0xbb, 0xb0, 0xd8, 0xf5, 0x46, 0x67, 0x34, 0xec, 0xe0, 0xc7, 0x43, 0x9f, 0x0e, 0x03, 0xdf,
0xeb, 0xb6, 0xac, 0xd5, 0xe2, 0x9d, 0xaa, 0x43, 0x38, 0x8e, 0x7d, 0xf1, 0x58, 0x60, 0xc8, 0x6d,
0x98, 0xa3, 0x3e, 0x87, 0xd3, 0x1e, 0x7e, 0x25, 0x9a, 0x6a, 0x24, 0x60, 0xf6, 0x81, 0xfd, 0xd7,
0x0a, 0x30, 0xff, 0xc8, 0xf7, 0xe2, 0xe7, 0xee, 0x60, 0x40, 0x63, 0x39, 0xa6, 0xdb, 0x30, 0x77,
0x81, 0x00, 0x1c, 0xd3, 0x45, 0x10, 0xf6, 0xc4, 0x88, 0x1a, 0x1c, 0x7c, 0x24, 0xa0, 0x13, 0x7b,
0x56, 0x98, 0xd8, 0xb3, 0xdc, 0xe9, 0x2a, 0x4e, 0x98, 0xae, 0xdb, 0x30, 0x17, 0xd2, 0x6e, 0x70,
0x4e, 0xc3, 0xcb, 0xce, 0x85, 0xe7, 0xf7, 0x82, 0x8b, 0x56, 0x69, 0xd5, 0xba, 0x53, 0x76, 0x1a,
0x12, 0xfc, 0x1c, 0xa1, 0x64, 0x1b, 0xe6, 0xba, 0x67, 0xae, 0xef, 0xd3, 0x41, 0xe7, 0xc4, 0xed,
0xbe, 0x18, 0x8f, 0xa2, 0x56, 0x79, 0xd5, 0xba, 0x53, 0xdb, 0xbc, 0xb6, 0x8e, 0xab, 0xba, 0xbe,
0x73, 0xe6, 0xfa, 0xdb, 0x88, 0x39, 0xf6, 0xdd, 0x51, 0x74, 0x16, 0xc4, 0x4e, 0x43, 0x7c, 0xc1,
0xc1, 0x91, 0xbd, 0x08, 0x44, 0x9f, 0x09, 0x3e, 0xf7, 0xf6, 0x3f, 0xb7, 0x60, 0xe1, 0x99, 0x3f,
0x08, 0xba, 0x2f, 0x7e, 0xc3, 0x29, 0xca, 0x19, 0x43, 0xe1, 0x4d, 0xc7, 0x50, 0xfc, 0xae, 0x63,
0x58, 0x86, 0x45, 0xb3, 0xb3, 0x62, 0x14, 0x14, 0x96, 0xd8, 0xd7, 0x7d, 0x2a, 0xbb, 0x25, 0x87,
0xf1, 0x1e, 0x34, 0xbb, 0xe3, 0x30, 0xa4, 0x7e, 0x66, 0x1c, 0x73, 0x02, 0xae, 0x06, 0xf2, 0x2e,
0xd4, 0x7d, 0x7a, 0x91, 0x90, 0x09, 0xde, 0xf5, 0xe9, 0x85, 0x24, 0xb1, 0x5b, 0xb0, 0x9c, 0x6e,
0x46, 0x74, 0xe0, 0xbf, 0x59, 0x50, 0x7a, 0x16, 0xbf, 0x0c, 0xc8, 0x3a, 0x94, 0xe2, 0xcb, 0x11,
0x97, 0x90, 0xc6, 0x26, 0x11, 0x43, 0xdb, 0xea, 0xf5, 0x42, 0x1a, 0x45, 0x4f, 0x2f, 0x47, 0xd4,
0xa9, 0xbb, 0xbc, 0xd0, 0x61, 0x74, 0xa4, 0x05, 0x33, 0xa2, 0x8c, 0x0d, 0x56, 0x1d, 0x59, 0x24,
0x37, 0x00, 0xdc, 0x61, 0x30, 0xf6, 0xe3, 0x4e, 0xe4, 0xc6, 0x38, 0x55, 0x45, 0x47, 0x83, 0x90,
0xeb, 0x50, 0x1d, 0xbd, 0xe8, 0x44, 0xdd, 0xd0, 0x1b, 0xc5, 0xc8, 0x36, 0x55, 0x27, 0x01, 0x90,
0xf7, 0xa1, 0x12, 0x8c, 0xe3, 0x51, 0xe0, 0xf9, 0xb1, 0x60, 0x95, 0x39, 0xd1, 0x97, 0x27, 0xe3,
0xf8, 0x88, 0x81, 0x1d, 0x45, 0x40, 0x6e, 0xc2, 0x6c, 0x37, 0xf0, 0x4f, 0xbd, 0x70, 0xc8, 0x95,
0x41, 0x6b, 0x1a, 0x5b, 0x33, 0x81, 0xf6, 0xbf, 0x2b, 0x40, 0xed, 0x69, 0xe8, 0xfa, 0x91, 0xdb,
0x65, 0x00, 0xd6, 0xf5, 0xf8, 0x65, 0xe7, 0xcc, 0x8d, 0xce, 0x70, 0xb4, 0x55, 0x47, 0x16, 0xc9,
0x32, 0x4c, 0xf3, 0x8e, 0xe2, 0x98, 0x8a, 0x8e, 0x28, 0x91, 0x0f, 0x60, 0xde, 0x1f, 0x0f, 0x3b,
0x66, 0x5b, 0x45, 0xe4, 0x96, 0x2c, 0x82, 0x4d, 0xc0, 0x09, 0x5b, 0x6b, 0xde, 0x04, 0x1f, 0xa1,
0x06, 0x21, 0x36, 0xd4, 0x45, 0x89, 0x7a, 0xfd, 0x33, 0x3e, 0xcc, 0xb2, 0x63, 0xc0, 0x58, 0x1d,
0xb1, 0x37, 0xa4, 0x9d, 0x28, 0x76, 0x87, 0x23, 0x31, 0x2c, 0x0d, 0x82, 0xf8, 0x20, 0x76, 0x07,
0x9d, 0x53, 0x4a, 0xa3, 0xd6, 0x8c, 0xc0, 0x2b, 0x08, 0xb9, 0x05, 0x8d, 0x1e, 0x8d, 0xe2, 0x8e,
0x58, 0x14, 0x1a, 0xb5, 0x2a, 0x28, 0xfa, 0x29, 0x28, 0xab, 0x27, 0x74, 0x2f, 0x3a, 0x6c, 0x02,
0xe8, 0xcb, 0x56, 0x95, 0xf7, 0x35, 0x81, 0x30, 0xce, 0x79, 0x48, 0x63, 0x6d, 0xf6, 0x22, 0xc1,
0xa1, 0xf6, 0x01, 0x10, 0x0d, 0xbc, 0x4b, 0x63, 0xd7, 0x1b, 0x44, 0xe4, 0x63, 0xa8, 0xc7, 0x1a,
0x31, 0xaa, 0xc2, 0x9a, 0x62, 0x27, 0xed, 0x03, 0xc7, 0xa0, 0xb3, 0x1f, 0x42, 0xe5, 0x01, 0xa5,
0x07, 0xde, 0xd0, 0x8b, 0xc9, 0x32, 0x94, 0x4f, 0xbd, 0x97, 0x94, 0x33, 0x7c, 0x71, 0x7f, 0xca,
0xe1, 0x45, 0xd2, 0x86, 0x99, 0x11, 0x0d, 0xbb, 0x54, 0x2e, 0xcf, 0xfe, 0x94, 0x23, 0x01, 0xdb,
0x33, 0x50, 0x1e, 0xb0, 0x8f, 0xed, 0xff, 0x5d, 0x80, 0xda, 0x31, 0xf5, 0x95, 0x20, 0x11, 0x28,
0xb1, 0x21, 0x0b, 0xe1, 0xc1, 0xdf, 0xe4, 0x1d, 0xa8, 0xe1, 0x34, 0x44, 0x71, 0xe8, 0xf9, 0x7d,
0xc1, 0xbf, 0xc0, 0x40, 0xc7, 0x08, 0x21, 0x4d, 0x28, 0xba, 0x43, 0xc9, 0xbb, 0xec, 0x27, 0x13,
0xb2, 0x91, 0x7b, 0x39, 0x64, 0xf2, 0xa8, 0x56, 0xb5, 0xee, 0xd4, 0x04, 0x6c, 0x9f, 0x2d, 0xeb,
0x3a, 0x2c, 0xe8, 0x24, 0xb2, 0xf6, 0x32, 0xd6, 0x3e, 0xaf, 0x51, 0x8a, 0x46, 0x6e, 0xc3, 0x9c,
0xa4, 0x0f, 0x79, 0x67, 0x71, 0x9d, 0xab, 0x4e, 0x43, 0x80, 0xe5, 0x10, 0xee, 0x40, 0xf3, 0xd4,
0xf3, 0xdd, 0x41, 0xa7, 0x3b, 0x88, 0xcf, 0x3b, 0x3d, 0x3a, 0x88, 0x5d, 0x5c, 0xf1, 0xb2, 0xd3,
0x40, 0xf8, 0xce, 0x20, 0x3e, 0xdf, 0x65, 0x50, 0xf2, 0x01, 0x54, 0x4f, 0x29, 0xed, 0xe0, 0x4c,
0xb4, 0x2a, 0x86, 0xf4, 0xc8, 0xd9, 0x75, 0x2a, 0xa7, 0x72, 0x9e, 0xef, 0x40, 0x33, 0x18, 0xc7,
0xfd, 0xc0, 0xf3, 0xfb, 0x1d, 0xa6, 0xaf, 0x3a, 0x5e, 0x0f, 0x39, 0xa0, 0xe4, 0x34, 0x24, 0x9c,
0x69, 0x8d, 0x47, 0x3d, 0xf2, 0x36, 0x00, 0xb6, 0xcd, 0x2b, 0x86, 0x55, 0xeb, 0xce, 0xac, 0x53,
0x65, 0x10, 0xac, 0xc8, 0xfe, 0xb7, 0x16, 0xd4, 0xf9, 0x9c, 0x8b, 0x8d, 0xf1, 0x26, 0xcc, 0xca,
0xa1, 0xd1, 0x30, 0x0c, 0x42, 0x21, 0x67, 0x26, 0x90, 0xac, 0x41, 0x53, 0x02, 0x46, 0x21, 0xf5,
0x86, 0x6e, 0x9f, 0x0a, 0xe5, 0x95, 0x81, 0x93, 0xcd, 0xa4, 0xc6, 0x30, 0x18, 0xc7, 0x54, 0xa8,
0xe0, 0xba, 0x18, 0x9d, 0xc3, 0x60, 0x8e, 0x49, 0xc2, 0xe4, 0x2c, 0x67, 0xcd, 0x0c, 0x98, 0xfd,
0xad, 0x05, 0x84, 0x75, 0xfd, 0x69, 0xc0, 0xab, 0x10, 0x53, 0x9e, 0x5e, 0x6e, 0xeb, 0x8d, 0x97,
0xbb, 0x30, 0x69, 0xb9, 0x6d, 0x28, 0xf3, 0x9e, 0x97, 0x72, 0x7a, 0xce, 0x51, 0x9f, 0x96, 0x2a,
0xc5, 0x66, 0xc9, 0xfe, 0xa9, 0x05, 0xf5, 0x1d, 0xbe, 0x7f, 0xa0, 0xc2, 0x23, 0x77, 0x81, 0x9c,
0x8e, 0xfd, 0x1e, 0x5b, 0xa7, 0xf8, 0xa5, 0xd7, 0xeb, 0x9c, 0x5c, 0xc6, 0x34, 0xe2, 0x7d, 0xda,
0x9f, 0x72, 0x72, 0x70, 0xe4, 0x03, 0x68, 0x1a, 0xd0, 0x28, 0x0e, 0x79, 0xcf, 0xf6, 0xa7, 0x9c,
0x0c, 0x86, 0x4d, 0x14, 0x53, 0xa9, 0xe3, 0xb8, 0xe3, 0xf9, 0x3d, 0xfa, 0x12, 0xe7, 0x76, 0xd6,
0x31, 0x60, 0xdb, 0x0d, 0xa8, 0xeb, 0xdf, 0xd9, 0x5f, 0x42, 0x45, 0x2a, 0x64, 0x54, 0x46, 0xa9,
0x7e, 0x39, 0x1a, 0x84, 0xb4, 0xa1, 0x62, 0xf6, 0xc2, 0xa9, 0x7c, 0x97, 0xb6, 0xed, 0x3f, 0x03,
0xcd, 0x03, 0xa6, 0x15, 0x7d, 0xcf, 0xef, 0x8b, 0x1d, 0x89, 0xa9, 0xea, 0xd1, 0xf8, 0xe4, 0x05,
0xbd, 0x14, 0xbc, 0x25, 0x4a, 0x4c, 0xde, 0xcf, 0x82, 0x28, 0x16, 0xed, 0xe0, 0x6f, 0xfb, 0x3f,
0x58, 0x40, 0xf6, 0xa2, 0xd8, 0x1b, 0xba, 0x31, 0x7d, 0x40, 0xd5, 0x22, 0x3f, 0x81, 0x3a, 0xab,
0xed, 0x69, 0xb0, 0xc5, 0x75, 0x3e, 0xd7, 0x55, 0xef, 0x8b, 0x85, 0xc9, 0x7e, 0xb0, 0xae, 0x53,
0x33, 0xb3, 0xf0, 0xd2, 0x31, 0x2a, 0x60, 0x7a, 0x25, 0x76, 0xc3, 0x3e, 0x8d, 0x71, 0x43, 0x10,
0xe6, 0x04, 0x70, 0xd0, 0x4e, 0xe0, 0x9f, 0xb6, 0xff, 0x08, 0xe6, 0x33, 0x75, 0x30, 0x65, 0x93,
0x0c, 0x83, 0xfd, 0x24, 0x8b, 0x50, 0x3e, 0x77, 0x07, 0x63, 0x2a, 0x76, 0x21, 0x5e, 0xf8, 0xa4,
0x70, 0xcf, 0xb2, 0xbb, 0xb0, 0x60, 0xf4, 0x4b, 0xc8, 0x5b, 0x0b, 0x66, 0x98, 0xdc, 0xb3, 0xfd,
0x16, 0x75, 0xa6, 0x23, 0x8b, 0x64, 0x13, 0x16, 0x4f, 0x29, 0x0d, 0xdd, 0x18, 0x8b, 0x9d, 0x11,
0x0d, 0x71, 0x4d, 0x44, 0xcd, 0xb9, 0x38, 0xfb, 0xbf, 0x5b, 0x30, 0xc7, 0x64, 0xe2, 0xb1, 0xeb,
0x5f, 0xca, 0xb9, 0x3a, 0xc8, 0x9d, 0xab, 0x3b, 0x62, 0xae, 0x52, 0xd4, 0xdf, 0x75, 0xa2, 0x8a,
0xe9, 0x89, 0x22, 0xab, 0x50, 0x37, 0xba, 0x5b, 0xe6, 0x1b, 0x5c, 0xe4, 0xc6, 0x47, 0x34, 0xdc,
0xbe, 0x8c, 0xe9, 0x6f, 0x3f, 0x95, 0xb7, 0xa0, 0x99, 0x74, 0x5b, 0xcc, 0x23, 0x81, 0x12, 0x63,
0x4c, 0x51, 0x01, 0xfe, 0xb6, 0xff, 0x91, 0xc5, 0x09, 0x77, 0x02, 0x4f, 0x6d, 0x7e, 0x8c, 0x90,
0xed, 0xa1, 0x92, 0x90, 0xfd, 0x9e, 0x68, 0x3c, 0xfc, 0xf6, 0x83, 0x25, 0xd7, 0xa0, 0x12, 0x51,
0xbf, 0xd7, 0x71, 0x07, 0x03, 0xdc, 0x23, 0x2a, 0xce, 0x0c, 0x2b, 0x6f, 0x0d, 0x06, 0xf6, 0x6d,
0x98, 0xd7, 0x7a, 0xf7, 0x9a, 0x71, 0x1c, 0x02, 0x39, 0xf0, 0xa2, 0xf8, 0x99, 0x1f, 0x8d, 0xb4,
0xbd, 0xe5, 0x2d, 0xa8, 0x0e, 0x3d, 0x1f, 0x7b, 0xc6, 0x25, 0xb7, 0xec, 0x54, 0x86, 0x9e, 0xcf,
0xfa, 0x15, 0x21, 0xd2, 0x7d, 0x29, 0x90, 0x05, 0x81, 0x74, 0x5f, 0x22, 0xd2, 0xbe, 0x07, 0x0b,
0x46, 0x7d, 0xa2, 0xe9, 0x77, 0xa1, 0x3c, 0x8e, 0x5f, 0x06, 0x72, 0xe7, 0xaf, 0x09, 0x0e, 0x61,
0x36, 0xa6, 0xc3, 0x31, 0xf6, 0x7d, 0x98, 0x3f, 0xa4, 0x17, 0x42, 0x90, 0x65, 0x47, 0x6e, 0x5d,
0x69, 0x7f, 0x22, 0xde, 0x5e, 0x07, 0xa2, 0x7f, 0x9c, 0x08, 0x80, 0xb4, 0x46, 0x2d, 0xc3, 0x1a,
0xb5, 0x6f, 0x01, 0x39, 0xf6, 0xfa, 0xfe, 0x63, 0x1a, 0x45, 0x6e, 0x5f, 0x89, 0x7e, 0x13, 0x8a,
0xc3, 0xa8, 0x2f, 0x54, 0x15, 0xfb, 0x69, 0x7f, 0x1f, 0x16, 0x0c, 0x3a, 0x51, 0xf1, 0x75, 0xa8,
0x46, 0x5e, 0xdf, 0x77, 0xe3, 0x71, 0x48, 0x45, 0xd5, 0x09, 0xc0, 0x7e, 0x00, 0x8b, 0x3f, 0xa2,
0xa1, 0x77, 0x7a, 0x79, 0x55, 0xf5, 0x66, 0x3d, 0x85, 0x74, 0x3d, 0x7b, 0xb0, 0x94, 0xaa, 0x47,
0x34, 0xcf, 0xd9, 0x57, 0xac, 0x64, 0xc5, 0xe1, 0x05, 0x4d, 0xf7, 0x15, 0x74, 0xdd, 0x67, 0x3f,
0x03, 0xb2, 0x13, 0xf8, 0x3e, 0xed, 0xc6, 0x47, 0x94, 0x86, 0x89, 0x23, 0x9c, 0xf0, 0x6a, 0x6d,
0x73, 0x45, 0xcc, 0x6c, 0x5a, 0xa1, 0x0a, 0x26, 0x26, 0x50, 0x1a, 0xd1, 0x70, 0x88, 0x15, 0x57,
0x1c, 0xfc, 0x6d, 0x2f, 0xc1, 0x82, 0x51, 0xad, 0x70, 0x1d, 0x3e, 0x84, 0xa5, 0x5d, 0x2f, 0xea,
0x66, 0x1b, 0x6c, 0xc1, 0xcc, 0x68, 0x7c, 0xd2, 0x49, 0x24, 0x51, 0x16, 0x99, 0x35, 0x99, 0xfe,
0x44, 0x54, 0xf6, 0x57, 0x2c, 0x28, 0xed, 0x3f, 0x3d, 0xd8, 0x61, 0x7b, 0x85, 0xe7, 0x77, 0x83,
0x21, 0xdb, 0x4b, 0xf9, 0xa0, 0x55, 0x79, 0xa2, 0x84, 0x5d, 0x87, 0x2a, 0x6e, 0xc1, 0xcc, 0x80,
0x16, 0x3e, 0x6b, 0x02, 0x60, 0xc6, 0x3b, 0x7d, 0x39, 0xf2, 0x42, 0xb4, 0xce, 0xa5, 0xcd, 0x5d,
0xc2, 0x6d, 0x26, 0x8b, 0xb0, 0x7f, 0x31, 0x0d, 0x33, 0x62, 0xf3, 0xc5, 0xf6, 0xba, 0xb1, 0x77,
0x4e, 0x45, 0x4f, 0x44, 0x89, 0x99, 0x37, 0x21, 0x1d, 0x06, 0x31, 0xed, 0x18, 0xcb, 0x60, 0x02,
0xd1, 0x39, 0x11, 0x7e, 0x23, 0x77, 0x67, 0x8a, 0x9c, 0xca, 0x00, 0xb2, 0xc9, 0x92, 0xb6, 0x57,
0x09, 0x6d, 0x2f, 0x59, 0x64, 0x33, 0xd1, 0x75, 0x47, 0x6e, 0xd7, 0x8b, 0x2f, 0x85, 0x4a, 0x50,
0x65, 0x56, 0xf7, 0x20, 0xe8, 0xba, 0xcc, 0x23, 0x1d, 0xb8, 0x7e, 0x97, 0x4a, 0xc7, 0xc7, 0x00,
0x32, 0x27, 0x40, 0x74, 0x49, 0x92, 0x71, 0x47, 0x21, 0x05, 0x65, 0xfb, 0x77, 0x37, 0x18, 0x0e,
0xbd, 0x98, 0xf9, 0x0e, 0x68, 0x37, 0x16, 0x1d, 0x0d, 0xc2, 0xdd, 0x2c, 0x2c, 0x5d, 0xf0, 0xd9,
0xab, 0x4a, 0x37, 0x4b, 0x03, 0xb2, 0x5a, 0xd8, 0xae, 0xc3, 0xd4, 0xd8, 0x8b, 0x0b, 0x34, 0x12,
0x8b, 0x8e, 0x06, 0x61, 0xeb, 0x30, 0xf6, 0x23, 0x1a, 0xc7, 0x03, 0xda, 0x53, 0x1d, 0xaa, 0x21,
0x59, 0x16, 0x41, 0xee, 0xc2, 0x02, 0x77, 0x67, 0x22, 0x37, 0x0e, 0xa2, 0x33, 0x2f, 0xea, 0x44,
0xcc, 0xf0, 0xaf, 0x23, 0x7d, 0x1e, 0x8a, 0xdc, 0x83, 0x95, 0x14, 0x38, 0xa4, 0x5d, 0xea, 0x9d,
0xd3, 0x5e, 0x6b, 0x16, 0xbf, 0x9a, 0x84, 0x26, 0xab, 0x50, 0x63, 0x5e, 0xdc, 0x78, 0xd4, 0x73,
0x99, 0x01, 0xd3, 0xc0, 0x75, 0xd0, 0x41, 0xe4, 0x43, 0x98, 0x1d, 0x51, 0x6e, 0xfd, 0x9c, 0xc5,
0x83, 0x6e, 0xd4, 0x9a, 0x33, 0xb4, 0x1b, 0xe3, 0x5c, 0xc7, 0xa4, 0x60, 0x4c, 0xd9, 0x8d, 0xd0,
0x5c, 0x77, 0x2f, 0x5b, 0x4d, 0x61, 0x32, 0x4b, 0x00, 0xca, 0x48, 0xe8, 0x9d, 0xbb, 0x31, 0x6d,
0xcd, 0x73, 0x85, 0x2e, 0x8a, 0xec, 0x3b, 0xcf, 0xf7, 0x62, 0xcf, 0x8d, 0x83, 0xb0, 0x45, 0x10,
0x97, 0x00, 0xd8, 0x24, 0x22, 0x7f, 0x44, 0xb1, 0x1b, 0x8f, 0xa3, 0xce, 0xe9, 0xc0, 0xed, 0x47,
0xad, 0x05, 0x6e, 0x73, 0x66, 0x10, 0xe4, 0x63, 0x58, 0xe6, 0x1c, 0x81, 0xa8, 0x90, 0x46, 0x34,
0x3c, 0xe7, 0x66, 0xc2, 0x22, 0xce, 0xc8, 0x04, 0x2c, 0x9b, 0x4a, 0xc1, 0x22, 0x99, 0x0f, 0x97,
0xf8, 0x54, 0x4e, 0x40, 0xdb, 0xff, 0xc4, 0xe2, 0xdb, 0x82, 0x10, 0x21, 0xa5, 0xde, 0xdf, 0x81,
0x1a, 0x17, 0x9e, 0x4e, 0xe0, 0x0f, 0x2e, 0x85, 0x3c, 0x01, 0x07, 0x3d, 0xf1, 0x07, 0x97, 0xe4,
0x7b, 0x30, 0xeb, 0xf9, 0x3a, 0x09, 0xd7, 0x40, 0x75, 0x09, 0x44, 0xa2, 0x77, 0xa0, 0x36, 0x1a,
0x9f, 0x0c, 0xbc, 0x2e, 0x27, 0x29, 0xf2, 0x5a, 0x38, 0x08, 0x09, 0x98, 0xdd, 0xce, 0xe7, 0x91,
0x53, 0x94, 0x90, 0xa2, 0x26, 0x60, 0x8c, 0xc4, 0xde, 0x86, 0x45, 0xb3, 0x83, 0x42, 0xd5, 0xae,
0x41, 0x45, 0x48, 0x66, 0xd4, 0xaa, 0xe1, 0xea, 0x36, 0xb4, 0xf8, 0x8e, 0x4f, 0x07, 0x8e, 0xc2,
0xdb, 0xff, 0xa6, 0x04, 0x0b, 0x02, 0xba, 0x33, 0x08, 0x22, 0x7a, 0x3c, 0x1e, 0x0e, 0xdd, 0x30,
0x47, 0xe4, 0xad, 0x2b, 0x44, 0xbe, 0x60, 0x8a, 0x3c, 0x13, 0xc4, 0x33, 0xd7, 0xf3, 0xb9, 0xd3,
0xc1, 0xf5, 0x85, 0x06, 0x21, 0x77, 0x60, 0xae, 0x3b, 0x08, 0x22, 0x6e, 0x84, 0xeb, 0xe1, 0x85,
0x34, 0x38, 0xab, 0xa2, 0xca, 0x79, 0x2a, 0x4a, 0x57, 0x31, 0xd3, 0x29, 0x15, 0x63, 0x43, 0x9d,
0x55, 0x4a, 0xa5, 0xc6, 0x9c, 0xe1, 0x86, 0xb9, 0x0e, 0x63, 0xfd, 0x49, 0x0b, 0x34, 0xd7, 0x1e,
0x73, 0x79, 0xe2, 0xec, 0x0d, 0x29, 0x6a, 0x64, 0x8d, 0xba, 0x2a, 0xc4, 0x39, 0x8b, 0x22, 0x0f,
0x98, 0xcf, 0xc9, 0xda, 0x42, 0xb3, 0x00, 0xd0, 0x2c, 0xb8, 0x65, 0xae, 0x88, 0x3e, 0xf7, 0xeb,
0xac, 0x30, 0x0e, 0x29, 0x9a, 0x0a, 0xda, 0x97, 0xf6, 0x5f, 0xb7, 0xa0, 0xa6, 0xe1, 0xc8, 0x12,
0xcc, 0xef, 0x3c, 0x79, 0x72, 0xb4, 0xe7, 0x6c, 0x3d, 0x7d, 0xf4, 0xa3, 0xbd, 0xce, 0xce, 0xc1,
0x93, 0xe3, 0xbd, 0xe6, 0x14, 0x03, 0x1f, 0x3c, 0xd9, 0xd9, 0x3a, 0xe8, 0x3c, 0x78, 0xe2, 0xec,
0x48, 0xb0, 0x45, 0x96, 0x81, 0x38, 0x7b, 0x8f, 0x9f, 0x3c, 0xdd, 0x33, 0xe0, 0x05, 0xd2, 0x84,
0xfa, 0xb6, 0xb3, 0xb7, 0xb5, 0xb3, 0x2f, 0x20, 0x45, 0xb2, 0x08, 0xcd, 0x07, 0xcf, 0x0e, 0x77,
0x1f, 0x1d, 0x3e, 0xec, 0xec, 0x6c, 0x1d, 0xee, 0xec, 0x1d, 0xec, 0xed, 0x36, 0x4b, 0x64, 0x16,
0xaa, 0x5b, 0xdb, 0x5b, 0x87, 0xbb, 0x4f, 0x0e, 0xf7, 0x76, 0x9b, 0x65, 0xfb, 0xbf, 0x5a, 0xb0,
0x84, 0xbd, 0xee, 0xa5, 0x05, 0x64, 0x15, 0x6a, 0xdd, 0x20, 0x18, 0x31, 0x73, 0x3c, 0xd9, 0x70,
0x74, 0x10, 0x63, 0x7e, 0x2e, 0xae, 0xa7, 0x41, 0xd8, 0xa5, 0x42, 0x3e, 0x00, 0x41, 0x0f, 0x18,
0x84, 0x31, 0xbf, 0x58, 0x5e, 0x4e, 0xc1, 0xc5, 0xa3, 0xc6, 0x61, 0x9c, 0x64, 0x19, 0xa6, 0x4f,
0x42, 0xea, 0x76, 0xcf, 0x84, 0x64, 0x88, 0x12, 0x79, 0x2f, 0xf1, 0x17, 0xbb, 0x6c, 0xf6, 0x07,
0xb4, 0x87, 0x1c, 0x53, 0x71, 0xe6, 0x04, 0x7c, 0x47, 0x80, 0x99, 0x7e, 0x72, 0x4f, 0x5c, 0xbf,
0x17, 0xf8, 0xb4, 0x27, 0x8c, 0xd1, 0x04, 0x60, 0x1f, 0xc1, 0x72, 0x7a, 0x7c, 0x42, 0xbe, 0x3e,
0xd6, 0xe4, 0x8b, 0xdb, 0x86, 0xed, 0xc9, 0xab, 0xa9, 0xc9, 0xda, 0xaf, 0x0a, 0x50, 0x62, 0xa6,
0xc2, 0x64, 0xb3, 0x42, 0xb7, 0xfe, 0x8a, 0x99, 0x58, 0x24, 0xba, 0xa0, 0x7c, 0xf3, 0xe0, 0x1b,
0xac, 0x06, 0x49, 0xf0, 0x21, 0xed, 0x9e, 0xe3, 0x88, 0x15, 0x9e, 0x41, 0x98, 0x80, 0x30, 0xd3,
0x1c, 0xbf, 0x16, 0x02, 0x22, 0xcb, 0x12, 0x87, 0x5f, 0xce, 0x24, 0x38, 0xfc, 0xae, 0x05, 0x33,
0x9e, 0x7f, 0x12, 0x8c, 0xfd, 0x1e, 0x0a, 0x44, 0xc5, 0x91, 0x45, 0x8c, 0x7e, 0xa2, 0xa0, 0x7a,
0x43, 0xc9, 0xfe, 0x09, 0x80, 0x6c, 0x42, 0x35, 0xba, 0xf4, 0xbb, 0x3a, 0xcf, 0x2f, 0x8a, 0x59,
0x62, 0x73, 0xb0, 0x7e, 0x7c, 0xe9, 0x77, 0x91, 0xc3, 0x13, 0x32, 0xfb, 0x8f, 0xa0, 0x22, 0xc1,
0x8c, 0x2d, 0x9f, 0x1d, 0x7e, 0x76, 0xf8, 0xe4, 0xf9, 0x61, 0xe7, 0xf8, 0xf3, 0xc3, 0x9d, 0xe6,
0x14, 0x99, 0x83, 0xda, 0xd6, 0x0e, 0x72, 0x3a, 0x02, 0x2c, 0x46, 0x72, 0xb4, 0x75, 0x7c, 0xac,
0x20, 0x05, 0x9b, 0x30, 0xf7, 0x3a, 0x42, 0x7b, 0x4c, 0x45, 0xf7, 0x3e, 0x86, 0x79, 0x0d, 0x96,
0xd8, 0xf6, 0x23, 0x06, 0x48, 0xd9, 0xf6, 0x68, 0xc8, 0x71, 0x8c, 0xdd, 0x84, 0xc6, 0x43, 0x1a,
0x3f, 0xf2, 0x4f, 0x03, 0x59, 0xd3, 0xff, 0x2c, 0xc1, 0x9c, 0x02, 0x89, 0x8a, 0xee, 0xc0, 0x9c,
0xd7, 0xa3, 0x7e, 0xec, 0xc5, 0x97, 0x1d, 0xc3, 0x8b, 0x4f, 0x83, 0x99, 0x01, 0xec, 0x0e, 0x3c,
0x57, 0x06, 0x99, 0x79, 0x81, 0x79, 0xb5, 0x6c, 0x77, 0x96, 0x1b, 0xae, 0xe2, 0x2b, 0x1e, 0x3c,
0xc8, 0xc5, 0x31, 0x0d, 0xc4, 0xe0, 0x62, 0x8b, 0x51, 0x9f, 0x70, 0x43, 0x30, 0x0f, 0xc5, 0x96,
0x8a, 0xd7, 0xc4, 0x86, 0x5c, 0xe6, 0x3b, 0xb8, 0x02, 0x64, 0xa2, 0xb8, 0xd3, 0x5c, 0x3f, 0xa6,
0xa3, 0xb8, 0x5a, 0x24, 0xb8, 0x92, 0x89, 0x04, 0x33, 0xfd, 0x79, 0xe9, 0x77, 0x69, 0xaf, 0x13,
0x07, 0x1d, 0xd4, 0xf3, 0xc8, 0x12, 0x15, 0x27, 0x0d, 0x26, 0xd7, 0x61, 0x26, 0xa6, 0x51, 0xec,
0x53, 0x1e, 0x7e, 0xab, 0x6c, 0x17, 0x5a, 0x96, 0x23, 0x41, 0xcc, 0x6a, 0x1f, 0x87, 0x5e, 0xd4,
0xaa, 0x63, 0x8c, 0x17, 0x7f, 0x93, 0x8f, 0x60, 0xe9, 0x84, 0x46, 0x71, 0xe7, 0x8c, 0xba, 0x3d,
0x1a, 0x22, 0x7b, 0xf1, 0x60, 0x32, 0x37, 0x86, 0xf2, 0x91, 0x8c, 0x71, 0xcf, 0x69, 0x18, 0x79,
0x81, 0x8f, 0x66, 0x50, 0xd5, 0x91, 0x45, 0x56, 0x1f, 0x1b, 0xbc, 0xda, 0xa4, 0xd5, 0x0c, 0xce,
0xe1, 0xc0, 0xf3, 0x91, 0xe4, 0x26, 0x4c, 0xe3, 0x00, 0xa2, 0x56, 0x13, 0x79, 0xa6, 0x9e, 0xc8,
0xbc, 0xe7, 0x3b, 0x02, 0xc7, 0x56, 0xb9, 0x1b, 0x0c, 0x82, 0x10, 0x6d, 0xa1, 0xaa, 0xc3, 0x0b,
0xe6, 0xec, 0xf4, 0x43, 0x77, 0x74, 0x26, 0xec, 0xa1, 0x34, 0xf8, 0xd3, 0x52, 0xa5, 0xd6, 0xac,
0xdb, 0x7f, 0x0a, 0xca, 0x58, 0x2d, 0x56, 0x87, 0x93, 0x69, 0x89, 0xea, 0x10, 0xda, 0x82, 0x19,
0x9f, 0xc6, 0x17, 0x41, 0xf8, 0x42, 0x9e, 0x58, 0x88, 0xa2, 0xfd, 0x35, 0xfa, 0x4d, 0x2a, 0x82,
0xff, 0x0c, 0x8d, 0x3e, 0xe6, 0xfd, 0xf2, 0xa5, 0x8a, 0xce, 0x5c, 0xe1, 0xca, 0x55, 0x10, 0x70,
0x7c, 0xe6, 0x32, 0x5d, 0x6b, 0xac, 0x3e, 0xf7, 0x8e, 0x6b, 0x08, 0xdb, 0xe7, 0x8b, 0x7f, 0x13,
0x1a, 0xf2, 0x6c, 0x20, 0xea, 0x0c, 0xe8, 0x69, 0x2c, 0x63, 0x5b, 0xfe, 0x78, 0x88, 0x2e, 0xf4,
0x01, 0x3d, 0x8d, 0xed, 0x43, 0x98, 0x17, 0xfa, 0xef, 0xc9, 0x88, 0xca, 0xa6, 0xff, 0x20, 0xcf,
0x8e, 0xa8, 0x6d, 0x2e, 0x98, 0x0a, 0x93, 0x9f, 0x86, 0x98, 0x94, 0xb6, 0x03, 0x44, 0xd7, 0xa7,
0xa2, 0x42, 0xb1, 0x99, 0xcb, 0xe8, 0x9d, 0x18, 0x8e, 0x01, 0x63, 0xf3, 0x13, 0x8d, 0xbb, 0x5d,
0x79, 0xa2, 0x53, 0x71, 0x64, 0xd1, 0xfe, 0x67, 0x16, 0x2c, 0x60, 0x6d, 0xd2, 0x12, 0x12, 0x7b,
0xd6, 0xbd, 0xef, 0xd0, 0xcd, 0x7a, 0x57, 0x8f, 0x68, 0x2e, 0x42, 0x59, 0xdf, 0xc5, 0x78, 0xe1,
0xbb, 0x47, 0x4a, 0x4a, 0xe9, 0x48, 0x89, 0xfd, 0xf7, 0x2d, 0x98, 0xe7, 0x1b, 0x09, 0xda, 0xc1,
0x62, 0xf8, 0x7f, 0x1a, 0x66, 0xb9, 0x45, 0x20, 0xb4, 0x82, 0xe8, 0x68, 0xa2, 0x5a, 0x11, 0xca,
0x89, 0xf7, 0xa7, 0x1c, 0x93, 0x98, 0xdc, 0x47, 0xab, 0xcc, 0xef, 0x20, 0x34, 0xe7, 0xec, 0xcf,
0x9c, 0xeb, 0xfd, 0x29, 0x47, 0x23, 0xdf, 0xae, 0xc0, 0x34, 0x77, 0x22, 0xec, 0x87, 0x30, 0x6b,
0x34, 0x64, 0x44, 0x69, 0xea, 0x3c, 0x4a, 0x93, 0x09, 0x87, 0x16, 0x72, 0xc2, 0xa1, 0xff, 0xaa,
0x08, 0x84, 0x31, 0x4b, 0x6a, 0x35, 0x98, 0x17, 0x13, 0xf4, 0x0c, 0x9f, 0xb4, 0xee, 0xe8, 0x20,
0xb2, 0x0e, 0x44, 0x2b, 0xca, 0x88, 0x35, 0xdf, 0x32, 0x73, 0x30, 0x4c, 0xcd, 0x0a, 0x8b, 0x43,
0xd8, 0x06, 0xc2, 0xfb, 0xe6, 0xd3, 0x9e, 0x8b, 0x63, 0xbb, 0xe2, 0x68, 0x1c, 0x9d, 0xa1, 0xaf,
0x20, 0xbc, 0x56, 0x59, 0x4e, 0xaf, 0xef, 0xf4, 0x95, 0xeb, 0x3b, 0x93, 0x89, 0x84, 0x69, 0x7e,
0x53, 0xc5, 0xf4, 0x9b, 0x6e, 0xc2, 0xec, 0x90, 0xd9, 0xc9, 0xf1, 0xa0, 0xdb, 0x19, 0xb2, 0xd6,
0x85, 0x93, 0x6a, 0x00, 0xc9, 0x1a, 0x34, 0xa5, 0xeb, 0xa2, 0x9c, 0x33, 0x7e, 0x9e, 0x91, 0x81,
0x33, 0xfd, 0x9f, 0xc4, 0xc6, 0x6a, 0xd8, 0xd9, 0x04, 0xc0, 0x3c, 0xb1, 0x88, 0x71, 0x48, 0x67,
0xec, 0x8b, 0xe3, 0x3f, 0xda, 0x43, 0xf7, 0xb4, 0xe2, 0x64, 0x11, 0xf6, 0xdf, 0xb6, 0xa0, 0xc9,
0xd6, 0xcc, 0x60, 0xcb, 0x4f, 0x00, 0xa5, 0xe2, 0x0d, 0xb9, 0xd2, 0xa0, 0x25, 0xf7, 0xa0, 0x8a,
0xe5, 0x60, 0x44, 0x7d, 0xc1, 0x93, 0x2d, 0x93, 0x27, 0x13, 0x7d, 0xb2, 0x3f, 0xe5, 0x24, 0xc4,
0x1a, 0x47, 0xfe, 0x27, 0x0b, 0x6a, 0xa2, 0x95, 0xdf, 0x38, 0xf6, 0xd2, 0xd6, 0xce, 0x6b, 0x39,
0x27, 0x25, 0xc7, 0xb3, 0x77, 0x60, 0x6e, 0xe8, 0xc6, 0xe3, 0x90, 0xed, 0xe7, 0x46, 0xdc, 0x25,
0x0d, 0x66, 0x9b, 0x33, 0xaa, 0xce, 0xa8, 0x13, 0x7b, 0x83, 0x8e, 0xc4, 0x8a, 0x93, 0xd1, 0x3c,
0x14, 0xd3, 0x20, 0x51, 0xec, 0xf6, 0xa9, 0xd8, 0x77, 0x79, 0xc1, 0x6e, 0xc1, 0xb2, 0x18, 0x50,
0xca, 0xbe, 0xb6, 0xff, 0xc5, 0x2c, 0xac, 0x64, 0x50, 0x2a, 0x8f, 0x43, 0x04, 0x14, 0x06, 0xde,
0xf0, 0x24, 0x50, 0xce, 0x89, 0xa5, 0xc7, 0x1a, 0x0c, 0x14, 0xe9, 0xc3, 0x92, 0x34, 0x30, 0xd8,
0x9c, 0x26, 0x9b, 0x61, 0x01, 0x77, 0xb9, 0x0f, 0xcd, 0x25, 0x4c, 0x37, 0x28, 0xe1, 0xba, 0x10,
0xe7, 0xd7, 0x47, 0xce, 0xa0, 0xa5, 0x2c, 0x19, 0xa1, 0xac, 0x35, 0x6b, 0x87, 0xb5, 0xf5, 0xc1,
0x15, 0x6d, 0x19, 0xe6, 0xb8, 0x33, 0xb1, 0x36, 0x72, 0x09, 0x37, 0x24, 0x0e, 0xb5, 0x71, 0xb6,
0xbd, 0xd2, 0x1b, 0x8d, 0x0d, 0x1d, 0x0d, 0xb3, 0xd1, 0x2b, 0x2a, 0x26, 0x5f, 0xc2, 0xf2, 0x85,
0xeb, 0xc5, 0xb2, 0x5b, 0x9a, 0x6d, 0x51, 0xc6, 0x26, 0x37, 0xaf, 0x68, 0xf2, 0x39, 0xff, 0xd8,
0xd8, 0xa2, 0x26, 0xd4, 0xd8, 0xfe, 0x45, 0x01, 0x1a, 0x66, 0x3d, 0x8c, 0x4d, 0x85, 0xec, 0x4b,
0x1d, 0x28, 0xad, 0xd1, 0x14, 0x38, 0xeb, 0xdf, 0x17, 0xf2, 0xfc, 0x7b, 0xdd, 0xab, 0x2e, 0x5e,
0x15, 0xb8, 0x2b, 0xbd, 0x59, 0xe0, 0xae, 0x9c, 0x1b, 0xb8, 0x9b, 0x1c, 0xdf, 0x99, 0xfe, 0x4d,
0xe3, 0x3b, 0x33, 0xaf, 0x8d, 0xef, 0xb4, 0xff, 0xaf, 0x05, 0x24, 0xcb, 0xbd, 0xe4, 0x21, 0x0f,
0x69, 0xf8, 0x74, 0x20, 0x94, 0xd8, 0xef, 0xbf, 0x99, 0x04, 0xc8, 0xd5, 0x92, 0x5f, 0x33, 0x51,
0xd4, 0x93, 0x29, 0x74, 0xf3, 0x6a, 0xd6, 0xc9, 0x43, 0xa5, 0x82, 0x97, 0xa5, 0xab, 0x83, 0x97,
0xe5, 0xab, 0x83, 0x97, 0xd3, 0xe9, 0xe0, 0x65, 0xfb, 0x2f, 0x5b, 0xb0, 0x90, 0xc3, 0x66, 0xbf,
0xbb, 0x81, 0x33, 0xc6, 0x30, 0xb4, 0x4f, 0x41, 0x30, 0x86, 0x0e, 0x6c, 0xff, 0x05, 0x98, 0x35,
0x44, 0xeb, 0x77, 0xd7, 0x7e, 0xda, 0x42, 0xe4, 0x9c, 0x6d, 0xc0, 0xda, 0xff, 0xab, 0x00, 0x24,
0x2b, 0xde, 0x7f, 0xa2, 0x7d, 0xc8, 0xce, 0x53, 0x31, 0x67, 0x9e, 0xfe, 0xbf, 0xee, 0x3c, 0x1f,
0xc0, 0xbc, 0xc8, 0x10, 0xd3, 0x02, 0x59, 0x9c, 0x63, 0xb2, 0x08, 0x66, 0x23, 0x9b, 0x91, 0xe3,
0x8a, 0x91, 0x11, 0xa3, 0x6d, 0xbf, 0xa9, 0x00, 0xb2, 0xdd, 0x86, 0x96, 0x98, 0xa1, 0xbd, 0x73,
0xea, 0xc7, 0xc7, 0xe3, 0x13, 0x9e, 0x22, 0xe5, 0x05, 0xbe, 0xfd, 0xaf, 0x8b, 0xca, 0xcc, 0x47,
0xa4, 0x30, 0x28, 0x3e, 0x82, 0xba, 0xbe, 0x7d, 0x88, 0xe5, 0x48, 0xc5, 0x31, 0x99, 0x29, 0xa1,
0x53, 0x91, 0x5d, 0x68, 0xa0, 0x92, 0xec, 0xa9, 0xef, 0x0a, 0xf8, 0xdd, 0x6b, 0xe2, 0x33, 0xfb,
0x53, 0x4e, 0xea, 0x1b, 0xf2, 0x87, 0xd0, 0x30, 0x9d, 0x3f, 0x61, 0x95, 0xe4, 0x79, 0x03, 0xec,
0x73, 0x93, 0x98, 0x6c, 0x41, 0x33, 0xed, 0x3d, 0x8a, 0x4c, 0x89, 0x09, 0x15, 0x64, 0xc8, 0xc9,
0x3d, 0x71, 0x84, 0x58, 0xc6, 0xb8, 0xc9, 0x4d, 0xf3, 0x33, 0x6d, 0x9a, 0xd6, 0xf9, 0x1f, 0xed,
0x50, 0xf1, 0x8f, 0x01, 0x12, 0x18, 0x69, 0x42, 0xfd, 0xc9, 0xd1, 0xde, 0x61, 0x67, 0x67, 0x7f,
0xeb, 0xf0, 0x70, 0xef, 0xa0, 0x39, 0x45, 0x08, 0x34, 0x30, 0xcc, 0xb7, 0xab, 0x60, 0x16, 0x83,
0x89, 0xc0, 0x8a, 0x84, 0x15, 0xc8, 0x22, 0x34, 0x1f, 0x1d, 0xa6, 0xa0, 0xc5, 0xed, 0xaa, 0x92,
0x0f, 0x7b, 0x19, 0x16, 0x79, 0x06, 0xe0, 0x36, 0x67, 0x0f, 0x69, 0x9d, 0xfc, 0x63, 0x0b, 0x96,
0x52, 0x88, 0x24, 0x95, 0x86, 0x1b, 0x20, 0xa6, 0x55, 0x62, 0x02, 0xf1, 0x58, 0x40, 0xda, 0x9a,
0x29, 0x0d, 0x92, 0x45, 0x30, 0x9e, 0xd7, 0x6c, 0xd3, 0x94, 0x24, 0xe5, 0xa1, 0xec, 0x15, 0x9e,
0xa7, 0x88, 0x19, 0x8d, 0x46, 0xc7, 0x4f, 0x79, 0x66, 0xa1, 0x8e, 0x48, 0x8e, 0x64, 0xcd, 0x2e,
0xcb, 0x22, 0x73, 0x2b, 0x0c, 0x63, 0xc7, 0xec, 0x6f, 0x2e, 0xce, 0xfe, 0x1b, 0x45, 0x20, 0x3f,
0x1c, 0xd3, 0xf0, 0x12, 0xf3, 0x65, 0x54, 0xd4, 0x74, 0x25, 0x1d, 0x13, 0x9c, 0x1e, 0x8d, 0x4f,
0x3e, 0xa3, 0x97, 0x32, 0x83, 0xab, 0x90, 0x64, 0x70, 0xe5, 0x65, 0x51, 0x95, 0xae, 0xce, 0xa2,
0x2a, 0x5f, 0x95, 0x45, 0xf5, 0x3d, 0x98, 0xf5, 0xfa, 0x7e, 0xc0, 0x64, 0x9e, 0xd9, 0x09, 0x51,
0x6b, 0x7a, 0xb5, 0xc8, 0x7c, 0x6b, 0x01, 0x3c, 0x64, 0x30, 0x72, 0x3f, 0x21, 0xa2, 0xbd, 0x3e,
0x66, 0xec, 0xe9, 0x5a, 0x60, 0xaf, 0xd7, 0xa7, 0x07, 0x41, 0xd7, 0x8d, 0x83, 0x10, 0x03, 0x3b,
0xf2, 0x63, 0x06, 0x8f, 0xc8, 0x4d, 0x68, 0x44, 0xc1, 0x98, 0x59, 0x4e, 0x72, 0xac, 0x3c, 0x92,
0x54, 0xe7, 0xd0, 0x23, 0x3e, 0xe2, 0x75, 0x58, 0x18, 0x47, 0xb4, 0x33, 0xf4, 0xa2, 0x88, 0xed,
0x8e, 0xdd, 0xc0, 0x8f, 0xc3, 0x60, 0x20, 0xe2, 0x49, 0xf3, 0xe3, 0x88, 0x3e, 0xe6, 0x98, 0x1d,
0x8e, 0x20, 0x1f, 0x25, 0x5d, 0x1a, 0xb9, 0x5e, 0x18, 0xb5, 0x00, 0xbb, 0x24, 0x47, 0xca, 0xfa,
0x7d, 0xe4, 0x7a, 0xa1, 0xea, 0x0b, 0x2b, 0x44, 0x22, 0x43, 0x69, 0x1d, 0x2a, 0x12, 0xcf, 0xbc,
0xd8, 0xd3, 0x30, 0x18, 0x4a, 0x2f, 0x96, 0xfd, 0x26, 0x0d, 0x28, 0xc4, 0x81, 0xf0, 0x40, 0x0b,
0x71, 0x60, 0x7f, 0x0e, 0x35, 0x6d, 0x88, 0x98, 0x4e, 0x26, 0x2c, 0x26, 0xe1, 0xfe, 0x96, 0xb8,
0x83, 0xe2, 0xd3, 0xc1, 0xa3, 0x1e, 0x79, 0x1f, 0xe6, 0x7b, 0x5e, 0x48, 0x31, 0x33, 0xb0, 0x13,
0xd2, 0x73, 0x1a, 0x46, 0x32, 0x50, 0xd0, 0x54, 0x08, 0x87, 0xc3, 0xed, 0xfb, 0xb0, 0x60, 0xf0,
0x85, 0x12, 0x9b, 0x69, 0x4c, 0xa9, 0x92, 0xb1, 0x4a, 0x33, 0xdd, 0x4a, 0xe0, 0xec, 0xbf, 0x5a,
0x80, 0xe2, 0x7e, 0x30, 0xd2, 0x4f, 0x64, 0x2c, 0xf3, 0x44, 0x46, 0x58, 0x7c, 0x1d, 0x65, 0xd0,
0x89, 0x6d, 0xd9, 0x00, 0x92, 0x35, 0x68, 0xb8, 0xc3, 0xb8, 0x13, 0x07, 0xcc, 0xc2, 0xbd, 0x70,
0xc3, 0x1e, 0x97, 0x25, 0x5c, 0xcb, 0x14, 0x86, 0x2c, 0x42, 0x51, 0x19, 0x2a, 0x48, 0xc0, 0x8a,
0xcc, 0xbd, 0xc2, 0xb3, 0xe8, 0x4b, 0x11, 0x68, 0x14, 0x25, 0x26, 0xaa, 0xe6, 0xf7, 0xdc, 0xb7,
0xe5, 0xdb, 0x4d, 0x1e, 0x8a, 0x59, 0x9f, 0x8c, 0x7b, 0x87, 0x89, 0x31, 0xa7, 0xca, 0x7a, 0x08,
0xbd, 0x62, 0x9e, 0xcc, 0xff, 0xda, 0x82, 0x32, 0xce, 0x0d, 0xdb, 0x3a, 0xb9, 0x6e, 0x51, 0x87,
0x32, 0x38, 0x27, 0xb3, 0x4e, 0x1a, 0x4c, 0x6c, 0x23, 0x07, 0xb5, 0xa0, 0x06, 0xa4, 0xe7, 0xa1,
0xae, 0x42, 0x95, 0x97, 0x54, 0x3e, 0x25, 0x92, 0x24, 0x40, 0x72, 0x03, 0x4a, 0x67, 0xc1, 0x48,
0x7a, 0x17, 0x20, 0x4f, 0x54, 0x83, 0x91, 0x83, 0xf0, 0xa4, 0x3f, 0xac, 0x3e, 0x3e, 0x2c, 0x6e,
0xc1, 0xa5, 0xc1, 0xcc, 0x6a, 0x56, 0xd5, 0xea, 0xd3, 0x94, 0x82, 0xda, 0xcf, 0x60, 0x8e, 0x71,
0xaf, 0x16, 0xa4, 0x9e, 0xac, 0x47, 0xde, 0x63, 0xdb, 0x52, 0x77, 0x30, 0xee, 0x51, 0xdd, 0xc7,
0xc3, 0x20, 0xa4, 0x80, 0x4b, 0xeb, 0xc6, 0xfe, 0x97, 0x16, 0x97, 0x0a, 0x56, 0x2f, 0xb9, 0x03,
0x25, 0xa6, 0x0d, 0x52, 0x2e, 0xbd, 0x4a, 0xba, 0x60, 0x74, 0x0e, 0x52, 0x30, 0xa3, 0x07, 0xc3,
0x84, 0x7a, 0xed, 0x3c, 0x48, 0x98, 0x38, 0x48, 0x6a, 0x64, 0x29, 0xbf, 0x22, 0x05, 0x25, 0xeb,
0xda, 0x19, 0x4b, 0xc9, 0xd0, 0x30, 0x72, 0x17, 0xec, 0xf5, 0xa9, 0x76, 0xb6, 0xf2, 0x73, 0x0b,
0x66, 0x8d, 0x3e, 0x91, 0x55, 0xa8, 0x0d, 0xdc, 0x28, 0x16, 0x07, 0xdf, 0x62, 0xe5, 0x75, 0x90,
0xce, 0x43, 0x05, 0xf3, 0x18, 0x46, 0xc5, 0xea, 0x8b, 0x7a, 0xac, 0xfe, 0x2e, 0x54, 0x93, 0x24,
0x64, 0xb3, 0x53, 0xac, 0x45, 0x99, 0x7e, 0x92, 0x10, 0x25, 0xd1, 0xe0, 0xb2, 0x16, 0x0d, 0xb6,
0xef, 0x43, 0x4d, 0xa3, 0xd7, 0xa3, 0xb9, 0x96, 0x11, 0xcd, 0x55, 0xb9, 0x59, 0x85, 0x24, 0x37,
0xcb, 0xfe, 0xb6, 0x00, 0xb3, 0x8c, 0xbd, 0x3d, 0xbf, 0x7f, 0x14, 0x0c, 0xbc, 0xee, 0x25, 0xb2,
0x95, 0xe4, 0x64, 0xb1, 0x1b, 0x48, 0x36, 0x37, 0xc1, 0x4c, 0xa0, 0x64, 0x0c, 0x49, 0x48, 0xbf,
0x2a, 0x33, 0xf5, 0xc0, 0x84, 0xeb, 0xc4, 0x8d, 0x84, 0xc4, 0x09, 0x6b, 0xd4, 0x00, 0x32, 0x21,
0x66, 0x00, 0xcc, 0xb4, 0x1b, 0x7a, 0x83, 0x81, 0xc7, 0x69, 0xb9, 0xaf, 0x92, 0x87, 0x62, 0x6d,
0xf6, 0xbc, 0xc8, 0x3d, 0x49, 0xce, 0xe1, 0x54, 0x19, 0x03, 0x5d, 0xee, 0x4b, 0x2d, 0xd0, 0x35,
0x8d, 0x2a, 0xcb, 0x04, 0xa6, 0x17, 0x72, 0x26, 0xb3, 0x90, 0xf6, 0xbf, 0x2f, 0x40, 0x4d, 0x63,
0x0b, 0x71, 0xf8, 0x6c, 0x6a, 0x65, 0x0d, 0x22, 0xf1, 0x86, 0xe7, 0xab, 0x41, 0xc8, 0x4d, 0xb3,
0x45, 0x0c, 0x76, 0xa3, 0xb0, 0x1b, 0xec, 0x73, 0x1d, 0xaa, 0x8c, 0xed, 0x3f, 0x44, 0x37, 0x5b,
0x64, 0xff, 0x2b, 0x80, 0xc4, 0x6e, 0x22, 0xb6, 0x9c, 0x60, 0x11, 0xf0, 0xda, 0xe3, 0xea, 0x7b,
0x50, 0x17, 0xd5, 0xe0, 0xfa, 0xe2, 0x80, 0x13, 0xc1, 0x33, 0xd6, 0xde, 0x31, 0x28, 0xe5, 0x97,
0x9b, 0xf2, 0xcb, 0xca, 0x55, 0x5f, 0x4a, 0x4a, 0xfb, 0xa1, 0xca, 0x02, 0x78, 0x18, 0xba, 0xa3,
0x33, 0xa9, 0x4c, 0xee, 0xc2, 0x82, 0xd4, 0x19, 0x63, 0xdf, 0xf5, 0xfd, 0x60, 0xec, 0x77, 0xa9,
0x4c, 0xe1, 0xca, 0x43, 0xd9, 0x3d, 0x95, 0xf0, 0x8b, 0x15, 0x91, 0x35, 0x28, 0x73, 0x5b, 0x82,
0x6f, 0x5e, 0xf9, 0xea, 0x83, 0x93, 0x90, 0x3b, 0x50, 0xe6, 0x26, 0x45, 0x61, 0xa2, 0xc0, 0x73,
0x02, 0x7b, 0x0d, 0xe6, 0x30, 0x9f, 0xdb, 0xd4, 0x7b, 0xe6, 0xc6, 0x37, 0xdd, 0xc5, 0x8c, 0x6f,
0x7b, 0x11, 0xc8, 0x21, 0x97, 0x27, 0xfd, 0x2c, 0xef, 0xd7, 0x45, 0xa8, 0x69, 0x60, 0xa6, 0x97,
0xf0, 0x00, 0xa6, 0xd3, 0xf3, 0xdc, 0x21, 0x8d, 0x69, 0x28, 0x64, 0x28, 0x05, 0x65, 0x74, 0xee,
0x79, 0xbf, 0x13, 0x8c, 0xe3, 0x4e, 0x8f, 0xf6, 0x43, 0xca, 0xb7, 0x73, 0xb6, 0x37, 0x1a, 0x50,
0x46, 0xc7, 0xb8, 0x58, 0xa3, 0xe3, 0x47, 0x26, 0x29, 0xa8, 0x3c, 0x99, 0xe3, 0x73, 0x54, 0x4a,
0x4e, 0xe6, 0xf8, 0x8c, 0xa4, 0x35, 0x6a, 0x39, 0x47, 0xa3, 0x7e, 0x0c, 0xcb, 0x5c, 0x77, 0x0a,
0xad, 0xd1, 0x49, 0x31, 0xd6, 0x04, 0x2c, 0x59, 0x83, 0x26, 0xeb, 0xb3, 0x14, 0x8b, 0xc8, 0xfb,
0x9a, 0xcb, 0x96, 0xe5, 0x64, 0xe0, 0x8c, 0x16, 0xc3, 0xc5, 0x3a, 0x2d, 0x4f, 0x8f, 0xc8, 0xc0,
0x91, 0xd6, 0x7d, 0x69, 0xd2, 0x56, 0x05, 0x6d, 0x0a, 0x4e, 0xee, 0xc1, 0xca, 0x90, 0xf6, 0x3c,
0xd7, 0xac, 0x02, 0xa3, 0x37, 0x3c, 0xeb, 0x6a, 0x12, 0x9a, 0xb5, 0xc2, 0x66, 0xe1, 0xeb, 0x60,
0x78, 0xe2, 0xf1, 0x0d, 0x8d, 0x07, 0xb6, 0x4b, 0x4e, 0x06, 0x6e, 0xcf, 0x42, 0xed, 0x38, 0x0e,
0x46, 0x72, 0xe9, 0x1b, 0x50, 0xe7, 0x45, 0x91, 0xb0, 0xf7, 0x16, 0x5c, 0x43, 0x5e, 0x7d, 0x1a,
0x8c, 0x82, 0x41, 0xd0, 0xbf, 0x34, 0xdc, 0xd3, 0xff, 0x68, 0xc1, 0x82, 0x81, 0x4d, 0xfc, 0x53,
0x8c, 0xa5, 0xc9, 0x4c, 0x2b, 0xce, 0xde, 0xf3, 0xda, 0x76, 0xc0, 0x09, 0xf9, 0xb1, 0xc5, 0x33,
0x91, 0x7c, 0xb5, 0x95, 0x5c, 0xc0, 0x92, 0x1f, 0x72, 0x5e, 0x6f, 0x65, 0x79, 0x5d, 0x7c, 0x2f,
0xef, 0x5f, 0xc9, 0x2a, 0xfe, 0x50, 0x24, 0xb3, 0xf4, 0xc4, 0xa0, 0x8b, 0x66, 0x02, 0x82, 0x1e,
0xce, 0x90, 0x3d, 0xe8, 0x2a, 0x60, 0x64, 0xff, 0xd4, 0x02, 0x48, 0x7a, 0x87, 0x29, 0x10, 0x6a,
0x4b, 0xe3, 0x97, 0xfd, 0xb4, 0xed, 0xeb, 0x5d, 0xa8, 0xab, 0x53, 0xec, 0x64, 0x97, 0xac, 0x49,
0x18, 0xb3, 0x2a, 0x6e, 0xc3, 0x5c, 0x7f, 0x10, 0x9c, 0xa0, 0xf5, 0x82, 0x19, 0xa0, 0x91, 0x48,
0x5b, 0x6c, 0x70, 0xf0, 0x03, 0x01, 0x4d, 0xb6, 0xd4, 0x92, 0xbe, 0xa5, 0xe6, 0x6f, 0x90, 0x7f,
0xb3, 0xa0, 0x8e, 0x12, 0x93, 0x99, 0x98, 0x28, 0xe1, 0x64, 0x33, 0xa3, 0xce, 0x27, 0x9c, 0xdc,
0xa1, 0x65, 0x7e, 0x74, 0x65, 0x64, 0xf3, 0x3e, 0x34, 0x42, 0xae, 0x2b, 0xa5, 0x22, 0x2d, 0xbd,
0x46, 0x91, 0xce, 0x86, 0xc6, 0x6e, 0xfc, 0x1e, 0x34, 0xdd, 0xde, 0x39, 0x0d, 0x63, 0x0f, 0x23,
0x3d, 0x68, 0x3a, 0xf1, 0xc1, 0xcd, 0x69, 0x70, 0xb4, 0x50, 0x6e, 0xc3, 0x9c, 0x48, 0x20, 0x55,
0x94, 0xe2, 0xda, 0x4c, 0x02, 0x66, 0x84, 0xf6, 0xcf, 0xe4, 0xa9, 0xa5, 0xb9, 0xb2, 0x93, 0x67,
0x44, 0x1f, 0x5d, 0x21, 0x35, 0xba, 0xef, 0x89, 0x13, 0xc4, 0x9e, 0x0c, 0x27, 0x15, 0xb5, 0x74,
0xa8, 0x9e, 0x38, 0xf1, 0x35, 0xa7, 0xb4, 0xf4, 0x26, 0x53, 0x6a, 0xff, 0xd2, 0x82, 0x99, 0xfd,
0x60, 0xb4, 0x2f, 0x12, 0xc3, 0x50, 0x3c, 0x54, 0xe6, 0xb6, 0x2c, 0xbe, 0x26, 0x65, 0x2c, 0xd7,
0x02, 0x99, 0x4d, 0x5b, 0x20, 0x7f, 0x16, 0xde, 0xc2, 0x60, 0x66, 0x18, 0x8c, 0x82, 0x90, 0x89,
0xa8, 0x3b, 0xe0, 0xe6, 0x46, 0xe0, 0xc7, 0x67, 0x52, 0x85, 0xbe, 0x8e, 0x04, 0x23, 0x0c, 0xcc,
0x71, 0xe6, 0x7e, 0x89, 0xb0, 0x98, 0xb8, 0x66, 0xcd, 0x22, 0xec, 0x3f, 0x80, 0x2a, 0x7a, 0x13,
0x38, 0xac, 0x0f, 0xa0, 0x7a, 0x16, 0x8c, 0x3a, 0x67, 0x9e, 0x1f, 0x4b, 0x91, 0x6f, 0x24, 0x66,
0xfe, 0x3e, 0x4e, 0x88, 0x22, 0xb0, 0xff, 0xee, 0x34, 0xcc, 0x3c, 0xf2, 0xcf, 0x03, 0xaf, 0x8b,
0x27, 0xa4, 0x43, 0x3a, 0x0c, 0x64, 0x1e, 0x3b, 0xfb, 0x4d, 0xae, 0xc3, 0x0c, 0x26, 0x6e, 0x8e,
0x38, 0xd3, 0xd6, 0x79, 0x26, 0x84, 0x00, 0xe1, 0x7d, 0xb6, 0xe4, 0x36, 0x11, 0x17, 0x2a, 0x0d,
0xc2, 0xfc, 0xac, 0x50, 0xbf, 0x0d, 0x24, 0x4a, 0xc9, 0x3d, 0x81, 0xb2, 0x76, 0x4f, 0x80, 0xb5,
0x25, 0x12, 0xd9, 0x78, 0xa6, 0x13, 0x6f, 0x4b, 0x80, 0xd0, 0x37, 0x0c, 0x29, 0x0f, 0x46, 0x2b,
0x23, 0x8b, 0xf9, 0x86, 0x3a, 0x90, 0x19, 0x62, 0xfc, 0x03, 0x4e, 0xc3, 0x37, 0x00, 0x1d, 0xc4,
0x4c, 0xd1, 0xf4, 0x45, 0x30, 0x7e, 0x11, 0x2f, 0x0d, 0x66, 0xfa, 0xbb, 0x47, 0x95, 0x9a, 0xe5,
0xe3, 0x00, 0x7e, 0x63, 0x2a, 0x0d, 0xd7, 0x3c, 0x4a, 0x9e, 0x63, 0x2b, 0x3d, 0x4a, 0xc6, 0x30,
0xee, 0x60, 0x70, 0xe2, 0x76, 0x5f, 0xe0, 0x3d, 0x40, 0x3c, 0xb3, 0xac, 0x3a, 0x26, 0x10, 0xd3,
0xd1, 0x92, 0x55, 0xc5, 0x9c, 0x91, 0x92, 0xa3, 0x83, 0xc8, 0x26, 0xd4, 0xd0, 0x8b, 0x16, 0xeb,
0xda, 0xc0, 0x75, 0x6d, 0xea, 0x6e, 0x36, 0xae, 0xac, 0x4e, 0xa4, 0x9f, 0xde, 0xce, 0x65, 0xb2,
0x5e, 0xdd, 0x5e, 0x4f, 0x1c, 0x7a, 0x37, 0x79, 0x44, 0x40, 0x01, 0xd8, 0x8e, 0x2e, 0x26, 0x8c,
0x13, 0xcc, 0x23, 0x81, 0x01, 0x23, 0x37, 0xa0, 0xc2, 0x3c, 0xbc, 0x91, 0xeb, 0xf5, 0x30, 0x4d,
0x84, 0x3b, 0x9a, 0x0a, 0xc6, 0xea, 0x90, 0xbf, 0x71, 0xab, 0x5c, 0xc0, 0x59, 0x31, 0x60, 0x6c,
0x6e, 0x54, 0x79, 0x98, 0xa4, 0xc9, 0x9a, 0x40, 0xf2, 0x21, 0x1e, 0x3d, 0xc6, 0x14, 0x73, 0x61,
0x1b, 0x9b, 0x6f, 0x89, 0x31, 0x0b, 0xa6, 0x95, 0x7f, 0x8f, 0x19, 0x89, 0xc3, 0x29, 0xed, 0x2d,
0xa8, 0xeb, 0x60, 0x52, 0x81, 0xd2, 0x93, 0xa3, 0xbd, 0xc3, 0xe6, 0x14, 0xa9, 0xc1, 0xcc, 0xf1,
0xde, 0xd3, 0xa7, 0x07, 0x7b, 0xbb, 0x4d, 0x8b, 0xd4, 0xa1, 0xa2, 0x72, 0x07, 0x0b, 0xac, 0xb4,
0xb5, 0xb3, 0xb3, 0x77, 0xf4, 0x74, 0x6f, 0xb7, 0x59, 0xb4, 0x63, 0x20, 0x5b, 0xbd, 0x9e, 0xa8,
0x45, 0xc5, 0x39, 0x12, 0x7e, 0xb6, 0x0c, 0x7e, 0xce, 0xe1, 0xa9, 0x42, 0x3e, 0x4f, 0xbd, 0x76,
0xe6, 0xed, 0x3d, 0xa8, 0x1d, 0x69, 0x97, 0xde, 0x50, 0xbc, 0xe4, 0x75, 0x37, 0x21, 0x96, 0x1a,
0x44, 0xeb, 0x4e, 0x41, 0xef, 0x8e, 0xfd, 0x4f, 0x2d, 0x7e, 0xfb, 0x44, 0x75, 0x9f, 0xb7, 0x6d,
0x43, 0x5d, 0x45, 0xfb, 0x92, 0xb4, 0x60, 0x03, 0xc6, 0x68, 0xb0, 0x2b, 0x9d, 0xe0, 0xf4, 0x34,
0xa2, 0x32, 0x89, 0xcf, 0x80, 0x49, 0xbb, 0x86, 0x59, 0x4a, 0x1e, 0x6f, 0x21, 0x12, 0xc9, 0x7c,
0x19, 0x38, 0xd3, 0xf2, 0x22, 0xa6, 0x24, 0xd3, 0x17, 0x55, 0x59, 0x65, 0x2f, 0xa7, 0x67, 0x79,
0x0d, 0x2a, 0xaa, 0x5e, 0x53, 0x81, 0x49, 0x4a, 0x85, 0x67, 0x8a, 0x12, 0xfd, 0x1d, 0xa3, 0xd3,
0x5c, 0x69, 0x67, 0x11, 0x64, 0x1d, 0xc8, 0xa9, 0x17, 0xa6, 0xc9, 0x8b, 0x48, 0x9e, 0x83, 0xb1,
0x9f, 0xc3, 0x82, 0x64, 0x24, 0xcd, 0xe0, 0x32, 0x17, 0xd1, 0xba, 0x4a, 0x7c, 0x0a, 0x59, 0xf1,
0xb1, 0x7f, 0x55, 0x84, 0x19, 0xb1, 0xd2, 0x99, 0x8b, 0x93, 0x7c, 0x9d, 0x0d, 0x18, 0x69, 0x19,
0x17, 0xab, 0x50, 0xd6, 0x84, 0xd2, 0xcc, 0xa8, 0xc5, 0x62, 0x9e, 0x5a, 0x24, 0x50, 0x1a, 0xb9,
0xf1, 0x19, 0x46, 0x04, 0xaa, 0x0e, 0xfe, 0x96, 0xa1, 0xb1, 0xb2, 0x19, 0x1a, 0xcb, 0xbb, 0x26,
0xca, 0x77, 0xfc, 0xec, 0x35, 0xd1, 0xeb, 0x50, 0xc5, 0x4e, 0x68, 0x47, 0x99, 0x09, 0x80, 0x71,
0x2f, 0x2f, 0xa0, 0x6c, 0x8b, 0x7b, 0x0e, 0x09, 0xe4, 0x3b, 0x28, 0xe2, 0x8f, 0x60, 0x9a, 0x27,
0xda, 0x8b, 0x24, 0xcd, 0xeb, 0xf2, 0x38, 0x87, 0xd3, 0xc9, 0xbf, 0x3c, 0xdb, 0xc3, 0x11, 0xb4,
0xfa, 0x35, 0xbd, 0x9a, 0x79, 0x4d, 0x4f, 0x0f, 0xda, 0xd5, 0xcd, 0xa0, 0x9d, 0xfd, 0x00, 0x66,
0x8d, 0xea, 0x98, 0xca, 0x10, 0x49, 0x9e, 0xcd, 0x29, 0x32, 0x0b, 0xd5, 0x47, 0x87, 0x9d, 0x07,
0x07, 0x8f, 0x1e, 0xee, 0x3f, 0x6d, 0x5a, 0xac, 0x78, 0xfc, 0x6c, 0x67, 0x67, 0x6f, 0x6f, 0x17,
0x55, 0x08, 0xc0, 0xf4, 0x83, 0xad, 0x47, 0x07, 0xa8, 0x40, 0x76, 0x39, 0x6f, 0x8b, 0xba, 0x54,
0x08, 0xfd, 0xf7, 0x81, 0x48, 0x97, 0x14, 0x93, 0x3d, 0x46, 0x03, 0x1a, 0xcb, 0xfc, 0xe3, 0x79,
0x81, 0x79, 0xa4, 0x10, 0x32, 0x7d, 0x3e, 0xa9, 0x25, 0x11, 0x11, 0x31, 0x49, 0x69, 0x11, 0x11,
0xa4, 0x8e, 0xc2, 0xdb, 0x6d, 0x68, 0xed, 0x52, 0x56, 0xdb, 0xd6, 0x60, 0x90, 0xea, 0x0e, 0xf3,
0x2b, 0x72, 0x70, 0xc2, 0xe9, 0xf8, 0x21, 0x2c, 0x6d, 0xf1, 0x54, 0xe3, 0xdf, 0x55, 0x26, 0x9a,
0xdd, 0x82, 0xe5, 0x74, 0x95, 0xa2, 0xb1, 0x07, 0x30, 0xbf, 0x4b, 0x4f, 0xc6, 0xfd, 0x03, 0x7a,
0x9e, 0x34, 0x44, 0xa0, 0x14, 0x9d, 0x05, 0x17, 0x62, 0x7e, 0xf0, 0x37, 0x79, 0x1b, 0x60, 0xc0,
0x68, 0x3a, 0xd1, 0x88, 0x76, 0xe5, 0xe5, 0x2e, 0x84, 0x1c, 0x8f, 0x68, 0xd7, 0xfe, 0x18, 0x88,
0x5e, 0x8f, 0x98, 0x2f, 0x66, 0x16, 0x8c, 0x4f, 0x3a, 0xd1, 0x65, 0x14, 0xd3, 0xa1, 0xbc, 0xb5,
0xa6, 0x83, 0xec, 0xdb, 0x50, 0x3f, 0x72, 0x2f, 0x1d, 0xfa, 0x95, 0xb8, 0x40, 0xbc, 0x02, 0x33,
0x23, 0xf7, 0x92, 0xb1, 0xa0, 0x8a, 0x51, 0x22, 0xda, 0xfe, 0x3f, 0x05, 0x98, 0xe6, 0x94, 0xac,
0xd6, 0x1e, 0x8d, 0x62, 0xcf, 0x47, 0x49, 0x93, 0xb5, 0x6a, 0xa0, 0x8c, 0x6c, 0x17, 0x72, 0x64,
0x5b, 0x38, 0xd0, 0xf2, 0xa2, 0x8c, 0x10, 0x60, 0x03, 0xc6, 0x24, 0x2d, 0x49, 0x29, 0xe5, 0x91,
0xac, 0x04, 0x90, 0x0a, 0x67, 0x27, 0xc6, 0x07, 0xef, 0x9f, 0x54, 0x5b, 0x42, 0x8c, 0x75, 0x50,
0xae, 0x89, 0x33, 0xc3, 0xa5, 0x3d, 0x63, 0xe2, 0x64, 0x4c, 0x99, 0xca, 0x1b, 0x98, 0x32, 0xdc,
0xab, 0x7e, 0x9d, 0x29, 0x03, 0x6f, 0x60, 0xca, 0xd8, 0x04, 0x9a, 0x78, 0x03, 0x97, 0x19, 0xcb,
0x92, 0x77, 0xff, 0x81, 0x05, 0x4d, 0xc1, 0x45, 0x0a, 0x47, 0xde, 0x35, 0x9c, 0x82, 0xdc, 0x0b,
0x21, 0x37, 0x61, 0x16, 0x4d, 0x75, 0xa5, 0x02, 0xc4, 0x21, 0x83, 0x01, 0x64, 0xe3, 0x90, 0x09,
0x09, 0x43, 0x6f, 0x20, 0x16, 0x45, 0x07, 0x49, 0x2d, 0x12, 0xba, 0x22, 0x35, 0xd2, 0x72, 0x54,
0xd9, 0xfe, 0x85, 0x05, 0xf3, 0x5a, 0x87, 0x05, 0x17, 0xde, 0x07, 0x29, 0x0d, 0x3c, 0x88, 0xcf,
0x25, 0x77, 0xc5, 0x14, 0x9b, 0xe4, 0x33, 0x83, 0x18, 0x17, 0xd3, 0xbd, 0xc4, 0x0e, 0x46, 0xe3,
0xa1, 0xd8, 0x55, 0x74, 0x10, 0x63, 0xa4, 0x0b, 0x4a, 0x5f, 0x28, 0x12, 0xbe, 0xaf, 0x19, 0x30,
0x0c, 0x67, 0x32, 0x17, 0x43, 0x11, 0x95, 0x44, 0x38, 0x53, 0x07, 0xda, 0xff, 0xc5, 0x82, 0x05,
0xee, 0x2b, 0x0a, 0xff, 0x5c, 0xdd, 0x35, 0x9c, 0xe6, 0x2e, 0x33, 0x97, 0xc8, 0xfd, 0x29, 0x47,
0x94, 0xc9, 0x0f, 0xde, 0xd0, 0xbf, 0x55, 0xf9, 0x9a, 0x13, 0xd6, 0xa2, 0x98, 0xb7, 0x16, 0xaf,
0x99, 0xe9, 0xbc, 0xc8, 0x72, 0x39, 0x37, 0xb2, 0xbc, 0x3d, 0x03, 0xe5, 0xa8, 0x1b, 0x8c, 0xa8,
0xbd, 0x0c, 0x8b, 0xe6, 0xe0, 0x84, 0x0a, 0xfa, 0xa9, 0x05, 0xad, 0x07, 0xfc, 0x70, 0xc7, 0xf3,
0xfb, 0xfb, 0x5e, 0x14, 0x07, 0xa1, 0xba, 0x92, 0x7d, 0x03, 0x20, 0x8a, 0xdd, 0x30, 0xe6, 0x57,
0x09, 0x44, 0xbc, 0x36, 0x81, 0xb0, 0x3e, 0x52, 0xbf, 0xc7, 0xb1, 0x7c, 0x6d, 0x54, 0x39, 0x63,
0x54, 0x09, 0x6f, 0xd6, 0x30, 0x4d, 0x6e, 0xf1, 0xfc, 0x65, 0x66, 0x3c, 0xd1, 0x73, 0xd4, 0xeb,
0xdc, 0x4d, 0x4c, 0x41, 0xed, 0xff, 0x6c, 0xc1, 0x5c, 0xd2, 0x49, 0x3c, 0x67, 0x37, 0xb5, 0x83,
0xb0, 0x47, 0x12, 0xed, 0x20, 0x23, 0xc9, 0x1e, 0x33, 0x50, 0x44, 0xdf, 0x34, 0x08, 0x4a, 0xac,
0x28, 0x05, 0x63, 0x69, 0xf1, 0xe9, 0x20, 0x9e, 0x8d, 0xc8, 0x4c, 0x23, 0x61, 0xe6, 0x89, 0x12,
0xde, 0x04, 0x19, 0xc6, 0xf8, 0x15, 0x8f, 0x8a, 0xcb, 0x22, 0x69, 0x72, 0xdb, 0x62, 0x06, 0xa1,
0x68, 0x57, 0xe8, 0x7b, 0x6e, 0x85, 0xcf, 0x8f, 0xda, 0x73, 0xff, 0x96, 0x05, 0xd7, 0x72, 0x26,
0x5e, 0x48, 0xcd, 0x2e, 0xcc, 0x9f, 0x2a, 0xa4, 0x9c, 0x1c, 0x2e, 0x3a, 0xcb, 0xf2, 0xa0, 0xd8,
0x9c, 0x10, 0x27, 0xfb, 0x81, 0x32, 0x14, 0xf9, 0x74, 0x1b, 0xf9, 0xbe, 0x59, 0x84, 0x7d, 0x04,
0xed, 0xbd, 0x97, 0x4c, 0x08, 0x77, 0xf4, 0x97, 0x85, 0x24, 0x2f, 0x6c, 0x66, 0x94, 0xcc, 0xd5,
0x91, 0x87, 0x53, 0x98, 0x35, 0xea, 0x22, 0xdf, 0x7f, 0xd3, 0x4a, 0x74, 0x79, 0x91, 0x6b, 0xc5,
0x9f, 0x46, 0x92, 0x59, 0xc7, 0x1a, 0xc8, 0x3e, 0x87, 0xb9, 0xc7, 0xe3, 0x41, 0xec, 0x25, 0xcf,
0x24, 0x91, 0x1f, 0x88, 0x8f, 0xb0, 0x0a, 0x39, 0x75, 0xb9, 0x4d, 0xe9, 0x74, 0x6c, 0xc6, 0x86,
0xac, 0xa6, 0x4e, 0xb6, 0xc5, 0x2c, 0xc2, 0xbe, 0x06, 0x2b, 0x49, 0x93, 0x7c, 0xee, 0xa4, 0xa2,
0xfe, 0x99, 0xc5, 0xd3, 0x67, 0xcc, 0x57, 0x9b, 0xc8, 0x43, 0x58, 0x88, 0x3c, 0xbf, 0x3f, 0xa0,
0x7a, 0x3d, 0x91, 0x98, 0x89, 0x25, 0xb3, 0x7b, 0xe2, 0x65, 0x27, 0x27, 0xef, 0x0b, 0xc6, 0x20,
0xf9, 0x1d, 0x4d, 0x18, 0x24, 0x35, 0x25, 0x79, 0x03, 0xf8, 0x14, 0x1a, 0x66, 0x63, 0xe4, 0x9e,
0x48, 0x18, 0x4e, 0x7a, 0xa6, 0x1f, 0x0f, 0x98, 0x9c, 0x61, 0x50, 0xda, 0xdf, 0x5a, 0xd0, 0x72,
0x28, 0x63, 0x63, 0xaa, 0x35, 0x2a, 0xb8, 0xe7, 0x7e, 0xa6, 0xda, 0xc9, 0x03, 0x56, 0x89, 0xc8,
0x72, 0xac, 0xeb, 0x13, 0x17, 0x65, 0x7f, 0x2a, 0x67, 0x54, 0xdb, 0x15, 0x98, 0x16, 0xe3, 0x5b,
0x81, 0x25, 0xd1, 0x25, 0xd9, 0x9d, 0x24, 0xb6, 0x6c, 0x34, 0x6a, 0xc4, 0x96, 0xdb, 0xd0, 0xe2,
0x77, 0xe5, 0xf5, 0x71, 0xf0, 0x0f, 0xd7, 0x5e, 0x41, 0x4d, 0x7b, 0x31, 0x80, 0xac, 0xc0, 0xc2,
0xf3, 0x47, 0x4f, 0x0f, 0xf7, 0x8e, 0x8f, 0x3b, 0x47, 0xcf, 0xb6, 0x3f, 0xdb, 0xfb, 0xbc, 0xb3,
0xbf, 0x75, 0xbc, 0xdf, 0x9c, 0x22, 0xcb, 0x40, 0x0e, 0xf7, 0x8e, 0x9f, 0xee, 0xed, 0x1a, 0x70,
0x8b, 0xdc, 0x80, 0xf6, 0xb3, 0xc3, 0x67, 0xc7, 0x7b, 0xbb, 0x9d, 0xbc, 0xef, 0x0a, 0xe4, 0x6d,
0xb8, 0x26, 0xf0, 0x39, 0x9f, 0x17, 0x37, 0xbf, 0x2d, 0x42, 0x83, 0x67, 0xf1, 0xf0, 0xc7, 0xbe,
0x68, 0x48, 0x1e, 0xc3, 0x8c, 0x78, 0x35, 0x8e, 0xc8, 0xf9, 0x34, 0xdf, 0xa9, 0x6b, 0x2f, 0xa7,
0xc1, 0x62, 0x12, 0x16, 0xfe, 0xd2, 0x2f, 0xff, 0xc7, 0xdf, 0x29, 0xcc, 0x92, 0xda, 0xc6, 0xf9,
0x87, 0x1b, 0x7d, 0xea, 0x47, 0xac, 0x8e, 0x3f, 0x06, 0x48, 0xde, 0x42, 0x23, 0x2d, 0xe5, 0x84,
0xa6, 0x1e, 0x8a, 0x6b, 0x5f, 0xcb, 0xc1, 0x88, 0x7a, 0xaf, 0x61, 0xbd, 0x0b, 0x76, 0x83, 0xd5,
0xeb, 0xf9, 0x5e, 0xcc, 0xdf, 0x45, 0xfb, 0xc4, 0x5a, 0x23, 0x3d, 0xa8, 0xeb, 0xaf, 0x94, 0x11,
0x19, 0x1f, 0xcf, 0x79, 0x67, 0xad, 0xfd, 0x56, 0x2e, 0x4e, 0x2e, 0x20, 0xb6, 0xb1, 0x64, 0x37,
0x59, 0x1b, 0x63, 0xa4, 0x48, 0x5a, 0x19, 0x70, 0xb6, 0x4e, 0x1e, 0x23, 0x23, 0xd7, 0x35, 0x4e,
0xcb, 0x3c, 0x85, 0xd6, 0x7e, 0x7b, 0x02, 0x56, 0xb4, 0xf5, 0x36, 0xb6, 0xb5, 0x62, 0x13, 0xd6,
0x56, 0x17, 0x69, 0xe4, 0x53, 0x68, 0x9f, 0x58, 0x6b, 0x9b, 0x7f, 0xef, 0x16, 0x54, 0xd5, 0xb9,
0x19, 0xf9, 0x12, 0x66, 0x8d, 0x34, 0x2b, 0x22, 0x87, 0x91, 0x97, 0x95, 0xd5, 0xbe, 0x9e, 0x8f,
0x14, 0x0d, 0xdf, 0xc0, 0x86, 0x5b, 0x64, 0x99, 0x35, 0x2c, 0xf2, 0x94, 0x36, 0x30, 0x61, 0x90,
0xdf, 0x37, 0x7a, 0xa1, 0x89, 0x2f, 0x6f, 0xec, 0x7a, 0x5a, 0xa2, 0x8c, 0xd6, 0xde, 0x9e, 0x80,
0x15, 0xcd, 0x5d, 0xc7, 0xe6, 0x96, 0xc9, 0xa2, 0xde, 0x9c, 0x3a, 0xcf, 0xa2, 0x78, 0xc9, 0x4e,
0x7f, 0xa7, 0x8b, 0xbc, 0xad, 0x18, 0x2b, 0xef, 0xfd, 0x2e, 0xc5, 0x22, 0xd9, 0x47, 0xbc, 0xec,
0x16, 0x36, 0x45, 0x08, 0x2e, 0x9f, 0xfe, 0x4c, 0x17, 0x39, 0x81, 0x9a, 0xf6, 0xfe, 0x0c, 0xb9,
0x36, 0xf1, 0xad, 0x9c, 0x76, 0x3b, 0x0f, 0x95, 0x37, 0x14, 0xbd, 0xfe, 0x0d, 0xb6, 0x2f, 0xff,
0x18, 0xaa, 0xea, 0x45, 0x13, 0xb2, 0xa2, 0xbd, 0x30, 0xa3, 0xbf, 0xc0, 0xd2, 0x6e, 0x65, 0x11,
0x79, 0xcc, 0xa7, 0xd7, 0xce, 0x98, 0xef, 0x39, 0xd4, 0xb4, 0x57, 0x4b, 0xd4, 0x00, 0xb2, 0x2f,
0xa3, 0xa8, 0x01, 0xe4, 0x3c, 0x72, 0x62, 0xcf, 0x63, 0x13, 0x35, 0x52, 0x45, 0xfe, 0x8e, 0x5f,
0x06, 0x11, 0x39, 0x80, 0x25, 0xa1, 0xa6, 0x4e, 0xe8, 0x77, 0x59, 0x86, 0x9c, 0xa7, 0xd1, 0xee,
0x5a, 0xe4, 0x3e, 0x54, 0xe4, 0xe3, 0x34, 0x64, 0x39, 0xff, 0x91, 0x9d, 0xf6, 0x4a, 0x06, 0x2e,
0xcc, 0x93, 0xcf, 0x01, 0x92, 0x27, 0x52, 0x94, 0x92, 0xc8, 0x3c, 0xb9, 0xa2, 0x38, 0x20, 0xfb,
0x9e, 0x8a, 0xbd, 0x8c, 0x03, 0x6c, 0x12, 0x54, 0x12, 0x3e, 0xbd, 0x90, 0xf7, 0x69, 0x7f, 0x02,
0x35, 0xed, 0x95, 0x14, 0x35, 0x7d, 0xd9, 0x17, 0x56, 0xd4, 0xf4, 0xe5, 0x3c, 0xaa, 0x62, 0xb7,
0xb1, 0xf6, 0x45, 0x7b, 0x8e, 0xd5, 0x1e, 0x79, 0x7d, 0x7f, 0xc8, 0x09, 0xd8, 0x02, 0x9d, 0xc1,
0xac, 0xf1, 0x14, 0x8a, 0x92, 0xd0, 0xbc, 0x87, 0x56, 0x94, 0x84, 0xe6, 0xbe, 0x9e, 0x22, 0xf9,
0xcc, 0x9e, 0x67, 0xed, 0x9c, 0x23, 0x89, 0xd6, 0xd2, 0x17, 0x50, 0xd3, 0x9e, 0x35, 0x51, 0x63,
0xc9, 0xbe, 0xa0, 0xa2, 0xc6, 0x92, 0xf7, 0x0a, 0xca, 0x22, 0xb6, 0xd1, 0xb0, 0x91, 0x15, 0xf0,
0x66, 0x28, 0xab, 0xfb, 0x4b, 0x68, 0x98, 0x0f, 0x9d, 0x28, 0xd9, 0xcf, 0x7d, 0x32, 0x45, 0xc9,
0xfe, 0x84, 0xd7, 0x51, 0x04, 0x4b, 0xaf, 0x2d, 0xa8, 0x46, 0x36, 0xbe, 0x11, 0x59, 0x37, 0xaf,
0xc8, 0x0f, 0x99, 0x82, 0x13, 0x57, 0x75, 0xc9, 0x8a, 0xc6, 0xb5, 0xfa, 0x85, 0x5e, 0x25, 0x2f,
0x99, 0x5b, 0xbd, 0x26, 0x33, 0xf3, 0xbb, 0xad, 0xb8, 0x6b, 0xe1, 0x95, 0x5d, 0x6d, 0xd7, 0xd2,
0x6f, 0xf5, 0x6a, 0xbb, 0x96, 0x71, 0xb3, 0x37, 0xbd, 0x6b, 0xc5, 0x1e, 0xab, 0xc3, 0x87, 0xb9,
0x54, 0x2a, 0xb8, 0x92, 0x8a, 0xfc, 0xdb, 0x3a, 0xed, 0x1b, 0xaf, 0xcf, 0x20, 0x37, 0x35, 0x88,
0x54, 0x82, 0x1b, 0xf2, 0x6e, 0xd4, 0x9f, 0x87, 0xba, 0xfe, 0xc4, 0x03, 0xd1, 0x45, 0x39, 0xdd,
0xd2, 0x5b, 0xb9, 0x38, 0x73, 0x71, 0x49, 0x5d, 0x6f, 0x86, 0xfc, 0x08, 0x96, 0x95, 0xa8, 0xeb,
0xd9, 0xc5, 0x11, 0x79, 0x27, 0x27, 0xe7, 0x58, 0x37, 0x5e, 0xda, 0xd7, 0x26, 0x26, 0x25, 0xdf,
0xb5, 0x18, 0xd3, 0x98, 0x77, 0xe7, 0x93, 0x0d, 0x23, 0xef, 0xc9, 0x80, 0x64, 0xc3, 0xc8, 0xbd,
0x70, 0x2f, 0x99, 0x86, 0x2c, 0x18, 0x73, 0xc4, 0x0f, 0x2c, 0xc9, 0x17, 0x30, 0xa7, 0xdd, 0xdf,
0x38, 0xbe, 0xf4, 0xbb, 0x4a, 0x00, 0xb2, 0x57, 0x0b, 0xdb, 0x79, 0xa6, 0xb9, 0xbd, 0x82, 0xf5,
0xcf, 0xdb, 0xc6, 0xe4, 0x30, 0xe6, 0xdf, 0x81, 0x9a, 0x7e, 0x37, 0xe4, 0x35, 0xf5, 0xae, 0x68,
0x28, 0xfd, 0x66, 0xdc, 0x5d, 0x8b, 0xfc, 0x43, 0x0b, 0xea, 0xc6, 0x4d, 0x0b, 0xe3, 0xb0, 0x3e,
0x55, 0x4f, 0x4b, 0xc7, 0xe9, 0x15, 0xd9, 0x0e, 0x76, 0xf2, 0x60, 0xed, 0x53, 0x63, 0x12, 0xbe,
0x31, 0xe2, 0x2f, 0xeb, 0xe9, 0x07, 0xf1, 0x5e, 0xa5, 0x09, 0xf4, 0xeb, 0x97, 0xaf, 0xee, 0x5a,
0xe4, 0xe7, 0x16, 0x34, 0xcc, 0xa8, 0xa1, 0x5a, 0xaa, 0xdc, 0xf8, 0xa4, 0x5a, 0xaa, 0x09, 0xa1,
0xc6, 0x2f, 0xb0, 0x97, 0x4f, 0xd7, 0x1c, 0xa3, 0x97, 0xe2, 0x55, 0x85, 0xdf, 0xae, 0xb7, 0xe4,
0x13, 0xfe, 0x1e, 0xa6, 0x8c, 0xed, 0x13, 0x6d, 0xd7, 0x48, 0x2f, 0xaf, 0xfe, 0x86, 0xe3, 0x1d,
0xeb, 0xae, 0x45, 0x7e, 0xc2, 0x1f, 0x82, 0x93, 0xe1, 0x67, 0xc6, 0x25, 0x6f, 0xfa, 0xbd, 0x7d,
0x13, 0xc7, 0x74, 0xc3, 0xbe, 0x66, 0x8c, 0x29, 0xbd, 0x1f, 0x6f, 0xf1, 0xde, 0x89, 0xe7, 0x17,
0x93, 0x0d, 0x25, 0xf3, 0x24, 0xe3, 0xe4, 0x4e, 0x0e, 0x79, 0x27, 0x05, 0xb9, 0xc1, 0xca, 0x6f,
0x58, 0x8d, 0xbd, 0x86, 0x7d, 0xbd, 0x69, 0xbf, 0x33, 0xb1, 0xaf, 0x1b, 0x18, 0xfb, 0x63, 0x3d,
0x3e, 0x02, 0x48, 0xce, 0xe1, 0x48, 0xea, 0x1c, 0x48, 0x09, 0x78, 0xf6, 0xa8, 0xce, 0x94, 0x17,
0x79, 0x5c, 0xc4, 0x6a, 0xfc, 0x31, 0x57, 0x57, 0x8f, 0xe4, 0x09, 0x92, 0x6e, 0x94, 0x98, 0x07,
0x66, 0x86, 0x51, 0x92, 0xae, 0xdf, 0x50, 0x56, 0xea, 0x38, 0xea, 0x19, 0xcc, 0x1e, 0x04, 0xc1,
0x8b, 0xf1, 0x48, 0x9d, 0xa9, 0x9b, 0x61, 0xf9, 0x7d, 0x37, 0x3a, 0x6b, 0xa7, 0x46, 0x61, 0xaf,
0x62, 0x55, 0x6d, 0xd2, 0xd2, 0xaa, 0xda, 0xf8, 0x26, 0x39, 0xe7, 0x7b, 0x45, 0x5c, 0x98, 0x57,
0x3a, 0x50, 0x75, 0xbc, 0x6d, 0x56, 0x63, 0x68, 0xbe, 0x74, 0x13, 0x86, 0xf5, 0x2c, 0x7b, 0xbb,
0x11, 0xc9, 0x3a, 0xef, 0x5a, 0xe4, 0x08, 0xea, 0xbb, 0xb4, 0x8b, 0x69, 0xe6, 0x18, 0xdb, 0x5e,
0x48, 0x3a, 0xae, 0x82, 0xe2, 0xed, 0x59, 0x03, 0x68, 0xee, 0x0b, 0x23, 0xf7, 0x32, 0xa4, 0x5f,
0x6d, 0x7c, 0x23, 0xa2, 0xe6, 0xaf, 0xe4, 0xbe, 0x20, 0x8f, 0x15, 0x8c, 0x7d, 0x21, 0x75, 0x0e,
0x61, 0xec, 0x0b, 0x99, 0x73, 0x08, 0x63, 0xaa, 0xe5, 0xb1, 0x06, 0x19, 0xc0, 0x7c, 0xe6, 0xe8,
0x42, 0x6d, 0x09, 0x93, 0x0e, 0x3c, 0xda, 0xab, 0x93, 0x09, 0xcc, 0xd6, 0xd6, 0xcc, 0xd6, 0x8e,
0x61, 0x76, 0x97, 0xf2, 0xc9, 0xe2, 0x49, 0x83, 0xa9, 0xeb, 0x3a, 0x7a, 0x4a, 0x62, 0x5a, 0x81,
0x23, 0xce, 0xdc, 0xf8, 0x31, 0x63, 0x8f, 0xfc, 0x18, 0x6a, 0x0f, 0x69, 0x2c, 0xb3, 0x04, 0x95,
0xe9, 0x99, 0x4a, 0x1b, 0x6c, 0xe7, 0x24, 0x19, 0x9a, 0x3c, 0x83, 0xb5, 0x6d, 0xd0, 0x5e, 0x9f,
0x72, 0xe5, 0xd4, 0xf1, 0x7a, 0xaf, 0xc8, 0x9f, 0xc3, 0xca, 0x55, 0x8a, 0xf4, 0xb2, 0x96, 0xf6,
0xa5, 0x57, 0x3e, 0x97, 0x82, 0xe7, 0xd5, 0xec, 0x07, 0x3d, 0xaa, 0x99, 0x40, 0x3e, 0xd4, 0xb4,
0x4b, 0x00, 0x4a, 0x80, 0xb2, 0x17, 0x46, 0x94, 0x00, 0xe5, 0xdc, 0x19, 0xb0, 0xef, 0x60, 0x3b,
0x36, 0x59, 0x4d, 0xda, 0xe1, 0xf7, 0x04, 0x92, 0x96, 0x36, 0xbe, 0x71, 0x87, 0xf1, 0x2b, 0xf2,
0x1c, 0x5f, 0x39, 0xd1, 0x33, 0x21, 0x13, 0x5b, 0x3a, 0x9d, 0x34, 0xa9, 0x26, 0x4b, 0x43, 0x99,
0xf6, 0x35, 0x6f, 0x0a, 0x2d, 0xa5, 0x1f, 0x00, 0x1c, 0xc7, 0xc1, 0x68, 0xd7, 0xa5, 0xc3, 0xc0,
0x4f, 0x74, 0x6d, 0x92, 0x87, 0x97, 0xe8, 0x2f, 0x2d, 0x19, 0x8f, 0x3c, 0xd7, 0x9c, 0x0f, 0x23,
0x91, 0x54, 0x32, 0xd7, 0xc4, 0x54, 0x3d, 0x35, 0x21, 0x39, 0xe9, 0x7a, 0x77, 0x2d, 0xb2, 0x05,
0x90, 0x9c, 0x5d, 0x29, 0x57, 0x22, 0x73, 0x2c, 0xa6, 0xd4, 0x5e, 0xce, 0x41, 0xd7, 0x11, 0x54,
0x93, 0xc3, 0x90, 0x95, 0xe4, 0x1e, 0x8d, 0x71, 0x74, 0xa2, 0x76, 0xf0, 0xcc, 0x11, 0x85, 0xdd,
0xc4, 0xa9, 0x02, 0x52, 0x61, 0x53, 0x85, 0xe7, 0x0e, 0x1e, 0x2c, 0xf0, 0x0e, 0x2a, 0x73, 0x04,
0x73, 0xc8, 0xe4, 0x48, 0x72, 0x8e, 0x09, 0x94, 0x34, 0xe7, 0x46, 0xd9, 0x8d, 0x88, 0x08, 0xe3,
0x56, 0x9e, 0xbf, 0xc6, 0x54, 0xf3, 0x10, 0xe6, 0x33, 0x61, 0x60, 0x25, 0xd2, 0x93, 0x22, 0xf3,
0x4a, 0xa4, 0x27, 0x46, 0x90, 0xed, 0x25, 0x6c, 0x72, 0xce, 0x06, 0xf4, 0x80, 0x2e, 0xbc, 0xb8,
0x7b, 0xc6, 0x9a, 0xfb, 0x99, 0x05, 0x0b, 0x39, 0x51, 0x5e, 0xf2, 0xae, 0x74, 0xa6, 0x27, 0x46,
0x80, 0xdb, 0xb9, 0x41, 0x40, 0xfb, 0x18, 0xdb, 0x79, 0x4c, 0x3e, 0x33, 0x36, 0x36, 0x1e, 0x7f,
0x13, 0x92, 0xf9, 0x5a, 0xa3, 0x22, 0xd7, 0xa2, 0xf8, 0x0a, 0x56, 0x78, 0x47, 0xb6, 0x06, 0x83,
0x54, 0x80, 0xf2, 0x46, 0xe6, 0x49, 0x7c, 0x23, 0xf0, 0xda, 0x9e, 0xfc, 0x64, 0xfe, 0x04, 0x73,
0x95, 0x77, 0x95, 0x8c, 0xa1, 0x99, 0x0e, 0xfa, 0x91, 0xc9, 0x75, 0xb5, 0xdf, 0x31, 0xdc, 0xc2,
0x6c, 0xa0, 0xd0, 0xfe, 0x3d, 0x6c, 0xec, 0x1d, 0xbb, 0x9d, 0x37, 0x2f, 0xdc, 0x53, 0x64, 0xeb,
0xf1, 0x17, 0x55, 0x84, 0x32, 0x35, 0x4e, 0xd9, 0xc0, 0xa4, 0x90, 0xaa, 0x72, 0x4c, 0xf3, 0x03,
0x9c, 0xb7, 0xb0, 0xf9, 0x55, 0xfb, 0xad, 0xbc, 0xe6, 0x43, 0xfe, 0x09, 0x77, 0x51, 0x57, 0xd2,
0x72, 0x2d, 0x7b, 0xb0, 0x9a, 0xb7, 0xde, 0x13, 0x7d, 0x8d, 0xd4, 0x5c, 0x4f, 0xdd, 0xb5, 0xb6,
0x6f, 0x7f, 0xf1, 0x7b, 0x7d, 0x2f, 0x3e, 0x1b, 0x9f, 0xac, 0x77, 0x83, 0xe1, 0xc6, 0x40, 0x86,
0xc8, 0x44, 0xc6, 0xf3, 0xc6, 0xc0, 0xef, 0x6d, 0xe0, 0xf7, 0x27, 0xd3, 0xf8, 0x1f, 0x36, 0xbe,
0xff, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x82, 0x63, 0x17, 0xa9, 0x93, 0x63, 0x00, 0x00,
// 8125 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7d, 0x6d, 0x6c, 0x24, 0xd9,
0xb5, 0x90, 0xab, 0x3f, 0xec, 0xee, 0xd3, 0xed, 0xee, 0xf6, 0xb5, 0xc7, 0xee, 0xe9, 0x9d, 0x9d,
0x9d, 0xad, 0xcc, 0xdb, 0x99, 0x4c, 0xf6, 0xd9, 0xb3, 0x93, 0x64, 0x99, 0xb7, 0xf3, 0xc2, 0xc3,
0x63, 0x7b, 0xc6, 0x93, 0x78, 0x3d, 0x4e, 0xd9, 0x93, 0x21, 0xc9, 0x43, 0x9d, 0x72, 0xf7, 0x75,
0xbb, 0x32, 0xd5, 0x55, 0x9d, 0xaa, 0x6a, 0x7b, 0x3a, 0xcb, 0xf2, 0x03, 0x21, 0x84, 0x9e, 0x84,
0x50, 0x40, 0x20, 0x40, 0x20, 0xa4, 0x04, 0x21, 0x9e, 0xf8, 0x01, 0xfc, 0x00, 0x81, 0x14, 0x89,
0x9f, 0xfc, 0x42, 0x08, 0xbd, 0x9f, 0x48, 0x3c, 0x21, 0x90, 0x50, 0xc4, 0x3f, 0x24, 0xfe, 0xa3,
0x7b, 0xee, 0x47, 0xdd, 0x5b, 0x55, 0x3d, 0x9e, 0x49, 0xc2, 0xfb, 0xe5, 0xbe, 0xe7, 0x9c, 0xba,
0x9f, 0xe7, 0x9c, 0x7b, 0xce, 0xb9, 0xe7, 0x5e, 0x43, 0x3d, 0x9a, 0x0c, 0x36, 0x27, 0x51, 0x98,
0x84, 0xa4, 0xea, 0x07, 0xd1, 0x64, 0xd0, 0xbb, 0x31, 0x0a, 0xc3, 0x91, 0x4f, 0xb7, 0xdc, 0x89,
0xb7, 0xe5, 0x06, 0x41, 0x98, 0xb8, 0x89, 0x17, 0x06, 0x31, 0x27, 0xb2, 0x7f, 0x04, 0xad, 0xa7,
0x34, 0x38, 0xa6, 0x74, 0xe8, 0xd0, 0x9f, 0x4c, 0x69, 0x9c, 0x90, 0xaf, 0xc1, 0x8a, 0x4b, 0x7f,
0x4a, 0xe9, 0xb0, 0x3f, 0x71, 0xe3, 0x78, 0x72, 0x1e, 0xb9, 0x31, 0xed, 0x5a, 0xb7, 0xac, 0xbb,
0x4d, 0xa7, 0xc3, 0x11, 0x47, 0x0a, 0x4e, 0x3e, 0x84, 0x66, 0xcc, 0x48, 0x69, 0x90, 0x44, 0xe1,
0x64, 0xd6, 0x2d, 0x21, 0x5d, 0x83, 0xc1, 0xf6, 0x38, 0xc8, 0xf6, 0xa1, 0xad, 0x5a, 0x88, 0x27,
0x61, 0x10, 0x53, 0x72, 0x1f, 0xd6, 0x06, 0xde, 0xe4, 0x9c, 0x46, 0x7d, 0xfc, 0x78, 0x1c, 0xd0,
0x71, 0x18, 0x78, 0x83, 0xae, 0x75, 0xab, 0x7c, 0xb7, 0xee, 0x10, 0x8e, 0x63, 0x5f, 0x7c, 0x2e,
0x30, 0xe4, 0x0e, 0xb4, 0x69, 0xc0, 0xe1, 0x74, 0x88, 0x5f, 0x89, 0xa6, 0x5a, 0x29, 0x98, 0x7d,
0x60, 0xff, 0x8d, 0x12, 0xac, 0x3c, 0x0b, 0xbc, 0xe4, 0xa5, 0xeb, 0xfb, 0x34, 0x91, 0x63, 0xba,
0x03, 0xed, 0x4b, 0x04, 0xe0, 0x98, 0x2e, 0xc3, 0x68, 0x28, 0x46, 0xd4, 0xe2, 0xe0, 0x23, 0x01,
0x9d, 0xdb, 0xb3, 0xd2, 0xdc, 0x9e, 0x15, 0x4e, 0x57, 0x79, 0xce, 0x74, 0xdd, 0x81, 0x76, 0x44,
0x07, 0xe1, 0x05, 0x8d, 0x66, 0xfd, 0x4b, 0x2f, 0x18, 0x86, 0x97, 0xdd, 0xca, 0x2d, 0xeb, 0x6e,
0xd5, 0x69, 0x49, 0xf0, 0x4b, 0x84, 0x92, 0xc7, 0xd0, 0x1e, 0x9c, 0xbb, 0x41, 0x40, 0xfd, 0xfe,
0xa9, 0x3b, 0x78, 0x35, 0x9d, 0xc4, 0xdd, 0xea, 0x2d, 0xeb, 0x6e, 0xe3, 0xc1, 0xf5, 0x4d, 0x5c,
0xd5, 0xcd, 0x9d, 0x73, 0x37, 0x78, 0x8c, 0x98, 0xe3, 0xc0, 0x9d, 0xc4, 0xe7, 0x61, 0xe2, 0xb4,
0xc4, 0x17, 0x1c, 0x1c, 0xdb, 0x6b, 0x40, 0xf4, 0x99, 0xe0, 0x73, 0x6f, 0xff, 0x0b, 0x0b, 0x56,
0x5f, 0x04, 0x7e, 0x38, 0x78, 0xf5, 0x6b, 0x4e, 0x51, 0xc1, 0x18, 0x4a, 0x6f, 0x3b, 0x86, 0xf2,
0xbb, 0x8e, 0x61, 0x1d, 0xd6, 0xcc, 0xce, 0x8a, 0x51, 0x50, 0xb8, 0xc6, 0xbe, 0x1e, 0x51, 0xd9,
0x2d, 0x39, 0x8c, 0xaf, 0x42, 0x67, 0x30, 0x8d, 0x22, 0x1a, 0xe4, 0xc6, 0xd1, 0x16, 0x70, 0x35,
0x90, 0x0f, 0xa1, 0x19, 0xd0, 0xcb, 0x94, 0x4c, 0xf0, 0x6e, 0x40, 0x2f, 0x25, 0x89, 0xdd, 0x85,
0xf5, 0x6c, 0x33, 0xa2, 0x03, 0xff, 0xdd, 0x82, 0xca, 0x8b, 0xe4, 0x75, 0x48, 0x36, 0xa1, 0x92,
0xcc, 0x26, 0x5c, 0x42, 0x5a, 0x0f, 0x88, 0x18, 0xda, 0xf6, 0x70, 0x18, 0xd1, 0x38, 0x3e, 0x99,
0x4d, 0xa8, 0xd3, 0x74, 0x79, 0xa1, 0xcf, 0xe8, 0x48, 0x17, 0x96, 0x44, 0x19, 0x1b, 0xac, 0x3b,
0xb2, 0x48, 0x6e, 0x02, 0xb8, 0xe3, 0x70, 0x1a, 0x24, 0xfd, 0xd8, 0x4d, 0x70, 0xaa, 0xca, 0x8e,
0x06, 0x21, 0x37, 0xa0, 0x3e, 0x79, 0xd5, 0x8f, 0x07, 0x91, 0x37, 0x49, 0x90, 0x6d, 0xea, 0x4e,
0x0a, 0x20, 0x5f, 0x83, 0x5a, 0x38, 0x4d, 0x26, 0xa1, 0x17, 0x24, 0x82, 0x55, 0xda, 0xa2, 0x2f,
0xcf, 0xa7, 0xc9, 0x11, 0x03, 0x3b, 0x8a, 0x80, 0xdc, 0x86, 0xe5, 0x41, 0x18, 0x9c, 0x79, 0xd1,
0x98, 0x2b, 0x83, 0xee, 0x22, 0xb6, 0x66, 0x02, 0xed, 0x7f, 0x5f, 0x82, 0xc6, 0x49, 0xe4, 0x06,
0xb1, 0x3b, 0x60, 0x00, 0xd6, 0xf5, 0xe4, 0x75, 0xff, 0xdc, 0x8d, 0xcf, 0x71, 0xb4, 0x75, 0x47,
0x16, 0xc9, 0x3a, 0x2c, 0xf2, 0x8e, 0xe2, 0x98, 0xca, 0x8e, 0x28, 0x91, 0x8f, 0x61, 0x25, 0x98,
0x8e, 0xfb, 0x66, 0x5b, 0x65, 0xe4, 0x96, 0x3c, 0x82, 0x4d, 0xc0, 0x29, 0x5b, 0x6b, 0xde, 0x04,
0x1f, 0xa1, 0x06, 0x21, 0x36, 0x34, 0x45, 0x89, 0x7a, 0xa3, 0x73, 0x3e, 0xcc, 0xaa, 0x63, 0xc0,
0x58, 0x1d, 0x89, 0x37, 0xa6, 0xfd, 0x38, 0x71, 0xc7, 0x13, 0x31, 0x2c, 0x0d, 0x82, 0xf8, 0x30,
0x71, 0xfd, 0xfe, 0x19, 0xa5, 0x71, 0x77, 0x49, 0xe0, 0x15, 0x84, 0x7c, 0x04, 0xad, 0x21, 0x8d,
0x93, 0xbe, 0x58, 0x14, 0x1a, 0x77, 0x6b, 0x28, 0xfa, 0x19, 0x28, 0xab, 0x27, 0x72, 0x2f, 0xfb,
0x6c, 0x02, 0xe8, 0xeb, 0x6e, 0x9d, 0xf7, 0x35, 0x85, 0x30, 0xce, 0x79, 0x4a, 0x13, 0x6d, 0xf6,
0x62, 0xc1, 0xa1, 0xf6, 0x01, 0x10, 0x0d, 0xbc, 0x4b, 0x13, 0xd7, 0xf3, 0x63, 0xf2, 0x29, 0x34,
0x13, 0x8d, 0x18, 0x55, 0x61, 0x43, 0xb1, 0x93, 0xf6, 0x81, 0x63, 0xd0, 0xd9, 0x4f, 0xa1, 0xf6,
0x84, 0xd2, 0x03, 0x6f, 0xec, 0x25, 0x64, 0x1d, 0xaa, 0x67, 0xde, 0x6b, 0xca, 0x19, 0xbe, 0xbc,
0xbf, 0xe0, 0xf0, 0x22, 0xe9, 0xc1, 0xd2, 0x84, 0x46, 0x03, 0x2a, 0x97, 0x67, 0x7f, 0xc1, 0x91,
0x80, 0xc7, 0x4b, 0x50, 0xf5, 0xd9, 0xc7, 0xf6, 0xaf, 0xca, 0xd0, 0x38, 0xa6, 0x81, 0x12, 0x24,
0x02, 0x15, 0x36, 0x64, 0x21, 0x3c, 0xf8, 0x9b, 0x7c, 0x00, 0x0d, 0x9c, 0x86, 0x38, 0x89, 0xbc,
0x60, 0x24, 0xf8, 0x17, 0x18, 0xe8, 0x18, 0x21, 0xa4, 0x03, 0x65, 0x77, 0x2c, 0x79, 0x97, 0xfd,
0x64, 0x42, 0x36, 0x71, 0x67, 0x63, 0x26, 0x8f, 0x6a, 0x55, 0x9b, 0x4e, 0x43, 0xc0, 0xf6, 0xd9,
0xb2, 0x6e, 0xc2, 0xaa, 0x4e, 0x22, 0x6b, 0xaf, 0x62, 0xed, 0x2b, 0x1a, 0xa5, 0x68, 0xe4, 0x0e,
0xb4, 0x25, 0x7d, 0xc4, 0x3b, 0x8b, 0xeb, 0x5c, 0x77, 0x5a, 0x02, 0x2c, 0x87, 0x70, 0x17, 0x3a,
0x67, 0x5e, 0xe0, 0xfa, 0xfd, 0x81, 0x9f, 0x5c, 0xf4, 0x87, 0xd4, 0x4f, 0x5c, 0x5c, 0xf1, 0xaa,
0xd3, 0x42, 0xf8, 0x8e, 0x9f, 0x5c, 0xec, 0x32, 0x28, 0xf9, 0x18, 0xea, 0x67, 0x94, 0xf6, 0x71,
0x26, 0xba, 0x35, 0x43, 0x7a, 0xe4, 0xec, 0x3a, 0xb5, 0x33, 0x39, 0xcf, 0x77, 0xa1, 0x13, 0x4e,
0x93, 0x51, 0xe8, 0x05, 0xa3, 0x3e, 0xd3, 0x57, 0x7d, 0x6f, 0x88, 0x1c, 0x50, 0x71, 0x5a, 0x12,
0xce, 0xb4, 0xc6, 0xb3, 0x21, 0x79, 0x1f, 0x00, 0xdb, 0xe6, 0x15, 0xc3, 0x2d, 0xeb, 0xee, 0xb2,
0x53, 0x67, 0x10, 0x5e, 0xd1, 0x67, 0x50, 0xc3, 0xf9, 0x4c, 0xfc, 0x8b, 0x6e, 0x03, 0x17, 0xfc,
0x03, 0xd1, 0xaa, 0xb6, 0x12, 0x9b, 0xbb, 0x34, 0x4e, 0x4e, 0xfc, 0x0b, 0xb6, 0x9f, 0xce, 0x9c,
0xa5, 0x21, 0x2f, 0xf5, 0x3e, 0x83, 0xa6, 0x8e, 0x60, 0x53, 0xff, 0x8a, 0xce, 0x70, 0xb9, 0x2a,
0x0e, 0xfb, 0x49, 0xd6, 0xa0, 0x7a, 0xe1, 0xfa, 0x53, 0x2a, 0x14, 0x1b, 0x2f, 0x7c, 0x56, 0x7a,
0x68, 0xd9, 0xff, 0xce, 0x82, 0x26, 0x6f, 0x41, 0x6c, 0xc8, 0xb7, 0x61, 0x59, 0x4e, 0x29, 0x8d,
0xa2, 0x30, 0x12, 0xf2, 0x6d, 0x02, 0xc9, 0x3d, 0xe8, 0x48, 0xc0, 0x24, 0xa2, 0xde, 0xd8, 0x1d,
0xc9, 0xba, 0x73, 0x70, 0xf2, 0x20, 0xad, 0x31, 0x0a, 0xa7, 0x09, 0x15, 0xaa, 0xbf, 0x29, 0xc6,
0xe7, 0x30, 0x98, 0x63, 0x92, 0x30, 0xf9, 0x2e, 0xe0, 0x15, 0x03, 0x66, 0xff, 0xcc, 0x02, 0xc2,
0xba, 0x7e, 0x12, 0xf2, 0x2a, 0xc4, 0x52, 0x67, 0xd9, 0xcc, 0x7a, 0x6b, 0x36, 0x2b, 0xcd, 0x63,
0x33, 0x1b, 0xaa, 0xbc, 0xe7, 0x95, 0x82, 0x9e, 0x73, 0xd4, 0xb7, 0x2b, 0xb5, 0x72, 0xa7, 0x62,
0xff, 0xdc, 0x82, 0xe6, 0x0e, 0xdf, 0xb7, 0x50, 0xd1, 0x92, 0xfb, 0x40, 0xce, 0xa6, 0xc1, 0x90,
0xf1, 0x47, 0xf2, 0xda, 0x1b, 0xf6, 0x4f, 0x67, 0x09, 0x8d, 0x79, 0x9f, 0xf6, 0x17, 0x9c, 0x02,
0x1c, 0xf9, 0x18, 0x3a, 0x06, 0x34, 0x4e, 0x22, 0xde, 0xb3, 0xfd, 0x05, 0x27, 0x87, 0x61, 0x13,
0xc5, 0x54, 0xf9, 0x34, 0xe9, 0x7b, 0xc1, 0x90, 0xbe, 0xc6, 0xb9, 0x5d, 0x76, 0x0c, 0xd8, 0xe3,
0x16, 0x34, 0xf5, 0xef, 0xec, 0x1f, 0x43, 0x4d, 0x6e, 0x04, 0xa8, 0x04, 0x33, 0xfd, 0x72, 0x34,
0x08, 0xe9, 0x41, 0xcd, 0xec, 0x85, 0x53, 0x7b, 0x97, 0xb6, 0xed, 0x3f, 0x0f, 0x9d, 0x03, 0xa6,
0x8d, 0x03, 0x2f, 0x18, 0x89, 0x9d, 0x90, 0x6d, 0x11, 0x93, 0xe9, 0xa9, 0x64, 0xd1, 0xba, 0x23,
0x4a, 0x4c, 0xcf, 0x9c, 0x87, 0x71, 0x22, 0xda, 0xc1, 0xdf, 0xf6, 0x7f, 0xb4, 0x80, 0xec, 0xc5,
0x89, 0x37, 0x76, 0x13, 0xfa, 0x84, 0xaa, 0x45, 0x7e, 0x0e, 0x4d, 0x56, 0xdb, 0x49, 0xb8, 0xcd,
0xf7, 0x1a, 0xae, 0x23, 0xbf, 0x26, 0x16, 0x26, 0xff, 0xc1, 0xa6, 0x4e, 0xcd, 0xc5, 0xc7, 0xa8,
0x80, 0xe9, 0xb3, 0xc4, 0x8d, 0x46, 0x34, 0xc1, 0x8d, 0x48, 0x98, 0x31, 0xc0, 0x41, 0x3b, 0x61,
0x70, 0xd6, 0xfb, 0x03, 0x58, 0xc9, 0xd5, 0xa1, 0x4b, 0x5a, 0xbd, 0x40, 0xd2, 0xca, 0xba, 0xa4,
0x0d, 0x60, 0xd5, 0xe8, 0x97, 0x90, 0xb7, 0x2e, 0x2c, 0x31, 0x7d, 0xc3, 0xf6, 0x79, 0xd4, 0xd5,
0x8e, 0x2c, 0x92, 0x07, 0xb0, 0x76, 0x46, 0x69, 0xe4, 0x26, 0x58, 0xec, 0x4f, 0x68, 0x84, 0x6b,
0x22, 0x6a, 0x2e, 0xc4, 0xd9, 0xff, 0xc3, 0x82, 0x36, 0x93, 0x89, 0xcf, 0xdd, 0x60, 0x26, 0xe7,
0xea, 0xa0, 0x70, 0xae, 0xee, 0x6a, 0xea, 0x45, 0xa3, 0x7e, 0xd7, 0x89, 0x2a, 0x67, 0x27, 0x8a,
0xdc, 0x82, 0xa6, 0xd1, 0xdd, 0x2a, 0xdf, 0x58, 0x63, 0x37, 0x39, 0xa2, 0xd1, 0xe3, 0x59, 0x42,
0x7f, 0xf3, 0xa9, 0xfc, 0x08, 0x3a, 0x69, 0xb7, 0xc5, 0x3c, 0x12, 0xa8, 0x30, 0xc6, 0x14, 0x15,
0xe0, 0x6f, 0xfb, 0x1f, 0x59, 0x9c, 0x70, 0x27, 0xf4, 0xd4, 0xa6, 0xcb, 0x08, 0xd9, 0xde, 0x2d,
0x09, 0xd9, 0xef, 0xb9, 0x46, 0xcb, 0x6f, 0x3e, 0x58, 0x72, 0x1d, 0x6a, 0x31, 0x0d, 0x86, 0x7d,
0xd7, 0xf7, 0x71, 0x6f, 0xaa, 0x39, 0x4b, 0xac, 0xbc, 0xed, 0xfb, 0xf6, 0x1d, 0x58, 0xd1, 0x7a,
0xf7, 0x86, 0x71, 0x1c, 0x02, 0x39, 0xf0, 0xe2, 0xe4, 0x45, 0x10, 0x4f, 0xb4, 0x3d, 0xed, 0x3d,
0xa8, 0x8f, 0xbd, 0x00, 0x7b, 0xc6, 0x25, 0xb7, 0xea, 0xd4, 0xc6, 0x5e, 0xc0, 0xfa, 0x15, 0x23,
0xd2, 0x7d, 0x2d, 0x90, 0x25, 0x81, 0x74, 0x5f, 0x23, 0xd2, 0x7e, 0x08, 0xab, 0x46, 0x7d, 0xa2,
0xe9, 0x0f, 0xa1, 0x3a, 0x4d, 0x5e, 0x87, 0xd2, 0xe2, 0x68, 0x08, 0x0e, 0x61, 0xb6, 0xad, 0xc3,
0x31, 0xf6, 0x23, 0x58, 0x39, 0xa4, 0x97, 0x42, 0x90, 0x65, 0x47, 0x3e, 0xba, 0xd2, 0xee, 0x45,
0xbc, 0xbd, 0x09, 0x44, 0xff, 0x38, 0x15, 0x00, 0x69, 0x05, 0x5b, 0x86, 0x15, 0x6c, 0x7f, 0x04,
0xe4, 0xd8, 0x1b, 0x05, 0x9f, 0xd3, 0x38, 0x76, 0x47, 0x4a, 0xf4, 0x3b, 0x50, 0x1e, 0xc7, 0x23,
0xa1, 0xaa, 0xd8, 0x4f, 0xfb, 0xeb, 0xb0, 0x6a, 0xd0, 0x89, 0x8a, 0x6f, 0x40, 0x3d, 0xf6, 0x46,
0x81, 0x9b, 0x4c, 0x23, 0x2a, 0xaa, 0x4e, 0x01, 0xf6, 0x13, 0x58, 0xfb, 0x1e, 0x8d, 0xbc, 0xb3,
0xd9, 0x55, 0xd5, 0x9b, 0xf5, 0x94, 0xb2, 0xf5, 0xec, 0xc1, 0xb5, 0x4c, 0x3d, 0xa2, 0x79, 0xce,
0xbe, 0x62, 0x25, 0x6b, 0x0e, 0x2f, 0x68, 0xba, 0xaf, 0xa4, 0xeb, 0x3e, 0xfb, 0x05, 0x90, 0x9d,
0x30, 0x08, 0xe8, 0x20, 0x39, 0xa2, 0x34, 0x4a, 0x1d, 0xf0, 0x94, 0x57, 0x1b, 0x0f, 0x36, 0xc4,
0xcc, 0x66, 0x15, 0xaa, 0x60, 0x62, 0x02, 0x95, 0x09, 0x8d, 0xc6, 0x58, 0x71, 0xcd, 0xc1, 0xdf,
0xf6, 0x35, 0x58, 0x35, 0xaa, 0x15, 0x2e, 0xcb, 0x27, 0x70, 0x6d, 0xd7, 0x8b, 0x07, 0xf9, 0x06,
0xbb, 0xb0, 0x34, 0x99, 0x9e, 0xf6, 0x53, 0x49, 0x94, 0x45, 0x66, 0xc5, 0x66, 0x3f, 0x11, 0x95,
0xfd, 0x75, 0x0b, 0x2a, 0xfb, 0x27, 0x07, 0x3b, 0x6c, 0xaf, 0xf0, 0x82, 0x41, 0x38, 0x66, 0x7b,
0x29, 0x1f, 0xb4, 0x2a, 0xcf, 0x95, 0xb0, 0x1b, 0x50, 0xc7, 0x2d, 0x98, 0x19, 0xee, 0xc2, 0x57,
0x4e, 0x01, 0xcc, 0x69, 0xa0, 0xaf, 0x27, 0x5e, 0x84, 0x5e, 0x81, 0xb4, 0xf5, 0x2b, 0xb8, 0xcd,
0xe4, 0x11, 0xf6, 0x2f, 0x17, 0x61, 0x49, 0x6c, 0xbe, 0xd8, 0xde, 0x20, 0xf1, 0x2e, 0xa8, 0xe8,
0x89, 0x28, 0x31, 0xf3, 0x26, 0xa2, 0xe3, 0x30, 0xa1, 0x7d, 0x63, 0x19, 0x4c, 0x20, 0x3a, 0x45,
0xc2, 0x5f, 0xe5, 0x6e, 0x54, 0x99, 0x53, 0x19, 0x40, 0x36, 0x59, 0xd2, 0xe6, 0xab, 0xa0, 0xad,
0x25, 0x8b, 0x6c, 0x26, 0x06, 0xee, 0xc4, 0x1d, 0x78, 0xc9, 0x4c, 0xa8, 0x04, 0x55, 0x66, 0x75,
0xfb, 0xe1, 0xc0, 0x65, 0x9e, 0xb0, 0xef, 0x06, 0x03, 0x2a, 0x1d, 0x2e, 0x03, 0xc8, 0x9c, 0x0f,
0xd1, 0x25, 0x49, 0xc6, 0x1d, 0x94, 0x0c, 0x94, 0xed, 0xdf, 0x83, 0x70, 0x3c, 0xf6, 0x12, 0xe6,
0xb3, 0xa0, 0xbd, 0x5a, 0x76, 0x34, 0x08, 0x77, 0xef, 0xb0, 0x74, 0xc9, 0x67, 0xaf, 0x2e, 0xdd,
0x3b, 0x0d, 0xc8, 0x6a, 0x61, 0xbb, 0x0e, 0x53, 0x63, 0xaf, 0x2e, 0xd1, 0x38, 0x2d, 0x3b, 0x1a,
0x84, 0xad, 0xc3, 0x34, 0x88, 0x69, 0x92, 0xf8, 0x74, 0xa8, 0x3a, 0xd4, 0x40, 0xb2, 0x3c, 0x82,
0xdc, 0x87, 0x55, 0xee, 0x46, 0xc5, 0x6e, 0x12, 0xc6, 0xe7, 0x5e, 0xdc, 0x8f, 0x99, 0xc3, 0xd1,
0x44, 0xfa, 0x22, 0x14, 0x79, 0x08, 0x1b, 0x19, 0x70, 0x44, 0x07, 0xd4, 0xbb, 0xa0, 0xc3, 0xee,
0x32, 0x7e, 0x35, 0x0f, 0x4d, 0x6e, 0x41, 0x83, 0x79, 0x8f, 0xd3, 0xc9, 0xd0, 0x65, 0x06, 0x4c,
0x0b, 0xd7, 0x41, 0x07, 0x91, 0x4f, 0x60, 0x79, 0x42, 0xb9, 0xf5, 0x73, 0x9e, 0xf8, 0x83, 0xb8,
0xdb, 0x36, 0xb4, 0x1b, 0xe3, 0x5c, 0xc7, 0xa4, 0x60, 0x4c, 0x39, 0x88, 0xd1, 0x4d, 0x70, 0x67,
0xdd, 0x8e, 0x30, 0xd5, 0x25, 0x00, 0x65, 0x24, 0xf2, 0x2e, 0xdc, 0x84, 0x76, 0x57, 0xb8, 0x42,
0x17, 0x45, 0xf6, 0x9d, 0x17, 0x78, 0x89, 0xe7, 0x26, 0x61, 0xd4, 0x25, 0x88, 0x4b, 0x01, 0x6c,
0x12, 0x91, 0x3f, 0xe2, 0xc4, 0x4d, 0xa6, 0x71, 0xff, 0xcc, 0x77, 0x47, 0x71, 0x77, 0x95, 0xdb,
0x9c, 0x39, 0x04, 0xf9, 0x14, 0xd6, 0x39, 0x47, 0x20, 0x2a, 0xa2, 0x31, 0x8d, 0x2e, 0xb8, 0x99,
0xb0, 0x86, 0x33, 0x32, 0x07, 0xcb, 0xa6, 0x52, 0xb0, 0x48, 0xee, 0xc3, 0x6b, 0x7c, 0x2a, 0xe7,
0xa0, 0xed, 0x7f, 0x62, 0xf1, 0x6d, 0x41, 0x88, 0x90, 0x52, 0xef, 0x1f, 0x40, 0x83, 0x0b, 0x4f,
0x3f, 0x0c, 0xfc, 0x99, 0x90, 0x27, 0xe0, 0xa0, 0xe7, 0x81, 0x3f, 0x23, 0x5f, 0x81, 0x65, 0x2f,
0xd0, 0x49, 0xb8, 0x06, 0x6a, 0x4a, 0x20, 0x12, 0x7d, 0x00, 0x8d, 0xc9, 0xf4, 0xd4, 0xf7, 0x06,
0x9c, 0xa4, 0xcc, 0x6b, 0xe1, 0x20, 0x24, 0x60, 0x76, 0x3b, 0x9f, 0x47, 0x4e, 0x51, 0x41, 0x8a,
0x86, 0x80, 0x31, 0x12, 0xfb, 0x31, 0xac, 0x99, 0x1d, 0x14, 0xaa, 0xf6, 0x1e, 0xd4, 0x84, 0x64,
0xc6, 0xc2, 0x79, 0x6a, 0x69, 0x71, 0xa5, 0x80, 0xfa, 0x8e, 0xc2, 0xdb, 0xff, 0xb6, 0x02, 0xab,
0x02, 0xba, 0xe3, 0x87, 0x31, 0x3d, 0x9e, 0x8e, 0xc7, 0x6e, 0x54, 0x20, 0xf2, 0xd6, 0x15, 0x22,
0x5f, 0x32, 0x45, 0x9e, 0x09, 0xe2, 0xb9, 0xeb, 0x05, 0xdc, 0xe9, 0xe0, 0xfa, 0x42, 0x83, 0x90,
0xbb, 0xd0, 0x1e, 0xf8, 0x61, 0xcc, 0x8d, 0x70, 0x3d, 0xac, 0x91, 0x05, 0xe7, 0x55, 0x54, 0xb5,
0x48, 0x45, 0xe9, 0x2a, 0x66, 0x31, 0xa3, 0x62, 0x6c, 0x68, 0xb2, 0x4a, 0xa9, 0xd4, 0x98, 0x4b,
0xdc, 0x30, 0xd7, 0x61, 0xac, 0x3f, 0x59, 0x81, 0xe6, 0xda, 0xa3, 0x5d, 0x24, 0xce, 0xde, 0x98,
0xa2, 0x46, 0xd6, 0xa8, 0xeb, 0x42, 0x9c, 0xf3, 0x28, 0xf2, 0x84, 0xf9, 0xba, 0xac, 0x2d, 0x34,
0x0b, 0x00, 0xcd, 0x82, 0x8f, 0xcc, 0x15, 0xd1, 0xe7, 0x7e, 0x93, 0x15, 0xa6, 0x11, 0x45, 0x53,
0x41, 0xfb, 0xd2, 0xfe, 0x23, 0x0b, 0x1a, 0x1a, 0x8e, 0x5c, 0x83, 0x95, 0x9d, 0xe7, 0xcf, 0x8f,
0xf6, 0x9c, 0xed, 0x93, 0x67, 0xdf, 0xdb, 0xeb, 0xef, 0x1c, 0x3c, 0x3f, 0xde, 0xeb, 0x2c, 0x30,
0xf0, 0xc1, 0xf3, 0x9d, 0xed, 0x83, 0xfe, 0x93, 0xe7, 0xce, 0x8e, 0x04, 0x5b, 0x64, 0x1d, 0x88,
0xb3, 0xf7, 0xf9, 0xf3, 0x93, 0x3d, 0x03, 0x5e, 0x22, 0x1d, 0x68, 0x3e, 0x76, 0xf6, 0xb6, 0x77,
0xf6, 0x05, 0xa4, 0x4c, 0xd6, 0xa0, 0xf3, 0xe4, 0xc5, 0xe1, 0xee, 0xb3, 0xc3, 0xa7, 0xfd, 0x9d,
0xed, 0xc3, 0x9d, 0xbd, 0x83, 0xbd, 0xdd, 0x4e, 0x85, 0x2c, 0x43, 0x7d, 0xfb, 0xf1, 0xf6, 0xe1,
0xee, 0xf3, 0xc3, 0xbd, 0xdd, 0x4e, 0xd5, 0xfe, 0x6f, 0x16, 0x5c, 0xc3, 0x5e, 0x0f, 0xb3, 0x02,
0x72, 0x0b, 0x1a, 0x83, 0x30, 0x9c, 0x30, 0x73, 0x3c, 0xdd, 0x70, 0x74, 0x10, 0x63, 0x7e, 0x2e,
0xae, 0x67, 0x61, 0x34, 0xa0, 0x42, 0x3e, 0x00, 0x41, 0x4f, 0x18, 0x84, 0x31, 0xbf, 0x58, 0x5e,
0x4e, 0xc1, 0xc5, 0xa3, 0xc1, 0x61, 0x9c, 0x64, 0x1d, 0x16, 0x4f, 0x23, 0xea, 0x0e, 0xce, 0x85,
0x64, 0x88, 0x12, 0xf9, 0x6a, 0xea, 0x2f, 0x0e, 0xd8, 0xec, 0xfb, 0x74, 0x88, 0x1c, 0x53, 0x73,
0xda, 0x02, 0xbe, 0x23, 0xc0, 0x4c, 0x3f, 0xb9, 0xa7, 0x6e, 0x30, 0x0c, 0x03, 0x3a, 0x14, 0xc6,
0x68, 0x0a, 0xb0, 0x8f, 0x60, 0x3d, 0x3b, 0x3e, 0x21, 0x5f, 0x9f, 0x6a, 0xf2, 0xc5, 0x6d, 0xc3,
0xde, 0xfc, 0xd5, 0xd4, 0x64, 0xed, 0x4f, 0x4b, 0x50, 0x61, 0xa6, 0xc2, 0x7c, 0xb3, 0x42, 0xb7,
0xfe, 0xca, 0xb9, 0x18, 0x28, 0xba, 0xa0, 0x7c, 0xf3, 0xe0, 0x1b, 0xac, 0x06, 0x49, 0xf1, 0x11,
0x1d, 0x5c, 0xe0, 0x88, 0x15, 0x9e, 0x41, 0x98, 0x80, 0x30, 0xd3, 0x1c, 0xbf, 0x16, 0x02, 0x22,
0xcb, 0x12, 0x87, 0x5f, 0x2e, 0xa5, 0x38, 0xfc, 0xae, 0x0b, 0x4b, 0x5e, 0x70, 0x1a, 0x4e, 0x83,
0x21, 0x0a, 0x44, 0xcd, 0x91, 0x45, 0x8c, 0xba, 0xa2, 0xa0, 0x7a, 0x63, 0xc9, 0xfe, 0x29, 0x80,
0x3c, 0x80, 0x7a, 0x3c, 0x0b, 0x06, 0x3a, 0xcf, 0xaf, 0x89, 0x59, 0x62, 0x73, 0xb0, 0x79, 0x3c,
0x0b, 0x06, 0xc8, 0xe1, 0x29, 0x99, 0xfd, 0x07, 0x50, 0x93, 0x60, 0xc6, 0x96, 0x2f, 0x0e, 0xbf,
0x73, 0xf8, 0xfc, 0xe5, 0x61, 0xff, 0xf8, 0xfb, 0x87, 0x3b, 0x9d, 0x05, 0xd2, 0x86, 0xc6, 0xf6,
0x0e, 0x72, 0x3a, 0x02, 0x2c, 0x46, 0x72, 0xb4, 0x7d, 0x7c, 0xac, 0x20, 0x25, 0x9b, 0x30, 0xf7,
0x3a, 0x46, 0x7b, 0x4c, 0x45, 0x15, 0x3f, 0x85, 0x15, 0x0d, 0x96, 0xda, 0xf6, 0x13, 0x06, 0xc8,
0xd8, 0xf6, 0x68, 0xc8, 0x71, 0x8c, 0xdd, 0x81, 0xd6, 0x53, 0x9a, 0x3c, 0x0b, 0xce, 0x42, 0x59,
0xd3, 0xff, 0xaa, 0x40, 0x5b, 0x81, 0x44, 0x45, 0x77, 0xa1, 0xed, 0x0d, 0x69, 0x90, 0x78, 0xc9,
0xac, 0x6f, 0x78, 0xf1, 0x59, 0x30, 0x33, 0x80, 0x5d, 0xdf, 0x73, 0x65, 0x70, 0x9b, 0x17, 0x98,
0x57, 0xcb, 0x76, 0x67, 0xb9, 0xe1, 0x2a, 0xbe, 0xe2, 0xc1, 0x83, 0x42, 0x1c, 0xd3, 0x40, 0x0c,
0x2e, 0xb6, 0x18, 0xf5, 0x09, 0x37, 0x04, 0x8b, 0x50, 0x6c, 0xa9, 0x78, 0x4d, 0x6c, 0xc8, 0x55,
0xbe, 0x83, 0x2b, 0x40, 0x2e, 0x7a, 0xbc, 0xc8, 0xf5, 0x63, 0x36, 0x7a, 0xac, 0x45, 0xa0, 0x6b,
0xb9, 0x08, 0x34, 0xd3, 0x9f, 0xb3, 0x60, 0x40, 0x87, 0xfd, 0x24, 0xec, 0xa3, 0x9e, 0x47, 0x96,
0xa8, 0x39, 0x59, 0x30, 0xb9, 0x01, 0x4b, 0x09, 0x8d, 0x93, 0x80, 0xf2, 0xb0, 0x5f, 0xed, 0x71,
0xa9, 0x6b, 0x39, 0x12, 0xc4, 0xac, 0xf6, 0x69, 0xe4, 0xc5, 0xdd, 0x26, 0xc6, 0x96, 0xf1, 0x37,
0xf9, 0x06, 0x5c, 0x3b, 0xa5, 0x71, 0xd2, 0x3f, 0xa7, 0xee, 0x90, 0x46, 0xc8, 0x5e, 0x3c, 0x88,
0xcd, 0x8d, 0xa1, 0x62, 0x24, 0x63, 0xdc, 0x0b, 0x1a, 0xc5, 0x5e, 0x18, 0xa0, 0x19, 0x54, 0x77,
0x64, 0x91, 0xd5, 0xc7, 0x06, 0xaf, 0x36, 0x69, 0x35, 0x83, 0x6d, 0x1c, 0x78, 0x31, 0x92, 0xdc,
0x86, 0x45, 0x1c, 0x40, 0xdc, 0xed, 0x20, 0xcf, 0x34, 0x53, 0x99, 0xf7, 0x02, 0x47, 0xe0, 0xd8,
0x2a, 0x0f, 0x42, 0x3f, 0x8c, 0xd0, 0x16, 0xaa, 0x3b, 0xbc, 0x60, 0xce, 0xce, 0x28, 0x72, 0x27,
0xe7, 0xc2, 0x1e, 0xca, 0x82, 0xbf, 0x5d, 0xa9, 0x35, 0x3a, 0x4d, 0xfb, 0xcf, 0x41, 0x15, 0xab,
0xc5, 0xea, 0x70, 0x32, 0x2d, 0x51, 0x1d, 0x42, 0xbb, 0xb0, 0x14, 0xd0, 0xe4, 0x32, 0x8c, 0x5e,
0xc9, 0x93, 0x12, 0x51, 0xb4, 0x7f, 0x8a, 0x7e, 0x93, 0x3a, 0x39, 0x78, 0x81, 0x46, 0x1f, 0xf3,
0x7e, 0xf9, 0x52, 0xc5, 0xe7, 0xae, 0x70, 0xe5, 0x6a, 0x08, 0x38, 0x3e, 0x77, 0x99, 0xae, 0x35,
0x56, 0x9f, 0x7b, 0xc7, 0x0d, 0x84, 0xed, 0xf3, 0xc5, 0xbf, 0x0d, 0x2d, 0x79, 0x26, 0x11, 0xf7,
0x7d, 0x7a, 0x96, 0xc8, 0xd8, 0x56, 0x30, 0x1d, 0xa3, 0x0b, 0x7d, 0x40, 0xcf, 0x12, 0xfb, 0x10,
0x56, 0x84, 0xfe, 0x7b, 0x3e, 0xa1, 0xb2, 0xe9, 0xdf, 0x2b, 0xb2, 0x23, 0x1a, 0x0f, 0x56, 0x4d,
0x85, 0xc9, 0x4f, 0x61, 0x4c, 0x4a, 0xdb, 0x01, 0xa2, 0xeb, 0x53, 0x51, 0xa1, 0xd8, 0xcc, 0x65,
0xf4, 0x4e, 0x0c, 0xc7, 0x80, 0xb1, 0xf9, 0x89, 0xa7, 0x83, 0x81, 0x3c, 0x49, 0xaa, 0x39, 0xb2,
0x68, 0xff, 0x73, 0x0b, 0x56, 0xb1, 0x36, 0x69, 0x09, 0x89, 0x3d, 0xeb, 0xe1, 0x3b, 0x74, 0xb3,
0x39, 0xd0, 0x23, 0x9a, 0x6b, 0x50, 0xd5, 0x77, 0x31, 0x5e, 0x78, 0xf7, 0x48, 0x49, 0x25, 0x1b,
0x29, 0xb1, 0xff, 0xbe, 0x05, 0x2b, 0x7c, 0x23, 0x41, 0x3b, 0x58, 0x0c, 0xff, 0xf7, 0x61, 0x99,
0x5b, 0x04, 0x42, 0x2b, 0x88, 0x8e, 0xa6, 0xaa, 0x15, 0xa1, 0x9c, 0x78, 0x7f, 0xc1, 0x31, 0x89,
0xc9, 0x23, 0xb4, 0xca, 0x82, 0x3e, 0x42, 0x0b, 0xce, 0x1c, 0xcd, 0xb9, 0xde, 0x5f, 0x70, 0x34,
0xf2, 0xc7, 0x35, 0x58, 0xe4, 0x4e, 0x84, 0xfd, 0x14, 0x96, 0x8d, 0x86, 0x8c, 0x28, 0x4d, 0x93,
0x47, 0x69, 0x72, 0xe1, 0xd0, 0x52, 0x41, 0x38, 0xf4, 0x5f, 0x97, 0x81, 0x30, 0x66, 0xc9, 0xac,
0x06, 0xf3, 0x62, 0xc2, 0xa1, 0xe1, 0x93, 0x36, 0x1d, 0x1d, 0x44, 0x36, 0x81, 0x68, 0x45, 0x19,
0xb1, 0xe6, 0x5b, 0x66, 0x01, 0x86, 0xa9, 0x59, 0x61, 0x71, 0x08, 0xdb, 0x40, 0x78, 0xdf, 0x7c,
0xda, 0x0b, 0x71, 0x6c, 0x57, 0x9c, 0x4c, 0xe3, 0x73, 0xf4, 0x15, 0x84, 0xd7, 0x2a, 0xcb, 0xd9,
0xf5, 0x5d, 0xbc, 0x72, 0x7d, 0x97, 0x72, 0x91, 0x30, 0xcd, 0x6f, 0xaa, 0x99, 0x7e, 0xd3, 0x6d,
0x58, 0x1e, 0x33, 0x3b, 0x39, 0xf1, 0x07, 0xfd, 0x31, 0x6b, 0x5d, 0x38, 0xa9, 0x06, 0x90, 0xdc,
0x83, 0x8e, 0x74, 0x5d, 0x94, 0x73, 0xc6, 0xcf, 0x51, 0x72, 0x70, 0xa6, 0xff, 0xd3, 0xd8, 0x58,
0x03, 0x3b, 0x9b, 0x02, 0x98, 0x27, 0x16, 0x33, 0x0e, 0xe9, 0x4f, 0x03, 0x71, 0xec, 0x48, 0x87,
0xe8, 0x9e, 0xd6, 0x9c, 0x3c, 0xc2, 0xfe, 0xdb, 0x16, 0x74, 0xd8, 0x9a, 0x19, 0x6c, 0xf9, 0x19,
0xa0, 0x54, 0xbc, 0x25, 0x57, 0x1a, 0xb4, 0xe4, 0x21, 0xd4, 0xb1, 0x1c, 0x4e, 0x68, 0x20, 0x78,
0xb2, 0x6b, 0xf2, 0x64, 0xaa, 0x4f, 0xf6, 0x17, 0x9c, 0x94, 0x58, 0xe3, 0xc8, 0xff, 0x6c, 0x41,
0x43, 0xb4, 0xf2, 0x6b, 0xc7, 0x5e, 0x7a, 0xda, 0x39, 0x31, 0xe7, 0xa4, 0xf4, 0x58, 0xf8, 0x2e,
0xb4, 0xc7, 0x6e, 0x32, 0x8d, 0xd8, 0x7e, 0x6e, 0xc4, 0x5d, 0xb2, 0x60, 0xb6, 0x39, 0xa3, 0xea,
0x8c, 0xfb, 0x89, 0xe7, 0xf7, 0x25, 0x56, 0x9c, 0xc8, 0x16, 0xa1, 0x98, 0x06, 0x89, 0x13, 0x77,
0x44, 0xc5, 0xbe, 0xcb, 0x0b, 0x76, 0x17, 0xd6, 0xc5, 0x80, 0x32, 0xf6, 0xb5, 0xfd, 0x2f, 0x97,
0x61, 0x23, 0x87, 0x52, 0xf9, 0x23, 0x22, 0xa0, 0xe0, 0x7b, 0xe3, 0xd3, 0x50, 0x39, 0x27, 0x96,
0x1e, 0x6b, 0x30, 0x50, 0x64, 0x04, 0xd7, 0xa4, 0x81, 0xc1, 0xe6, 0x34, 0xdd, 0x0c, 0x4b, 0xb8,
0xcb, 0x7d, 0x62, 0x2e, 0x61, 0xb6, 0x41, 0x09, 0xd7, 0x85, 0xb8, 0xb8, 0x3e, 0x72, 0x0e, 0x5d,
0x65, 0xc9, 0x08, 0x65, 0xad, 0x59, 0x3b, 0xac, 0xad, 0x8f, 0xaf, 0x68, 0xcb, 0x30, 0xc7, 0x9d,
0xb9, 0xb5, 0x91, 0x19, 0xdc, 0x94, 0x38, 0xd4, 0xc6, 0xf9, 0xf6, 0x2a, 0x6f, 0x35, 0x36, 0x74,
0x34, 0xcc, 0x46, 0xaf, 0xa8, 0x98, 0xfc, 0x18, 0xd6, 0x2f, 0x5d, 0x2f, 0x91, 0xdd, 0xd2, 0x6c,
0x8b, 0x2a, 0x36, 0xf9, 0xe0, 0x8a, 0x26, 0x5f, 0xf2, 0x8f, 0x8d, 0x2d, 0x6a, 0x4e, 0x8d, 0xbd,
0x5f, 0x96, 0xa0, 0x65, 0xd6, 0xc3, 0xd8, 0x54, 0xc8, 0xbe, 0xd4, 0x81, 0xd2, 0x1a, 0xcd, 0x80,
0xf3, 0xfe, 0x7d, 0xa9, 0xc8, 0xbf, 0xd7, 0xbd, 0xea, 0xf2, 0x55, 0x81, 0xbb, 0xca, 0xdb, 0x05,
0xee, 0xaa, 0x85, 0x81, 0xbb, 0xf9, 0xf1, 0x9d, 0xc5, 0x5f, 0x37, 0xbe, 0xb3, 0xf4, 0xc6, 0xf8,
0x4e, 0xef, 0xff, 0x5a, 0x40, 0xf2, 0xdc, 0x4b, 0x9e, 0xf2, 0x90, 0x46, 0x40, 0x7d, 0xa1, 0xc4,
0x7e, 0xf7, 0xed, 0x24, 0x40, 0xae, 0x96, 0xfc, 0x9a, 0x89, 0xa2, 0x9e, 0xc4, 0xa1, 0x9b, 0x57,
0xcb, 0x4e, 0x11, 0x2a, 0x13, 0xbc, 0xac, 0x5c, 0x1d, 0xbc, 0xac, 0x5e, 0x1d, 0xbc, 0x5c, 0xcc,
0x06, 0x2f, 0x7b, 0x7f, 0xcd, 0x82, 0xd5, 0x02, 0x36, 0xfb, 0xed, 0x0d, 0x9c, 0x31, 0x86, 0xa1,
0x7d, 0x4a, 0x82, 0x31, 0x74, 0x60, 0xef, 0x2f, 0xc3, 0xb2, 0x21, 0x5a, 0xbf, 0xbd, 0xf6, 0xb3,
0x16, 0x22, 0xe7, 0x6c, 0x03, 0xd6, 0xfb, 0xdf, 0x25, 0x20, 0x79, 0xf1, 0xfe, 0x33, 0xed, 0x43,
0x7e, 0x9e, 0xca, 0x05, 0xf3, 0xf4, 0xff, 0x75, 0xe7, 0xf9, 0x18, 0x56, 0x44, 0x66, 0x9a, 0x16,
0xc8, 0xe2, 0x1c, 0x93, 0x47, 0x30, 0x1b, 0xd9, 0x8c, 0x1c, 0xd7, 0x8c, 0x4c, 0x1c, 0x6d, 0xfb,
0xcd, 0x04, 0x90, 0xed, 0x1e, 0x74, 0xc5, 0x0c, 0xed, 0x5d, 0xd0, 0x20, 0x39, 0x9e, 0x9e, 0xf2,
0xd4, 0x2c, 0x2f, 0x0c, 0xec, 0x7f, 0x53, 0x56, 0x66, 0x3e, 0x22, 0x85, 0x41, 0xf1, 0x0d, 0x68,
0xea, 0xdb, 0x87, 0x58, 0x8e, 0x4c, 0x1c, 0x93, 0x99, 0x12, 0x3a, 0x15, 0xd9, 0x85, 0x16, 0x2a,
0xc9, 0xa1, 0xfa, 0xae, 0x84, 0xdf, 0xbd, 0x21, 0x3e, 0xb3, 0xbf, 0xe0, 0x64, 0xbe, 0x21, 0xdf,
0x82, 0x96, 0xe9, 0xfc, 0x09, 0xab, 0xa4, 0xc8, 0x1b, 0x60, 0x9f, 0x9b, 0xc4, 0x64, 0x1b, 0x3a,
0x59, 0xef, 0x51, 0x64, 0x4a, 0xcc, 0xa9, 0x20, 0x47, 0x4e, 0x1e, 0x8a, 0x23, 0xc4, 0x2a, 0xc6,
0x4d, 0x6e, 0x9b, 0x9f, 0x69, 0xd3, 0xb4, 0xc9, 0xff, 0x68, 0x87, 0x8a, 0x7f, 0x08, 0x90, 0xc2,
0x48, 0x07, 0x9a, 0xcf, 0x8f, 0xf6, 0x0e, 0xfb, 0x3b, 0xfb, 0xdb, 0x87, 0x87, 0x7b, 0x07, 0x9d,
0x05, 0x42, 0xa0, 0x85, 0x61, 0xbe, 0x5d, 0x05, 0xb3, 0x18, 0x4c, 0x04, 0x56, 0x24, 0xac, 0x44,
0xd6, 0xa0, 0xf3, 0xec, 0x30, 0x03, 0x2d, 0x3f, 0xae, 0x2b, 0xf9, 0xb0, 0xd7, 0x61, 0x8d, 0x67,
0x1e, 0x3e, 0xe6, 0xec, 0x21, 0xad, 0x93, 0x7f, 0x6c, 0xc1, 0xb5, 0x0c, 0x22, 0x4d, 0xa5, 0xe1,
0x06, 0x88, 0x69, 0x95, 0x98, 0x40, 0x3c, 0x16, 0x90, 0xb6, 0x66, 0x46, 0x83, 0xe4, 0x11, 0x8c,
0xe7, 0x35, 0xdb, 0x34, 0x23, 0x49, 0x45, 0x28, 0x7b, 0x83, 0xe7, 0x47, 0x62, 0x26, 0xa5, 0xd1,
0xf1, 0x33, 0x9e, 0xd1, 0xa8, 0x23, 0xd2, 0x23, 0x59, 0xb3, 0xcb, 0xb2, 0xc8, 0xdc, 0x0a, 0xc3,
0xd8, 0x31, 0xfb, 0x5b, 0x88, 0xb3, 0xff, 0xa8, 0x02, 0xe4, 0xbb, 0x53, 0x1a, 0xcd, 0x30, 0x5f,
0x46, 0x45, 0x4d, 0x37, 0xb2, 0x31, 0xc1, 0xc5, 0xc9, 0xf4, 0xf4, 0x3b, 0x74, 0x26, 0x33, 0xc7,
0x4a, 0x69, 0xe6, 0x58, 0x51, 0xf6, 0x56, 0xe5, 0xea, 0xec, 0xad, 0xea, 0x55, 0xd9, 0x5b, 0x5f,
0x81, 0x65, 0x6f, 0x14, 0x84, 0x4c, 0xe6, 0x99, 0x9d, 0x10, 0x77, 0x17, 0x6f, 0x95, 0x99, 0x6f,
0x2d, 0x80, 0x87, 0x0c, 0x46, 0x1e, 0xa5, 0x44, 0x74, 0x38, 0xc2, 0x4c, 0x41, 0x5d, 0x0b, 0xec,
0x0d, 0x47, 0xf4, 0x20, 0x1c, 0xb8, 0x49, 0x18, 0x61, 0x60, 0x47, 0x7e, 0xcc, 0xe0, 0x31, 0xb9,
0x0d, 0xad, 0x38, 0x9c, 0x32, 0xcb, 0x49, 0x8e, 0x95, 0x47, 0x92, 0x9a, 0x1c, 0x7a, 0xc4, 0x47,
0xbc, 0x09, 0xab, 0xd3, 0x98, 0xf6, 0xc7, 0x5e, 0x1c, 0xb3, 0xdd, 0x71, 0x10, 0x06, 0x49, 0x14,
0xfa, 0x22, 0x9e, 0xb4, 0x32, 0x8d, 0xe9, 0xe7, 0x1c, 0xb3, 0xc3, 0x11, 0xe4, 0x1b, 0x69, 0x97,
0x26, 0xae, 0x17, 0xc5, 0x5d, 0xc0, 0x2e, 0xc9, 0x91, 0xb2, 0x7e, 0x1f, 0xb9, 0x5e, 0xa4, 0xfa,
0xc2, 0x0a, 0x31, 0xd9, 0xce, 0xa5, 0x98, 0xc9, 0x98, 0x7c, 0x7e, 0x75, 0x7e, 0xfb, 0x99, 0x66,
0x22, 0x41, 0x6a, 0x13, 0x6a, 0xb2, 0x7b, 0xcc, 0x89, 0x3e, 0x8b, 0xc2, 0xb1, 0x74, 0xa2, 0xd9,
0x6f, 0xd2, 0x82, 0x52, 0x12, 0x8a, 0x8f, 0x4b, 0x49, 0x68, 0x7f, 0x1f, 0x1a, 0xda, 0x0c, 0x63,
0x16, 0x9d, 0x30, 0xd8, 0x84, 0xf7, 0x5d, 0xe1, 0xfe, 0x51, 0x40, 0xfd, 0x67, 0x43, 0xf2, 0x35,
0x58, 0x19, 0x7a, 0x11, 0xc5, 0x84, 0xc8, 0x7e, 0x44, 0x2f, 0x68, 0x14, 0xcb, 0x38, 0x45, 0x47,
0x21, 0x1c, 0x0e, 0xb7, 0x1f, 0xc1, 0xaa, 0x31, 0x70, 0x25, 0xb5, 0x8b, 0x98, 0xd1, 0x25, 0x43,
0xa5, 0x66, 0xb6, 0x97, 0xc0, 0xd9, 0xff, 0xac, 0x0c, 0xe5, 0xfd, 0x70, 0xa2, 0x1f, 0x08, 0x59,
0xe6, 0x81, 0x90, 0x30, 0x38, 0xfb, 0xca, 0x9e, 0x14, 0x56, 0x81, 0x01, 0x24, 0xf7, 0xa0, 0xe5,
0x8e, 0x93, 0x7e, 0x12, 0x32, 0x03, 0xfb, 0xd2, 0x8d, 0x86, 0x5c, 0x94, 0x91, 0x95, 0x32, 0x18,
0xb2, 0x06, 0x65, 0x65, 0x27, 0x21, 0x01, 0x2b, 0x32, 0xef, 0x0e, 0x8f, 0xc2, 0x67, 0x22, 0xce,
0x29, 0x4a, 0x4c, 0x53, 0x98, 0xdf, 0x73, 0xd7, 0x9a, 0xef, 0x76, 0x45, 0x28, 0x66, 0xfc, 0x32,
0xe1, 0x19, 0xa7, 0xb6, 0xa4, 0x2a, 0xeb, 0x11, 0xfc, 0x9a, 0x19, 0xc1, 0xbf, 0x05, 0x8d, 0xc4,
0xbf, 0xe8, 0x4f, 0xdc, 0x99, 0x1f, 0xba, 0x43, 0xc1, 0xb4, 0x3a, 0x88, 0xfc, 0x3e, 0xa7, 0x60,
0x1b, 0x6c, 0x34, 0x94, 0xcc, 0x2a, 0x77, 0xa8, 0xfd, 0x70, 0xb2, 0x79, 0xe2, 0x5f, 0x38, 0x1c,
0xc9, 0xf9, 0x4d, 0x27, 0xef, 0x7d, 0x0b, 0xda, 0x19, 0xfc, 0x3b, 0x25, 0x38, 0xfe, 0xca, 0x82,
0x2a, 0x2e, 0x1d, 0x33, 0x2c, 0xb8, 0xe6, 0x55, 0x47, 0x56, 0x58, 0xc3, 0xb2, 0x93, 0x05, 0x13,
0xdb, 0xc8, 0x0c, 0x2e, 0xa9, 0xf9, 0xd6, 0xb3, 0x83, 0x6f, 0x41, 0x9d, 0x97, 0x54, 0x96, 0x2b,
0x92, 0xa4, 0x40, 0x72, 0x13, 0x2a, 0xe7, 0xe1, 0x44, 0xfa, 0x5e, 0x90, 0x8e, 0xd7, 0x41, 0x78,
0xda, 0x1f, 0x56, 0x1f, 0x9f, 0x75, 0x6e, 0xdf, 0x66, 0xc1, 0xcc, 0xa7, 0x50, 0xd5, 0xea, 0xab,
0x98, 0x81, 0xda, 0x2f, 0xa0, 0xcd, 0x84, 0x4b, 0x0b, 0xe1, 0xcf, 0xd7, 0xb2, 0x5f, 0x65, 0x9b,
0xf6, 0xc0, 0x9f, 0x0e, 0xa9, 0xee, 0x01, 0x63, 0x88, 0x56, 0xc0, 0xa5, 0xed, 0x67, 0xff, 0x2b,
0x8b, 0x0b, 0x2d, 0xab, 0x97, 0xdc, 0x85, 0x0a, 0xd3, 0x95, 0x99, 0x80, 0x87, 0x4a, 0x49, 0x61,
0x74, 0x0e, 0x52, 0x30, 0x93, 0x10, 0x83, 0xa8, 0x7a, 0xed, 0x3c, 0x84, 0x9a, 0xba, 0x8f, 0x6a,
0x64, 0x19, 0xaf, 0x2b, 0x03, 0x25, 0x9b, 0xda, 0x09, 0x54, 0xc5, 0xd0, 0xbf, 0xd2, 0x46, 0x18,
0x8e, 0xa8, 0x76, 0xf2, 0xf4, 0xc7, 0x16, 0x2c, 0x1b, 0x7d, 0x62, 0x6c, 0xea, 0xbb, 0x71, 0x22,
0xd2, 0x02, 0xc4, 0xca, 0xeb, 0x20, 0x9d, 0xc5, 0x4b, 0x26, 0x8b, 0xab, 0x93, 0x8c, 0xb2, 0x7e,
0x92, 0x71, 0x1f, 0xea, 0x69, 0x6a, 0xb8, 0xd9, 0x29, 0xd6, 0xa2, 0x4c, 0xce, 0x49, 0x89, 0xd2,
0x58, 0x79, 0x55, 0x8b, 0x95, 0xdb, 0x8f, 0xa0, 0xa1, 0xd1, 0xeb, 0xb1, 0x6e, 0xcb, 0x88, 0x75,
0xab, 0xcc, 0xb5, 0x52, 0x9a, 0xb9, 0x66, 0xff, 0xac, 0x04, 0xcb, 0x8c, 0xbd, 0xbd, 0x60, 0x74,
0x14, 0xfa, 0xde, 0x60, 0x86, 0x6c, 0x25, 0x39, 0x59, 0xec, 0x95, 0x92, 0xcd, 0x4d, 0x30, 0x93,
0x77, 0x19, 0x61, 0x13, 0xca, 0x49, 0x95, 0x99, 0xf6, 0x62, 0xb2, 0x7f, 0xea, 0xc6, 0x42, 0x21,
0x08, 0x5b, 0xdd, 0x00, 0x32, 0x1d, 0xc3, 0x00, 0x98, 0x87, 0x38, 0xf6, 0x7c, 0xdf, 0xe3, 0xb4,
0xdc, 0x93, 0x2b, 0x42, 0xb1, 0x36, 0x87, 0x5e, 0xec, 0x9e, 0xa6, 0xa7, 0x94, 0xaa, 0x8c, 0x61,
0x40, 0xf7, 0xb5, 0x16, 0x06, 0x5c, 0x44, 0x01, 0x37, 0x81, 0xd9, 0x85, 0x5c, 0xca, 0x2d, 0xa4,
0xfd, 0x1f, 0x4a, 0xd0, 0xd0, 0xd8, 0x42, 0x1c, 0xcd, 0x9b, 0x9b, 0x86, 0x06, 0x91, 0x78, 0x23,
0x2e, 0xa0, 0x41, 0xc8, 0x6d, 0xb3, 0x45, 0x3c, 0x0a, 0x40, 0x61, 0x37, 0xd8, 0xe7, 0x06, 0xd4,
0x19, 0xdb, 0x7f, 0x82, 0x41, 0x08, 0x71, 0x27, 0x43, 0x01, 0x24, 0xf6, 0x01, 0x62, 0xab, 0x29,
0x16, 0x01, 0x6f, 0x3c, 0xcc, 0x7f, 0x08, 0x4d, 0x51, 0x0d, 0xae, 0x2f, 0x0e, 0x38, 0x15, 0x3c,
0x63, 0xed, 0x1d, 0x83, 0x52, 0x7e, 0xf9, 0x40, 0x7e, 0x59, 0xbb, 0xea, 0x4b, 0x49, 0x69, 0x3f,
0x55, 0x39, 0x12, 0x4f, 0x23, 0x77, 0x72, 0x2e, 0x95, 0xc9, 0x7d, 0x58, 0x95, 0x3a, 0x63, 0x1a,
0xb8, 0x41, 0x10, 0x4e, 0x83, 0x01, 0x95, 0x09, 0x6e, 0x45, 0x28, 0x7b, 0xa8, 0xd2, 0xa1, 0xb1,
0x22, 0x72, 0x0f, 0xaa, 0xdc, 0xd2, 0xe2, 0x7b, 0x6b, 0xb1, 0xfa, 0xe0, 0x24, 0xe4, 0x2e, 0x54,
0xb9, 0xc1, 0x55, 0x9a, 0x2b, 0xf0, 0x9c, 0xc0, 0xbe, 0x07, 0x6d, 0xcc, 0xb2, 0x37, 0xf5, 0x9e,
0xb9, 0x2f, 0x2f, 0x0e, 0x30, 0x0f, 0xdf, 0x5e, 0x03, 0x72, 0xc8, 0xe5, 0x49, 0x3f, 0xe9, 0xfc,
0x55, 0x19, 0x1a, 0x1a, 0x98, 0xe9, 0x25, 0x3c, 0x9e, 0xea, 0x0f, 0x3d, 0x77, 0x4c, 0x13, 0x1a,
0x09, 0x19, 0xca, 0x40, 0x19, 0x9d, 0x7b, 0x31, 0xea, 0x87, 0xd3, 0xa4, 0x3f, 0xa4, 0xa3, 0x88,
0xf2, 0x0d, 0x88, 0x6d, 0xdd, 0x06, 0x94, 0xd1, 0x31, 0x2e, 0xd6, 0xe8, 0xf8, 0x81, 0x52, 0x06,
0x2a, 0xcf, 0x2d, 0xf9, 0x1c, 0x55, 0xd2, 0x73, 0x4b, 0x3e, 0x23, 0x59, 0x8d, 0x5a, 0x2d, 0xd0,
0xa8, 0x9f, 0xc2, 0x3a, 0xd7, 0x9d, 0x42, 0x6b, 0xf4, 0x33, 0x8c, 0x35, 0x07, 0x4b, 0xee, 0x41,
0x87, 0xf5, 0x59, 0x8a, 0x45, 0xec, 0xfd, 0x94, 0xcb, 0x96, 0xe5, 0xe4, 0xe0, 0x8c, 0x16, 0x83,
0xe9, 0x3a, 0x2d, 0x4f, 0x1e, 0xc9, 0xc1, 0x91, 0xd6, 0x7d, 0x6d, 0xd2, 0xd6, 0x05, 0x6d, 0x06,
0x4e, 0x1e, 0xc2, 0xc6, 0x98, 0x0e, 0x3d, 0xd7, 0xac, 0x02, 0x63, 0x5b, 0x3c, 0x27, 0x6d, 0x1e,
0x9a, 0xb5, 0xc2, 0x66, 0xe1, 0xa7, 0xe1, 0xf8, 0xd4, 0xe3, 0x1b, 0x1a, 0x0f, 0xfb, 0x57, 0x9c,
0x1c, 0xdc, 0x5e, 0x86, 0xc6, 0x71, 0x12, 0x4e, 0xe4, 0xd2, 0xb7, 0xa0, 0xc9, 0x8b, 0x22, 0x9d,
0xf1, 0x3d, 0xb8, 0x8e, 0xbc, 0x7a, 0x12, 0x4e, 0x42, 0x3f, 0x1c, 0xcd, 0x0c, 0xe7, 0xfd, 0x3f,
0x59, 0xb0, 0x6a, 0x60, 0x53, 0xef, 0x1d, 0x23, 0x8d, 0x32, 0x0f, 0x8d, 0xb3, 0xf7, 0x8a, 0xb6,
0x1d, 0x70, 0x42, 0x7e, 0xa8, 0xf3, 0x42, 0xa4, 0xa6, 0x6d, 0xa7, 0xd7, 0xe2, 0xe4, 0x87, 0x9c,
0xd7, 0xbb, 0x79, 0x5e, 0x17, 0xdf, 0xcb, 0x5b, 0x71, 0xb2, 0x8a, 0x6f, 0x89, 0x54, 0x9f, 0xa1,
0x18, 0x74, 0xd9, 0x4c, 0xcf, 0xd0, 0x83, 0x3d, 0xb2, 0x07, 0x03, 0x05, 0x8c, 0xed, 0x9f, 0x5b,
0x00, 0x69, 0xef, 0x30, 0x41, 0x44, 0x6d, 0x69, 0xfc, 0x0a, 0xa6, 0xb6, 0x7d, 0x7d, 0x08, 0x4d,
0x75, 0xc6, 0x9f, 0xee, 0x92, 0x0d, 0x09, 0x63, 0x56, 0xc5, 0x1d, 0x68, 0x8f, 0xfc, 0xf0, 0x14,
0xad, 0x17, 0xcc, 0x8f, 0x8d, 0x45, 0x52, 0x67, 0x8b, 0x83, 0x9f, 0x08, 0x68, 0xba, 0xa5, 0x56,
0xf4, 0x2d, 0xb5, 0x78, 0x83, 0xfc, 0x9b, 0x25, 0x75, 0xd0, 0x9a, 0xce, 0xc4, 0x5c, 0x09, 0x27,
0x0f, 0x72, 0xea, 0x7c, 0xce, 0xb9, 0x26, 0x3a, 0x0e, 0x47, 0x57, 0xc6, 0x7d, 0x1f, 0x41, 0x2b,
0xe2, 0xba, 0x52, 0x2a, 0xd2, 0xca, 0x1b, 0x14, 0xe9, 0x72, 0x64, 0xec, 0xc6, 0x5f, 0x85, 0x8e,
0x3b, 0xbc, 0xa0, 0x51, 0xe2, 0x61, 0x1c, 0x0c, 0x4d, 0x27, 0x3e, 0xb8, 0xb6, 0x06, 0x47, 0x0b,
0xe5, 0x0e, 0xb4, 0x45, 0x7a, 0xad, 0xa2, 0x14, 0x97, 0x99, 0x52, 0x30, 0x23, 0xb4, 0x7f, 0x21,
0xcf, 0x74, 0xcd, 0x95, 0x9d, 0x3f, 0x23, 0xfa, 0xe8, 0x4a, 0x99, 0xd1, 0x7d, 0x45, 0x9c, 0xaf,
0x0e, 0x65, 0xb0, 0xad, 0xac, 0x25, 0x8b, 0x0d, 0xc5, 0x79, 0xb8, 0x39, 0xa5, 0x95, 0xb7, 0x99,
0x52, 0xfb, 0x4f, 0x2c, 0x58, 0xda, 0x0f, 0x27, 0xfb, 0x22, 0x6d, 0x0e, 0xc5, 0x43, 0xe5, 0xb5,
0xcb, 0xe2, 0x1b, 0x12, 0xea, 0x0a, 0x2d, 0x90, 0xe5, 0xac, 0x05, 0xf2, 0x17, 0xe0, 0x3d, 0x0c,
0xf5, 0x46, 0xe1, 0x24, 0x8c, 0x98, 0x88, 0xba, 0x3e, 0x37, 0x37, 0xc2, 0x20, 0x39, 0x97, 0x2a,
0xf4, 0x4d, 0x24, 0x18, 0x7f, 0xf1, 0x93, 0x8b, 0x3e, 0x77, 0x9b, 0x84, 0xc5, 0xc4, 0x35, 0x6b,
0x1e, 0x61, 0xff, 0x1e, 0xd4, 0xd1, 0x9b, 0xc0, 0x61, 0x7d, 0x0c, 0xf5, 0xf3, 0x70, 0xd2, 0x3f,
0xf7, 0x82, 0x44, 0x8a, 0x7c, 0x2b, 0x35, 0xf3, 0xf7, 0x71, 0x42, 0x14, 0x81, 0xfd, 0x77, 0x17,
0x61, 0xe9, 0x59, 0x70, 0x11, 0x7a, 0x03, 0x3c, 0x3f, 0x1e, 0xd3, 0x71, 0x28, 0xb3, 0xfc, 0xd9,
0x6f, 0x72, 0x03, 0x96, 0x30, 0xad, 0x75, 0xc2, 0x99, 0xb6, 0xc9, 0xf3, 0x44, 0x04, 0x08, 0x6f,
0x19, 0xa6, 0x77, 0xad, 0xb8, 0x50, 0x69, 0x10, 0xe6, 0x06, 0x46, 0xfa, 0x5d, 0x29, 0x51, 0x4a,
0x3d, 0xa3, 0xaa, 0x76, 0x8b, 0x82, 0xb5, 0x25, 0xd2, 0xfc, 0x78, 0x1e, 0x18, 0x6f, 0x4b, 0x80,
0xd0, 0x75, 0x8d, 0x28, 0x0f, 0xd5, 0x2b, 0x23, 0x8b, 0xb9, 0xae, 0x3a, 0x90, 0x19, 0x62, 0xfc,
0x03, 0x4e, 0xc3, 0x37, 0x00, 0x1d, 0xc4, 0x4c, 0xd1, 0xec, 0xf5, 0x3c, 0x7e, 0x3d, 0x32, 0x0b,
0x66, 0xfa, 0x7b, 0x48, 0x95, 0x9a, 0xe5, 0xe3, 0x00, 0x7e, 0x9f, 0x2c, 0x0b, 0xd7, 0x1c, 0x5e,
0x9e, 0x81, 0x2c, 0x1d, 0x5e, 0xc6, 0x30, 0xae, 0xef, 0x9f, 0xba, 0x83, 0x57, 0x78, 0x3b, 0x13,
0x4f, 0x74, 0xeb, 0x8e, 0x09, 0xc4, 0x64, 0xbd, 0x74, 0x55, 0x31, 0xa3, 0xa6, 0xe2, 0xe8, 0x20,
0xf2, 0x00, 0x1a, 0xe8, 0xe4, 0x8b, 0x75, 0x6d, 0xe1, 0xba, 0x76, 0xf4, 0x28, 0x00, 0xae, 0xac,
0x4e, 0xa4, 0x9f, 0x6d, 0xb7, 0x73, 0x39, 0xc1, 0xee, 0x70, 0x28, 0x52, 0x02, 0x3a, 0x3c, 0x60,
0xa1, 0x00, 0x6c, 0x47, 0x17, 0x13, 0xc6, 0x09, 0x56, 0x90, 0xc0, 0x80, 0x91, 0x9b, 0x50, 0x63,
0x1e, 0xde, 0xc4, 0xf5, 0x86, 0x98, 0x44, 0xc3, 0x1d, 0x4d, 0x05, 0x63, 0x75, 0xc8, 0xdf, 0xb8,
0x55, 0xae, 0xe2, 0xac, 0x18, 0x30, 0x36, 0x37, 0xaa, 0x3c, 0x4e, 0x93, 0x88, 0x4d, 0x20, 0xf9,
0x04, 0x0f, 0x66, 0x13, 0x8a, 0x99, 0xc2, 0xad, 0x07, 0xef, 0x89, 0x31, 0x0b, 0xa6, 0x95, 0x7f,
0x8f, 0x19, 0x89, 0xc3, 0x29, 0xed, 0x6d, 0x68, 0xea, 0x60, 0x52, 0x83, 0xca, 0xf3, 0xa3, 0xbd,
0xc3, 0xce, 0x02, 0x69, 0xc0, 0xd2, 0xf1, 0xde, 0xc9, 0xc9, 0xc1, 0xde, 0x6e, 0xc7, 0x22, 0x4d,
0xa8, 0xa9, 0xcc, 0xca, 0x12, 0x2b, 0x6d, 0xef, 0xec, 0xec, 0x1d, 0x9d, 0xec, 0xed, 0x76, 0xca,
0x76, 0x02, 0x64, 0x7b, 0x38, 0x14, 0xb5, 0xa8, 0x30, 0x4c, 0xca, 0xcf, 0x96, 0xc1, 0xcf, 0x05,
0x3c, 0x55, 0x2a, 0xe6, 0xa9, 0x37, 0xce, 0xbc, 0xbd, 0x07, 0x8d, 0x23, 0xed, 0x4a, 0x20, 0x8a,
0x97, 0xbc, 0x0c, 0x28, 0xc4, 0x52, 0x83, 0x68, 0xdd, 0x29, 0xe9, 0xdd, 0xb1, 0xff, 0xa9, 0xc5,
0xef, 0xe6, 0xa8, 0xee, 0xf3, 0xb6, 0x6d, 0x68, 0xaa, 0x58, 0x68, 0x9a, 0x34, 0x6d, 0xc0, 0x18,
0x0d, 0x76, 0xa5, 0x1f, 0x9e, 0x9d, 0xc5, 0x54, 0xa6, 0x38, 0x1a, 0x30, 0x69, 0xd7, 0x30, 0x4b,
0xc9, 0xe3, 0x2d, 0xc4, 0x22, 0xd5, 0x31, 0x07, 0x67, 0x5a, 0x5e, 0x84, 0xbc, 0x64, 0x72, 0xa7,
0x2a, 0xab, 0xdc, 0xee, 0xec, 0x2c, 0xdf, 0x83, 0x9a, 0xaa, 0xd7, 0x54, 0x60, 0x92, 0x52, 0xe1,
0x99, 0xa2, 0x44, 0x7f, 0xc7, 0xe8, 0x34, 0x57, 0xda, 0x79, 0x04, 0xd9, 0x04, 0x72, 0xe6, 0x45,
0x59, 0xf2, 0x32, 0x92, 0x17, 0x60, 0xec, 0x97, 0xb0, 0x2a, 0x19, 0x49, 0x33, 0xb8, 0xcc, 0x45,
0xb4, 0xae, 0x12, 0x9f, 0x52, 0x5e, 0x7c, 0xec, 0x3f, 0x2d, 0xc3, 0x92, 0x58, 0xe9, 0xdc, 0xb5,
0x52, 0xbe, 0xce, 0x06, 0x8c, 0x74, 0x8d, 0x6b, 0x67, 0x28, 0x6b, 0x42, 0x69, 0xe6, 0xd4, 0x62,
0xb9, 0x48, 0x2d, 0x12, 0xa8, 0x4c, 0xdc, 0xe4, 0x1c, 0x23, 0x02, 0x75, 0x07, 0x7f, 0xcb, 0xc8,
0x5d, 0xd5, 0x8c, 0xdc, 0x15, 0x5d, 0xa2, 0xe5, 0x3b, 0x7e, 0xfe, 0x12, 0xed, 0x0d, 0xa8, 0x63,
0x27, 0xb4, 0x83, 0xde, 0x14, 0xc0, 0xb8, 0x97, 0x17, 0x50, 0xb6, 0xc5, 0x2d, 0x90, 0x14, 0xf2,
0x0e, 0x8a, 0xf8, 0x1b, 0xb0, 0xc8, 0xaf, 0x21, 0x88, 0x14, 0xd6, 0x1b, 0xf2, 0xb0, 0x8b, 0xd3,
0xc9, 0xbf, 0x3c, 0x17, 0xc6, 0x11, 0xb4, 0xfa, 0x25, 0xc6, 0x86, 0x79, 0x89, 0x51, 0x8f, 0x29,
0x36, 0xcd, 0x98, 0xa2, 0xfd, 0x04, 0x96, 0x8d, 0xea, 0x98, 0xca, 0x10, 0x29, 0xb0, 0x9d, 0x05,
0xb2, 0x0c, 0xf5, 0x67, 0x87, 0xfd, 0x27, 0x07, 0xcf, 0x9e, 0xee, 0x9f, 0x74, 0x2c, 0x56, 0x3c,
0x7e, 0xb1, 0xb3, 0xb3, 0xb7, 0xb7, 0x8b, 0x2a, 0x04, 0x60, 0xf1, 0xc9, 0xf6, 0xb3, 0x03, 0x54,
0x20, 0xbb, 0x9c, 0xb7, 0x45, 0x5d, 0xea, 0x80, 0xe1, 0x77, 0x81, 0x48, 0x97, 0x14, 0x53, 0x61,
0x26, 0x3e, 0x4d, 0x64, 0x76, 0xf6, 0x8a, 0xc0, 0x3c, 0x53, 0x08, 0x79, 0xb9, 0x20, 0xad, 0x25,
0x15, 0x11, 0x31, 0x49, 0x59, 0x11, 0x11, 0xa4, 0x8e, 0xc2, 0xdb, 0x3d, 0xe8, 0xee, 0x52, 0x56,
0xdb, 0xb6, 0xef, 0x67, 0xba, 0xc3, 0xfc, 0x8a, 0x02, 0x9c, 0x70, 0x3a, 0xbe, 0x0b, 0xd7, 0xb6,
0x79, 0x22, 0xf6, 0x6f, 0x2b, 0x4f, 0xcf, 0xee, 0xc2, 0x7a, 0xb6, 0x4a, 0xd1, 0xd8, 0x13, 0x58,
0xd9, 0xa5, 0xa7, 0xd3, 0xd1, 0x01, 0xbd, 0x48, 0x1b, 0x22, 0x50, 0x89, 0xcf, 0xc3, 0x4b, 0x31,
0x3f, 0xf8, 0x9b, 0xbc, 0x0f, 0xe0, 0x33, 0x9a, 0x7e, 0x3c, 0xa1, 0x03, 0x79, 0xf5, 0x0d, 0x21,
0xc7, 0x13, 0x3a, 0xb0, 0x3f, 0x05, 0xa2, 0xd7, 0x23, 0xe6, 0x8b, 0x99, 0x05, 0xd3, 0xd3, 0x7e,
0x3c, 0x8b, 0x13, 0x3a, 0x96, 0x77, 0xfa, 0x74, 0x90, 0x7d, 0x07, 0x9a, 0x47, 0xee, 0xcc, 0xa1,
0x3f, 0x11, 0xd7, 0xab, 0x37, 0x60, 0x69, 0xe2, 0xce, 0x18, 0x0b, 0xaa, 0x18, 0x25, 0xa2, 0xed,
0xff, 0x53, 0x82, 0x45, 0x4e, 0xc9, 0x6a, 0x1d, 0xd2, 0x38, 0xf1, 0x02, 0x94, 0x34, 0x59, 0xab,
0x06, 0xca, 0xc9, 0x76, 0xa9, 0x40, 0xb6, 0x85, 0x03, 0x2d, 0xaf, 0x11, 0x09, 0x01, 0x36, 0x60,
0x4c, 0xd2, 0xd2, 0x84, 0x5b, 0x1e, 0xc9, 0x4a, 0x01, 0x99, 0x68, 0x7b, 0x6a, 0x7c, 0xf0, 0xfe,
0x49, 0xb5, 0x25, 0xc4, 0x58, 0x07, 0x15, 0x9a, 0x38, 0x4b, 0x5c, 0xda, 0x73, 0x26, 0x4e, 0xce,
0x94, 0xa9, 0xbd, 0x85, 0x29, 0xc3, 0xbd, 0xea, 0x37, 0x99, 0x32, 0xf0, 0x16, 0xa6, 0x8c, 0x4d,
0xa0, 0x83, 0xf7, 0x93, 0x99, 0xb1, 0x2c, 0x79, 0xf7, 0x1f, 0x58, 0xd0, 0x11, 0x5c, 0xa4, 0x70,
0xe4, 0x43, 0xc3, 0x29, 0x28, 0xbc, 0x2e, 0x73, 0x1b, 0x96, 0xd1, 0x54, 0x57, 0x2a, 0x40, 0x9c,
0x81, 0x18, 0x40, 0x36, 0x0e, 0x99, 0xae, 0x31, 0xf6, 0x7c, 0xb1, 0x28, 0x3a, 0x48, 0x6a, 0x91,
0xc8, 0x15, 0x89, 0xa3, 0x96, 0xa3, 0xca, 0xf6, 0x2f, 0x2d, 0x58, 0xd1, 0x3a, 0x2c, 0xb8, 0xf0,
0x11, 0x48, 0x69, 0xe0, 0x41, 0x7c, 0x2e, 0xb9, 0x1b, 0xa6, 0xd8, 0xa4, 0x9f, 0x19, 0xc4, 0xb8,
0x98, 0xee, 0x0c, 0x3b, 0x18, 0x4f, 0xc7, 0x62, 0x57, 0xd1, 0x41, 0x8c, 0x91, 0x2e, 0x29, 0x7d,
0xa5, 0x48, 0xf8, 0xbe, 0x66, 0xc0, 0x30, 0x9c, 0xc9, 0x5c, 0x0c, 0x45, 0x54, 0x11, 0xe1, 0x4c,
0x1d, 0x68, 0xff, 0x57, 0x0b, 0x56, 0xb9, 0xaf, 0x28, 0xfc, 0x73, 0x75, 0x13, 0x73, 0x91, 0xbb,
0xcc, 0x5c, 0x22, 0xf7, 0x17, 0x1c, 0x51, 0x26, 0xdf, 0x7c, 0x4b, 0xff, 0x56, 0x65, 0xb3, 0xce,
0x59, 0x8b, 0x72, 0xd1, 0x5a, 0xbc, 0x61, 0xa6, 0x8b, 0x22, 0xcb, 0xd5, 0xc2, 0xc8, 0xf2, 0xe3,
0x25, 0xa8, 0xc6, 0x83, 0x70, 0x42, 0xed, 0x75, 0x58, 0x33, 0x07, 0x27, 0x54, 0xd0, 0xcf, 0x2d,
0xe8, 0x3e, 0xe1, 0x67, 0x4f, 0x5e, 0x30, 0xda, 0xf7, 0xe2, 0x24, 0x8c, 0xd4, 0x85, 0xf5, 0x9b,
0x00, 0x71, 0xe2, 0x46, 0x09, 0xbf, 0x68, 0x21, 0xe2, 0xb5, 0x29, 0x84, 0xf5, 0x91, 0x06, 0x43,
0x8e, 0xe5, 0x6b, 0xa3, 0xca, 0x39, 0xa3, 0x4a, 0x78, 0xb3, 0x86, 0x69, 0xf2, 0x11, 0xcf, 0xee,
0x66, 0xc6, 0x13, 0xbd, 0x40, 0xbd, 0xce, 0xdd, 0xc4, 0x0c, 0xd4, 0xfe, 0x2f, 0x16, 0xb4, 0xd3,
0x4e, 0x62, 0x16, 0x82, 0xa9, 0x1d, 0x84, 0x3d, 0x92, 0x6a, 0x07, 0x19, 0x49, 0xf6, 0x98, 0x81,
0x22, 0xfa, 0xa6, 0x41, 0x50, 0x62, 0x45, 0x29, 0x9c, 0x4a, 0x8b, 0x4f, 0x07, 0xf1, 0x5c, 0x4d,
0x66, 0x1a, 0x09, 0x33, 0x4f, 0x94, 0xf0, 0x9e, 0xcc, 0x38, 0xc1, 0xaf, 0x78, 0x54, 0x5c, 0x16,
0x49, 0x87, 0xdb, 0x16, 0x4b, 0xfc, 0x30, 0x8c, 0xd9, 0x15, 0xfa, 0x9e, 0x5b, 0xe3, 0xf3, 0xa3,
0xf6, 0xdc, 0xbf, 0x65, 0xc1, 0xf5, 0x82, 0x89, 0x17, 0x52, 0xb3, 0x0b, 0x2b, 0x67, 0x0a, 0x29,
0x27, 0x87, 0x8b, 0xce, 0xba, 0x3c, 0x46, 0x37, 0x27, 0xc4, 0xc9, 0x7f, 0xa0, 0x0c, 0x45, 0x3e,
0xdd, 0x46, 0x36, 0x74, 0x1e, 0x61, 0x1f, 0x41, 0x6f, 0xef, 0x35, 0x13, 0xc2, 0x1d, 0xfd, 0xbd,
0x27, 0xc9, 0x0b, 0x0f, 0x72, 0x4a, 0xe6, 0xea, 0xc8, 0xc3, 0x19, 0x2c, 0x1b, 0x75, 0x91, 0xaf,
0xbf, 0x6d, 0x25, 0xba, 0xbc, 0xc8, 0xb5, 0xe2, 0x0f, 0x56, 0xc9, 0x9c, 0x6c, 0x0d, 0x64, 0x5f,
0x40, 0xfb, 0xf3, 0xa9, 0x9f, 0x78, 0xe9, 0xe3, 0x55, 0xe4, 0x9b, 0xe2, 0x23, 0xac, 0x42, 0x4e,
0x5d, 0x61, 0x53, 0x3a, 0x1d, 0x9b, 0xb1, 0x31, 0xab, 0xa9, 0x9f, 0x6f, 0x31, 0x8f, 0xb0, 0xaf,
0xc3, 0x46, 0xda, 0x24, 0x9f, 0x3b, 0xa9, 0xa8, 0x7f, 0x61, 0xf1, 0xe4, 0x22, 0xf3, 0x2d, 0x2d,
0xf2, 0x14, 0x56, 0x63, 0x2f, 0x18, 0xf9, 0x54, 0xaf, 0x27, 0x16, 0x33, 0x71, 0xcd, 0xec, 0x9e,
0x78, 0x6f, 0xcb, 0x29, 0xfa, 0x82, 0x31, 0x48, 0x71, 0x47, 0x53, 0x06, 0xc9, 0x4c, 0x49, 0xd1,
0x00, 0xbe, 0x0d, 0x2d, 0xb3, 0x31, 0xf2, 0x50, 0xa4, 0x53, 0xa7, 0x3d, 0xd3, 0x8f, 0x07, 0x4c,
0xce, 0x30, 0x28, 0xed, 0x9f, 0x59, 0xd0, 0x75, 0x28, 0x63, 0x63, 0xaa, 0x35, 0x2a, 0xb8, 0xe7,
0x51, 0xae, 0xda, 0xf9, 0x03, 0x56, 0x69, 0xda, 0x72, 0xac, 0x9b, 0x73, 0x17, 0x65, 0x7f, 0xa1,
0x60, 0x54, 0x8f, 0x6b, 0xb0, 0x28, 0xc6, 0xb7, 0x01, 0xd7, 0x44, 0x97, 0x64, 0x77, 0xd2, 0xd8,
0xb2, 0xd1, 0xa8, 0x11, 0x5b, 0xee, 0x41, 0x97, 0xbf, 0x24, 0xa0, 0x8f, 0x83, 0x7f, 0x78, 0xef,
0x4b, 0x68, 0x68, 0xef, 0x29, 0x90, 0x0d, 0x58, 0x7d, 0xf9, 0xec, 0xe4, 0x70, 0xef, 0xf8, 0xb8,
0x7f, 0xf4, 0xe2, 0xf1, 0x77, 0xf6, 0xbe, 0xdf, 0xdf, 0xdf, 0x3e, 0xde, 0xef, 0x2c, 0x90, 0x75,
0x20, 0x87, 0x7b, 0xc7, 0x27, 0x7b, 0xbb, 0x06, 0xdc, 0x22, 0x37, 0xa1, 0xf7, 0xe2, 0xf0, 0xc5,
0xf1, 0xde, 0x6e, 0xbf, 0xe8, 0xbb, 0x12, 0x79, 0x1f, 0xae, 0x0b, 0x7c, 0xc1, 0xe7, 0xe5, 0x07,
0x3f, 0x2b, 0x43, 0x8b, 0xe7, 0x38, 0xf1, 0x27, 0xd8, 0x68, 0x44, 0x3e, 0x87, 0x25, 0xf1, 0x96,
0x1f, 0x91, 0xf3, 0x69, 0xbe, 0x1e, 0xd8, 0x5b, 0xcf, 0x82, 0xc5, 0x24, 0xac, 0xfe, 0xd5, 0x3f,
0xf9, 0x9f, 0x7f, 0xa7, 0xb4, 0x4c, 0x1a, 0x5b, 0x17, 0x9f, 0x6c, 0x8d, 0x68, 0x10, 0xb3, 0x3a,
0xfe, 0x10, 0x20, 0x7d, 0xa1, 0x8e, 0x74, 0x95, 0x13, 0x9a, 0x79, 0xbe, 0xaf, 0x77, 0xbd, 0x00,
0x23, 0xea, 0xbd, 0x8e, 0xf5, 0xae, 0xda, 0x2d, 0x56, 0xaf, 0x17, 0x78, 0x09, 0x7f, 0xad, 0xee,
0x33, 0xeb, 0x1e, 0x19, 0x42, 0x53, 0x7f, 0x3b, 0x8e, 0xc8, 0xf8, 0x78, 0xc1, 0xeb, 0x77, 0xbd,
0xf7, 0x0a, 0x71, 0x72, 0x01, 0xb1, 0x8d, 0x6b, 0x76, 0x87, 0xb5, 0x31, 0x45, 0x8a, 0xb4, 0x15,
0x9f, 0xb3, 0x75, 0xfa, 0x44, 0x1c, 0xb9, 0xa1, 0x71, 0x5a, 0xee, 0x81, 0xba, 0xde, 0xfb, 0x73,
0xb0, 0xa2, 0xad, 0xf7, 0xb1, 0xad, 0x0d, 0x9b, 0xb0, 0xb6, 0x06, 0x48, 0x23, 0x1f, 0xa8, 0xfb,
0xcc, 0xba, 0xf7, 0xe0, 0xef, 0x7d, 0x04, 0x75, 0x75, 0x6e, 0x46, 0x7e, 0x0c, 0xcb, 0x46, 0x12,
0x1a, 0x91, 0xc3, 0x28, 0xca, 0x59, 0xeb, 0xdd, 0x28, 0x46, 0x8a, 0x86, 0x6f, 0x62, 0xc3, 0x5d,
0xb2, 0xce, 0x1a, 0x16, 0x59, 0x5c, 0x5b, 0x98, 0x4e, 0xc9, 0x6f, 0x63, 0xbd, 0xd2, 0xc4, 0x97,
0x37, 0x76, 0x23, 0x2b, 0x51, 0x46, 0x6b, 0xef, 0xcf, 0xc1, 0x8a, 0xe6, 0x6e, 0x60, 0x73, 0xeb,
0x64, 0x4d, 0x6f, 0x4e, 0x9d, 0x67, 0x51, 0xbc, 0x82, 0xa8, 0xbf, 0x9e, 0x46, 0xde, 0x57, 0x8c,
0x55, 0xf4, 0xaa, 0x9a, 0x62, 0x91, 0xfc, 0xd3, 0x6a, 0x76, 0x17, 0x9b, 0x22, 0x04, 0x97, 0x4f,
0x7f, 0x3c, 0x8d, 0x9c, 0x42, 0x43, 0x7b, 0x9d, 0x87, 0x5c, 0x9f, 0xfb, 0x92, 0x50, 0xaf, 0x57,
0x84, 0x2a, 0x1a, 0x8a, 0x5e, 0xff, 0x16, 0xdb, 0x97, 0x7f, 0x08, 0x75, 0xf5, 0xde, 0x0b, 0xd9,
0xd0, 0xde, 0xdf, 0xd1, 0xdf, 0xa7, 0xe9, 0x75, 0xf3, 0x88, 0x22, 0xe6, 0xd3, 0x6b, 0x67, 0xcc,
0xf7, 0x12, 0x1a, 0xda, 0x9b, 0x2e, 0x6a, 0x00, 0xf9, 0x77, 0x63, 0xd4, 0x00, 0x0a, 0x9e, 0x80,
0xb1, 0x57, 0xb0, 0x89, 0x06, 0xa9, 0x23, 0x7f, 0x27, 0xaf, 0xc3, 0x98, 0x1c, 0xc0, 0x35, 0xa1,
0xa6, 0x4e, 0xe9, 0xbb, 0x2c, 0x43, 0xc1, 0x83, 0x75, 0xf7, 0x2d, 0xf2, 0x08, 0x6a, 0xf2, 0xe9,
0x1e, 0xb2, 0x5e, 0xfc, 0x04, 0x51, 0x6f, 0x23, 0x07, 0x17, 0xe6, 0xc9, 0xf7, 0x01, 0xd2, 0x07,
0x64, 0x94, 0x92, 0xc8, 0x3d, 0x48, 0xa3, 0x38, 0x20, 0xff, 0xda, 0x8c, 0xbd, 0x8e, 0x03, 0xec,
0x10, 0x54, 0x12, 0x01, 0xbd, 0x94, 0xb7, 0x8d, 0x7f, 0x04, 0x0d, 0xed, 0x0d, 0x19, 0x35, 0x7d,
0xf9, 0xf7, 0x67, 0xd4, 0xf4, 0x15, 0x3c, 0x39, 0x63, 0xf7, 0xb0, 0xf6, 0x35, 0xbb, 0xcd, 0x6a,
0x8f, 0xbd, 0x51, 0x30, 0xe6, 0x04, 0x6c, 0x81, 0xce, 0x61, 0xd9, 0x78, 0x28, 0x46, 0x49, 0x68,
0xd1, 0x33, 0x34, 0x4a, 0x42, 0x0b, 0xdf, 0x96, 0x91, 0x7c, 0x66, 0xaf, 0xb0, 0x76, 0x2e, 0x90,
0x44, 0x6b, 0xe9, 0x07, 0xd0, 0xd0, 0x1e, 0x7d, 0x51, 0x63, 0xc9, 0xbf, 0x2f, 0xa3, 0xc6, 0x52,
0xf4, 0x46, 0xcc, 0x1a, 0xb6, 0xd1, 0xb2, 0x91, 0x15, 0xf0, 0xde, 0x2c, 0xab, 0xfb, 0xc7, 0xd0,
0x32, 0x9f, 0x81, 0x51, 0xb2, 0x5f, 0xf8, 0xa0, 0x8c, 0x92, 0xfd, 0x39, 0x6f, 0xc7, 0x08, 0x96,
0xbe, 0xb7, 0xaa, 0x1a, 0xd9, 0xfa, 0x42, 0x64, 0xdd, 0x7c, 0x49, 0xbe, 0xcb, 0x14, 0x9c, 0xb8,
0xc8, 0x4c, 0x36, 0x34, 0xae, 0xd5, 0xaf, 0x3b, 0x2b, 0x79, 0xc9, 0xdd, 0x79, 0x36, 0x99, 0x99,
0xdf, 0xfc, 0xc5, 0x5d, 0x0b, 0x2f, 0x34, 0x6b, 0xbb, 0x96, 0x7e, 0xe7, 0x59, 0xdb, 0xb5, 0x8c,
0x7b, 0xcf, 0xd9, 0x5d, 0x2b, 0xf1, 0x58, 0x1d, 0x01, 0xb4, 0x33, 0x89, 0xf2, 0x4a, 0x2a, 0x8a,
0xef, 0x32, 0xf5, 0x6e, 0xbe, 0x39, 0xbf, 0xde, 0xd4, 0x20, 0x52, 0x09, 0x6e, 0xc9, 0x9b, 0x63,
0x7f, 0x09, 0x9a, 0xfa, 0x03, 0x18, 0x44, 0x17, 0xe5, 0x6c, 0x4b, 0xef, 0x15, 0xe2, 0xcc, 0xc5,
0x25, 0x4d, 0xbd, 0x19, 0xf2, 0x3d, 0x58, 0x57, 0xa2, 0xae, 0xe7, 0x5e, 0xc7, 0xe4, 0x83, 0x82,
0x8c, 0x6c, 0xdd, 0x78, 0xe9, 0x5d, 0x9f, 0x9b, 0xb2, 0x7d, 0xdf, 0x62, 0x4c, 0x63, 0xbe, 0x2c,
0x90, 0x6e, 0x18, 0x45, 0x0f, 0x2a, 0xa4, 0x1b, 0x46, 0xe1, 0x73, 0x04, 0x92, 0x69, 0xc8, 0xaa,
0x31, 0x47, 0xfc, 0xc0, 0x92, 0xfc, 0x00, 0xda, 0xda, 0xed, 0x96, 0xe3, 0x59, 0x30, 0x50, 0x02,
0x90, 0xbf, 0x78, 0xd9, 0x2b, 0x32, 0xcd, 0xed, 0x0d, 0xac, 0x7f, 0xc5, 0x36, 0x26, 0x87, 0x31,
0xff, 0x0e, 0x34, 0xf4, 0x9b, 0x33, 0x6f, 0xa8, 0x77, 0x43, 0x43, 0xe9, 0xf7, 0x06, 0xef, 0x5b,
0xe4, 0x1f, 0x5a, 0xd0, 0x34, 0xee, 0xa1, 0x18, 0x87, 0xf5, 0x99, 0x7a, 0xba, 0x3a, 0x4e, 0xaf,
0xc8, 0x76, 0xb0, 0x93, 0x07, 0xf7, 0xbe, 0x6d, 0x4c, 0xc2, 0x17, 0x46, 0xfc, 0x65, 0x33, 0xfb,
0x5c, 0xe0, 0x97, 0x59, 0x02, 0xfd, 0x72, 0xea, 0x97, 0xf7, 0x2d, 0xf2, 0xc7, 0x16, 0xb4, 0xcc,
0xa8, 0xa1, 0x5a, 0xaa, 0xc2, 0xf8, 0xa4, 0x5a, 0xaa, 0x39, 0xa1, 0xc6, 0x1f, 0x60, 0x2f, 0x4f,
0xee, 0x39, 0x46, 0x2f, 0xc5, 0x9b, 0x13, 0xbf, 0x59, 0x6f, 0xc9, 0x67, 0xfc, 0x95, 0x52, 0x19,
0xdb, 0x27, 0xf9, 0xf7, 0x32, 0xd5, 0xf2, 0xea, 0x2f, 0x5c, 0xde, 0xb5, 0xee, 0x5b, 0xe4, 0x47,
0xfc, 0x99, 0x3c, 0x19, 0x7e, 0x66, 0x5c, 0xf2, 0xb6, 0xdf, 0xdb, 0xb7, 0x71, 0x4c, 0x37, 0xed,
0xeb, 0xc6, 0x98, 0xb2, 0xfb, 0xf1, 0x36, 0xef, 0x9d, 0x78, 0x9c, 0x32, 0xdd, 0x50, 0x72, 0x0f,
0x56, 0xce, 0xef, 0xe4, 0x98, 0x77, 0x52, 0x90, 0x1b, 0xac, 0xfc, 0x96, 0xd5, 0xd8, 0xf7, 0xb0,
0xaf, 0xb7, 0xed, 0x0f, 0xe6, 0xf6, 0x75, 0x0b, 0x63, 0x7f, 0xac, 0xc7, 0x47, 0x00, 0xe9, 0x39,
0x1c, 0xc9, 0x9c, 0x03, 0x29, 0x01, 0xcf, 0x1f, 0xd5, 0x99, 0xf2, 0x22, 0x8f, 0x8b, 0x58, 0x8d,
0x3f, 0xe4, 0xea, 0xea, 0x99, 0x3c, 0x41, 0xd2, 0x8d, 0x12, 0xf3, 0xc0, 0xcc, 0x30, 0x4a, 0xb2,
0xf5, 0x1b, 0xca, 0x4a, 0x1d, 0x47, 0xbd, 0x80, 0xe5, 0x83, 0x30, 0x7c, 0x35, 0x9d, 0xa8, 0x33,
0x75, 0x33, 0x2c, 0xbf, 0xef, 0xc6, 0xe7, 0xbd, 0xcc, 0x28, 0xec, 0x5b, 0x58, 0x55, 0x8f, 0x74,
0xb5, 0xaa, 0xb6, 0xbe, 0x48, 0xcf, 0xf9, 0xbe, 0x24, 0x2e, 0xac, 0x28, 0x1d, 0xa8, 0x3a, 0xde,
0x33, 0xab, 0x31, 0x34, 0x5f, 0xb6, 0x09, 0xc3, 0x7a, 0x96, 0xbd, 0xdd, 0x8a, 0x65, 0x9d, 0xf7,
0x2d, 0x72, 0x04, 0xcd, 0x5d, 0x3a, 0xc0, 0x2c, 0x78, 0x8c, 0x6d, 0xaf, 0xa6, 0x1d, 0x57, 0x41,
0xf1, 0xde, 0xb2, 0x01, 0x34, 0xf7, 0x85, 0x89, 0x3b, 0x8b, 0xe8, 0x4f, 0xb6, 0xbe, 0x10, 0x51,
0xf3, 0x2f, 0xe5, 0xbe, 0x20, 0x8f, 0x15, 0x8c, 0x7d, 0x21, 0x73, 0x0e, 0x61, 0xec, 0x0b, 0xb9,
0x73, 0x08, 0x63, 0xaa, 0xe5, 0xb1, 0x06, 0xf1, 0x61, 0x25, 0x77, 0x74, 0xa1, 0xb6, 0x84, 0x79,
0x07, 0x1e, 0xbd, 0x5b, 0xf3, 0x09, 0xcc, 0xd6, 0xee, 0x99, 0xad, 0x1d, 0xc3, 0xf2, 0x2e, 0xe5,
0x93, 0xc5, 0x93, 0x06, 0x33, 0x97, 0x99, 0xf4, 0x94, 0xc4, 0xac, 0x02, 0x47, 0x9c, 0xb9, 0xf1,
0x63, 0xc6, 0x1e, 0xf9, 0x21, 0x34, 0x9e, 0xd2, 0x44, 0x66, 0x09, 0x2a, 0xd3, 0x33, 0x93, 0x36,
0xd8, 0x2b, 0x48, 0x32, 0x34, 0x79, 0x06, 0x6b, 0xdb, 0xa2, 0xc3, 0x11, 0xe5, 0xca, 0xa9, 0xef,
0x0d, 0xbf, 0x24, 0x7f, 0x11, 0x2b, 0x57, 0x29, 0xd2, 0xeb, 0x5a, 0xda, 0x97, 0x5e, 0x79, 0x3b,
0x03, 0x2f, 0xaa, 0x39, 0x08, 0x87, 0x54, 0x33, 0x81, 0x02, 0x68, 0x68, 0x77, 0x14, 0x94, 0x00,
0xe5, 0x2f, 0x6c, 0x28, 0x01, 0x2a, 0xb8, 0xd2, 0x60, 0xdf, 0xc5, 0x76, 0x6c, 0x72, 0x2b, 0x6d,
0x87, 0x5f, 0x63, 0x48, 0x5b, 0xda, 0xfa, 0xc2, 0x1d, 0x27, 0x5f, 0x92, 0x97, 0xf8, 0x06, 0x8c,
0x9e, 0x09, 0x99, 0xda, 0xd2, 0xd9, 0xa4, 0x49, 0x35, 0x59, 0x1a, 0xca, 0xb4, 0xaf, 0x79, 0x53,
0x68, 0x29, 0x7d, 0x13, 0xe0, 0x38, 0x09, 0x27, 0xbb, 0x2e, 0x1d, 0x87, 0x41, 0xaa, 0x6b, 0xd3,
0x3c, 0xbc, 0x54, 0x7f, 0x69, 0xc9, 0x78, 0xe4, 0xa5, 0xe6, 0x7c, 0x18, 0x89, 0xa4, 0x92, 0xb9,
0xe6, 0xa6, 0xea, 0xa9, 0x09, 0x29, 0x48, 0xd7, 0xbb, 0x6f, 0x91, 0x6d, 0x80, 0xf4, 0xec, 0x4a,
0xb9, 0x12, 0xb9, 0x63, 0x31, 0xa5, 0xf6, 0x0a, 0x0e, 0xba, 0x8e, 0xa0, 0x9e, 0x1e, 0x86, 0x6c,
0xa4, 0xb7, 0x8c, 0x8c, 0xa3, 0x13, 0xb5, 0x83, 0xe7, 0x8e, 0x28, 0xec, 0x0e, 0x4e, 0x15, 0x90,
0x1a, 0x9b, 0x2a, 0x3c, 0x77, 0xf0, 0x60, 0x95, 0x77, 0x50, 0x99, 0x23, 0x98, 0x43, 0x26, 0x47,
0x52, 0x70, 0x4c, 0xa0, 0xa4, 0xb9, 0x30, 0xca, 0x6e, 0x44, 0x44, 0x18, 0xb7, 0xf2, 0xfc, 0x35,
0xa6, 0x9a, 0xc7, 0xb0, 0x92, 0x0b, 0x03, 0x2b, 0x91, 0x9e, 0x17, 0x99, 0x57, 0x22, 0x3d, 0x37,
0x82, 0x6c, 0x5f, 0xc3, 0x26, 0xdb, 0x36, 0xa0, 0x07, 0x74, 0xe9, 0x25, 0x83, 0x73, 0xd6, 0xdc,
0x2f, 0x2c, 0x58, 0x2d, 0x88, 0xf2, 0x92, 0x0f, 0xa5, 0x33, 0x3d, 0x37, 0x02, 0xdc, 0x2b, 0x0c,
0x02, 0xda, 0xc7, 0xd8, 0xce, 0xe7, 0xe4, 0x3b, 0xc6, 0xc6, 0xc6, 0xe3, 0x6f, 0x42, 0x32, 0xdf,
0x68, 0x54, 0x14, 0x5a, 0x14, 0x3f, 0x81, 0x0d, 0xde, 0x91, 0x6d, 0xdf, 0xcf, 0x04, 0x28, 0x6f,
0xe6, 0xfe, 0x51, 0x81, 0x11, 0x78, 0xed, 0xcd, 0xff, 0x47, 0x06, 0x73, 0xcc, 0x55, 0xde, 0x55,
0x32, 0x85, 0x4e, 0x36, 0xe8, 0x47, 0xe6, 0xd7, 0xd5, 0xfb, 0xc0, 0x70, 0x0b, 0xf3, 0x81, 0x42,
0xfb, 0x77, 0xb0, 0xb1, 0x0f, 0xec, 0x5e, 0xd1, 0xbc, 0x70, 0x4f, 0x91, 0xad, 0xc7, 0x5f, 0x51,
0x11, 0xca, 0xcc, 0x38, 0x65, 0x03, 0xf3, 0x42, 0xaa, 0xca, 0x31, 0x2d, 0x0e, 0x70, 0x7e, 0x84,
0xcd, 0xdf, 0xb2, 0xdf, 0x2b, 0x6a, 0x3e, 0xe2, 0x9f, 0x70, 0x17, 0x75, 0x23, 0x2b, 0xd7, 0xb2,
0x07, 0xb7, 0x8a, 0xd6, 0x7b, 0xae, 0xaf, 0x91, 0x99, 0xeb, 0x85, 0xfb, 0xd6, 0xe3, 0x3b, 0x3f,
0xf8, 0x9d, 0x91, 0x97, 0x9c, 0x4f, 0x4f, 0x37, 0x07, 0xe1, 0x78, 0xcb, 0x97, 0x21, 0x32, 0x91,
0xf1, 0xbc, 0xe5, 0x07, 0xc3, 0x2d, 0xfc, 0xfe, 0x74, 0x11, 0xff, 0xef, 0xc9, 0xd7, 0xff, 0x5f,
0x00, 0x00, 0x00, 0xff, 0xff, 0x77, 0xa0, 0xa0, 0x17, 0x29, 0x65, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

@ -883,6 +883,13 @@ message SendRequest {
maximum enforced.
*/
uint32 cltv_limit = 10;
/**
An optional field that can be used to pass an arbitrary set of TLV records
to a peer which understands the new records. This can be used to pass
application specific data during the payment attempt.
*/
map<uint64, bytes> dest_tlv = 11;
}
message SendResponse {
@ -1665,6 +1672,14 @@ message QueryRoutesRequest {
A list of directed node pairs that will be ignored during path finding.
*/
repeated NodePair ignored_pairs = 10;
/**
An optional field that can be used to pass an arbitrary set of TLV records
to a peer which understands the new records. This can be used to pass
application specific data during the payment attempt. If the destination
does not support the specified recrods, and error will be returned.
*/
map<uint64, bytes> dest_tlv = 11;
}
message NodePair {
@ -1711,6 +1726,20 @@ message Hop {
can be executed without relying on a copy of the channel graph.
*/
string pub_key = 8 [json_name = "pub_key"];
/**
If set to true, then this hop will be encoded using the new variable length
TLV format. Note that if any custom tlv_records below are specified, then
this field MUST be set to true for them to be encoded properly.
*/
bool tlv_payload = 9 [json_name = "tlv_payload"];
/**
An optional set of key-value TLV records. This is useful within the context
of the SendToRoute call as it allows callers to specify arbitrary K-V pairs
to drop off at each hop within the onion.
*/
map<uint64, bytes> tlv_records = 10 [json_name = "tlv_records"];
}
/**

@ -2305,6 +2305,19 @@
"pub_key": {
"type": "string",
"description": "*\nAn optional public key of the hop. If the public key is given, the payment\ncan be executed without relying on a copy of the channel graph."
},
"tlv_payload": {
"type": "boolean",
"format": "boolean",
"description": "* \nIf set to true, then this hop will be encoded using the new variable length\nTLV format. Note that if any custom tlv_records below are specified, then\nthis field MUST be set to true for them to be encoded properly."
},
"tlv_records": {
"type": "object",
"additionalProperties": {
"type": "string",
"format": "byte"
},
"description": "*\nAn optional set of key-value TLV records. This is useful within the context\nof the SendToRoute call as it allows callers to specify arbitrary K-V pairs\nto drop off at each hop within the onion."
}
}
},
@ -3286,6 +3299,14 @@
"type": "integer",
"format": "int64",
"description": "* \nAn optional maximum total time lock for the route. If zero, there is no\nmaximum enforced."
},
"dest_tlv": {
"type": "object",
"additionalProperties": {
"type": "string",
"format": "byte"
},
"description": "* \nAn optional field that can be used to pass an arbitrary set of TLV records\nto a peer which understands the new records. This can be used to pass\napplication specific data during the payment attempt."
}
}
},

@ -4013,13 +4013,15 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) {
}
// As preliminary setup, we'll create two new nodes: Carol and Dave,
// such that we now have a 4 ndoe, 3 channel topology. Dave will make
// a channel with Alice, and Carol with Dave. After this setup, the
// such that we now have a 4 node, 3 channel topology. Dave will make a
// channel with Alice, and Carol with Dave. After this setup, the
// network topology should now look like:
// Carol -> Dave -> Alice -> Bob
//
// First, we'll create Dave and establish a channel to Alice.
dave, err := net.NewNode("Dave", nil)
// First, we'll create Dave and establish a channel to Alice. Dave will
// be running an older node that requires the legacy onion payload.
daveArgs := []string{"--legacyprotocol.onion"}
dave, err := net.NewNode("Dave", daveArgs)
if err != nil {
t.Fatalf("unable to create new nodes: %v", err)
}

@ -46,6 +46,15 @@ const (
// efficient network view reconciliation.
GossipQueriesOptional FeatureBit = 7
// TLVOnionPayloadRequired is a feature bit that indicates a node is
// able to decode the new TLV information included in the onion packet.
TLVOnionPayloadRequired FeatureBit = 8
// TLVOnionPayloadRequired is an optional feature bit that indicates a
// node is able to decode the new TLV information included in the onion
// packet.
TLVOnionPayloadOptional FeatureBit = 9
// maxAllowedSize is a maximum allowed size of feature vector.
//
// NOTE: Within the protocol, the maximum allowed message size is 65535
@ -76,7 +85,10 @@ var LocalFeatures = map[FeatureBit]string{
// name. All known global feature bits must be assigned a name in this mapping.
// Global features are those which are advertised to the entire network. A full
// description of these feature bits is provided in the BOLT-09 specification.
var GlobalFeatures map[FeatureBit]string
var GlobalFeatures = map[FeatureBit]string{
TLVOnionPayloadRequired: "tlv-onion",
TLVOnionPayloadOptional: "tlv-onion",
}
// RawFeatureVector represents a set of feature bits as defined in BOLT-09. A
// RawFeatureVector itself just stores a set of bit flags but can be used to

@ -11,6 +11,7 @@ import (
"time"
"github.com/btcsuite/btcd/btcec"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/routing/route"
@ -26,6 +27,7 @@ var (
ChannelID: 12345,
OutgoingTimeLock: 111,
AmtToForward: 555,
LegacyPayload: true,
}
testRoute = route.Route{
@ -142,8 +144,11 @@ func TestControlTowerSubscribeSuccess(t *testing.T) {
if result.Preimage != preimg {
t.Fatal("unexpected preimage")
}
if !reflect.DeepEqual(result.Route, &attempt.Route) {
t.Fatal("unexpected route")
t.Fatalf("unexpected route: %v vs %v",
spew.Sdump(result.Route),
spew.Sdump(attempt.Route))
}
// After the final event, we expect the channel to be closed.

@ -7,6 +7,7 @@ import (
"testing"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/coreos/bbolt"
@ -50,7 +51,8 @@ func TestMissionControlStore(t *testing.T) {
SourcePubKey: route.Vertex{1},
Hops: []*route.Hop{
{
PubKeyBytes: route.Vertex{2},
PubKeyBytes: route.Vertex{2},
LegacyPayload: true,
},
},
}
@ -99,10 +101,12 @@ func TestMissionControlStore(t *testing.T) {
// Check that results are stored in chronological order.
if !reflect.DeepEqual(&result1, results[0]) {
t.Fatal()
t.Fatalf("the results differ: %v vs %v", spew.Sdump(&result1),
spew.Sdump(results[0]))
}
if !reflect.DeepEqual(&result2, results[1]) {
t.Fatal()
t.Fatalf("the results differ: %v vs %v", spew.Sdump(&result2),
spew.Sdump(results[1]))
}
// Recreate store to test pruning.
@ -132,9 +136,11 @@ func TestMissionControlStore(t *testing.T) {
}
if !reflect.DeepEqual(&result2, results[0]) {
t.Fatal()
t.Fatalf("the results differ: %v vs %v", spew.Sdump(&result2),
spew.Sdump(results[0]))
}
if !reflect.DeepEqual(&result3, results[1]) {
t.Fatal()
t.Fatalf("the results differ: %v vs %v", spew.Sdump(&result3),
spew.Sdump(results[1]))
}
}

@ -16,13 +16,15 @@ var (
SourcePubKey: route.Vertex{10},
Hops: []*route.Hop{
{
ChannelID: 1,
PubKeyBytes: route.Vertex{11},
AmtToForward: 1000,
ChannelID: 1,
PubKeyBytes: route.Vertex{11},
AmtToForward: 1000,
LegacyPayload: true,
},
{
ChannelID: 2,
PubKeyBytes: route.Vertex{12},
ChannelID: 2,
PubKeyBytes: route.Vertex{12},
LegacyPayload: true,
},
},
}
@ -167,7 +169,8 @@ func TestMissionControl(t *testing.T) {
// Check whether history snapshot looks sane.
history := ctx.mc.GetHistorySnapshot()
if len(history.Nodes) != 1 {
t.Fatal("unexpected number of nodes")
t.Fatalf("unexpected number of nodes: expected 1 got %v",
len(history.Nodes))
}
if len(history.Pairs) != 1 {

@ -2,6 +2,7 @@ package routing
import (
"container/heap"
"fmt"
"math"
"github.com/coreos/bbolt"
@ -9,6 +10,7 @@ import (
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/tlv"
)
const (
@ -98,7 +100,8 @@ func isSamePath(path1, path2 []*channeldb.ChannelEdgePolicy) bool {
// the source to the target node of the path finding attempt.
func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex route.Vertex,
pathEdges []*channeldb.ChannelEdgePolicy, currentHeight uint32,
finalCLTVDelta uint16) (*route.Route, error) {
finalCLTVDelta uint16,
finalDestRecords []tlv.Record) (*route.Route, error) {
var (
hops []*route.Hop
@ -179,7 +182,27 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex route.Vertex,
ChannelID: edge.ChannelID,
AmtToForward: amtToForward,
OutgoingTimeLock: outgoingTimeLock,
LegacyPayload: true,
}
// We start out above by assuming that this node needs the
// legacy payload, as if we don't have the full
// NodeAnnouncement information for this node, then we can't
// assume it knows the latest features. If we do have a feature
// vector for this node, then we'll update the info now.
if edge.Node.Features != nil {
features := edge.Node.Features
currentHop.LegacyPayload = !features.HasFeature(
lnwire.TLVOnionPayloadOptional,
)
}
// If this is the last hop, then we'll populate any TLV records
// destined for it.
if i == len(pathEdges)-1 && len(finalDestRecords) != 0 {
currentHop.TLVRecords = finalDestRecords
}
hops = append([]*route.Hop{currentHop}, hops...)
// Finally, we update the amount that needs to flow into the
@ -190,7 +213,8 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex route.Vertex,
// With the base routing data expressed as hops, build the full route
newRoute, err := route.NewRouteFromHops(
nextIncomingAmount, totalTimeLock, route.Vertex(sourceVertex), hops,
nextIncomingAmount, totalTimeLock, route.Vertex(sourceVertex),
hops,
)
if err != nil {
return nil, err
@ -261,6 +285,11 @@ type RestrictParams struct {
// ctlv. After path finding is complete, the caller needs to increase
// all cltv expiry heights with the required final cltv delta.
CltvLimit *uint32
// DestPayloadTLV should be set to true if we need to drop off a TLV
// payload at the final hop in order to properly complete this payment
// attempt.
DestPayloadTLV bool
}
// PathFindingConfig defines global parameters that control the trade-off in
@ -316,10 +345,34 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig,
node *channeldb.LightningNode) error {
// TODO(roasbeef): with larger graph can just use disk seeks
// with a visited map
distance[route.Vertex(node.PubKeyBytes)] = nodeWithDist{
vertex := route.Vertex(node.PubKeyBytes)
distance[vertex] = nodeWithDist{
dist: infinity,
node: route.Vertex(node.PubKeyBytes),
}
// If we don't have any features for this node, then we can
// stop here.
if node.Features == nil || !r.DestPayloadTLV {
return nil
}
// We only need to perform this check for the final node, so we
// can exit here if this isn't them.
if vertex != target {
return nil
}
// If we have any records for the final hop, then we'll check
// not to ensure that they are actually able to interpret them.
supportsTLV := node.Features.HasFeature(
lnwire.TLVOnionPayloadOptional,
)
if !supportsTLV {
return fmt.Errorf("destination hop doesn't " +
"understand new TLV paylods")
}
return nil
}); err != nil {
return nil, err

@ -670,7 +670,8 @@ func TestFindLowestFeePath(t *testing.T) {
}
route, err := newRoute(
paymentAmt, sourceVertex, path, startingHeight,
finalHopCLTV)
finalHopCLTV, nil,
)
if err != nil {
t.Fatalf("unable to create path: %v", err)
}
@ -819,7 +820,7 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
route, err := newRoute(
paymentAmt, sourceVertex, path, startingHeight,
finalHopCLTV,
finalHopCLTV, nil,
)
if err != nil {
t.Fatalf("unable to create path: %v", err)
@ -857,9 +858,15 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
for i := 0; i < len(expectedHops)-1; i++ {
var expectedHop [8]byte
binary.BigEndian.PutUint64(expectedHop[:], route.Hops[i+1].ChannelID)
if !bytes.Equal(sphinxPath[i].HopData.NextAddress[:], expectedHop[:]) {
hopData, err := sphinxPath[i].HopPayload.HopData()
if err != nil {
t.Fatalf("unable to make hop data: %v", err)
}
if !bytes.Equal(hopData.NextAddress[:], expectedHop[:]) {
t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
expectedHop[:], sphinxPath[i].HopData.NextAddress)
expectedHop[:], hopData.NextAddress[:])
}
}
@ -867,9 +874,15 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
// to indicate it's the exit hop.
var exitHop [8]byte
lastHopIndex := len(expectedHops) - 1
if !bytes.Equal(sphinxPath[lastHopIndex].HopData.NextAddress[:], exitHop[:]) {
hopData, err := sphinxPath[lastHopIndex].HopPayload.HopData()
if err != nil {
t.Fatalf("unable to create hop data: %v", err)
}
if !bytes.Equal(hopData.NextAddress[:], exitHop[:]) {
t.Fatalf("first hop has incorrect next hop: expected %x, got %x",
exitHop[:], sphinxPath[lastHopIndex].HopData.NextAddress)
exitHop[:], hopData.NextAddress)
}
var expectedTotalFee lnwire.MilliSatoshi
@ -1001,7 +1014,11 @@ func TestNewRoute(t *testing.T) {
timeLockDelta uint16) *channeldb.ChannelEdgePolicy {
return &channeldb.ChannelEdgePolicy{
Node: &channeldb.LightningNode{},
Node: &channeldb.LightningNode{
Features: lnwire.NewFeatureVector(
nil, nil,
),
},
FeeProportionalMillionths: feeRate,
FeeBaseMSat: baseFee,
TimeLockDelta: timeLockDelta,
@ -1176,9 +1193,11 @@ func TestNewRoute(t *testing.T) {
}
t.Run(testCase.name, func(t *testing.T) {
route, err := newRoute(testCase.paymentAmount,
sourceVertex, testCase.hops, startingHeight,
finalHopCLTV)
route, err := newRoute(
testCase.paymentAmount, sourceVertex,
testCase.hops, startingHeight, finalHopCLTV,
nil,
)
if testCase.expectError {
expectedCode := testCase.expectedErrorCode
@ -1683,7 +1702,7 @@ func TestPathFindSpecExample(t *testing.T) {
carol := ctx.aliases["C"]
const amt lnwire.MilliSatoshi = 4999999
route, err := ctx.router.FindRoute(
bobNode.PubKeyBytes, carol, amt, noRestrictions,
bobNode.PubKeyBytes, carol, amt, noRestrictions, nil,
)
if err != nil {
t.Fatalf("unable to find route: %v", err)
@ -1742,7 +1761,7 @@ func TestPathFindSpecExample(t *testing.T) {
// We'll now request a route from A -> B -> C.
route, err = ctx.router.FindRoute(
source.PubKeyBytes, carol, amt, noRestrictions,
source.PubKeyBytes, carol, amt, noRestrictions, nil,
)
if err != nil {
t.Fatalf("unable to find routes: %v", err)
@ -1925,7 +1944,7 @@ func TestRestrictOutgoingChannel(t *testing.T) {
}
route, err := newRoute(
paymentAmt, sourceVertex, path, startingHeight,
finalHopCLTV,
finalHopCLTV, nil,
)
if err != nil {
t.Fatalf("unable to create path: %v", err)
@ -2033,6 +2052,7 @@ func testCltvLimit(t *testing.T, limit uint32, expectedChannel uint64) {
)
route, err := newRoute(
paymentAmt, sourceVertex, path, startingHeight, finalHopCLTV,
nil,
)
if err != nil {
t.Fatalf("unable to create path: %v", err)

@ -127,6 +127,7 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
sourceVertex := route.Vertex(ss.SelfNode.PubKeyBytes)
route, err := newRoute(
payment.Amount, sourceVertex, path, height, finalCltvDelta,
payment.FinalDestRecords,
)
if err != nil {
// TODO(roasbeef): return which edge/vertex didn't work

@ -26,7 +26,11 @@ func TestRequestRoute(t *testing.T) {
path := []*channeldb.ChannelEdgePolicy{
{
Node: &channeldb.LightningNode{},
Node: &channeldb.LightningNode{
Features: lnwire.NewFeatureVector(
nil, nil,
),
},
},
}

@ -1,14 +1,17 @@
package route
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"strconv"
"strings"
"github.com/btcsuite/btcd/btcec"
sphinx "github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tlv"
)
// VertexSize is the size of the array to store a vertex.
@ -72,6 +75,61 @@ type Hop struct {
// hop. This value is less than the value that the incoming HTLC
// carries as a fee will be subtracted by the hop.
AmtToForward lnwire.MilliSatoshi
// TLVRecords if non-nil are a set of additional TLV records that
// should be included in the forwarding instructions for this node.
TLVRecords []tlv.Record
// LegacyPayload if true, then this signals that this node doesn't
// understand the new TLV payload, so we must instead use the legacy
// payload.
LegacyPayload bool
}
// PackHopPayload writes to the passed io.Writer, the series of byes that can
// be placed directly into the per-hop payload (EOB) for this hop. This will
// include the required routing fields, as well as serializing any of the
// passed optional TLVRecords. nextChanID is the unique channel ID that
// references the _outgoing_ channel ID that follows this hop. This field
// follows the same semantics as the NextAddress field in the onion: it should
// be set to zero to indicate the terminal hop.
func (h *Hop) PackHopPayload(w io.Writer, nextChanID uint64) error {
// If this is a legacy payload, then we'll exit here as this method
// shouldn't be called.
if h.LegacyPayload == true {
return fmt.Errorf("cannot pack hop payloads for legacy " +
"payloads")
}
// Otherwise, we'll need to make a new stream that includes our
// required routing fields, as well as these optional values.
amt := uint64(h.AmtToForward)
combinedRecords := append(h.TLVRecords,
tlv.MakeDynamicRecord(
tlv.AmtOnionType, &amt, func() uint64 {
return tlv.SizeTUint64(amt)
},
tlv.ETUint64, tlv.DTUint64,
),
tlv.MakeDynamicRecord(
tlv.LockTimeOnionType, &h.OutgoingTimeLock, func() uint64 {
return tlv.SizeTUint32(h.OutgoingTimeLock)
},
tlv.ETUint32, tlv.DTUint32,
),
tlv.MakePrimitiveRecord(tlv.NextHopOnionType, &nextChanID),
)
// To ensure we produce a canonical stream, we'll sort the records
// before encoding them as a stream in the hop payload.
tlv.SortRecords(combinedRecords)
tlvStream, err := tlv.NewStream(combinedRecords...)
if err != nil {
return err
}
return tlvStream.Encode(w)
}
// Route represents a path through the channel graph which runs over one or
@ -156,7 +214,8 @@ func NewRouteFromHops(amtToSend lnwire.MilliSatoshi, timeLock uint32,
// ToSphinxPath converts a complete route into a sphinx PaymentPath that
// contains the per-hop paylods used to encoding the HTLC routing data for each
// hop in the route.
// hop in the route. This method also accepts an optional EOB payload for the
// final hop.
func (r *Route) ToSphinxPath() (*sphinx.PaymentPath, error) {
var path sphinx.PaymentPath
@ -171,17 +230,6 @@ func (r *Route) ToSphinxPath() (*sphinx.PaymentPath, error) {
return nil, err
}
path[i] = sphinx.OnionHop{
NodePub: *pub,
HopData: sphinx.HopData{
// TODO(roasbeef): properly set realm, make
// sphinx type an enum actually?
Realm: [1]byte{0},
ForwardAmount: uint64(hop.AmtToForward),
OutgoingCltv: hop.OutgoingTimeLock,
},
}
// As a base case, the next hop is set to all zeroes in order
// to indicate that the "last hop" as no further hops after it.
nextHop := uint64(0)
@ -192,9 +240,50 @@ func (r *Route) ToSphinxPath() (*sphinx.PaymentPath, error) {
nextHop = r.Hops[i+1].ChannelID
}
binary.BigEndian.PutUint64(
path[i].HopData.NextAddress[:], nextHop,
)
var payload sphinx.HopPayload
// If this is the legacy payload, then we can just include the
// hop data as normal.
if hop.LegacyPayload {
// Before we encode this value, we'll pack the next hop
// into the NextAddress field of the hop info to ensure
// we point to the right now.
hopData := sphinx.HopData{
ForwardAmount: uint64(hop.AmtToForward),
OutgoingCltv: hop.OutgoingTimeLock,
}
binary.BigEndian.PutUint64(
hopData.NextAddress[:], nextHop,
)
payload, err = sphinx.NewHopPayload(&hopData, nil)
if err != nil {
return nil, err
}
} else {
// For non-legacy payloads, we'll need to pack the
// routing information, along with any extra TLV
// information into the new per-hop payload format.
// We'll also pass in the chan ID of the hop this
// channel should be forwarded to so we can construct a
// valid payload.
var b bytes.Buffer
err := hop.PackHopPayload(&b, nextHop)
if err != nil {
return nil, err
}
// TODO(roasbeef): make better API for NewHopPayload?
payload, err = sphinx.NewHopPayload(nil, b.Bytes())
if err != nil {
return nil, err
}
}
path[i] = sphinx.OnionHop{
NodePub: *pub,
HopPayload: payload,
}
}
return &path, nil

@ -26,6 +26,7 @@ import (
"github.com/lightningnetwork/lnd/routing/chainview"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/ticker"
"github.com/lightningnetwork/lnd/tlv"
"github.com/lightningnetwork/lnd/zpay32"
)
@ -1429,6 +1430,7 @@ type routingMsg struct {
// factoring in channel capacities and cumulative fees along the route.
func (r *ChannelRouter) FindRoute(source, target route.Vertex,
amt lnwire.MilliSatoshi, restrictions *RestrictParams,
destTlvRecords []tlv.Record,
finalExpiry ...uint16) (*route.Route, error) {
var finalCLTVDelta uint16
@ -1482,6 +1484,7 @@ func (r *ChannelRouter) FindRoute(source, target route.Vertex,
// Create the route with absolute time lock values.
route, err := newRoute(
amt, source, path, uint32(currentHeight), finalCLTVDelta,
destTlvRecords,
)
if err != nil {
return nil, err
@ -1630,7 +1633,11 @@ type LightningPayment struct {
// attempting to complete.
PaymentRequest []byte
// TODO(roasbeef): add e2e message?
// FinalDestRecords are TLV records that are to be sent to the final
// hop in the new onion payload format. If the destination does not
// understand this new onion payload format, then the payment will
// fail.
FinalDestRecords []tlv.Record
}
// SendPayment attempts to send a payment as described within the passed
@ -1694,6 +1701,8 @@ func (r *ChannelRouter) preparePayment(payment *LightningPayment) (
// Record this payment hash with the ControlTower, ensuring it is not
// already in-flight.
//
// TODO(roasbeef): store records as part of creation info?
info := &channeldb.PaymentCreationInfo{
PaymentHash: payment.PaymentHash,
Value: payment.Amount,

@ -231,7 +231,7 @@ func TestFindRoutesWithFeeLimit(t *testing.T) {
route, err := ctx.router.FindRoute(
ctx.router.selfNode.PubKeyBytes,
target, paymentAmt, restrictions,
target, paymentAmt, restrictions, nil,
zpay32.DefaultFinalCLTVDelta,
)
if err != nil {
@ -390,12 +390,14 @@ func TestChannelUpdateValidation(t *testing.T) {
hops := []*route.Hop{
{
ChannelID: 1,
PubKeyBytes: hop1,
ChannelID: 1,
PubKeyBytes: hop1,
LegacyPayload: true,
},
{
ChannelID: 2,
PubKeyBytes: hop2,
ChannelID: 2,
PubKeyBytes: hop2,
LegacyPayload: true,
},
}
@ -1074,8 +1076,9 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
t.Parallel()
const startingBlockHeight = 101
ctx, cleanUp, err := createTestCtxFromFile(startingBlockHeight,
basicGraphFilePath)
ctx, cleanUp, err := createTestCtxFromFile(
startingBlockHeight, basicGraphFilePath,
)
if err != nil {
t.Fatalf("unable to create router: %v", err)
}
@ -1108,7 +1111,8 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
fundingTx, _, chanID, err := createChannelEdge(ctx,
bitcoinKey1.SerializeCompressed(),
bitcoinKey2.SerializeCompressed(),
10000, 500)
10000, 500,
)
if err != nil {
t.Fatalf("unable to create channel edge: %v", err)
}
@ -1266,7 +1270,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
copy(targetPubKeyBytes[:], targetNode.SerializeCompressed())
_, err = ctx.router.FindRoute(
ctx.router.selfNode.PubKeyBytes,
targetPubKeyBytes, paymentAmt, noRestrictions,
targetPubKeyBytes, paymentAmt, noRestrictions, nil,
zpay32.DefaultFinalCLTVDelta,
)
if err != nil {
@ -1309,7 +1313,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// updated.
_, err = ctx.router.FindRoute(
ctx.router.selfNode.PubKeyBytes,
targetPubKeyBytes, paymentAmt, noRestrictions,
targetPubKeyBytes, paymentAmt, noRestrictions, nil,
zpay32.DefaultFinalCLTVDelta,
)
if err != nil {
@ -2632,12 +2636,14 @@ func TestRouterPaymentStateMachine(t *testing.T) {
hop2 := testGraph.aliasMap["c"]
hops := []*route.Hop{
{
ChannelID: 1,
PubKeyBytes: hop1,
ChannelID: 1,
PubKeyBytes: hop1,
LegacyPayload: true,
},
{
ChannelID: 2,
PubKeyBytes: hop2,
ChannelID: 2,
PubKeyBytes: hop2,
LegacyPayload: true,
},
}
@ -3270,14 +3276,16 @@ func TestSendToRouteStructuredError(t *testing.T) {
hop2 := ctx.aliases["c"]
hops := []*route.Hop{
{
ChannelID: 1,
PubKeyBytes: hop1,
AmtToForward: payAmt,
ChannelID: 1,
PubKeyBytes: hop1,
AmtToForward: payAmt,
LegacyPayload: true,
},
{
ChannelID: 2,
PubKeyBytes: hop2,
AmtToForward: payAmt,
ChannelID: 2,
PubKeyBytes: hop2,
AmtToForward: payAmt,
LegacyPayload: true,
},
}

@ -17,6 +17,7 @@ import (
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/lightningnetwork/lnd/tlv"
"github.com/lightningnetwork/lnd/watchtower"
"github.com/btcsuite/btcd/blockchain"
@ -2926,6 +2927,8 @@ type rpcPaymentIntent struct {
outgoingChannelID *uint64
payReq []byte
destTLV []tlv.Record
route *route.Route
}
@ -2968,6 +2971,16 @@ func extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPaymentIntent, error
payIntent.cltvLimit = &rpcPayReq.CltvLimit
}
if len(rpcPayReq.DestTlv) != 0 {
var err error
payIntent.destTLV, err = tlv.MapToRecords(
rpcPayReq.DestTlv,
)
if err != nil {
return payIntent, err
}
}
// If the payment request field isn't blank, then the details of the
// invoice are encoded entirely within the encoded payReq. So we'll
// attempt to decode it, populating the payment accordingly.
@ -3123,6 +3136,7 @@ func (r *rpcServer) dispatchPaymentIntent(
OutgoingChannelID: payIntent.outgoingChannelID,
PaymentRequest: payIntent.payReq,
PayAttemptTimeout: routing.DefaultPayAttemptTimeout,
FinalDestRecords: payIntent.destTLV,
}
preImage, route, routerErr = r.server.chanRouter.SendPayment(
@ -3293,10 +3307,16 @@ func (r *rpcServer) sendPayment(stream *paymentStream) error {
return
}
marshalledRouted := r.routerBackend.
MarshallRoute(resp.Route)
backend := r.routerBackend
marshalledRouted, err := backend.MarshallRoute(
resp.Route,
)
if err != nil {
errChan <- err
return
}
err := stream.send(&lnrpc.SendResponse{
err = stream.send(&lnrpc.SendResponse{
PaymentHash: payIntent.rHash[:],
PaymentPreimage: resp.Preimage[:],
PaymentRoute: marshalledRouted,
@ -3375,10 +3395,15 @@ func (r *rpcServer) sendPaymentSync(ctx context.Context,
}, nil
}
rpcRoute, err := r.routerBackend.MarshallRoute(resp.Route)
if err != nil {
return nil, err
}
return &lnrpc.SendResponse{
PaymentHash: payIntent.rHash[:],
PaymentPreimage: resp.Preimage[:],
PaymentRoute: r.routerBackend.MarshallRoute(resp.Route),
PaymentRoute: rpcRoute,
}, nil
}

@ -313,6 +313,12 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
globalFeatures := lnwire.NewRawFeatureVector()
// Only if we're not being forced to use the legacy onion format, will
// we signal our knowledge of the new TLV onion format.
if !cfg.LegacyProtocol.LegacyOnion() {
globalFeatures.Set(lnwire.TLVOnionPayloadOptional)
}
var serializedPubKey [33]byte
copy(serializedPubKey[:], privKey.PubKey().SerializeCompressed())

15
tlv/onion_types.go Normal file

@ -0,0 +1,15 @@
package tlv
const (
// AmtOnionType is the type used in the onion to refrence the amount to
// send to the next hop.
AmtOnionType Type = 2
// LockTimeTLV is the type used in the onion to refenernce the CLTV
// value that should be used for the next hop's HTLC.
LockTimeOnionType Type = 4
// NextHopOnionType is the type used in the onion to reference the ID
// of the next hop.
NextHopOnionType Type = 6
)

@ -1,7 +1,10 @@
package tlv
import (
"bytes"
"fmt"
"io"
"sort"
"github.com/btcsuite/btcd/btcec"
)
@ -57,6 +60,20 @@ func (f *Record) Size() uint64 {
return f.sizeFunc()
}
// Type returns the type of the underlying TLV record.
func (f *Record) Type() Type {
return f.typ
}
// Encode writes out the TLV record to the passed writer. This is useful when a
// caller wants to obtain the raw encoding of a *single* TLV record, outside
// the context of the Stream struct.
func (f *Record) Encode(w io.Writer) error {
var b [8]byte
return f.encoder(w, f.value, &b)
}
// MakePrimitiveRecord creates a record for common types.
func MakePrimitiveRecord(typ Type, val interface{}) Record {
var (
@ -112,7 +129,7 @@ func MakePrimitiveRecord(typ Type, val interface{}) Record {
decoder = DVarBytes
default:
panic("unknown primitive type")
panic(fmt.Sprintf("unknown primitive type: %T", val))
}
return Record{
@ -151,3 +168,63 @@ func MakeDynamicRecord(typ Type, val interface{}, sizeFunc SizeFunc,
decoder: decoder,
}
}
// RecordsToMap encodes a series of TLV records as raw key-value pairs in the
// form of a map.
func RecordsToMap(records []Record) (map[uint64][]byte, error) {
tlvMap := make(map[uint64][]byte, len(records))
for _, record := range records {
var b bytes.Buffer
if err := record.Encode(&b); err != nil {
return nil, err
}
tlvMap[uint64(record.Type())] = b.Bytes()
}
return tlvMap, nil
}
// StubEncoder is a factory function that makes a stub tlv.Encoder out of a raw
// value. We can use this to make a record that can be encoded when we don't
// actually know it's true underlying value, and only it serialization.
func StubEncoder(v []byte) Encoder {
return func(w io.Writer, val interface{}, buf *[8]byte) error {
_, err := w.Write(v)
return err
}
}
// MapToRecords encodes the passed TLV map as a series of regular tlv.Record
// instances. The resulting set of records will be returned in sorted order by
// their type.
func MapToRecords(tlvMap map[uint64][]byte) ([]Record, error) {
records := make([]Record, 0, len(tlvMap))
for k, v := range tlvMap {
// We don't pass in a decoder here since we don't actually know
// the type, and only expect this Record to be used for display
// and encoding purposes.
record := MakeStaticRecord(
Type(k), nil, uint64(len(v)), StubEncoder(v), nil,
)
records = append(records, record)
}
SortRecords(records)
return records, nil
}
// SortRecords is a helper function that will sort a slice of records in place
// according to their type.
func SortRecords(records []Record) {
if len(records) == 0 {
return
}
sort.Slice(records, func(i, j int) bool {
return records[i].Type() < records[j].Type()
})
}

149
tlv/record_test.go Normal file

@ -0,0 +1,149 @@
package tlv
import (
"bytes"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
)
// TestSortRecords tests that SortRecords is able to properly sort records in
// place.
func TestSortRecords(t *testing.T) {
t.Parallel()
testCases := []struct {
preSort []Record
postSort []Record
}{
// An empty slice requires no sorting.
{
preSort: []Record{},
postSort: []Record{},
},
// An already sorted slice should be passed through.
{
preSort: []Record{
MakeStaticRecord(1, nil, 0, nil, nil),
MakeStaticRecord(2, nil, 0, nil, nil),
MakeStaticRecord(3, nil, 0, nil, nil),
},
postSort: []Record{
MakeStaticRecord(1, nil, 0, nil, nil),
MakeStaticRecord(2, nil, 0, nil, nil),
MakeStaticRecord(3, nil, 0, nil, nil),
},
},
// We should be able to sort a randomized set of records .
{
preSort: []Record{
MakeStaticRecord(9, nil, 0, nil, nil),
MakeStaticRecord(43, nil, 0, nil, nil),
MakeStaticRecord(1, nil, 0, nil, nil),
MakeStaticRecord(0, nil, 0, nil, nil),
},
postSort: []Record{
MakeStaticRecord(0, nil, 0, nil, nil),
MakeStaticRecord(1, nil, 0, nil, nil),
MakeStaticRecord(9, nil, 0, nil, nil),
MakeStaticRecord(43, nil, 0, nil, nil),
},
},
}
for i, testCase := range testCases {
SortRecords(testCase.preSort)
if !reflect.DeepEqual(testCase.preSort, testCase.postSort) {
t.Fatalf("#%v: wrong order: expected %v, got %v", i,
spew.Sdump(testCase.preSort),
spew.Sdump(testCase.postSort))
}
}
}
// TestRecordMapTransformation tests that we're able to properly morph a set of
// records into a map using TlvRecordsToMap, then the other way around using
// the MapToTlvRecords method.
func TestRecordMapTransformation(t *testing.T) {
t.Parallel()
tlvBytes := []byte{1, 2, 3, 4}
encoder := StubEncoder(tlvBytes)
testCases := []struct {
records []Record
tlvMap map[uint64][]byte
}{
// An empty set of records should yield an empty map, and the other
// way around.
{
records: []Record{},
tlvMap: map[uint64][]byte{},
},
// We should be able to transform this set of records, then obtain
// the records back in the same order.
{
records: []Record{
MakeStaticRecord(1, nil, 4, encoder, nil),
MakeStaticRecord(2, nil, 4, encoder, nil),
MakeStaticRecord(3, nil, 4, encoder, nil),
},
tlvMap: map[uint64][]byte{
1: tlvBytes,
2: tlvBytes,
3: tlvBytes,
},
},
}
for i, testCase := range testCases {
mappedRecords, err := RecordsToMap(testCase.records)
if err != nil {
t.Fatalf("#%v: unable to map records: %v", i, err)
}
if !reflect.DeepEqual(mappedRecords, testCase.tlvMap) {
t.Fatalf("#%v: incorrect record map: expected %v, got %v",
i, spew.Sdump(testCase.tlvMap),
spew.Sdump(mappedRecords))
}
unmappedRecords, err := MapToRecords(mappedRecords)
if err != nil {
t.Fatalf("#%v: unable to unmap records: %v", i, err)
}
for i := 0; i < len(testCase.records); i++ {
if unmappedRecords[i].Type() != testCase.records[i].Type() {
t.Fatalf("#%v: wrong type: expected %v, got %v",
i, unmappedRecords[i].Type(),
testCase.records[i].Type())
}
var b bytes.Buffer
if err := unmappedRecords[i].Encode(&b); err != nil {
t.Fatalf("#%v: unable to encode record: %v",
i, err)
}
if !bytes.Equal(b.Bytes(), tlvBytes) {
t.Fatalf("#%v: wrong raw record: "+
"expected %x, got %x",
i, tlvBytes, b.Bytes())
}
if unmappedRecords[i].Size() != testCase.records[0].Size() {
t.Fatalf("#%v: wrong size: expected %v, "+
"got %v", i,
unmappedRecords[i].Size(),
testCase.records[i].Size())
}
}
}
}