From b3b51923dc40a10b5caacdbfdaaf08654615cbc6 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 14:10:43 -0800 Subject: [PATCH 01/11] tlv/truncated: add non-generic encoders for truncated types These encoders can be composed to create composite types without incurring additional allocations that would be required to pass the truncated types through the generic interface. --- tlv/truncated.go | 27 ++++++++++++++++++++++++ tlv/truncated_test.go | 48 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/tlv/truncated.go b/tlv/truncated.go index 8ed9cb0d4..930a2cceb 100644 --- a/tlv/truncated.go +++ b/tlv/truncated.go @@ -40,6 +40,15 @@ func ETUint16(w io.Writer, val interface{}, buf *[8]byte) error { return NewTypeForEncodingErr(val, "uint16") } +// ETUint16T is an Encoder for truncated uint16 values, where leading zeros will +// be omitted. An error is returned if val is not a *uint16. +func ETUint16T(w io.Writer, val uint16, buf *[8]byte) error { + binary.BigEndian.PutUint16(buf[:2], val) + numZeros := numLeadingZeroBytes16(val) + _, err := w.Write(buf[numZeros:2]) + return err +} + // DTUint16 is an Decoder for truncated uint16 values, where leading zeros will // be resurrected. An error is returned if val is not a *uint16. func DTUint16(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { @@ -92,6 +101,15 @@ func ETUint32(w io.Writer, val interface{}, buf *[8]byte) error { return NewTypeForEncodingErr(val, "uint32") } +// ETUint32T is an Encoder for truncated uint32 values, where leading zeros will +// be omitted. An error is returned if val is not a *uint32. +func ETUint32T(w io.Writer, val uint32, buf *[8]byte) error { + binary.BigEndian.PutUint32(buf[:4], val) + numZeros := numLeadingZeroBytes32(val) + _, err := w.Write(buf[numZeros:4]) + return err +} + // DTUint32 is an Decoder for truncated uint32 values, where leading zeros will // be resurrected. An error is returned if val is not a *uint32. func DTUint32(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { @@ -154,6 +172,15 @@ func ETUint64(w io.Writer, val interface{}, buf *[8]byte) error { return NewTypeForEncodingErr(val, "uint64") } +// ETUint64T is an Encoder for truncated uint64 values, where leading zeros will +// be omitted. An error is returned if val is not a *uint64. +func ETUint64T(w io.Writer, val uint64, buf *[8]byte) error { + binary.BigEndian.PutUint64(buf[:], val) + numZeros := numLeadingZeroBytes64(val) + _, err := w.Write(buf[numZeros:]) + return err +} + // DTUint64 is an Decoder for truncated uint64 values, where leading zeros will // be resurrected. An error is returned if val is not a *uint64. func DTUint64(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { diff --git a/tlv/truncated_test.go b/tlv/truncated_test.go index d2a34562e..eb0f83a75 100644 --- a/tlv/truncated_test.go +++ b/tlv/truncated_test.go @@ -60,6 +60,8 @@ func TestSizeTUint16(t *testing.T) { func TestTUint16(t *testing.T) { var buf [8]byte for _, test := range tuint16Tests { + test := test + if len(test.bytes) != int(test.size) { t.Fatalf("invalid test case, "+ "len(bytes)[%d] != size[%d]", @@ -68,6 +70,7 @@ func TestTUint16(t *testing.T) { name := fmt.Sprintf("0x%x", test.value) t.Run(name, func(t *testing.T) { + // Test generic encoder. var b bytes.Buffer err := tlv.ETUint16(&b, &test.value, &buf) if err != nil { @@ -80,6 +83,19 @@ func TestTUint16(t *testing.T) { test.bytes, b.Bytes()) } + // Test non-generic encoder. + var b2 bytes.Buffer + err = tlv.ETUint16T(&b2, test.value, &buf) + if err != nil { + t.Fatalf("unable to encode tuint16: %v", err) + } + + if !bytes.Equal(b2.Bytes(), test.bytes) { + t.Fatalf("encoding mismatch, "+ + "expected: %x, got: %x", + test.bytes, b2.Bytes()) + } + var value uint16 r := bytes.NewReader(b.Bytes()) err = tlv.DTUint16(r, &value, &buf, test.size) @@ -168,6 +184,8 @@ func TestSizeTUint32(t *testing.T) { func TestTUint32(t *testing.T) { var buf [8]byte for _, test := range tuint32Tests { + test := test + if len(test.bytes) != int(test.size) { t.Fatalf("invalid test case, "+ "len(bytes)[%d] != size[%d]", @@ -176,6 +194,7 @@ func TestTUint32(t *testing.T) { name := fmt.Sprintf("0x%x", test.value) t.Run(name, func(t *testing.T) { + // Test generic encoder. var b bytes.Buffer err := tlv.ETUint32(&b, &test.value, &buf) if err != nil { @@ -188,6 +207,19 @@ func TestTUint32(t *testing.T) { test.bytes, b.Bytes()) } + // Test non-generic encoder. + var b2 bytes.Buffer + err = tlv.ETUint32T(&b2, test.value, &buf) + if err != nil { + t.Fatalf("unable to encode tuint32: %v", err) + } + + if !bytes.Equal(b2.Bytes(), test.bytes) { + t.Fatalf("encoding mismatch, "+ + "expected: %x, got: %x", + test.bytes, b2.Bytes()) + } + var value uint32 r := bytes.NewReader(b.Bytes()) err = tlv.DTUint32(r, &value, &buf, test.size) @@ -322,6 +354,8 @@ func TestSizeTUint64(t *testing.T) { func TestTUint64(t *testing.T) { var buf [8]byte for _, test := range tuint64Tests { + test := test + if len(test.bytes) != int(test.size) { t.Fatalf("invalid test case, "+ "len(bytes)[%d] != size[%d]", @@ -330,6 +364,7 @@ func TestTUint64(t *testing.T) { name := fmt.Sprintf("0x%x", test.value) t.Run(name, func(t *testing.T) { + // Test generic encoder. var b bytes.Buffer err := tlv.ETUint64(&b, &test.value, &buf) if err != nil { @@ -342,6 +377,19 @@ func TestTUint64(t *testing.T) { test.bytes, b.Bytes()) } + // Test non-generic encoder. + var b2 bytes.Buffer + err = tlv.ETUint64T(&b2, test.value, &buf) + if err != nil { + t.Fatalf("unable to encode tuint64: %v", err) + } + + if !bytes.Equal(b2.Bytes(), test.bytes) { + t.Fatalf("encoding mismatch, "+ + "expected: %x, got: %x", + test.bytes, b2.Bytes()) + } + var value uint64 r := bytes.NewReader(b.Bytes()) err = tlv.DTUint64(r, &value, &buf, test.size) From b1b7ff80069c7b50298fc781f7f29bb3a61be642 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 14:11:02 -0800 Subject: [PATCH 02/11] records/mpp: add MPP struct to create corresponding tlv.Record Used to encode/decode MPP tlv records --- record/mpp.go | 98 +++++++++++++++++++++++++++++++++++++++++++ record/record_test.go | 73 ++++++++++++++++++++++++++++++++ tlv/record.go | 8 ++++ 3 files changed, 179 insertions(+) create mode 100644 record/mpp.go create mode 100644 record/record_test.go diff --git a/record/mpp.go b/record/mpp.go new file mode 100644 index 000000000..b28d10858 --- /dev/null +++ b/record/mpp.go @@ -0,0 +1,98 @@ +package record + +import ( + "io" + + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/tlv" +) + +// MPPOnionType is the type used in the onion to reference the MPP fields: +// total_amt and payment_addr. +const MPPOnionType tlv.Type = 8 + +// MPP is a record that encodes the fields necessary for multi-path payments. +type MPP struct { + // paymentAddr is a random, receiver-generated value used to avoid + // collisions with concurrent payers. + paymentAddr [32]byte + + // totalMsat is the total value of the payment, potentially spread + // across more than one HTLC. + totalMsat lnwire.MilliSatoshi +} + +// NewMPP generates a new MPP record with the given total and payment address. +func NewMPP(total lnwire.MilliSatoshi, addr [32]byte) *MPP { + return &MPP{ + paymentAddr: addr, + totalMsat: total, + } +} + +// PaymentAddr returns the payment address contained in the MPP record. +func (r *MPP) PaymentAddr() [32]byte { + return r.paymentAddr +} + +// TotalMsat returns the total value of an MPP payment in msats. +func (r *MPP) TotalMsat() lnwire.MilliSatoshi { + return r.totalMsat +} + +// MPPEncoder writes the MPP record to the provided io.Writer. +func MPPEncoder(w io.Writer, val interface{}, buf *[8]byte) error { + if v, ok := val.(*MPP); ok { + err := tlv.EBytes32(w, &v.paymentAddr, buf) + if err != nil { + return err + } + + return tlv.ETUint64T(w, uint64(v.totalMsat), buf) + } + return tlv.NewTypeForEncodingErr(val, "MPP") +} + +const ( + // minMPPLength is the minimum length of a serialized MPP TLV record, + // which occurs when the truncated encoding of total_amt_msat takes 0 + // bytes, leaving only the payment_addr. + minMPPLength = 32 + + // maxMPPLength is the maximum length of a serialized MPP TLV record, + // which occurs when the truncated encoding of total_amt_msat takes 8 + // bytes. + maxMPPLength = 40 +) + +// MPPDecoder reads the MPP record to the provided io.Reader. +func MPPDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { + if v, ok := val.(*MPP); ok && minMPPLength <= l && l <= maxMPPLength { + if err := tlv.DBytes32(r, &v.paymentAddr, buf, 32); err != nil { + return err + } + + var total uint64 + if err := tlv.DTUint64(r, &total, buf, l-32); err != nil { + return err + } + v.totalMsat = lnwire.MilliSatoshi(total) + + return nil + + } + return tlv.NewTypeForDecodingErr(val, "MPP", l, maxMPPLength) +} + +// Record returns a tlv.Record that can be used to encode or decode this record. +func (r *MPP) Record() tlv.Record { + // Fixed-size, 32 byte payment address followed by truncated 64-bit + // total msat. + size := func() uint64 { + return 32 + tlv.SizeTUint64(uint64(r.totalMsat)) + } + + return tlv.MakeDynamicRecord( + MPPOnionType, r, size, MPPEncoder, MPPDecoder, + ) +} diff --git a/record/record_test.go b/record/record_test.go new file mode 100644 index 000000000..052e2f1f0 --- /dev/null +++ b/record/record_test.go @@ -0,0 +1,73 @@ +package record_test + +import ( + "bytes" + "testing" + + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/record" + "github.com/lightningnetwork/lnd/tlv" +) + +type recordEncDecTest struct { + name string + encRecord func() tlv.RecordProducer + decRecord func() tlv.RecordProducer + assert func(*testing.T, interface{}) +} + +var ( + testTotal = lnwire.MilliSatoshi(45) + testAddr = [32]byte{0x01, 0x02} +) + +var recordEncDecTests = []recordEncDecTest{ + { + name: "mpp", + encRecord: func() tlv.RecordProducer { + return record.NewMPP(testTotal, testAddr) + }, + decRecord: func() tlv.RecordProducer { + return new(record.MPP) + }, + assert: func(t *testing.T, r interface{}) { + mpp := r.(*record.MPP) + if mpp.TotalMsat() != testTotal { + t.Fatal("incorrect total msat") + } + if mpp.PaymentAddr() != testAddr { + t.Fatal("incorrect payment addr") + } + }, + }, +} + +// TestRecordEncodeDecode is a generic test framework for custom TLV records. It +// asserts that records can encode and decode themselves, and that the value of +// the original record matches the decoded record. +func TestRecordEncodeDecode(t *testing.T) { + for _, test := range recordEncDecTests { + test := test + t.Run(test.name, func(t *testing.T) { + r := test.encRecord() + r2 := test.decRecord() + encStream := tlv.MustNewStream(r.Record()) + decStream := tlv.MustNewStream(r2.Record()) + + test.assert(t, r) + + var b bytes.Buffer + err := encStream.Encode(&b) + if err != nil { + t.Fatalf("unable to encode record: %v", err) + } + + err = decStream.Decode(bytes.NewReader(b.Bytes())) + if err != nil { + t.Fatalf("unable to decode record: %v", err) + } + + test.assert(t, r2) + }) + } +} diff --git a/tlv/record.go b/tlv/record.go index 75647e03c..66ae8f1c7 100644 --- a/tlv/record.go +++ b/tlv/record.go @@ -43,6 +43,14 @@ func SizeVarBytes(e *[]byte) SizeFunc { } } +// RecorderProducer is an interface for objects that can produce a Record object +// capable of encoding and/or decoding the RecordProducer as a Record. +type RecordProducer interface { + // Record returns a Record that can be used to encode or decode the + // backing object. + Record() Record +} + // Record holds the required information to encode or decode a TLV record. type Record struct { value interface{} From 6d971e5113f6f4e917f54a70be03b6862e46c4b6 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 14:11:28 -0800 Subject: [PATCH 03/11] routing/route/route: add optional MPP field to Hop This commit also modifies the Router serialization to persist the MPP struct when present, and properly restore it when loading from disk. --- channeldb/payments.go | 43 +++++++++++++++++++++++++++++++++++-- channeldb/payments_test.go | 4 +++- routing/route/route.go | 30 +++++++++++++++++++++++--- routing/route/route_test.go | 37 +++++++++++++++++++++++++++++++ tlv/record.go | 8 +++++++ 5 files changed, 116 insertions(+), 6 deletions(-) diff --git a/channeldb/payments.go b/channeldb/payments.go index 00d29366d..d576c65c7 100644 --- a/channeldb/payments.go +++ b/channeldb/payments.go @@ -14,6 +14,7 @@ import ( "github.com/coreos/bbolt" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" ) @@ -508,7 +509,9 @@ func deserializePaymentAttemptInfo(r io.Reader) (*PaymentAttemptInfo, error) { func serializeHop(w io.Writer, h *route.Hop) error { if err := WriteElements(w, - h.PubKeyBytes[:], h.ChannelID, h.OutgoingTimeLock, + h.PubKeyBytes[:], + h.ChannelID, + h.OutgoingTimeLock, h.AmtToForward, ); err != nil { return err @@ -525,10 +528,23 @@ func serializeHop(w io.Writer, h *route.Hop) error { return WriteElements(w, uint32(0)) } + // Gather all non-primitive TLV records so that they can be serialized + // as a single blob. + // + // TODO(conner): add migration to unify all fields in a single TLV + // blobs. The split approach will cause headaches down the road as more + // fields are added, which we can avoid by having a single TLV stream + // for all payload fields. + var records []tlv.Record + if h.MPP != nil { + records = append(records, h.MPP.Record()) + } + records = append(records, h.TLVRecords...) + // 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) + mapRecords, err := tlv.RecordsToMap(records) if err != nil { return err } @@ -604,6 +620,29 @@ func deserializeHop(r io.Reader) (*route.Hop, error) { tlvMap[tlvType] = rawRecordBytes } + // If the MPP type is present, remove it from the generic TLV map and + // parse it back into a proper MPP struct. + // + // TODO(conner): add migration to unify all fields in a single TLV + // blobs. The split approach will cause headaches down the road as more + // fields are added, which we can avoid by having a single TLV stream + // for all payload fields. + mppType := uint64(record.MPPOnionType) + if mppBytes, ok := tlvMap[mppType]; ok { + delete(tlvMap, mppType) + + var ( + mpp = &record.MPP{} + mppRec = mpp.Record() + r = bytes.NewReader(mppBytes) + ) + err := mppRec.Decode(r, uint64(len(mppBytes))) + if err != nil { + return nil, err + } + h.MPP = mpp + } + tlvRecords, err := tlv.MapToRecords(tlvMap) if err != nil { return nil, err diff --git a/channeldb/payments_test.go b/channeldb/payments_test.go index a792f9654..bec8e528c 100644 --- a/channeldb/payments_test.go +++ b/channeldb/payments_test.go @@ -12,6 +12,7 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/lntypes" + "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" ) @@ -31,6 +32,7 @@ var ( tlv.MakeStaticRecord(1, nil, 3, tlvEncoder, nil), tlv.MakeStaticRecord(2, nil, 3, tlvEncoder, nil), }, + MPP: record.NewMPP(32, [32]byte{0x42}), } testHop2 = &route.Hop{ @@ -46,8 +48,8 @@ var ( TotalAmount: 1234567, SourcePubKey: route.NewVertex(pub), Hops: []*route.Hop{ - testHop1, testHop2, + testHop1, }, } ) diff --git a/routing/route/route.go b/routing/route/route.go index ed51d7d02..62511c3f1 100644 --- a/routing/route/route.go +++ b/routing/route/route.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "encoding/hex" + "errors" "fmt" "io" "strconv" @@ -19,9 +20,17 @@ import ( // VertexSize is the size of the array to store a vertex. const VertexSize = 33 -// ErrNoRouteHopsProvided is returned when a caller attempts to construct a new -// sphinx packet, but provides an empty set of hops for each route. -var ErrNoRouteHopsProvided = fmt.Errorf("empty route hops provided") +var ( + // ErrNoRouteHopsProvided is returned when a caller attempts to + // construct a new sphinx packet, but provides an empty set of hops for + // each route. + ErrNoRouteHopsProvided = fmt.Errorf("empty route hops provided") + + // ErrIntermediateMPPHop is returned when a hop tries to deliver an MPP + // record to an intermediate hop, only final hops can receive MPP + // records. + ErrIntermediateMPPHop = errors.New("cannot send MPP to intermediate") +) // Vertex is a simple alias for the serialization of a compressed Bitcoin // public key. @@ -94,6 +103,10 @@ type Hop struct { // carries as a fee will be subtracted by the hop. AmtToForward lnwire.MilliSatoshi + // MPP encapsulates the data required for option_mpp. This field should + // only be set for the final hop. + MPP *record.MPP + // 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 @@ -140,6 +153,17 @@ func (h *Hop) PackHopPayload(w io.Writer, nextChanID uint64) error { ) } + // If an MPP record is destined for this hop, ensure that we only ever + // attach it to the final hop. Otherwise the route was constructed + // incorrectly. + if h.MPP != nil { + if nextChanID == 0 { + records = append(records, h.MPP.Record()) + } else { + return ErrIntermediateMPPHop + } + } + // Append any custom types destined for this hop. records = append(records, h.TLVRecords...) diff --git a/routing/route/route_test.go b/routing/route/route_test.go index 92b0ee0df..2894cbdc0 100644 --- a/routing/route/route_test.go +++ b/routing/route/route_test.go @@ -1,9 +1,11 @@ package route import ( + "bytes" "testing" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/record" ) // TestRouteTotalFees checks that a route reports the expected total fee. @@ -56,3 +58,38 @@ func TestRouteTotalFees(t *testing.T) { } } + +var ( + testAmt = lnwire.MilliSatoshi(1000) + testAddr = [32]byte{0x01, 0x02} +) + +// TestMPPHop asserts that a Hop will encode a non-nil to final nodes, and fail +// when trying to send to intermediaries. +func TestMPPHop(t *testing.T) { + t.Parallel() + + hop := Hop{ + ChannelID: 1, + OutgoingTimeLock: 44, + AmtToForward: testAmt, + LegacyPayload: false, + MPP: record.NewMPP(testAmt, testAddr), + } + + // Encoding an MPP record to an intermediate hop should result in a + // failure. + var b bytes.Buffer + err := hop.PackHopPayload(&b, 2) + if err != ErrIntermediateMPPHop { + t.Fatalf("expected err: %v, got: %v", + ErrIntermediateMPPHop, err) + } + + // Encoding an MPP record to a final hop should be successful. + b.Reset() + err = hop.PackHopPayload(&b, 0) + if err != nil { + t.Fatalf("expected err: %v, got: %v", nil, err) + } +} diff --git a/tlv/record.go b/tlv/record.go index 66ae8f1c7..fe7742635 100644 --- a/tlv/record.go +++ b/tlv/record.go @@ -85,6 +85,14 @@ func (f *Record) Encode(w io.Writer) error { return f.encoder(w, f.value, &b) } +// Decode read in the TLV record from the passed reader. This is useful when a +// caller wants decode a *single* TLV record, outside the context of the Stream +// struct. +func (f *Record) Decode(r io.Reader, l uint64) error { + var b [8]byte + return f.decoder(r, f.value, &b, l) +} + // MakePrimitiveRecord creates a record for common types. func MakePrimitiveRecord(typ Type, val interface{}) Record { var ( From 4a6f5d8d3d4485d33245ced96aee5aab86729655 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 15:10:00 -0800 Subject: [PATCH 04/11] htlcswitch/hop/payload: parse option_mpp --- htlcswitch/hop/payload.go | 22 +++++++ htlcswitch/hop/payload_test.go | 102 ++++++++++++++++++++++++++++++--- 2 files changed, 115 insertions(+), 9 deletions(-) diff --git a/htlcswitch/hop/payload.go b/htlcswitch/hop/payload.go index 2edd9aa8b..ad164e287 100644 --- a/htlcswitch/hop/payload.go +++ b/htlcswitch/hop/payload.go @@ -81,6 +81,10 @@ type Payload struct { // FwdInfo holds the basic parameters required for HTLC forwarding, e.g. // amount, cltv, and next hop. FwdInfo ForwardingInfo + + // MPP holds the info provided in an option_mpp record when parsed from + // a TLV onion payload. + MPP *record.MPP } // NewLegacyPayload builds a Payload from the amount, cltv, and next hop @@ -105,12 +109,14 @@ func NewPayloadFromReader(r io.Reader) (*Payload, error) { cid uint64 amt uint64 cltv uint32 + mpp = &record.MPP{} ) tlvStream, err := tlv.NewStream( record.NewAmtToFwdRecord(&amt), record.NewLockTimeRecord(&cltv), record.NewNextHopIDRecord(&cid), + mpp.Record(), ) if err != nil { return nil, err @@ -151,6 +157,12 @@ func NewPayloadFromReader(r io.Reader) (*Payload, error) { return nil, err } + // If no MPP field was parsed, set the MPP field on the resulting + // payload to nil. + if _, ok := parsedTypes[record.MPPOnionType]; !ok { + mpp = nil + } + return &Payload{ FwdInfo: ForwardingInfo{ Network: BitcoinNetwork, @@ -158,6 +170,7 @@ func NewPayloadFromReader(r io.Reader) (*Payload, error) { AmountToForward: lnwire.MilliSatoshi(amt), OutgoingCTLV: cltv, }, + MPP: mpp, }, nil } @@ -179,6 +192,7 @@ func ValidateParsedPayloadTypes(parsedTypes tlv.TypeSet, _, hasAmt := parsedTypes[record.AmtOnionType] _, hasLockTime := parsedTypes[record.LockTimeOnionType] _, hasNextHop := parsedTypes[record.NextHopOnionType] + _, hasMPP := parsedTypes[record.MPPOnionType] switch { @@ -207,6 +221,14 @@ func ValidateParsedPayloadTypes(parsedTypes tlv.TypeSet, Violation: IncludedViolation, FinalHop: true, } + + // Intermediate nodes should never receive MPP fields. + case !isFinalHop && hasMPP: + return ErrInvalidPayload{ + Type: record.MPPOnionType, + Violation: IncludedViolation, + FinalHop: isFinalHop, + } } return nil diff --git a/htlcswitch/hop/payload_test.go b/htlcswitch/hop/payload_test.go index a49cd2b11..7ef35e8b4 100644 --- a/htlcswitch/hop/payload_test.go +++ b/htlcswitch/hop/payload_test.go @@ -6,13 +6,15 @@ import ( "testing" "github.com/lightningnetwork/lnd/htlcswitch/hop" + "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/record" ) type decodePayloadTest struct { - name string - payload []byte - expErr error + name string + payload []byte + expErr error + shouldHaveMPP bool } var decodePayloadTests = []decodePayloadTest{ @@ -79,9 +81,9 @@ var decodePayloadTests = []decodePayloadTest{ }, { name: "required type after omitted hop id", - payload: []byte{0x02, 0x00, 0x04, 0x00, 0x08, 0x00}, + payload: []byte{0x02, 0x00, 0x04, 0x00, 0x0a, 0x00}, expErr: hop.ErrInvalidPayload{ - Type: 8, + Type: 10, Violation: hop.RequiredViolation, FinalHop: true, }, @@ -89,10 +91,10 @@ var decodePayloadTests = []decodePayloadTest{ { name: "required type after included hop id", payload: []byte{0x02, 0x00, 0x04, 0x00, 0x06, 0x08, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, }, expErr: hop.ErrInvalidPayload{ - Type: 8, + Type: 10, Violation: hop.RequiredViolation, FinalHop: false, }, @@ -112,7 +114,7 @@ var decodePayloadTests = []decodePayloadTest{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, expErr: hop.ErrInvalidPayload{ - Type: 6, + Type: record.NextHopOnionType, Violation: hop.IncludedViolation, FinalHop: true, }, @@ -128,6 +130,60 @@ var decodePayloadTests = []decodePayloadTest{ FinalHop: false, }, }, + { + name: "valid intermediate hop", + payload: []byte{0x02, 0x00, 0x04, 0x00, 0x06, 0x08, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, + expErr: nil, + }, + { + name: "valid final hop", + payload: []byte{0x02, 0x00, 0x04, 0x00}, + expErr: nil, + }, + { + name: "intermediate hop with mpp", + payload: []byte{ + // amount + 0x02, 0x00, + // cltv + 0x04, 0x00, + // next hop id + 0x06, 0x08, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // mpp + 0x08, 0x21, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x08, + }, + expErr: hop.ErrInvalidPayload{ + Type: record.MPPOnionType, + Violation: hop.IncludedViolation, + FinalHop: false, + }, + }, + { + name: "final hop with mpp", + payload: []byte{ + // amount + 0x02, 0x00, + // cltv + 0x04, 0x00, + // mpp + 0x08, 0x21, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x08, + }, + expErr: nil, + shouldHaveMPP: true, + }, } // TestDecodeHopPayloadRecordValidation asserts that parsing the payloads in the @@ -142,9 +198,37 @@ func TestDecodeHopPayloadRecordValidation(t *testing.T) { } func testDecodeHopPayloadValidation(t *testing.T, test decodePayloadTest) { - _, err := hop.NewPayloadFromReader(bytes.NewReader(test.payload)) + var ( + testTotalMsat = lnwire.MilliSatoshi(8) + testAddr = [32]byte{ + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + } + ) + + p, err := hop.NewPayloadFromReader(bytes.NewReader(test.payload)) if !reflect.DeepEqual(test.expErr, err) { t.Fatalf("expected error mismatch, want: %v, got: %v", test.expErr, err) } + if err != nil { + return + } + + // Assert MPP fields if we expect them. + if test.shouldHaveMPP { + if p.MPP == nil { + t.Fatalf("payload should have MPP record") + } + if p.MPP.TotalMsat() != testTotalMsat { + t.Fatalf("invalid total msat") + } + if p.MPP.PaymentAddr() != testAddr { + t.Fatalf("invalid payment addr") + } + } else if p.MPP != nil { + t.Fatalf("unexpected MPP payload") + } } From 70708e2e71879394c445cb7696df577d5e96ea34 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 15:10:15 -0800 Subject: [PATCH 05/11] htlcswitch: return hop.Payload from HopIterator --- htlcswitch/hop/iterator.go | 39 ++++++++++++++------------------- htlcswitch/hop/iterator_test.go | 3 ++- htlcswitch/link.go | 4 +++- htlcswitch/link_test.go | 19 ++++++++-------- htlcswitch/mock.go | 27 ++++++++++++++--------- htlcswitch/test_utils.go | 31 ++++++++++++++------------ 6 files changed, 66 insertions(+), 57 deletions(-) diff --git a/htlcswitch/hop/iterator.go b/htlcswitch/hop/iterator.go index 062ca8794..bf9f7b48e 100644 --- a/htlcswitch/hop/iterator.go +++ b/htlcswitch/hop/iterator.go @@ -16,12 +16,13 @@ import ( // interpret the forwarding information encoded within the HTLC packet, and hop // to encode the forwarding information for the _next_ hop. type Iterator interface { - // ForwardingInstructions returns the set of fields that detail exactly - // _how_ this hop should forward the HTLC to the next hop. - // 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, error) + // HopPayload returns the set of fields that detail exactly _how_ this + // hop should forward the HTLC to the next hop. 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. The payload will also contain any additional TLV fields provided + // by the sender. + HopPayload() (*Payload, error) // ExtraOnionBlob returns the additional EOB data (if available). ExtraOnionBlob() []byte @@ -72,37 +73,31 @@ func (r *sphinxHopIterator) EncodeNextHop(w io.Writer) error { return r.processedPacket.NextPacket.Encode(w) } -// ForwardingInstructions returns the set of fields that detail exactly _how_ -// this hop should forward the HTLC to the next hop. 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. +// HopPayload returns the set of fields that detail exactly _how_ this hop +// should forward the HTLC to the next hop. 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. The payload will +// also contain any additional TLV fields provided by the sender. // // NOTE: Part of the HopIterator interface. -func (r *sphinxHopIterator) ForwardingInstructions() (ForwardingInfo, error) { +func (r *sphinxHopIterator) HopPayload() (*Payload, error) { 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 - p := NewLegacyPayload(fwdInst) - - return p.ForwardingInfo(), nil + return NewLegacyPayload(fwdInst), nil // 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: - p, err := NewPayloadFromReader(bytes.NewReader( + return NewPayloadFromReader(bytes.NewReader( r.processedPacket.Payload.Payload, )) - if err != nil { - return ForwardingInfo{}, err - } - - return p.ForwardingInfo(), nil default: - return ForwardingInfo{}, fmt.Errorf("unknown "+ - "sphinx payload type: %v", + return nil, fmt.Errorf("unknown sphinx payload type: %v", r.processedPacket.Payload.Type) } } diff --git a/htlcswitch/hop/iterator_test.go b/htlcswitch/hop/iterator_test.go index 822e8794b..20c5632b2 100644 --- a/htlcswitch/hop/iterator_test.go +++ b/htlcswitch/hop/iterator_test.go @@ -85,12 +85,13 @@ func TestSphinxHopIteratorForwardingInstructions(t *testing.T) { for i, testCase := range testCases { iterator.processedPacket = testCase.sphinxPacket - fwdInfo, err := iterator.ForwardingInstructions() + pld, err := iterator.HopPayload() if err != nil { t.Fatalf("#%v: unable to extract forwarding "+ "instructions: %v", i, err) } + fwdInfo := pld.ForwardingInfo() if fwdInfo != testCase.expectedFwdInfo { t.Fatalf("#%v: wrong fwding info: expected %v, got %v", i, spew.Sdump(testCase.expectedFwdInfo), diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 7209789de..4593d0420 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -2642,7 +2642,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, heightNow := l.cfg.Switch.BestHeight() - fwdInfo, err := chanIterator.ForwardingInstructions() + pld, err := chanIterator.HopPayload() if err != nil { // If we're unable to process the onion payload, or we // received invalid onion payload failure, then we @@ -2671,6 +2671,8 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, continue } + fwdInfo := pld.ForwardingInfo() + switch fwdInfo.NextHop { case hop.Exit: updated, err := l.processExitHop( diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go index 13dd78693..93eb37635 100644 --- a/htlcswitch/link_test.go +++ b/htlcswitch/link_test.go @@ -22,6 +22,7 @@ import ( "github.com/coreos/bbolt" "github.com/davecgh/go-spew/spew" "github.com/go-errors/errors" + sphinx "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/contractcourt" @@ -563,7 +564,7 @@ func TestExitNodeTimelockPayloadMismatch(t *testing.T) { // per-hop payload for outgoing time lock to be the incorrect value. // The proper value of the outgoing CLTV should be the policy set by // the receiving node, instead we set it to be a random value. - hops[0].OutgoingCTLV = 500 + hops[0].FwdInfo.OutgoingCTLV = 500 firstHop := n.firstBobChannelLink.ShortChanID() _, err = makePayment( n.aliceServer, n.bobServer, firstHop, hops, amount, htlcAmt, @@ -616,7 +617,7 @@ func TestExitNodeAmountPayloadMismatch(t *testing.T) { // per-hop payload for amount to be the incorrect value. The proper // value of the amount to forward should be the amount that the // receiving node expects to receive. - hops[0].AmountToForward = 1 + hops[0].FwdInfo.AmountToForward = 1 firstHop := n.firstBobChannelLink.ShortChanID() _, err = makePayment( n.aliceServer, n.bobServer, firstHop, hops, amount, htlcAmt, @@ -4354,13 +4355,13 @@ func generateHtlcAndInvoice(t *testing.T, htlcAmt := lnwire.NewMSatFromSatoshis(10000) htlcExpiry := testStartingHeight + testInvoiceCltvExpiry - hops := []hop.ForwardingInfo{ - { - Network: hop.BitcoinNetwork, - NextHop: hop.Exit, - AmountToForward: htlcAmt, - OutgoingCTLV: uint32(htlcExpiry), - }, + hops := []*hop.Payload{ + hop.NewLegacyPayload(&sphinx.HopData{ + Realm: [1]byte{}, // hop.BitcoinNetwork + NextAddress: [8]byte{}, // hop.Exit, + ForwardAmount: uint64(htlcAmt), + OutgoingCltv: uint32(htlcExpiry), + }), } blob, err := generateRoute(hops...) if err != nil { diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index 69bbec900..7701846e1 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -265,16 +265,14 @@ func (s *mockServer) QuitSignal() <-chan struct{} { // mockHopIterator represents the test version of hop iterator which instead // of encrypting the path in onion blob just stores the path as a list of hops. type mockHopIterator struct { - hops []hop.ForwardingInfo + hops []*hop.Payload } -func newMockHopIterator(hops ...hop.ForwardingInfo) hop.Iterator { +func newMockHopIterator(hops ...*hop.Payload) hop.Iterator { return &mockHopIterator{hops: hops} } -func (r *mockHopIterator) ForwardingInstructions() ( - hop.ForwardingInfo, error) { - +func (r *mockHopIterator) HopPayload() (*hop.Payload, error) { h := r.hops[0] r.hops = r.hops[1:] return h, nil @@ -300,7 +298,8 @@ func (r *mockHopIterator) EncodeNextHop(w io.Writer) error { } for _, hop := range r.hops { - if err := encodeFwdInfo(w, &hop); err != nil { + fwdInfo := hop.ForwardingInfo() + if err := encodeFwdInfo(w, &fwdInfo); err != nil { return err } } @@ -434,14 +433,22 @@ func (p *mockIteratorDecoder) DecodeHopIterator(r io.Reader, rHash []byte, } hopLength := binary.BigEndian.Uint32(b[:]) - hops := make([]hop.ForwardingInfo, hopLength) + hops := make([]*hop.Payload, hopLength) for i := uint32(0); i < hopLength; i++ { - f := &hop.ForwardingInfo{} - if err := decodeFwdInfo(r, f); err != nil { + var f hop.ForwardingInfo + if err := decodeFwdInfo(r, &f); err != nil { return nil, lnwire.CodeTemporaryChannelFailure } - hops[i] = *f + var nextHopBytes [8]byte + binary.BigEndian.PutUint64(nextHopBytes[:], f.NextHop.ToUint64()) + + hops[i] = hop.NewLegacyPayload(&sphinx.HopData{ + Realm: [1]byte{}, // hop.BitcoinNetwork + NextAddress: nextHopBytes, + ForwardAmount: uint64(f.AmountToForward), + OutgoingCltv: f.OutgoingCTLV, + }) } return newMockHopIterator(hops...), lnwire.CodeNone diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index 6c424b438..44085f90d 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -23,6 +23,7 @@ import ( "github.com/btcsuite/fastsha256" "github.com/coreos/bbolt" "github.com/go-errors/errors" + sphinx "github.com/lightningnetwork/lightning-onion" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/htlcswitch/hop" @@ -601,7 +602,7 @@ func generatePayment(invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32, } // generateRoute generates the path blob by given array of peers. -func generateRoute(hops ...hop.ForwardingInfo) ( +func generateRoute(hops ...*hop.Payload) ( [lnwire.OnionPacketSize]byte, error) { var blob [lnwire.OnionPacketSize]byte @@ -642,13 +643,12 @@ type threeHopNetwork struct { // also the time lock value needed to route an HTLC with the target amount over // the specified path. func generateHops(payAmt lnwire.MilliSatoshi, startingHeight uint32, - path ...*channelLink) (lnwire.MilliSatoshi, uint32, - []hop.ForwardingInfo) { + path ...*channelLink) (lnwire.MilliSatoshi, uint32, []*hop.Payload) { totalTimelock := startingHeight runningAmt := payAmt - hops := make([]hop.ForwardingInfo, len(path)) + hops := make([]*hop.Payload, len(path)) for i := len(path) - 1; i >= 0; i-- { // If this is the last hop, then the next hop is the special // "exit node". Otherwise, we look to the "prior" hop. @@ -676,7 +676,7 @@ func generateHops(payAmt lnwire.MilliSatoshi, startingHeight uint32, amount := payAmt if i != len(path)-1 { prevHop := hops[i+1] - prevAmount := prevHop.AmountToForward + prevAmount := prevHop.ForwardingInfo().AmountToForward fee := ExpectedFee(path[i].cfg.FwrdingPolicy, prevAmount) runningAmt += fee @@ -687,12 +687,15 @@ func generateHops(payAmt lnwire.MilliSatoshi, startingHeight uint32, amount = runningAmt - fee } - hops[i] = hop.ForwardingInfo{ - Network: hop.BitcoinNetwork, - NextHop: nextHop, - AmountToForward: amount, - OutgoingCTLV: timeLock, - } + var nextHopBytes [8]byte + binary.BigEndian.PutUint64(nextHopBytes[:], nextHop.ToUint64()) + + hops[i] = hop.NewLegacyPayload(&sphinx.HopData{ + Realm: [1]byte{}, // hop.BitcoinNetwork + NextAddress: nextHopBytes, + ForwardAmount: uint64(amount), + OutgoingCltv: timeLock, + }) } return runningAmt, totalTimelock, hops @@ -739,7 +742,7 @@ func waitForPayFuncResult(payFunc func() error, d time.Duration) error { // * from Alice to Carol through the Bob // * from Alice to some another peer through the Bob func makePayment(sendingPeer, receivingPeer lnpeer.Peer, - firstHop lnwire.ShortChannelID, hops []hop.ForwardingInfo, + firstHop lnwire.ShortChannelID, hops []*hop.Payload, invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32) *paymentResponse { @@ -773,7 +776,7 @@ func makePayment(sendingPeer, receivingPeer lnpeer.Peer, // preparePayment creates an invoice at the receivingPeer and returns a function // that, when called, launches the payment from the sendingPeer. func preparePayment(sendingPeer, receivingPeer lnpeer.Peer, - firstHop lnwire.ShortChannelID, hops []hop.ForwardingInfo, + firstHop lnwire.ShortChannelID, hops []*hop.Payload, invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32) (*channeldb.Invoice, func() error, error) { @@ -1265,7 +1268,7 @@ func (n *twoHopNetwork) stop() { } func (n *twoHopNetwork) makeHoldPayment(sendingPeer, receivingPeer lnpeer.Peer, - firstHop lnwire.ShortChannelID, hops []hop.ForwardingInfo, + firstHop lnwire.ShortChannelID, hops []*hop.Payload, invoiceAmt, htlcAmt lnwire.MilliSatoshi, timelock uint32, preimage lntypes.Preimage) chan error { From 9e9b912d3a14cbe4727191988ada7b69ad54f19b Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 15:10:32 -0800 Subject: [PATCH 06/11] multi: replace NotifyExitHopHtlc eob param with hop.Payload --- contractcourt/interfaces.go | 2 +- contractcourt/mock_registry_test.go | 2 +- htlcswitch/hop/payload.go | 6 ++++++ htlcswitch/interfaces.go | 2 +- htlcswitch/link.go | 7 +++---- htlcswitch/mock.go | 5 +++-- invoices/interface.go | 11 +++++++++++ invoices/invoiceregistry.go | 2 +- 8 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 invoices/interface.go diff --git a/contractcourt/interfaces.go b/contractcourt/interfaces.go index c928f4289..c73a23a03 100644 --- a/contractcourt/interfaces.go +++ b/contractcourt/interfaces.go @@ -21,7 +21,7 @@ type Registry interface { NotifyExitHopHtlc(payHash lntypes.Hash, paidAmount lnwire.MilliSatoshi, expiry uint32, currentHeight int32, circuitKey channeldb.CircuitKey, hodlChan chan<- interface{}, - eob []byte) (*invoices.HodlEvent, error) + payload invoices.Payload) (*invoices.HodlEvent, error) // HodlUnsubscribeAll unsubscribes from all hodl events. HodlUnsubscribeAll(subscriber chan<- interface{}) diff --git a/contractcourt/mock_registry_test.go b/contractcourt/mock_registry_test.go index e45022893..43195249c 100644 --- a/contractcourt/mock_registry_test.go +++ b/contractcourt/mock_registry_test.go @@ -24,7 +24,7 @@ type mockRegistry struct { func (r *mockRegistry) NotifyExitHopHtlc(payHash lntypes.Hash, paidAmount lnwire.MilliSatoshi, expiry uint32, currentHeight int32, circuitKey channeldb.CircuitKey, hodlChan chan<- interface{}, - eob []byte) (*invoices.HodlEvent, error) { + payload invoices.Payload) (*invoices.HodlEvent, error) { r.notifyChan <- notifyExitHopData{ hodlChan: hodlChan, diff --git a/htlcswitch/hop/payload.go b/htlcswitch/hop/payload.go index ad164e287..e05b4ee98 100644 --- a/htlcswitch/hop/payload.go +++ b/htlcswitch/hop/payload.go @@ -233,3 +233,9 @@ func ValidateParsedPayloadTypes(parsedTypes tlv.TypeSet, return nil } + +// MultiPath returns the record corresponding the option_mpp parsed from the +// onion payload. +func (h *Payload) MultiPath() *record.MPP { + return h.MPP +} diff --git a/htlcswitch/interfaces.go b/htlcswitch/interfaces.go index cd050856c..3b9ac6dff 100644 --- a/htlcswitch/interfaces.go +++ b/htlcswitch/interfaces.go @@ -27,7 +27,7 @@ type InvoiceDatabase interface { NotifyExitHopHtlc(payHash lntypes.Hash, paidAmount lnwire.MilliSatoshi, expiry uint32, currentHeight int32, circuitKey channeldb.CircuitKey, hodlChan chan<- interface{}, - eob []byte) (*invoices.HodlEvent, error) + payload invoices.Payload) (*invoices.HodlEvent, error) // CancelInvoice attempts to cancel the invoice corresponding to the // passed payment hash. diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 4593d0420..4da9c0db6 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -2676,8 +2676,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, switch fwdInfo.NextHop { case hop.Exit: updated, err := l.processExitHop( - pd, obfuscator, fwdInfo, heightNow, - chanIterator.ExtraOnionBlob(), + pd, obfuscator, fwdInfo, heightNow, pld, ) if err != nil { l.fail(LinkFailureError{code: ErrInternalError}, @@ -2846,7 +2845,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, // returns a boolean indicating whether the commitment tx needs an update. func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor, obfuscator hop.ErrorEncrypter, fwdInfo hop.ForwardingInfo, - heightNow uint32, eob []byte) (bool, error) { + heightNow uint32, payload invoices.Payload) (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 @@ -2897,7 +2896,7 @@ func (l *channelLink) processExitHop(pd *lnwallet.PaymentDescriptor, event, err := l.cfg.Registry.NotifyExitHopHtlc( invoiceHash, pd.Amount, pd.Timeout, int32(heightNow), - circuitKey, l.hodlQueue.ChanIn(), eob, + circuitKey, l.hodlQueue.ChanIn(), payload, ) switch err { diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go index 7701846e1..3dc1160df 100644 --- a/htlcswitch/mock.go +++ b/htlcswitch/mock.go @@ -814,10 +814,11 @@ func (i *mockInvoiceRegistry) SettleHodlInvoice(preimage lntypes.Preimage) error func (i *mockInvoiceRegistry) NotifyExitHopHtlc(rhash lntypes.Hash, amt lnwire.MilliSatoshi, expiry uint32, currentHeight int32, circuitKey channeldb.CircuitKey, hodlChan chan<- interface{}, - eob []byte) (*invoices.HodlEvent, error) { + payload invoices.Payload) (*invoices.HodlEvent, error) { event, err := i.registry.NotifyExitHopHtlc( - rhash, amt, expiry, currentHeight, circuitKey, hodlChan, eob, + rhash, amt, expiry, currentHeight, circuitKey, hodlChan, + payload, ) if err != nil { return nil, err diff --git a/invoices/interface.go b/invoices/interface.go new file mode 100644 index 000000000..8bbe2ec9f --- /dev/null +++ b/invoices/interface.go @@ -0,0 +1,11 @@ +package invoices + +import "github.com/lightningnetwork/lnd/record" + +// Payload abstracts access to any additional fields provided in the final hop's +// TLV onion payload. +type Payload interface { + // MultiPath returns the record corresponding the option_mpp parsed from + // the onion payload. + MultiPath() *record.MPP +} diff --git a/invoices/invoiceregistry.go b/invoices/invoiceregistry.go index 3f35954f8..61f0feaf2 100644 --- a/invoices/invoiceregistry.go +++ b/invoices/invoiceregistry.go @@ -429,7 +429,7 @@ func (i *InvoiceRegistry) LookupInvoice(rHash lntypes.Hash) (channeldb.Invoice, func (i *InvoiceRegistry) NotifyExitHopHtlc(rHash lntypes.Hash, amtPaid lnwire.MilliSatoshi, expiry uint32, currentHeight int32, circuitKey channeldb.CircuitKey, hodlChan chan<- interface{}, - eob []byte) (*HodlEvent, error) { + payload Payload) (*HodlEvent, error) { i.Lock() defer i.Unlock() From 014ea0abd042d5ea2a9872892e602a20a7a5c69c Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 15:10:50 -0800 Subject: [PATCH 07/11] htlcswitch/iterator: remove unused ExtraOnionBlob method --- htlcswitch/hop/iterator.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/htlcswitch/hop/iterator.go b/htlcswitch/hop/iterator.go index bf9f7b48e..a11ce632c 100644 --- a/htlcswitch/hop/iterator.go +++ b/htlcswitch/hop/iterator.go @@ -24,9 +24,6 @@ type Iterator interface { // by the sender. HopPayload() (*Payload, 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. EncodeNextHop(w io.Writer) error @@ -102,15 +99,6 @@ func (r *sphinxHopIterator) HopPayload() (*Payload, error) { } } -// 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, // along with a failure code to signal if the decoding was successful. The // ErrorEncrypter is used to encrypt errors back to the sender in the event that From 92aa78dd5f73f4d5ac031f2ef7c56135ebc9cc3b Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 15:11:07 -0800 Subject: [PATCH 08/11] lnrpc/rpc.proto: add mpp fields to Hop message This commit add mpp_total_amt_msat and mpp_payment_addr to the Hop message. Doing so enables users submitting mpp payments via rpc to set these parameters for the destination. In addition, it will allow us to display these fields in rpc responses. --- lnrpc/rpc.pb.go | 1288 +++++++++++++++++++++------------------- lnrpc/rpc.proto | 26 + lnrpc/rpc.swagger.json | 19 + 3 files changed, 726 insertions(+), 607 deletions(-) diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index 9fdd10111..2dbed936e 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -217,7 +217,7 @@ func (x Invoice_InvoiceState) String() string { } func (Invoice_InvoiceState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{95, 0} + return fileDescriptor_77a6da22d6a3feb1, []int{96, 0} } type Payment_PaymentStatus int32 @@ -248,7 +248,7 @@ func (x Payment_PaymentStatus) String() string { } func (Payment_PaymentStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{102, 0} + return fileDescriptor_77a6da22d6a3feb1, []int{103, 0} } type GenSeedRequest struct { @@ -5374,10 +5374,16 @@ type Hop struct { //* //If set to true, then this hop will be encoded using the new variable length //TLV format. - TlvPayload bool `protobuf:"varint,9,opt,name=tlv_payload,proto3" json:"tlv_payload,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + TlvPayload bool `protobuf:"varint,9,opt,name=tlv_payload,proto3" json:"tlv_payload,omitempty"` + //* + //An optional TLV record tha singals the use of an MPP payment. If present, + //the receiver will enforce that that the same mpp_record is included in the + //final hop payload of all non-zero payments in the HTLC set. If empty, a + //regular single-shot payment is or was attempted. + MppRecord *MPPRecord `protobuf:"bytes,10,opt,name=mpp_record,proto3" json:"mpp_record,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Hop) Reset() { *m = Hop{} } @@ -5470,6 +5476,70 @@ func (m *Hop) GetTlvPayload() bool { return false } +func (m *Hop) GetMppRecord() *MPPRecord { + if m != nil { + return m.MppRecord + } + return nil +} + +type MPPRecord struct { + //* + //A unique, random identifier used to authenticate the sender as the intended + //payer of a multi-path payment. The payment_addr must be the same for all + //subpayments, and match the payment_addr provided in the receiver's invoice. + //The same payment_addr must be used on all subpayments. + PaymentAddr []byte `protobuf:"bytes,11,opt,name=payment_addr,proto3" json:"payment_addr,omitempty"` + //* + //The total amount in milli-satoshis being sent as part of a larger multi-path + //payment. The caller is responsible for ensuring subpayments to the same node + //and payment_hash sum exactly to total_amt_msat. The same + //total_amt_msat must be used on all subpayments. + TotalAmtMsat int64 `protobuf:"varint,10,opt,name=total_amt_msat,proto3" json:"total_amt_msat,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *MPPRecord) Reset() { *m = MPPRecord{} } +func (m *MPPRecord) String() string { return proto.CompactTextString(m) } +func (*MPPRecord) ProtoMessage() {} +func (*MPPRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_77a6da22d6a3feb1, []int{74} +} + +func (m *MPPRecord) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_MPPRecord.Unmarshal(m, b) +} +func (m *MPPRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_MPPRecord.Marshal(b, m, deterministic) +} +func (m *MPPRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_MPPRecord.Merge(m, src) +} +func (m *MPPRecord) XXX_Size() int { + return xxx_messageInfo_MPPRecord.Size(m) +} +func (m *MPPRecord) XXX_DiscardUnknown() { + xxx_messageInfo_MPPRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_MPPRecord proto.InternalMessageInfo + +func (m *MPPRecord) GetPaymentAddr() []byte { + if m != nil { + return m.PaymentAddr + } + return nil +} + +func (m *MPPRecord) GetTotalAmtMsat() int64 { + if m != nil { + return m.TotalAmtMsat + } + return 0 +} + //* //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 @@ -5513,7 +5583,7 @@ func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} func (*Route) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{74} + return fileDescriptor_77a6da22d6a3feb1, []int{75} } func (m *Route) XXX_Unmarshal(b []byte) error { @@ -5592,7 +5662,7 @@ func (m *NodeInfoRequest) Reset() { *m = NodeInfoRequest{} } func (m *NodeInfoRequest) String() string { return proto.CompactTextString(m) } func (*NodeInfoRequest) ProtoMessage() {} func (*NodeInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{75} + return fileDescriptor_77a6da22d6a3feb1, []int{76} } func (m *NodeInfoRequest) XXX_Unmarshal(b []byte) error { @@ -5649,7 +5719,7 @@ func (m *NodeInfo) Reset() { *m = NodeInfo{} } func (m *NodeInfo) String() string { return proto.CompactTextString(m) } func (*NodeInfo) ProtoMessage() {} func (*NodeInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{76} + return fileDescriptor_77a6da22d6a3feb1, []int{77} } func (m *NodeInfo) XXX_Unmarshal(b []byte) error { @@ -5718,7 +5788,7 @@ func (m *LightningNode) Reset() { *m = LightningNode{} } func (m *LightningNode) String() string { return proto.CompactTextString(m) } func (*LightningNode) ProtoMessage() {} func (*LightningNode) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{77} + return fileDescriptor_77a6da22d6a3feb1, []int{78} } func (m *LightningNode) XXX_Unmarshal(b []byte) error { @@ -5786,7 +5856,7 @@ func (m *NodeAddress) Reset() { *m = NodeAddress{} } func (m *NodeAddress) String() string { return proto.CompactTextString(m) } func (*NodeAddress) ProtoMessage() {} func (*NodeAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{78} + return fileDescriptor_77a6da22d6a3feb1, []int{79} } func (m *NodeAddress) XXX_Unmarshal(b []byte) error { @@ -5838,7 +5908,7 @@ func (m *RoutingPolicy) Reset() { *m = RoutingPolicy{} } func (m *RoutingPolicy) String() string { return proto.CompactTextString(m) } func (*RoutingPolicy) ProtoMessage() {} func (*RoutingPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{79} + return fileDescriptor_77a6da22d6a3feb1, []int{80} } func (m *RoutingPolicy) XXX_Unmarshal(b []byte) error { @@ -5936,7 +6006,7 @@ func (m *ChannelEdge) Reset() { *m = ChannelEdge{} } func (m *ChannelEdge) String() string { return proto.CompactTextString(m) } func (*ChannelEdge) ProtoMessage() {} func (*ChannelEdge) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{80} + return fileDescriptor_77a6da22d6a3feb1, []int{81} } func (m *ChannelEdge) XXX_Unmarshal(b []byte) error { @@ -6029,7 +6099,7 @@ func (m *ChannelGraphRequest) Reset() { *m = ChannelGraphRequest{} } func (m *ChannelGraphRequest) String() string { return proto.CompactTextString(m) } func (*ChannelGraphRequest) ProtoMessage() {} func (*ChannelGraphRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{81} + return fileDescriptor_77a6da22d6a3feb1, []int{82} } func (m *ChannelGraphRequest) XXX_Unmarshal(b []byte) error { @@ -6072,7 +6142,7 @@ func (m *ChannelGraph) Reset() { *m = ChannelGraph{} } func (m *ChannelGraph) String() string { return proto.CompactTextString(m) } func (*ChannelGraph) ProtoMessage() {} func (*ChannelGraph) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{82} + return fileDescriptor_77a6da22d6a3feb1, []int{83} } func (m *ChannelGraph) XXX_Unmarshal(b []byte) error { @@ -6122,7 +6192,7 @@ func (m *ChanInfoRequest) Reset() { *m = ChanInfoRequest{} } func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) } func (*ChanInfoRequest) ProtoMessage() {} func (*ChanInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{83} + return fileDescriptor_77a6da22d6a3feb1, []int{84} } func (m *ChanInfoRequest) XXX_Unmarshal(b []byte) error { @@ -6160,7 +6230,7 @@ func (m *NetworkInfoRequest) Reset() { *m = NetworkInfoRequest{} } func (m *NetworkInfoRequest) String() string { return proto.CompactTextString(m) } func (*NetworkInfoRequest) ProtoMessage() {} func (*NetworkInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{84} + return fileDescriptor_77a6da22d6a3feb1, []int{85} } func (m *NetworkInfoRequest) XXX_Unmarshal(b []byte) error { @@ -6203,7 +6273,7 @@ func (m *NetworkInfo) Reset() { *m = NetworkInfo{} } func (m *NetworkInfo) String() string { return proto.CompactTextString(m) } func (*NetworkInfo) ProtoMessage() {} func (*NetworkInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{85} + return fileDescriptor_77a6da22d6a3feb1, []int{86} } func (m *NetworkInfo) XXX_Unmarshal(b []byte) error { @@ -6311,7 +6381,7 @@ func (m *StopRequest) Reset() { *m = StopRequest{} } func (m *StopRequest) String() string { return proto.CompactTextString(m) } func (*StopRequest) ProtoMessage() {} func (*StopRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{86} + return fileDescriptor_77a6da22d6a3feb1, []int{87} } func (m *StopRequest) XXX_Unmarshal(b []byte) error { @@ -6342,7 +6412,7 @@ func (m *StopResponse) Reset() { *m = StopResponse{} } func (m *StopResponse) String() string { return proto.CompactTextString(m) } func (*StopResponse) ProtoMessage() {} func (*StopResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{87} + return fileDescriptor_77a6da22d6a3feb1, []int{88} } func (m *StopResponse) XXX_Unmarshal(b []byte) error { @@ -6373,7 +6443,7 @@ func (m *GraphTopologySubscription) Reset() { *m = GraphTopologySubscrip func (m *GraphTopologySubscription) String() string { return proto.CompactTextString(m) } func (*GraphTopologySubscription) ProtoMessage() {} func (*GraphTopologySubscription) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{88} + return fileDescriptor_77a6da22d6a3feb1, []int{89} } func (m *GraphTopologySubscription) XXX_Unmarshal(b []byte) error { @@ -6407,7 +6477,7 @@ func (m *GraphTopologyUpdate) Reset() { *m = GraphTopologyUpdate{} } func (m *GraphTopologyUpdate) String() string { return proto.CompactTextString(m) } func (*GraphTopologyUpdate) ProtoMessage() {} func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{89} + return fileDescriptor_77a6da22d6a3feb1, []int{90} } func (m *GraphTopologyUpdate) XXX_Unmarshal(b []byte) error { @@ -6464,7 +6534,7 @@ func (m *NodeUpdate) Reset() { *m = NodeUpdate{} } func (m *NodeUpdate) String() string { return proto.CompactTextString(m) } func (*NodeUpdate) ProtoMessage() {} func (*NodeUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{90} + return fileDescriptor_77a6da22d6a3feb1, []int{91} } func (m *NodeUpdate) XXX_Unmarshal(b []byte) error { @@ -6540,7 +6610,7 @@ func (m *ChannelEdgeUpdate) Reset() { *m = ChannelEdgeUpdate{} } func (m *ChannelEdgeUpdate) String() string { return proto.CompactTextString(m) } func (*ChannelEdgeUpdate) ProtoMessage() {} func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{91} + return fileDescriptor_77a6da22d6a3feb1, []int{92} } func (m *ChannelEdgeUpdate) XXX_Unmarshal(b []byte) error { @@ -6621,7 +6691,7 @@ func (m *ClosedChannelUpdate) Reset() { *m = ClosedChannelUpdate{} } func (m *ClosedChannelUpdate) String() string { return proto.CompactTextString(m) } func (*ClosedChannelUpdate) ProtoMessage() {} func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{92} + return fileDescriptor_77a6da22d6a3feb1, []int{93} } func (m *ClosedChannelUpdate) XXX_Unmarshal(b []byte) error { @@ -6692,7 +6762,7 @@ func (m *HopHint) Reset() { *m = HopHint{} } func (m *HopHint) String() string { return proto.CompactTextString(m) } func (*HopHint) ProtoMessage() {} func (*HopHint) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{93} + return fileDescriptor_77a6da22d6a3feb1, []int{94} } func (m *HopHint) XXX_Unmarshal(b []byte) error { @@ -6762,7 +6832,7 @@ func (m *RouteHint) Reset() { *m = RouteHint{} } func (m *RouteHint) String() string { return proto.CompactTextString(m) } func (*RouteHint) ProtoMessage() {} func (*RouteHint) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{94} + return fileDescriptor_77a6da22d6a3feb1, []int{95} } func (m *RouteHint) XXX_Unmarshal(b []byte) error { @@ -6880,7 +6950,7 @@ func (m *Invoice) Reset() { *m = Invoice{} } func (m *Invoice) String() string { return proto.CompactTextString(m) } func (*Invoice) ProtoMessage() {} func (*Invoice) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{95} + return fileDescriptor_77a6da22d6a3feb1, []int{96} } func (m *Invoice) XXX_Unmarshal(b []byte) error { @@ -7085,7 +7155,7 @@ func (m *InvoiceHTLC) Reset() { *m = InvoiceHTLC{} } func (m *InvoiceHTLC) String() string { return proto.CompactTextString(m) } func (*InvoiceHTLC) ProtoMessage() {} func (*InvoiceHTLC) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{96} + return fileDescriptor_77a6da22d6a3feb1, []int{97} } func (m *InvoiceHTLC) XXX_Unmarshal(b []byte) error { @@ -7184,7 +7254,7 @@ func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} } func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*AddInvoiceResponse) ProtoMessage() {} func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{97} + return fileDescriptor_77a6da22d6a3feb1, []int{98} } func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error { @@ -7242,7 +7312,7 @@ func (m *PaymentHash) Reset() { *m = PaymentHash{} } func (m *PaymentHash) String() string { return proto.CompactTextString(m) } func (*PaymentHash) ProtoMessage() {} func (*PaymentHash) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{98} + return fileDescriptor_77a6da22d6a3feb1, []int{99} } func (m *PaymentHash) XXX_Unmarshal(b []byte) error { @@ -7299,7 +7369,7 @@ func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} } func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) } func (*ListInvoiceRequest) ProtoMessage() {} func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{99} + return fileDescriptor_77a6da22d6a3feb1, []int{100} } func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error { @@ -7370,7 +7440,7 @@ func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} } func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*ListInvoiceResponse) ProtoMessage() {} func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{100} + return fileDescriptor_77a6da22d6a3feb1, []int{101} } func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error { @@ -7434,7 +7504,7 @@ func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} } func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) } func (*InvoiceSubscription) ProtoMessage() {} func (*InvoiceSubscription) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{101} + return fileDescriptor_77a6da22d6a3feb1, []int{102} } func (m *InvoiceSubscription) XXX_Unmarshal(b []byte) error { @@ -7503,7 +7573,7 @@ func (m *Payment) Reset() { *m = Payment{} } func (m *Payment) String() string { return proto.CompactTextString(m) } func (*Payment) ProtoMessage() {} func (*Payment) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{102} + return fileDescriptor_77a6da22d6a3feb1, []int{103} } func (m *Payment) XXX_Unmarshal(b []byte) error { @@ -7625,7 +7695,7 @@ func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} } func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*ListPaymentsRequest) ProtoMessage() {} func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{103} + return fileDescriptor_77a6da22d6a3feb1, []int{104} } func (m *ListPaymentsRequest) XXX_Unmarshal(b []byte) error { @@ -7665,7 +7735,7 @@ func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} } func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*ListPaymentsResponse) ProtoMessage() {} func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{104} + return fileDescriptor_77a6da22d6a3feb1, []int{105} } func (m *ListPaymentsResponse) XXX_Unmarshal(b []byte) error { @@ -7703,7 +7773,7 @@ func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsReque func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsRequest) ProtoMessage() {} func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{105} + return fileDescriptor_77a6da22d6a3feb1, []int{106} } func (m *DeleteAllPaymentsRequest) XXX_Unmarshal(b []byte) error { @@ -7734,7 +7804,7 @@ func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResp func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsResponse) ProtoMessage() {} func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{106} + return fileDescriptor_77a6da22d6a3feb1, []int{107} } func (m *DeleteAllPaymentsResponse) XXX_Unmarshal(b []byte) error { @@ -7766,7 +7836,7 @@ func (m *AbandonChannelRequest) Reset() { *m = AbandonChannelRequest{} } func (m *AbandonChannelRequest) String() string { return proto.CompactTextString(m) } func (*AbandonChannelRequest) ProtoMessage() {} func (*AbandonChannelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{107} + return fileDescriptor_77a6da22d6a3feb1, []int{108} } func (m *AbandonChannelRequest) XXX_Unmarshal(b []byte) error { @@ -7804,7 +7874,7 @@ func (m *AbandonChannelResponse) Reset() { *m = AbandonChannelResponse{} func (m *AbandonChannelResponse) String() string { return proto.CompactTextString(m) } func (*AbandonChannelResponse) ProtoMessage() {} func (*AbandonChannelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{108} + return fileDescriptor_77a6da22d6a3feb1, []int{109} } func (m *AbandonChannelResponse) XXX_Unmarshal(b []byte) error { @@ -7837,7 +7907,7 @@ func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} } func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) } func (*DebugLevelRequest) ProtoMessage() {} func (*DebugLevelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{109} + return fileDescriptor_77a6da22d6a3feb1, []int{110} } func (m *DebugLevelRequest) XXX_Unmarshal(b []byte) error { @@ -7883,7 +7953,7 @@ func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} } func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) } func (*DebugLevelResponse) ProtoMessage() {} func (*DebugLevelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{110} + return fileDescriptor_77a6da22d6a3feb1, []int{111} } func (m *DebugLevelResponse) XXX_Unmarshal(b []byte) error { @@ -7923,7 +7993,7 @@ func (m *PayReqString) Reset() { *m = PayReqString{} } func (m *PayReqString) String() string { return proto.CompactTextString(m) } func (*PayReqString) ProtoMessage() {} func (*PayReqString) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{111} + return fileDescriptor_77a6da22d6a3feb1, []int{112} } func (m *PayReqString) XXX_Unmarshal(b []byte) error { @@ -7971,7 +8041,7 @@ func (m *PayReq) Reset() { *m = PayReq{} } func (m *PayReq) String() string { return proto.CompactTextString(m) } func (*PayReq) ProtoMessage() {} func (*PayReq) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{112} + return fileDescriptor_77a6da22d6a3feb1, []int{113} } func (m *PayReq) XXX_Unmarshal(b []byte) error { @@ -8072,7 +8142,7 @@ func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} } func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) } func (*FeeReportRequest) ProtoMessage() {} func (*FeeReportRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{113} + return fileDescriptor_77a6da22d6a3feb1, []int{114} } func (m *FeeReportRequest) XXX_Unmarshal(b []byte) error { @@ -8111,7 +8181,7 @@ func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} } func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) } func (*ChannelFeeReport) ProtoMessage() {} func (*ChannelFeeReport) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{114} + return fileDescriptor_77a6da22d6a3feb1, []int{115} } func (m *ChannelFeeReport) XXX_Unmarshal(b []byte) error { @@ -8178,7 +8248,7 @@ func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} } func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) } func (*FeeReportResponse) ProtoMessage() {} func (*FeeReportResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{115} + return fileDescriptor_77a6da22d6a3feb1, []int{116} } func (m *FeeReportResponse) XXX_Unmarshal(b []byte) error { @@ -8249,7 +8319,7 @@ func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} } func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateRequest) ProtoMessage() {} func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{116} + return fileDescriptor_77a6da22d6a3feb1, []int{117} } func (m *PolicyUpdateRequest) XXX_Unmarshal(b []byte) error { @@ -8353,7 +8423,7 @@ func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} } func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateResponse) ProtoMessage() {} func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{117} + return fileDescriptor_77a6da22d6a3feb1, []int{118} } func (m *PolicyUpdateResponse) XXX_Unmarshal(b []byte) error { @@ -8392,7 +8462,7 @@ func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryReque func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryRequest) ProtoMessage() {} func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{118} + return fileDescriptor_77a6da22d6a3feb1, []int{119} } func (m *ForwardingHistoryRequest) XXX_Unmarshal(b []byte) error { @@ -8469,7 +8539,7 @@ func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} } func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) } func (*ForwardingEvent) ProtoMessage() {} func (*ForwardingEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{119} + return fileDescriptor_77a6da22d6a3feb1, []int{120} } func (m *ForwardingEvent) XXX_Unmarshal(b []byte) error { @@ -8567,7 +8637,7 @@ func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResp func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryResponse) ProtoMessage() {} func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{120} + return fileDescriptor_77a6da22d6a3feb1, []int{121} } func (m *ForwardingHistoryResponse) XXX_Unmarshal(b []byte) error { @@ -8614,7 +8684,7 @@ func (m *ExportChannelBackupRequest) Reset() { *m = ExportChannelBackupR func (m *ExportChannelBackupRequest) String() string { return proto.CompactTextString(m) } func (*ExportChannelBackupRequest) ProtoMessage() {} func (*ExportChannelBackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{121} + return fileDescriptor_77a6da22d6a3feb1, []int{122} } func (m *ExportChannelBackupRequest) XXX_Unmarshal(b []byte) error { @@ -8660,7 +8730,7 @@ func (m *ChannelBackup) Reset() { *m = ChannelBackup{} } func (m *ChannelBackup) String() string { return proto.CompactTextString(m) } func (*ChannelBackup) ProtoMessage() {} func (*ChannelBackup) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{122} + return fileDescriptor_77a6da22d6a3feb1, []int{123} } func (m *ChannelBackup) XXX_Unmarshal(b []byte) error { @@ -8713,7 +8783,7 @@ func (m *MultiChanBackup) Reset() { *m = MultiChanBackup{} } func (m *MultiChanBackup) String() string { return proto.CompactTextString(m) } func (*MultiChanBackup) ProtoMessage() {} func (*MultiChanBackup) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{123} + return fileDescriptor_77a6da22d6a3feb1, []int{124} } func (m *MultiChanBackup) XXX_Unmarshal(b []byte) error { @@ -8758,7 +8828,7 @@ func (m *ChanBackupExportRequest) Reset() { *m = ChanBackupExportRequest func (m *ChanBackupExportRequest) String() string { return proto.CompactTextString(m) } func (*ChanBackupExportRequest) ProtoMessage() {} func (*ChanBackupExportRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{124} + return fileDescriptor_77a6da22d6a3feb1, []int{125} } func (m *ChanBackupExportRequest) XXX_Unmarshal(b []byte) error { @@ -8797,7 +8867,7 @@ func (m *ChanBackupSnapshot) Reset() { *m = ChanBackupSnapshot{} } func (m *ChanBackupSnapshot) String() string { return proto.CompactTextString(m) } func (*ChanBackupSnapshot) ProtoMessage() {} func (*ChanBackupSnapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{125} + return fileDescriptor_77a6da22d6a3feb1, []int{126} } func (m *ChanBackupSnapshot) XXX_Unmarshal(b []byte) error { @@ -8845,7 +8915,7 @@ func (m *ChannelBackups) Reset() { *m = ChannelBackups{} } func (m *ChannelBackups) String() string { return proto.CompactTextString(m) } func (*ChannelBackups) ProtoMessage() {} func (*ChannelBackups) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{126} + return fileDescriptor_77a6da22d6a3feb1, []int{127} } func (m *ChannelBackups) XXX_Unmarshal(b []byte) error { @@ -8887,7 +8957,7 @@ func (m *RestoreChanBackupRequest) Reset() { *m = RestoreChanBackupReque func (m *RestoreChanBackupRequest) String() string { return proto.CompactTextString(m) } func (*RestoreChanBackupRequest) ProtoMessage() {} func (*RestoreChanBackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{127} + return fileDescriptor_77a6da22d6a3feb1, []int{128} } func (m *RestoreChanBackupRequest) XXX_Unmarshal(b []byte) error { @@ -8963,7 +9033,7 @@ func (m *RestoreBackupResponse) Reset() { *m = RestoreBackupResponse{} } func (m *RestoreBackupResponse) String() string { return proto.CompactTextString(m) } func (*RestoreBackupResponse) ProtoMessage() {} func (*RestoreBackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{128} + return fileDescriptor_77a6da22d6a3feb1, []int{129} } func (m *RestoreBackupResponse) XXX_Unmarshal(b []byte) error { @@ -8994,7 +9064,7 @@ func (m *ChannelBackupSubscription) Reset() { *m = ChannelBackupSubscrip func (m *ChannelBackupSubscription) String() string { return proto.CompactTextString(m) } func (*ChannelBackupSubscription) ProtoMessage() {} func (*ChannelBackupSubscription) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{129} + return fileDescriptor_77a6da22d6a3feb1, []int{130} } func (m *ChannelBackupSubscription) XXX_Unmarshal(b []byte) error { @@ -9025,7 +9095,7 @@ func (m *VerifyChanBackupResponse) Reset() { *m = VerifyChanBackupRespon func (m *VerifyChanBackupResponse) String() string { return proto.CompactTextString(m) } func (*VerifyChanBackupResponse) ProtoMessage() {} func (*VerifyChanBackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{130} + return fileDescriptor_77a6da22d6a3feb1, []int{131} } func (m *VerifyChanBackupResponse) XXX_Unmarshal(b []byte) error { @@ -9060,7 +9130,7 @@ func (m *MacaroonPermission) Reset() { *m = MacaroonPermission{} } func (m *MacaroonPermission) String() string { return proto.CompactTextString(m) } func (*MacaroonPermission) ProtoMessage() {} func (*MacaroonPermission) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{131} + return fileDescriptor_77a6da22d6a3feb1, []int{132} } func (m *MacaroonPermission) XXX_Unmarshal(b []byte) error { @@ -9107,7 +9177,7 @@ func (m *BakeMacaroonRequest) Reset() { *m = BakeMacaroonRequest{} } func (m *BakeMacaroonRequest) String() string { return proto.CompactTextString(m) } func (*BakeMacaroonRequest) ProtoMessage() {} func (*BakeMacaroonRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{132} + return fileDescriptor_77a6da22d6a3feb1, []int{133} } func (m *BakeMacaroonRequest) XXX_Unmarshal(b []byte) error { @@ -9147,7 +9217,7 @@ func (m *BakeMacaroonResponse) Reset() { *m = BakeMacaroonResponse{} } func (m *BakeMacaroonResponse) String() string { return proto.CompactTextString(m) } func (*BakeMacaroonResponse) ProtoMessage() {} func (*BakeMacaroonResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_77a6da22d6a3feb1, []int{133} + return fileDescriptor_77a6da22d6a3feb1, []int{134} } func (m *BakeMacaroonResponse) XXX_Unmarshal(b []byte) error { @@ -9265,6 +9335,7 @@ func init() { proto.RegisterType((*EdgeLocator)(nil), "lnrpc.EdgeLocator") proto.RegisterType((*QueryRoutesResponse)(nil), "lnrpc.QueryRoutesResponse") proto.RegisterType((*Hop)(nil), "lnrpc.Hop") + proto.RegisterType((*MPPRecord)(nil), "lnrpc.MPPRecord") proto.RegisterType((*Route)(nil), "lnrpc.Route") proto.RegisterType((*NodeInfoRequest)(nil), "lnrpc.NodeInfoRequest") proto.RegisterType((*NodeInfo)(nil), "lnrpc.NodeInfo") @@ -9330,547 +9401,550 @@ func init() { func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) } var fileDescriptor_77a6da22d6a3feb1 = []byte{ - // 8631 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7d, 0x5d, 0x6c, 0x1c, 0x5b, - 0xb6, 0x56, 0xfa, 0xcf, 0xee, 0x5e, 0xdd, 0xb6, 0xdb, 0xdb, 0x8e, 0xdd, 0xe9, 0xe4, 0x24, 0x3e, - 0x35, 0xb9, 0x27, 0x99, 0xcc, 0x19, 0x27, 0x27, 0x33, 0x73, 0xc8, 0x3d, 0xe1, 0x72, 0xf1, 0x5f, - 0xe2, 0xcc, 0x38, 0x8e, 0xa7, 0x9c, 0x4c, 0x98, 0x99, 0x7b, 0xd5, 0x53, 0xee, 0xde, 0xb6, 0x6b, - 0xd2, 0x5d, 0xd5, 0x53, 0x55, 0x6d, 0xc7, 0x73, 0x38, 0x48, 0x20, 0x84, 0x10, 0x2f, 0xe8, 0xc0, - 0x0b, 0x20, 0xd0, 0x95, 0xe6, 0x22, 0x71, 0x2f, 0x08, 0x01, 0x0f, 0x48, 0x80, 0xae, 0xc4, 0x03, - 0x0f, 0x48, 0x48, 0x88, 0x07, 0x1e, 0x90, 0x78, 0xe0, 0x0a, 0x81, 0x84, 0xae, 0x10, 0x2f, 0x48, - 0xbc, 0xa3, 0xb5, 0xf6, 0x4f, 0xed, 0x5d, 0x55, 0x1d, 0xe7, 0xcc, 0x0c, 0x3c, 0xb9, 0xf7, 0xb7, - 0x77, 0xed, 0xdf, 0xb5, 0xd6, 0x5e, 0x6b, 0xed, 0xb5, 0xb7, 0xa1, 0x11, 0x8d, 0xfb, 0xeb, 0xe3, - 0x28, 0x4c, 0x42, 0x56, 0x1b, 0x06, 0xd1, 0xb8, 0xdf, 0xbd, 0x71, 0x12, 0x86, 0x27, 0x43, 0x7e, - 0xdf, 0x1b, 0xfb, 0xf7, 0xbd, 0x20, 0x08, 0x13, 0x2f, 0xf1, 0xc3, 0x20, 0x16, 0x85, 0x9c, 0x9f, - 0xc0, 0xfc, 0x53, 0x1e, 0x1c, 0x72, 0x3e, 0x70, 0xf9, 0xcf, 0x26, 0x3c, 0x4e, 0xd8, 0x37, 0x60, - 0xd1, 0xe3, 0x3f, 0xe7, 0x7c, 0xd0, 0x1b, 0x7b, 0x71, 0x3c, 0x3e, 0x8d, 0xbc, 0x98, 0x77, 0x4a, - 0x6b, 0xa5, 0xbb, 0x2d, 0xb7, 0x2d, 0x32, 0x0e, 0x34, 0xce, 0x3e, 0x84, 0x56, 0x8c, 0x45, 0x79, - 0x90, 0x44, 0xe1, 0xf8, 0xa2, 0x53, 0xa6, 0x72, 0x4d, 0xc4, 0x76, 0x04, 0xe4, 0x0c, 0x61, 0x41, - 0xb7, 0x10, 0x8f, 0xc3, 0x20, 0xe6, 0xec, 0x01, 0x2c, 0xf7, 0xfd, 0xf1, 0x29, 0x8f, 0x7a, 0xf4, - 0xf1, 0x28, 0xe0, 0xa3, 0x30, 0xf0, 0xfb, 0x9d, 0xd2, 0x5a, 0xe5, 0x6e, 0xc3, 0x65, 0x22, 0x0f, - 0xbf, 0x78, 0x2e, 0x73, 0xd8, 0x1d, 0x58, 0xe0, 0x81, 0xc0, 0xf9, 0x80, 0xbe, 0x92, 0x4d, 0xcd, - 0xa7, 0x30, 0x7e, 0xe0, 0xfc, 0xd5, 0x32, 0x2c, 0x3e, 0x0b, 0xfc, 0xe4, 0xb5, 0x37, 0x1c, 0xf2, - 0x44, 0x8d, 0xe9, 0x0e, 0x2c, 0x9c, 0x13, 0x40, 0x63, 0x3a, 0x0f, 0xa3, 0x81, 0x1c, 0xd1, 0xbc, - 0x80, 0x0f, 0x24, 0x3a, 0xb5, 0x67, 0xe5, 0xa9, 0x3d, 0x2b, 0x9c, 0xae, 0xca, 0x94, 0xe9, 0xba, - 0x03, 0x0b, 0x11, 0xef, 0x87, 0x67, 0x3c, 0xba, 0xe8, 0x9d, 0xfb, 0xc1, 0x20, 0x3c, 0xef, 0x54, - 0xd7, 0x4a, 0x77, 0x6b, 0xee, 0xbc, 0x82, 0x5f, 0x13, 0xca, 0x36, 0x61, 0xa1, 0x7f, 0xea, 0x05, - 0x01, 0x1f, 0xf6, 0x8e, 0xbc, 0xfe, 0x9b, 0xc9, 0x38, 0xee, 0xd4, 0xd6, 0x4a, 0x77, 0x9b, 0x0f, - 0xaf, 0xad, 0xd3, 0xaa, 0xae, 0x6f, 0x9d, 0x7a, 0xc1, 0x26, 0xe5, 0x1c, 0x06, 0xde, 0x38, 0x3e, - 0x0d, 0x13, 0x77, 0x5e, 0x7e, 0x21, 0xe0, 0xd8, 0x59, 0x06, 0x66, 0xce, 0x84, 0x98, 0x7b, 0xe7, - 0x1f, 0x95, 0x60, 0xe9, 0x55, 0x30, 0x0c, 0xfb, 0x6f, 0x7e, 0xc9, 0x29, 0x2a, 0x18, 0x43, 0xf9, - 0x7d, 0xc7, 0x50, 0xf9, 0xaa, 0x63, 0x58, 0x81, 0x65, 0xbb, 0xb3, 0x72, 0x14, 0x1c, 0xae, 0xe2, - 0xd7, 0x27, 0x5c, 0x75, 0x4b, 0x0d, 0xe3, 0xeb, 0xd0, 0xee, 0x4f, 0xa2, 0x88, 0x07, 0xb9, 0x71, - 0x2c, 0x48, 0x5c, 0x0f, 0xe4, 0x43, 0x68, 0x05, 0xfc, 0x3c, 0x2d, 0x26, 0x69, 0x37, 0xe0, 0xe7, - 0xaa, 0x88, 0xd3, 0x81, 0x95, 0x6c, 0x33, 0xb2, 0x03, 0xff, 0xb5, 0x04, 0xd5, 0x57, 0xc9, 0xdb, - 0x90, 0xad, 0x43, 0x35, 0xb9, 0x18, 0x0b, 0x0e, 0x99, 0x7f, 0xc8, 0xe4, 0xd0, 0x36, 0x06, 0x83, - 0x88, 0xc7, 0xf1, 0xcb, 0x8b, 0x31, 0x77, 0x5b, 0x9e, 0x48, 0xf4, 0xb0, 0x1c, 0xeb, 0xc0, 0xac, - 0x4c, 0x53, 0x83, 0x0d, 0x57, 0x25, 0xd9, 0x4d, 0x00, 0x6f, 0x14, 0x4e, 0x82, 0xa4, 0x17, 0x7b, - 0x09, 0x4d, 0x55, 0xc5, 0x35, 0x10, 0x76, 0x03, 0x1a, 0xe3, 0x37, 0xbd, 0xb8, 0x1f, 0xf9, 0xe3, - 0x84, 0xc8, 0xa6, 0xe1, 0xa6, 0x00, 0xfb, 0x06, 0xd4, 0xc3, 0x49, 0x32, 0x0e, 0xfd, 0x20, 0x91, - 0xa4, 0xb2, 0x20, 0xfb, 0xf2, 0x62, 0x92, 0x1c, 0x20, 0xec, 0xea, 0x02, 0xec, 0x36, 0xcc, 0xf5, - 0xc3, 0xe0, 0xd8, 0x8f, 0x46, 0x42, 0x18, 0x74, 0x66, 0xa8, 0x35, 0x1b, 0x74, 0xfe, 0x65, 0x19, - 0x9a, 0x2f, 0x23, 0x2f, 0x88, 0xbd, 0x3e, 0x02, 0xd8, 0xf5, 0xe4, 0x6d, 0xef, 0xd4, 0x8b, 0x4f, - 0x69, 0xb4, 0x0d, 0x57, 0x25, 0xd9, 0x0a, 0xcc, 0x88, 0x8e, 0xd2, 0x98, 0x2a, 0xae, 0x4c, 0xb1, - 0x8f, 0x61, 0x31, 0x98, 0x8c, 0x7a, 0x76, 0x5b, 0x15, 0xa2, 0x96, 0x7c, 0x06, 0x4e, 0xc0, 0x11, - 0xae, 0xb5, 0x68, 0x42, 0x8c, 0xd0, 0x40, 0x98, 0x03, 0x2d, 0x99, 0xe2, 0xfe, 0xc9, 0xa9, 0x18, - 0x66, 0xcd, 0xb5, 0x30, 0xac, 0x23, 0xf1, 0x47, 0xbc, 0x17, 0x27, 0xde, 0x68, 0x2c, 0x87, 0x65, - 0x20, 0x94, 0x1f, 0x26, 0xde, 0xb0, 0x77, 0xcc, 0x79, 0xdc, 0x99, 0x95, 0xf9, 0x1a, 0x61, 0x1f, - 0xc1, 0xfc, 0x80, 0xc7, 0x49, 0x4f, 0x2e, 0x0a, 0x8f, 0x3b, 0x75, 0x62, 0xfd, 0x0c, 0x8a, 0xf5, - 0x44, 0xde, 0x79, 0x0f, 0x27, 0x80, 0xbf, 0xed, 0x34, 0x44, 0x5f, 0x53, 0x04, 0x29, 0xe7, 0x29, - 0x4f, 0x8c, 0xd9, 0x8b, 0x25, 0x85, 0x3a, 0x7b, 0xc0, 0x0c, 0x78, 0x9b, 0x27, 0x9e, 0x3f, 0x8c, - 0xd9, 0xa7, 0xd0, 0x4a, 0x8c, 0xc2, 0x24, 0x0a, 0x9b, 0x9a, 0x9c, 0x8c, 0x0f, 0x5c, 0xab, 0x9c, - 0xf3, 0x14, 0xea, 0x4f, 0x38, 0xdf, 0xf3, 0x47, 0x7e, 0xc2, 0x56, 0xa0, 0x76, 0xec, 0xbf, 0xe5, - 0x82, 0xe0, 0x2b, 0xbb, 0x57, 0x5c, 0x91, 0x64, 0x5d, 0x98, 0x1d, 0xf3, 0xa8, 0xcf, 0xd5, 0xf2, - 0xec, 0x5e, 0x71, 0x15, 0xb0, 0x39, 0x0b, 0xb5, 0x21, 0x7e, 0xec, 0xfc, 0xaf, 0x0a, 0x34, 0x0f, - 0x79, 0xa0, 0x19, 0x89, 0x41, 0x15, 0x87, 0x2c, 0x99, 0x87, 0x7e, 0xb3, 0x5b, 0xd0, 0xa4, 0x69, - 0x88, 0x93, 0xc8, 0x0f, 0x4e, 0x24, 0xfd, 0x02, 0x42, 0x87, 0x84, 0xb0, 0x36, 0x54, 0xbc, 0x91, - 0xa2, 0x5d, 0xfc, 0x89, 0x4c, 0x36, 0xf6, 0x2e, 0x46, 0xc8, 0x8f, 0x7a, 0x55, 0x5b, 0x6e, 0x53, - 0x62, 0xbb, 0xb8, 0xac, 0xeb, 0xb0, 0x64, 0x16, 0x51, 0xb5, 0xd7, 0xa8, 0xf6, 0x45, 0xa3, 0xa4, - 0x6c, 0xe4, 0x0e, 0x2c, 0xa8, 0xf2, 0x91, 0xe8, 0x2c, 0xad, 0x73, 0xc3, 0x9d, 0x97, 0xb0, 0x1a, - 0xc2, 0x5d, 0x68, 0x1f, 0xfb, 0x81, 0x37, 0xec, 0xf5, 0x87, 0xc9, 0x59, 0x6f, 0xc0, 0x87, 0x89, - 0x47, 0x2b, 0x5e, 0x73, 0xe7, 0x09, 0xdf, 0x1a, 0x26, 0x67, 0xdb, 0x88, 0xb2, 0x8f, 0xa1, 0x71, - 0xcc, 0x79, 0x8f, 0x66, 0xa2, 0x53, 0xb7, 0xb8, 0x47, 0xcd, 0xae, 0x5b, 0x3f, 0x56, 0xf3, 0xfc, - 0x31, 0xb4, 0xc3, 0x49, 0x72, 0x12, 0xfa, 0xc1, 0x49, 0x0f, 0xe5, 0x55, 0xcf, 0x1f, 0x10, 0x05, - 0x54, 0x37, 0xcb, 0x0f, 0x4a, 0xee, 0xbc, 0xca, 0x43, 0xc9, 0xf1, 0x6c, 0xc0, 0x3e, 0x00, 0xa0, - 0xf6, 0x45, 0xe5, 0xb0, 0x56, 0xba, 0x3b, 0xe7, 0x36, 0x10, 0x11, 0x95, 0x7d, 0x06, 0x75, 0x9a, - 0xd3, 0x64, 0x78, 0xd6, 0x69, 0xd2, 0xa2, 0xdf, 0x92, 0x2d, 0x1b, 0xab, 0xb1, 0xbe, 0xcd, 0xe3, - 0xe4, 0xe5, 0xf0, 0x0c, 0xf7, 0xd4, 0x0b, 0x77, 0x76, 0x20, 0x52, 0xdd, 0xcf, 0xa0, 0x65, 0x66, - 0xe0, 0xf4, 0xbf, 0xe1, 0x17, 0xb4, 0x64, 0x55, 0x17, 0x7f, 0xb2, 0x65, 0xa8, 0x9d, 0x79, 0xc3, - 0x09, 0x97, 0xc2, 0x4d, 0x24, 0x3e, 0x2b, 0x3f, 0x2a, 0x39, 0xff, 0xa2, 0x04, 0x2d, 0xd1, 0x82, - 0xdc, 0x94, 0x6f, 0xc3, 0x9c, 0x9a, 0x56, 0x1e, 0x45, 0x61, 0x24, 0x79, 0xdc, 0x06, 0xd9, 0x3d, - 0x68, 0x2b, 0x60, 0x1c, 0x71, 0x7f, 0xe4, 0x9d, 0xa8, 0xba, 0x73, 0x38, 0x7b, 0x98, 0xd6, 0x18, - 0x85, 0x93, 0x84, 0x4b, 0xf1, 0xdf, 0x92, 0xe3, 0x73, 0x11, 0x73, 0xed, 0x22, 0xc8, 0xe3, 0x05, - 0xf4, 0x62, 0x61, 0xce, 0x97, 0x25, 0x60, 0xd8, 0xf5, 0x97, 0xa1, 0xa8, 0x42, 0x2e, 0x77, 0x96, - 0xd4, 0x4a, 0xef, 0x4d, 0x6a, 0xe5, 0x69, 0xa4, 0xe6, 0x40, 0x4d, 0xf4, 0xbc, 0x5a, 0xd0, 0x73, - 0x91, 0xf5, 0xdd, 0x6a, 0xbd, 0xd2, 0xae, 0x3a, 0xff, 0xb9, 0x02, 0xcb, 0x5b, 0x62, 0xef, 0xda, - 0xe8, 0xf7, 0xf9, 0x58, 0x13, 0xe1, 0x2d, 0x68, 0x06, 0xe1, 0x80, 0xf7, 0xc6, 0x93, 0x23, 0xb5, - 0x36, 0x2d, 0x17, 0x10, 0x3a, 0x20, 0x84, 0xe8, 0xe3, 0xd4, 0xf3, 0x03, 0xd1, 0x69, 0x31, 0x97, - 0x0d, 0x42, 0xa8, 0xcb, 0x1f, 0xc1, 0xc2, 0x98, 0x07, 0x03, 0x93, 0xd6, 0x84, 0x76, 0x31, 0x27, - 0x61, 0x49, 0x66, 0xb7, 0xa0, 0x79, 0x3c, 0x11, 0xe5, 0x90, 0x05, 0xab, 0x44, 0x03, 0x20, 0xa1, - 0x8d, 0x51, 0xc2, 0xae, 0x41, 0x7d, 0x3c, 0x89, 0x4f, 0x29, 0xb7, 0x46, 0xb9, 0xb3, 0x98, 0xc6, - 0xac, 0x0f, 0x00, 0x06, 0x93, 0x38, 0x91, 0x24, 0x3a, 0x43, 0x99, 0x0d, 0x44, 0x04, 0x89, 0x7e, - 0x13, 0x96, 0x46, 0xde, 0xdb, 0x1e, 0xd1, 0x4e, 0xcf, 0x0f, 0x7a, 0xc7, 0x43, 0x12, 0xbf, 0xb3, - 0x54, 0xae, 0x3d, 0xf2, 0xde, 0xfe, 0x00, 0x73, 0x9e, 0x05, 0x4f, 0x08, 0x47, 0xfe, 0x54, 0xfb, - 0x7e, 0xc4, 0x63, 0x1e, 0x9d, 0x71, 0x62, 0xa9, 0xaa, 0xde, 0xdc, 0x5d, 0x81, 0x62, 0x8f, 0x46, - 0x38, 0xee, 0x64, 0xd8, 0x17, 0xfc, 0xe3, 0xce, 0x8e, 0xfc, 0x60, 0x37, 0x19, 0xf6, 0xd9, 0x0d, - 0x00, 0x64, 0xc8, 0x31, 0x8f, 0x7a, 0x6f, 0xce, 0x89, 0x69, 0xaa, 0xc4, 0x80, 0x07, 0x3c, 0xfa, - 0xde, 0x39, 0xbb, 0x0e, 0x8d, 0x7e, 0x4c, 0x1c, 0xed, 0x5d, 0x74, 0x9a, 0xc4, 0x51, 0xf5, 0x7e, - 0x8c, 0xbc, 0xec, 0x5d, 0xb0, 0x8f, 0x81, 0x61, 0x6f, 0x3d, 0x5a, 0x05, 0x3e, 0xa0, 0xea, 0xe3, - 0x4e, 0x8b, 0x4a, 0x61, 0x67, 0x37, 0x64, 0x06, 0xb6, 0x13, 0xb3, 0xaf, 0xc1, 0x9c, 0xea, 0xec, - 0xf1, 0xd0, 0x3b, 0x89, 0x3b, 0x73, 0x54, 0xb0, 0x25, 0xc1, 0x27, 0x88, 0x39, 0xaf, 0x85, 0xb6, - 0x61, 0xac, 0xad, 0xe4, 0x19, 0xdc, 0xf7, 0x08, 0xa1, 0x75, 0xad, 0xbb, 0x32, 0x55, 0xb4, 0x68, - 0xe5, 0x82, 0x45, 0x73, 0x7e, 0x51, 0x82, 0x96, 0xac, 0x99, 0xb6, 0x68, 0xf6, 0x00, 0x98, 0x5a, - 0xc5, 0xe4, 0xad, 0x3f, 0xe8, 0x1d, 0x5d, 0x24, 0x3c, 0x16, 0x44, 0xb3, 0x7b, 0xc5, 0x2d, 0xc8, - 0x43, 0x61, 0x64, 0xa1, 0x71, 0x12, 0x09, 0x7a, 0xde, 0xbd, 0xe2, 0xe6, 0x72, 0x90, 0xbd, 0x50, - 0x09, 0x98, 0x24, 0x3d, 0x3f, 0x18, 0xf0, 0xb7, 0x44, 0x4a, 0x73, 0xae, 0x85, 0x6d, 0xce, 0x43, - 0xcb, 0xfc, 0xce, 0xf9, 0x29, 0xd4, 0x95, 0x0a, 0x41, 0xdb, 0x67, 0xa6, 0x5f, 0xae, 0x81, 0xb0, - 0x2e, 0xd4, 0xed, 0x5e, 0xb8, 0xf5, 0xaf, 0xd2, 0xb6, 0xf3, 0x67, 0xa0, 0xbd, 0x87, 0x44, 0x14, - 0x20, 0xd1, 0x4a, 0xbd, 0x68, 0x05, 0x66, 0x0c, 0xe6, 0x69, 0xb8, 0x32, 0x85, 0x3b, 0xd4, 0x69, - 0x18, 0x27, 0xb2, 0x1d, 0xfa, 0xed, 0xfc, 0xdb, 0x12, 0xb0, 0x9d, 0x38, 0xf1, 0x47, 0x5e, 0xc2, - 0x9f, 0x70, 0x2d, 0x1a, 0x5e, 0x40, 0x0b, 0x6b, 0x7b, 0x19, 0x6e, 0x08, 0x2d, 0x45, 0xec, 0xae, - 0xdf, 0x90, 0xec, 0x9c, 0xff, 0x60, 0xdd, 0x2c, 0x2d, 0x84, 0xae, 0x55, 0x01, 0x72, 0x5b, 0xe2, - 0x45, 0x27, 0x3c, 0x21, 0x15, 0x46, 0x2a, 0xc0, 0x20, 0xa0, 0xad, 0x30, 0x38, 0xee, 0xfe, 0x36, - 0x2c, 0xe6, 0xea, 0x30, 0xe5, 0x73, 0xa3, 0x40, 0x3e, 0x57, 0x4c, 0xf9, 0xdc, 0x87, 0x25, 0xab, - 0x5f, 0x92, 0xe2, 0x3a, 0x30, 0x8b, 0x8c, 0x81, 0x1a, 0x22, 0xed, 0xf2, 0xae, 0x4a, 0xb2, 0x87, - 0xb0, 0x7c, 0xcc, 0x79, 0xe4, 0x25, 0x94, 0x24, 0xd6, 0xc1, 0x35, 0x91, 0x35, 0x17, 0xe6, 0x39, - 0xff, 0xad, 0x04, 0x0b, 0x28, 0x49, 0x9f, 0x7b, 0xc1, 0x85, 0x9a, 0xab, 0xbd, 0xc2, 0xb9, 0xba, - 0x6b, 0x6c, 0x4a, 0x46, 0xe9, 0xaf, 0x3a, 0x51, 0x95, 0xec, 0x44, 0xb1, 0x35, 0x68, 0x59, 0xdd, - 0xad, 0x09, 0x95, 0x2c, 0xf6, 0x92, 0x03, 0x1e, 0x6d, 0x5e, 0x24, 0xfc, 0x57, 0x9f, 0xca, 0x8f, - 0xa0, 0x9d, 0x76, 0x5b, 0xce, 0x23, 0x83, 0x2a, 0x12, 0xa6, 0xac, 0x80, 0x7e, 0x3b, 0x7f, 0xb7, - 0x24, 0x0a, 0x6e, 0x85, 0xbe, 0x56, 0xd7, 0xb0, 0x20, 0x6a, 0x7d, 0xaa, 0x20, 0xfe, 0x9e, 0xaa, - 0xee, 0xfe, 0xea, 0x83, 0x45, 0x99, 0x18, 0xf3, 0x60, 0xd0, 0xf3, 0x86, 0x43, 0x12, 0xc4, 0x75, - 0x77, 0x16, 0xd3, 0x1b, 0xc3, 0xa1, 0x73, 0x07, 0x16, 0x8d, 0xde, 0xbd, 0x63, 0x1c, 0xfb, 0xc0, - 0xf6, 0xfc, 0x38, 0x79, 0x15, 0xc4, 0x63, 0x43, 0x1b, 0xba, 0x0e, 0x0d, 0x94, 0xb6, 0xd8, 0x33, - 0xc1, 0xb9, 0x35, 0x17, 0xc5, 0x2f, 0xf6, 0x2b, 0xa6, 0x4c, 0xef, 0xad, 0xcc, 0x2c, 0xcb, 0x4c, - 0xef, 0x2d, 0x65, 0x3a, 0x8f, 0x60, 0xc9, 0xaa, 0x4f, 0x36, 0xfd, 0x21, 0xd4, 0x26, 0xc9, 0xdb, - 0x50, 0xe9, 0xaa, 0x4d, 0x49, 0x21, 0x68, 0x15, 0xb9, 0x22, 0xc7, 0x79, 0x0c, 0x8b, 0xfb, 0xfc, - 0x5c, 0x32, 0xb2, 0xea, 0xc8, 0x47, 0x97, 0x5a, 0x4c, 0x94, 0xef, 0xac, 0x03, 0x33, 0x3f, 0x4e, - 0x19, 0x40, 0xd9, 0x4f, 0x25, 0xcb, 0x7e, 0x72, 0x3e, 0x02, 0x76, 0xe8, 0x9f, 0x04, 0xcf, 0x79, - 0x1c, 0x7b, 0x27, 0x9a, 0xf5, 0xdb, 0x50, 0x19, 0xc5, 0x27, 0x52, 0x54, 0xe1, 0x4f, 0xe7, 0x5b, - 0xb0, 0x64, 0x95, 0x93, 0x15, 0xdf, 0x80, 0x46, 0xec, 0x9f, 0x04, 0x5e, 0x32, 0x89, 0xb8, 0xac, - 0x3a, 0x05, 0x9c, 0x27, 0xb0, 0xfc, 0x03, 0x1e, 0xf9, 0xc7, 0x17, 0x97, 0x55, 0x6f, 0xd7, 0x53, - 0xce, 0xd6, 0xb3, 0x03, 0x57, 0x33, 0xf5, 0xc8, 0xe6, 0x05, 0xf9, 0xca, 0x95, 0xac, 0xbb, 0x22, - 0x61, 0xc8, 0xbe, 0xb2, 0x29, 0xfb, 0x9c, 0x57, 0xc0, 0xb6, 0xc2, 0x20, 0xe0, 0xfd, 0xe4, 0x80, - 0xf3, 0x28, 0x75, 0xdd, 0xa4, 0xb4, 0xda, 0x7c, 0xb8, 0x2a, 0x67, 0x36, 0x2b, 0x50, 0x25, 0x11, - 0x33, 0xa8, 0x8e, 0x79, 0x34, 0xa2, 0x8a, 0xeb, 0x2e, 0xfd, 0x76, 0xae, 0xc2, 0x92, 0x55, 0xad, - 0x34, 0x76, 0x3f, 0x81, 0xab, 0xdb, 0x7e, 0xdc, 0xcf, 0x37, 0xd8, 0x81, 0xd9, 0xf1, 0xe4, 0xa8, - 0x97, 0x72, 0xa2, 0x4a, 0xa2, 0xfd, 0x93, 0xfd, 0x44, 0x56, 0xf6, 0x57, 0x4a, 0x50, 0xdd, 0x7d, - 0xb9, 0xb7, 0x85, 0x7b, 0x85, 0x1f, 0xf4, 0xc3, 0x11, 0x6a, 0x60, 0x62, 0xd0, 0x3a, 0x3d, 0x95, - 0xc3, 0x6e, 0x40, 0x83, 0x14, 0x37, 0x34, 0xf9, 0xa4, 0x1e, 0x94, 0x02, 0x68, 0x6e, 0xf2, 0xb7, - 0x63, 0x3f, 0x22, 0x7b, 0x52, 0x59, 0x89, 0x55, 0xda, 0x66, 0xf2, 0x19, 0xce, 0x2f, 0x66, 0x61, - 0x56, 0x6e, 0xbe, 0x62, 0x23, 0x4f, 0xfc, 0x33, 0x9e, 0x6e, 0xe4, 0x98, 0x42, 0xa5, 0x38, 0xe2, - 0xa3, 0x30, 0xd1, 0xfa, 0x9b, 0x58, 0x06, 0x1b, 0x24, 0x73, 0x5a, 0x2a, 0x11, 0xc2, 0x00, 0xaf, - 0x88, 0x52, 0x16, 0xc8, 0x6e, 0xc0, 0xac, 0x52, 0x06, 0xaa, 0xda, 0x5a, 0x50, 0x10, 0xce, 0x46, - 0xdf, 0x1b, 0x7b, 0x7d, 0x3f, 0xb9, 0x90, 0x62, 0x41, 0xa7, 0xb1, 0xfe, 0x61, 0xd8, 0xf7, 0x86, - 0xbd, 0x23, 0x6f, 0xe8, 0x05, 0x7d, 0xae, 0xcc, 0x75, 0x0b, 0x44, 0xd3, 0x55, 0x76, 0x4b, 0x15, - 0x13, 0xe6, 0x6d, 0x06, 0xc5, 0x3d, 0xbc, 0x1f, 0x8e, 0x46, 0x7e, 0x82, 0x16, 0x2f, 0xa9, 0x66, - 0x15, 0xd7, 0x40, 0x84, 0x73, 0x80, 0x52, 0xe7, 0x62, 0x06, 0x1b, 0xca, 0x39, 0x60, 0x80, 0x58, - 0x4b, 0x46, 0x43, 0xab, 0xb8, 0x06, 0x82, 0x6b, 0x31, 0x09, 0x62, 0x9e, 0x24, 0x43, 0x3e, 0xd0, - 0x1d, 0x6a, 0x52, 0xb1, 0x7c, 0x06, 0x7b, 0x00, 0x4b, 0xc2, 0x08, 0x8f, 0xbd, 0x24, 0x8c, 0x4f, - 0xfd, 0xb8, 0x17, 0xa3, 0xb9, 0xda, 0xa2, 0xf2, 0x45, 0x59, 0xec, 0x11, 0xac, 0x66, 0xe0, 0x88, - 0xf7, 0xb9, 0x7f, 0xc6, 0x07, 0xa4, 0xc2, 0x55, 0xdc, 0x69, 0xd9, 0x6c, 0x0d, 0x9a, 0xc1, 0x64, - 0xd4, 0x9b, 0x8c, 0x07, 0x1e, 0x2a, 0x31, 0xf3, 0xa4, 0x5c, 0x9a, 0x10, 0xfb, 0x04, 0x94, 0x9e, - 0x26, 0xb5, 0xc7, 0x05, 0x4b, 0xc2, 0x21, 0xf5, 0xba, 0x76, 0x09, 0x24, 0xcc, 0x54, 0x25, 0x6d, - 0x4b, 0x23, 0x4f, 0x01, 0xc4, 0x27, 0x91, 0x7f, 0xe6, 0x25, 0xbc, 0xb3, 0x28, 0x84, 0xba, 0x4c, - 0xe2, 0x77, 0x7e, 0xe0, 0x27, 0xbe, 0x97, 0x84, 0x51, 0x87, 0x51, 0x5e, 0x0a, 0xe0, 0x24, 0x12, - 0x7d, 0xc4, 0x89, 0x97, 0x4c, 0x62, 0xa9, 0xa1, 0x2e, 0x09, 0x6b, 0x25, 0x97, 0xc1, 0x3e, 0x85, - 0x15, 0x41, 0x11, 0x94, 0x25, 0x75, 0x6f, 0x52, 0x15, 0x96, 0x69, 0x46, 0xa6, 0xe4, 0xe2, 0x54, - 0x4a, 0x12, 0xc9, 0x7d, 0x78, 0x55, 0x4c, 0xe5, 0x94, 0x6c, 0xec, 0x1f, 0xf6, 0xc0, 0xef, 0xf7, - 0x64, 0x09, 0x64, 0x91, 0x15, 0x1a, 0x45, 0x3e, 0x03, 0x49, 0x7c, 0xe8, 0x1f, 0xf3, 0xc4, 0x1f, - 0xf1, 0xce, 0xaa, 0x20, 0x71, 0x95, 0x46, 0x06, 0x9c, 0x8c, 0x29, 0xa7, 0x23, 0x18, 0x5e, 0xa4, - 0x9c, 0xdf, 0x2b, 0x89, 0xcd, 0x47, 0x32, 0x6a, 0x6c, 0x98, 0x55, 0x82, 0x45, 0x7b, 0x61, 0x30, - 0xbc, 0x90, 0x5c, 0x0b, 0x02, 0x7a, 0x11, 0x0c, 0x2f, 0x50, 0xb1, 0xf7, 0x03, 0xb3, 0x88, 0x90, - 0x73, 0x2d, 0x05, 0x52, 0xa1, 0x5b, 0xd0, 0x1c, 0x4f, 0x8e, 0x86, 0x7e, 0x5f, 0x14, 0xa9, 0x88, - 0x5a, 0x04, 0x44, 0x05, 0xd0, 0xa6, 0x14, 0x2b, 0x25, 0x4a, 0x54, 0xa9, 0x44, 0x53, 0x62, 0x58, - 0xc4, 0xd9, 0x84, 0x65, 0xbb, 0x83, 0x52, 0xa0, 0xdf, 0x83, 0xba, 0xe4, 0xff, 0x58, 0x1a, 0xf6, - 0xf3, 0x86, 0xdf, 0x13, 0xcd, 0x20, 0x9d, 0xef, 0xfc, 0xab, 0x2a, 0x2c, 0x49, 0x74, 0x6b, 0x18, - 0xc6, 0xfc, 0x70, 0x32, 0x1a, 0x79, 0x51, 0x81, 0x60, 0x29, 0x5d, 0x22, 0x58, 0xca, 0x79, 0xc1, - 0x72, 0xd3, 0xb2, 0x2f, 0x85, 0x64, 0x32, 0x10, 0x76, 0x17, 0x16, 0xfa, 0xc3, 0x30, 0x16, 0xea, - 0xbe, 0xe9, 0x7a, 0xcb, 0xc2, 0x79, 0x61, 0x58, 0x2b, 0x12, 0x86, 0xa6, 0x20, 0x9b, 0xc9, 0x08, - 0x32, 0x07, 0x5a, 0x58, 0x29, 0x57, 0xb2, 0x79, 0x56, 0x1a, 0x5b, 0x06, 0x86, 0xfd, 0xc9, 0x8a, - 0x0d, 0x21, 0xa3, 0x16, 0x8a, 0x84, 0x86, 0x3f, 0xe2, 0x24, 0xfb, 0x8d, 0xd2, 0x0d, 0x29, 0x34, - 0xf2, 0x59, 0xec, 0x09, 0x80, 0x68, 0x8b, 0x14, 0x10, 0x20, 0x05, 0xe4, 0x23, 0x7b, 0x55, 0xcc, - 0xf9, 0x5f, 0xc7, 0xc4, 0x24, 0xe2, 0xa4, 0x94, 0x18, 0x5f, 0x3a, 0x7f, 0xad, 0x04, 0x4d, 0x23, - 0x8f, 0x5d, 0x85, 0xc5, 0xad, 0x17, 0x2f, 0x0e, 0x76, 0xdc, 0x8d, 0x97, 0xcf, 0x7e, 0xb0, 0xd3, - 0xdb, 0xda, 0x7b, 0x71, 0xb8, 0xd3, 0xbe, 0x82, 0xf0, 0xde, 0x8b, 0xad, 0x8d, 0xbd, 0xde, 0x93, - 0x17, 0xee, 0x96, 0x82, 0x4b, 0x6c, 0x05, 0x98, 0xbb, 0xf3, 0xfc, 0xc5, 0xcb, 0x1d, 0x0b, 0x2f, - 0xb3, 0x36, 0xb4, 0x36, 0xdd, 0x9d, 0x8d, 0xad, 0x5d, 0x89, 0x54, 0xd8, 0x32, 0xb4, 0x9f, 0xbc, - 0xda, 0xdf, 0x7e, 0xb6, 0xff, 0xb4, 0xb7, 0xb5, 0xb1, 0xbf, 0xb5, 0xb3, 0xb7, 0xb3, 0xdd, 0xae, - 0xb2, 0x39, 0x68, 0x6c, 0x6c, 0x6e, 0xec, 0x6f, 0xbf, 0xd8, 0xdf, 0xd9, 0x6e, 0xd7, 0x9c, 0xff, - 0x52, 0x82, 0xab, 0xd4, 0xeb, 0x41, 0x96, 0x49, 0xd6, 0xa0, 0xd9, 0x0f, 0xc3, 0x31, 0x2a, 0xfe, - 0xe9, 0xd6, 0x66, 0x42, 0xc8, 0x00, 0x42, 0x28, 0x1c, 0x87, 0x51, 0x9f, 0x4b, 0x1e, 0x01, 0x82, - 0x9e, 0x20, 0x82, 0x0c, 0x20, 0x97, 0x57, 0x94, 0x10, 0x2c, 0xd2, 0x14, 0x98, 0x28, 0xb2, 0x02, - 0x33, 0x47, 0x11, 0xf7, 0xfa, 0xa7, 0x92, 0x3b, 0x64, 0x8a, 0x7d, 0x3d, 0xb5, 0x4c, 0xfb, 0x38, - 0xfb, 0x43, 0x3e, 0x20, 0x8a, 0xa9, 0xbb, 0x0b, 0x12, 0xdf, 0x92, 0x30, 0x4a, 0x41, 0xef, 0xc8, - 0x0b, 0x06, 0x61, 0xc0, 0x07, 0x52, 0xed, 0x4d, 0x01, 0xe7, 0x00, 0x56, 0xb2, 0xe3, 0x93, 0x3c, - 0xf6, 0xa9, 0xc1, 0x63, 0x42, 0x0b, 0xed, 0x4e, 0x5f, 0x4d, 0x83, 0xdf, 0xfe, 0xb8, 0x0c, 0x55, - 0x54, 0x4a, 0xa6, 0x2b, 0x30, 0xa6, 0x9e, 0x59, 0xc9, 0xf9, 0xe9, 0xc9, 0xd8, 0x15, 0x5b, 0x94, - 0x74, 0xb4, 0xa4, 0x48, 0x9a, 0x1f, 0xf1, 0xfe, 0x99, 0x74, 0xb5, 0x18, 0x08, 0x32, 0x08, 0x1a, - 0x01, 0xf4, 0xb5, 0x64, 0x10, 0x95, 0x56, 0x79, 0xf4, 0xe5, 0x6c, 0x9a, 0x47, 0xdf, 0x75, 0x60, - 0xd6, 0x0f, 0x8e, 0xc2, 0x49, 0x30, 0x20, 0x86, 0xa8, 0xbb, 0x2a, 0x49, 0x27, 0x03, 0xc4, 0xa8, - 0x28, 0x3f, 0x05, 0xf9, 0xa7, 0x00, 0x7b, 0x08, 0x8d, 0xf8, 0x22, 0xe8, 0x9b, 0x34, 0xbf, 0x2c, - 0x67, 0x09, 0xe7, 0x60, 0xfd, 0xf0, 0x22, 0xe8, 0x13, 0x85, 0xa7, 0xc5, 0x9c, 0xdf, 0x86, 0xba, - 0x82, 0x91, 0x2c, 0x5f, 0xed, 0x7f, 0x6f, 0xff, 0xc5, 0xeb, 0xfd, 0xde, 0xe1, 0x0f, 0xf7, 0xb7, - 0xda, 0x57, 0xd8, 0x02, 0x34, 0x37, 0xb6, 0x88, 0xd2, 0x09, 0x28, 0x61, 0x91, 0x83, 0x8d, 0xc3, - 0x43, 0x8d, 0x94, 0x1d, 0x86, 0x86, 0x7c, 0x4c, 0x9a, 0x9f, 0xf6, 0x7c, 0x7f, 0x0a, 0x8b, 0x06, - 0x96, 0x5a, 0x11, 0x63, 0x04, 0x32, 0x56, 0x04, 0xa9, 0x8c, 0x22, 0xc7, 0x69, 0xc3, 0xfc, 0x53, - 0x9e, 0x3c, 0x0b, 0x8e, 0x43, 0x55, 0xd3, 0xff, 0xa8, 0xc2, 0x82, 0x86, 0x64, 0x45, 0x77, 0x61, - 0xc1, 0x1f, 0xf0, 0x20, 0xf1, 0x93, 0x8b, 0x9e, 0xe5, 0x2f, 0xc8, 0xc2, 0xa8, 0x6a, 0x7b, 0x43, - 0xdf, 0x53, 0x07, 0x30, 0x22, 0x81, 0xf6, 0x33, 0xea, 0x00, 0xa6, 0xdf, 0x86, 0xe8, 0x4a, 0xb8, - 0x29, 0x0a, 0xf3, 0x50, 0x02, 0x21, 0x2e, 0xb7, 0x19, 0xfd, 0x89, 0x50, 0x39, 0x8b, 0xb2, 0x70, - 0xa9, 0x44, 0x4d, 0x38, 0xe4, 0x9a, 0xd0, 0x13, 0x34, 0x90, 0x3b, 0xe1, 0x98, 0x11, 0xf2, 0x31, - 0x7b, 0xc2, 0x61, 0x9c, 0x92, 0xd4, 0x73, 0xa7, 0x24, 0x28, 0x3f, 0x2f, 0x82, 0x3e, 0x1f, 0xf4, - 0x92, 0xb0, 0x47, 0x72, 0x9e, 0x48, 0xa2, 0xee, 0x66, 0x61, 0xdc, 0x37, 0x12, 0x1e, 0x27, 0x01, - 0x17, 0x6e, 0xe9, 0xfa, 0x66, 0xb9, 0x53, 0x72, 0x15, 0x84, 0xf6, 0xc1, 0x24, 0xf2, 0xe3, 0x4e, - 0x8b, 0xce, 0x3f, 0xe8, 0x37, 0xfb, 0x36, 0x5c, 0x3d, 0xe2, 0x71, 0xd2, 0x3b, 0xe5, 0xde, 0x80, - 0x47, 0x44, 0x5e, 0xe2, 0xa0, 0x45, 0xa8, 0x5c, 0xc5, 0x99, 0x48, 0xb8, 0x67, 0x3c, 0x8a, 0xfd, - 0x30, 0x20, 0x65, 0xab, 0xe1, 0xaa, 0x24, 0xd6, 0x87, 0x83, 0xd7, 0x1b, 0xb5, 0x9e, 0xc1, 0x05, - 0x1a, 0x78, 0x71, 0x26, 0xbb, 0x0d, 0x33, 0x34, 0x80, 0xb8, 0xd3, 0x26, 0x9a, 0x69, 0xa5, 0x3c, - 0xef, 0x07, 0xae, 0xcc, 0xc3, 0x55, 0xee, 0x87, 0xc3, 0x30, 0x22, 0x8d, 0xab, 0xe1, 0x8a, 0x84, - 0x3d, 0x3b, 0x27, 0x91, 0x37, 0x3e, 0x95, 0x5a, 0x57, 0x16, 0xfe, 0x6e, 0xb5, 0xde, 0x6c, 0xb7, - 0x9c, 0x3f, 0x05, 0x35, 0xaa, 0x96, 0xaa, 0xa3, 0xc9, 0x2c, 0xc9, 0xea, 0x08, 0xed, 0xc0, 0x6c, - 0xc0, 0x93, 0xf3, 0x30, 0x7a, 0xa3, 0x4e, 0xf3, 0x64, 0xd2, 0xf9, 0x39, 0x59, 0x68, 0xfa, 0x74, - 0xeb, 0x15, 0xa9, 0x96, 0x68, 0x67, 0x8b, 0xa5, 0x8a, 0x4f, 0x3d, 0x69, 0x34, 0xd6, 0x09, 0x38, - 0x3c, 0xf5, 0x50, 0xd6, 0x5a, 0xab, 0x2f, 0xec, 0xf0, 0x26, 0x61, 0xbb, 0x62, 0xf1, 0x6f, 0xc3, - 0xbc, 0x3a, 0x37, 0x8b, 0x7b, 0x43, 0x7e, 0x9c, 0x28, 0x2f, 0x5a, 0x30, 0x19, 0x91, 0xb1, 0xbe, - 0xc7, 0x8f, 0x13, 0x67, 0x1f, 0x16, 0xa5, 0xfc, 0x7b, 0x31, 0xe6, 0xaa, 0xe9, 0xdf, 0x2c, 0xd2, - 0x25, 0x9a, 0x0f, 0x97, 0x6c, 0x81, 0x29, 0x4e, 0x0a, 0xed, 0x92, 0x8e, 0x0b, 0xcc, 0x94, 0xa7, - 0xb2, 0x42, 0xb9, 0x99, 0x2b, 0x3f, 0xa1, 0x1c, 0x8e, 0x85, 0xe1, 0xfc, 0xc4, 0x93, 0x7e, 0x5f, - 0x9d, 0x76, 0xd6, 0x5d, 0x95, 0x74, 0xfe, 0xa0, 0x04, 0x4b, 0x54, 0x9b, 0xd2, 0x86, 0xe4, 0x9e, - 0xf5, 0xe8, 0x2b, 0x74, 0x53, 0x79, 0x69, 0x85, 0x6f, 0x72, 0x19, 0x6a, 0xe6, 0x2e, 0x26, 0x12, - 0x5f, 0xdd, 0x27, 0x53, 0xcd, 0xfa, 0x64, 0x9c, 0xbf, 0x55, 0x82, 0x45, 0xb1, 0x91, 0x90, 0xb6, - 0x2d, 0x87, 0xff, 0xa7, 0x61, 0x4e, 0x68, 0x04, 0x52, 0x2a, 0xc8, 0x8e, 0xa6, 0xa2, 0x95, 0x50, - 0x51, 0x78, 0xf7, 0x8a, 0x6b, 0x17, 0x66, 0x8f, 0x49, 0x2b, 0x0b, 0x7a, 0x84, 0x16, 0x9c, 0x8b, - 0xdb, 0x73, 0xbd, 0x7b, 0xc5, 0x35, 0x8a, 0x6f, 0xd6, 0x51, 0x59, 0x46, 0xdc, 0x79, 0x0a, 0x73, - 0x56, 0x43, 0x96, 0x3f, 0xa8, 0x25, 0xfc, 0x41, 0x39, 0xc7, 0x6b, 0xb9, 0xc0, 0xf1, 0xfa, 0xcf, - 0x2a, 0xc0, 0x90, 0x58, 0x32, 0xab, 0xb1, 0x66, 0x9f, 0x5e, 0xa8, 0x23, 0xf2, 0x14, 0x62, 0xeb, - 0xc0, 0x8c, 0xa4, 0x3a, 0x51, 0x11, 0x5b, 0x66, 0x41, 0x0e, 0x8a, 0x59, 0xa9, 0x71, 0xe8, 0xd3, - 0x0a, 0xb2, 0xf3, 0xc5, 0xb4, 0x17, 0xe6, 0xe1, 0xae, 0x48, 0x47, 0x17, 0x68, 0x91, 0x48, 0xdb, - 0x58, 0xa5, 0xb3, 0xeb, 0x3b, 0x73, 0xe9, 0xfa, 0xce, 0xe6, 0x7c, 0x6e, 0x86, 0x75, 0x56, 0xb7, - 0xad, 0xb3, 0xdb, 0x30, 0xa7, 0x4e, 0x28, 0x7a, 0x23, 0x6c, 0x5d, 0x9a, 0xc2, 0x16, 0xc8, 0xee, - 0x41, 0x5b, 0x19, 0x48, 0xda, 0x04, 0x14, 0xe7, 0x7c, 0x39, 0x1c, 0xe5, 0x7f, 0xea, 0x85, 0x6b, - 0x52, 0x67, 0x53, 0x80, 0xec, 0x29, 0xa4, 0x90, 0xde, 0x24, 0x90, 0x47, 0xe3, 0x7c, 0x40, 0x46, - 0x30, 0xda, 0x53, 0xd9, 0x0c, 0xe7, 0x6f, 0x94, 0xa0, 0x8d, 0x6b, 0x66, 0x91, 0xe5, 0x67, 0x40, - 0x5c, 0xf1, 0x9e, 0x54, 0x69, 0x95, 0x65, 0x8f, 0xa0, 0x41, 0xe9, 0x70, 0xcc, 0x03, 0x49, 0x93, - 0x1d, 0x9b, 0x26, 0x53, 0x79, 0xb2, 0x7b, 0xc5, 0x4d, 0x0b, 0x1b, 0x14, 0xf9, 0x1f, 0x4a, 0xd0, - 0x94, 0xad, 0xfc, 0xd2, 0x5e, 0x9e, 0xae, 0x11, 0xcb, 0x20, 0x28, 0x29, 0x0d, 0x5d, 0xb8, 0x0b, - 0x0b, 0x23, 0x2f, 0x99, 0x44, 0xb8, 0x9f, 0x5b, 0x1e, 0x9e, 0x2c, 0x8c, 0x9b, 0x33, 0x89, 0xce, - 0xb8, 0x97, 0xf8, 0xc3, 0x9e, 0xca, 0x95, 0x51, 0x03, 0x45, 0x59, 0x28, 0x41, 0xe2, 0xc4, 0x3b, - 0xe1, 0x72, 0xdf, 0x15, 0x09, 0xa7, 0x03, 0x2b, 0x07, 0xe9, 0xa9, 0x8d, 0xa1, 0x5f, 0x3b, 0xff, - 0x64, 0x0e, 0x56, 0x73, 0x59, 0x3a, 0xc6, 0x49, 0xba, 0x2d, 0x86, 0xfe, 0xe8, 0x28, 0xd4, 0xc6, - 0x49, 0xc9, 0xf4, 0x68, 0x58, 0x59, 0xec, 0x04, 0xae, 0x2a, 0x05, 0x03, 0xe7, 0x34, 0xdd, 0x0c, - 0xcb, 0xb4, 0xcb, 0x7d, 0x62, 0x2f, 0x61, 0xb6, 0x41, 0x85, 0x9b, 0x4c, 0x5c, 0x5c, 0x1f, 0x3b, - 0x85, 0x8e, 0xd6, 0x64, 0xa4, 0xb0, 0x36, 0xb4, 0x1d, 0x6c, 0xeb, 0xe3, 0x4b, 0xda, 0xb2, 0xd4, - 0x71, 0x77, 0x6a, 0x6d, 0xec, 0x02, 0x6e, 0xaa, 0x3c, 0x92, 0xc6, 0xf9, 0xf6, 0xaa, 0xef, 0x35, - 0x36, 0x32, 0x34, 0xec, 0x46, 0x2f, 0xa9, 0x98, 0xfd, 0x14, 0x56, 0xce, 0x3d, 0x3f, 0x51, 0xdd, - 0x32, 0x74, 0x8b, 0x1a, 0x35, 0xf9, 0xf0, 0x92, 0x26, 0x5f, 0x8b, 0x8f, 0xad, 0x2d, 0x6a, 0x4a, - 0x8d, 0xdd, 0x3f, 0x2a, 0xc3, 0xbc, 0x5d, 0x0f, 0x92, 0xa9, 0xe4, 0x7d, 0x25, 0x03, 0x95, 0x36, - 0x9a, 0x81, 0xf3, 0x36, 0x7e, 0xb9, 0xc8, 0xc6, 0x37, 0xad, 0xea, 0xca, 0x65, 0xee, 0xc1, 0xea, - 0xfb, 0xb9, 0x07, 0x6b, 0x85, 0xee, 0xc1, 0xe9, 0x5e, 0xa4, 0x99, 0x5f, 0xd6, 0x8b, 0x34, 0xfb, - 0x4e, 0x2f, 0x52, 0xf7, 0xff, 0x94, 0x80, 0xe5, 0xa9, 0x97, 0x3d, 0x15, 0x6e, 0x8d, 0x80, 0x0f, - 0xa5, 0x10, 0xfb, 0xe6, 0xfb, 0x71, 0x80, 0x5a, 0x2d, 0xf5, 0x35, 0xb2, 0xa2, 0x19, 0x68, 0x64, - 0xaa, 0x57, 0x73, 0x6e, 0x51, 0x56, 0xc6, 0x45, 0x5a, 0xbd, 0xdc, 0x45, 0x5a, 0xbb, 0xdc, 0x45, - 0x3a, 0x93, 0x75, 0x91, 0x76, 0xff, 0x72, 0x09, 0x96, 0x0a, 0xc8, 0xec, 0xd7, 0x37, 0x70, 0x24, - 0x0c, 0x4b, 0xfa, 0x94, 0x25, 0x61, 0x98, 0x60, 0xf7, 0xcf, 0xc3, 0x9c, 0xc5, 0x5a, 0xbf, 0xbe, - 0xf6, 0xb3, 0x1a, 0xa2, 0xa0, 0x6c, 0x0b, 0xeb, 0xfe, 0xcf, 0x32, 0xb0, 0x3c, 0x7b, 0xff, 0x7f, - 0xed, 0x43, 0x7e, 0x9e, 0x2a, 0x05, 0xf3, 0xf4, 0xff, 0x74, 0xe7, 0xf9, 0x18, 0x16, 0x65, 0xf4, - 0xa4, 0xe1, 0xc8, 0x12, 0x14, 0x93, 0xcf, 0x40, 0x1d, 0xd9, 0xf6, 0x4f, 0xd7, 0xad, 0x68, 0x31, - 0x63, 0xfb, 0xcd, 0xb8, 0xa9, 0x9d, 0x2e, 0x74, 0xe4, 0x0c, 0xed, 0x9c, 0xf1, 0x20, 0x39, 0x9c, - 0x1c, 0x89, 0xf0, 0x41, 0x3f, 0x0c, 0x9c, 0x7f, 0x5e, 0xd1, 0x6a, 0x3e, 0x65, 0x4a, 0x85, 0xe2, - 0xdb, 0xd0, 0x32, 0xb7, 0x0f, 0xb9, 0x1c, 0x19, 0x5f, 0x26, 0xaa, 0x12, 0x66, 0x29, 0xb6, 0x0d, - 0xf3, 0x24, 0x24, 0x07, 0xfa, 0xbb, 0x32, 0x7d, 0xf7, 0x0e, 0xff, 0xcc, 0xee, 0x15, 0x37, 0xf3, - 0x0d, 0xfb, 0x2d, 0x98, 0xb7, 0x8d, 0x3f, 0xa9, 0x95, 0x14, 0x59, 0x03, 0xf8, 0xb9, 0x5d, 0x98, - 0x6d, 0x40, 0x3b, 0x6b, 0x3d, 0xca, 0x48, 0x9e, 0x29, 0x15, 0xe4, 0x8a, 0xb3, 0x47, 0xf2, 0xb0, - 0xb2, 0x46, 0x7e, 0x93, 0xdb, 0xf6, 0x67, 0xc6, 0x34, 0xad, 0x8b, 0x3f, 0xc6, 0xf1, 0xe5, 0xef, - 0x00, 0xa4, 0x18, 0x6b, 0x43, 0xeb, 0xc5, 0xc1, 0xce, 0x7e, 0x6f, 0x6b, 0x77, 0x63, 0x7f, 0x7f, - 0x67, 0xaf, 0x7d, 0x85, 0x31, 0x98, 0x27, 0x37, 0xdf, 0xb6, 0xc6, 0x4a, 0x88, 0x49, 0xc7, 0x8a, - 0xc2, 0xca, 0x6c, 0x19, 0xda, 0xcf, 0xf6, 0x33, 0x68, 0x65, 0xb3, 0xa1, 0xf9, 0xc3, 0x59, 0x81, - 0x65, 0x11, 0x1d, 0xbb, 0x29, 0xc8, 0x43, 0x69, 0x27, 0x7f, 0xaf, 0x04, 0x57, 0x33, 0x19, 0x69, - 0xa8, 0x97, 0x50, 0x40, 0x6c, 0xad, 0xc4, 0x06, 0xe9, 0xf0, 0x41, 0xe9, 0x9a, 0x19, 0x09, 0x92, - 0xcf, 0x40, 0x9a, 0x37, 0x74, 0xd3, 0x0c, 0x27, 0x15, 0x65, 0x39, 0xab, 0x3a, 0xaa, 0x26, 0xd3, - 0xf1, 0x63, 0x11, 0x75, 0x6b, 0x66, 0xa4, 0x87, 0xbf, 0x76, 0x97, 0x55, 0x12, 0xcd, 0x0a, 0x4b, - 0xd9, 0xb1, 0xfb, 0x5b, 0x98, 0xe7, 0xfc, 0xc3, 0x0a, 0xb0, 0xef, 0x4f, 0x78, 0x74, 0x41, 0xf1, - 0x5c, 0xda, 0x6b, 0xba, 0x9a, 0xf5, 0x09, 0xce, 0x8c, 0x27, 0x47, 0xdf, 0xe3, 0x17, 0x2a, 0xba, - 0xb1, 0x9c, 0x46, 0x37, 0x16, 0x45, 0x18, 0x56, 0x2f, 0x8f, 0x30, 0xac, 0x5d, 0x16, 0x61, 0xf8, - 0x35, 0x98, 0xf3, 0x4f, 0x82, 0x10, 0x79, 0x1e, 0xf5, 0x84, 0xb8, 0x33, 0xb3, 0x56, 0x41, 0xdb, - 0x5a, 0x82, 0xfb, 0x88, 0xb1, 0xc7, 0x69, 0x21, 0x3e, 0x38, 0xa1, 0x68, 0x56, 0x53, 0x0a, 0xec, - 0x0c, 0x4e, 0xf8, 0x5e, 0xd8, 0xf7, 0x92, 0x30, 0x22, 0xc7, 0x8e, 0xfa, 0x18, 0xf1, 0x98, 0xdd, - 0x86, 0xf9, 0x38, 0x9c, 0xa0, 0xe6, 0xa4, 0xc6, 0x2a, 0x3c, 0x49, 0x2d, 0x81, 0x1e, 0x88, 0x11, - 0xaf, 0xc3, 0xd2, 0x24, 0xe6, 0xbd, 0x91, 0x1f, 0xc7, 0xb8, 0x3b, 0xf6, 0xc3, 0x20, 0x89, 0xc2, - 0xa1, 0xf4, 0x27, 0x2d, 0x4e, 0x62, 0xfe, 0x5c, 0xe4, 0x6c, 0x89, 0x0c, 0xf6, 0xed, 0xb4, 0x4b, - 0x63, 0xcf, 0x8f, 0xe2, 0x0e, 0x50, 0x97, 0xd4, 0x48, 0xb1, 0xdf, 0x07, 0x9e, 0x1f, 0xe9, 0xbe, - 0x60, 0x22, 0xce, 0x44, 0x48, 0x36, 0x33, 0x11, 0x92, 0x32, 0xc0, 0x6e, 0x1d, 0xea, 0xea, 0x73, - 0x34, 0x72, 0x8f, 0xa3, 0x70, 0xa4, 0x8c, 0x5c, 0xfc, 0xcd, 0xe6, 0xa1, 0x9c, 0x84, 0xd2, 0x40, - 0x2d, 0x27, 0xa1, 0xf3, 0xbb, 0xd0, 0x34, 0x66, 0x80, 0x7d, 0x28, 0xec, 0x6d, 0x54, 0xa8, 0xa4, - 0x75, 0x2c, 0x8e, 0x49, 0x1a, 0x12, 0x7d, 0x36, 0x60, 0xdf, 0x80, 0xc5, 0x81, 0x1f, 0x71, 0x0a, - 0xac, 0xed, 0x45, 0xfc, 0x8c, 0x47, 0xb1, 0xf2, 0x25, 0xb4, 0x75, 0x86, 0x2b, 0x70, 0xa7, 0x07, - 0x4b, 0x16, 0xe9, 0x68, 0xce, 0x9a, 0xa1, 0xa8, 0x40, 0xe5, 0xce, 0xb4, 0x23, 0x06, 0x65, 0x1e, - 0xee, 0x49, 0xd2, 0x0d, 0xd2, 0x1b, 0x47, 0xe1, 0x11, 0x35, 0x52, 0x72, 0x2d, 0xcc, 0xf9, 0xc7, - 0x65, 0xa8, 0xec, 0x86, 0x63, 0xf3, 0x70, 0xa7, 0x94, 0x3f, 0xdc, 0x91, 0xca, 0x63, 0x4f, 0xeb, - 0x86, 0x72, 0x87, 0xb7, 0x40, 0x76, 0x0f, 0xe6, 0xbd, 0x51, 0xd2, 0x4b, 0x42, 0x54, 0x96, 0xcf, - 0xbd, 0x48, 0x84, 0x10, 0x56, 0x88, 0x2c, 0x32, 0x39, 0x6c, 0x19, 0x2a, 0x5a, 0xe7, 0xa1, 0x02, - 0x98, 0x44, 0x4b, 0x8d, 0x0e, 0xd0, 0x2f, 0xa4, 0xcf, 0x52, 0xa6, 0x90, 0xeb, 0xed, 0xef, 0x85, - 0x99, 0x2c, 0x76, 0xae, 0xa2, 0x2c, 0x54, 0x64, 0x91, 0x11, 0x46, 0xa9, 0x5e, 0xa8, 0xd3, 0xa6, - 0x37, 0xbe, 0x6e, 0x7b, 0xe3, 0xd7, 0xa0, 0x99, 0x0c, 0xcf, 0x7a, 0x63, 0xef, 0x62, 0x18, 0x7a, - 0x03, 0x49, 0x80, 0x26, 0xe4, 0xfc, 0x49, 0x09, 0x6a, 0x34, 0xcb, 0xb8, 0x4f, 0x0b, 0x41, 0xa6, - 0x4f, 0x80, 0x68, 0xe6, 0xe6, 0xdc, 0x2c, 0xcc, 0x1c, 0x2b, 0x18, 0xbc, 0xac, 0x87, 0x6c, 0x06, - 0x84, 0xaf, 0x41, 0x43, 0xa4, 0x74, 0x60, 0x33, 0x15, 0x49, 0x41, 0x76, 0x13, 0xaa, 0xa7, 0xe1, - 0x58, 0x99, 0x32, 0xa0, 0x0e, 0x89, 0xc3, 0xb1, 0x4b, 0x78, 0xda, 0x1f, 0xac, 0x4f, 0x0c, 0x5c, - 0xa8, 0x8b, 0x59, 0x18, 0x55, 0x74, 0x5d, 0xad, 0x39, 0x91, 0x19, 0xd4, 0x79, 0x05, 0x0b, 0xc8, - 0x0b, 0x86, 0x47, 0x7c, 0xba, 0xd0, 0xfa, 0x3a, 0xee, 0x81, 0xfd, 0xe1, 0x64, 0xc0, 0x4d, 0x83, - 0x92, 0x3c, 0x9e, 0x12, 0x57, 0xaa, 0x94, 0xf3, 0x4f, 0x4b, 0x82, 0xc7, 0xb0, 0x5e, 0x76, 0x17, - 0xaa, 0x28, 0x7a, 0x32, 0xfe, 0x03, 0x1d, 0x4b, 0x82, 0xe5, 0x5c, 0x2a, 0x81, 0xd4, 0x4c, 0x3e, - 0x49, 0xb3, 0x76, 0xe1, 0x91, 0x4c, 0xad, 0x31, 0x3d, 0xb2, 0x8c, 0x11, 0x93, 0x41, 0xd9, 0xba, - 0x71, 0xa0, 0x53, 0xb5, 0xc4, 0x99, 0xda, 0x72, 0x07, 0x27, 0xdc, 0x38, 0xc8, 0xf9, 0xc3, 0x12, - 0xcc, 0x59, 0x7d, 0x42, 0x4a, 0x19, 0x7a, 0x71, 0x22, 0xcf, 0xf2, 0xe5, 0xca, 0x9b, 0x90, 0x49, - 0x65, 0x65, 0x9b, 0xca, 0xf4, 0xc1, 0x40, 0xc5, 0x3c, 0x18, 0x78, 0x00, 0x8d, 0xf4, 0x36, 0x80, - 0xdd, 0x29, 0x6c, 0x51, 0x45, 0xd5, 0xa4, 0x85, 0x52, 0xd7, 0x73, 0xcd, 0x70, 0x3d, 0x3b, 0x8f, - 0xa1, 0x69, 0x94, 0x37, 0x5d, 0xc7, 0x25, 0xcb, 0x75, 0xac, 0x43, 0xce, 0xca, 0x69, 0xc8, 0x99, - 0xf3, 0x65, 0x19, 0xe6, 0x90, 0xbc, 0xfd, 0xe0, 0xe4, 0x20, 0x1c, 0xfa, 0xfd, 0x0b, 0x22, 0x2b, - 0x45, 0xc9, 0x72, 0xeb, 0x51, 0x64, 0x6e, 0xc3, 0xc8, 0x72, 0x3a, 0xce, 0x56, 0xc8, 0x07, 0x9d, - 0x46, 0x01, 0x82, 0xec, 0x77, 0xe4, 0xc5, 0x92, 0x27, 0xa5, 0xea, 0x6b, 0x81, 0xc8, 0xe6, 0x08, - 0x50, 0x00, 0xe1, 0xc8, 0x1f, 0x0e, 0x7d, 0x51, 0x56, 0x18, 0x46, 0x45, 0x59, 0xd8, 0xe6, 0xc0, - 0x8f, 0xbd, 0xa3, 0xf4, 0xd0, 0x4f, 0xa7, 0xc9, 0xab, 0xe6, 0xbd, 0x35, 0xbc, 0x6a, 0x22, 0xe2, - 0xd8, 0x06, 0xb3, 0x0b, 0x39, 0x9b, 0x5b, 0x48, 0xe7, 0xdf, 0x94, 0xa1, 0x69, 0x90, 0x05, 0xb2, - 0x73, 0xa1, 0x8c, 0x37, 0x50, 0x79, 0x1a, 0x1e, 0x58, 0xa6, 0xb6, 0x81, 0xb0, 0xdb, 0x76, 0xab, - 0xe4, 0x5d, 0x27, 0x86, 0xb7, 0x48, 0xe8, 0x06, 0x34, 0x90, 0xf4, 0x3f, 0x21, 0xbb, 0x5e, 0x5e, - 0xc5, 0xd1, 0x80, 0xca, 0x7d, 0x48, 0xb9, 0xb5, 0x34, 0x97, 0x80, 0x77, 0x9e, 0x8f, 0x3f, 0x82, - 0x96, 0xac, 0x86, 0xd6, 0x98, 0x06, 0x9d, 0x32, 0x9f, 0xb5, 0xfe, 0xae, 0x55, 0x52, 0x7d, 0xf9, - 0x50, 0x7d, 0x59, 0xbf, 0xec, 0x4b, 0x55, 0xd2, 0x79, 0xaa, 0x43, 0x0f, 0x9e, 0x46, 0xde, 0xf8, - 0x54, 0x09, 0x94, 0x07, 0xb0, 0xa4, 0xe4, 0xc6, 0x24, 0xf0, 0x82, 0x20, 0x9c, 0x04, 0x7d, 0xae, - 0xa2, 0xd3, 0x8a, 0xb2, 0x9c, 0x81, 0x8e, 0x65, 0xa6, 0x8a, 0xd8, 0x3d, 0xa8, 0x09, 0xe5, 0x45, - 0x6c, 0x85, 0xc5, 0x22, 0x44, 0x14, 0x61, 0x77, 0xa1, 0x26, 0x74, 0x98, 0xf2, 0x54, 0xa6, 0x17, - 0x05, 0x9c, 0x75, 0x58, 0xa0, 0xe0, 0x69, 0x43, 0xf6, 0x5d, 0x2f, 0xda, 0x22, 0x67, 0xfa, 0x22, - 0xc4, 0x7a, 0x19, 0xd8, 0xbe, 0xe0, 0x2b, 0xf3, 0x00, 0xf1, 0x4f, 0x2a, 0xd0, 0x34, 0x60, 0x94, - 0x4f, 0x74, 0xea, 0xd3, 0x1b, 0xf8, 0xde, 0x88, 0x27, 0x3c, 0x92, 0xbc, 0x94, 0x41, 0xb1, 0x9c, - 0x77, 0x76, 0xd2, 0x0b, 0x27, 0x49, 0x6f, 0xc0, 0x4f, 0x22, 0xce, 0xe5, 0xde, 0x9d, 0x41, 0xb1, - 0x1c, 0x52, 0xb3, 0x51, 0x4e, 0x9c, 0xd3, 0x64, 0x50, 0x75, 0x1c, 0x28, 0xe6, 0xa9, 0x9a, 0x1e, - 0x07, 0x8a, 0x59, 0xc9, 0x4a, 0xd6, 0x5a, 0x81, 0x64, 0xfd, 0x14, 0x56, 0x84, 0x0c, 0x95, 0xd2, - 0xa3, 0x97, 0x21, 0xae, 0x29, 0xb9, 0xec, 0x1e, 0xb4, 0xb1, 0xcf, 0x8a, 0x35, 0x62, 0xff, 0xe7, - 0x82, 0xc7, 0x4a, 0x6e, 0x0e, 0xc7, 0xb2, 0xe4, 0xa3, 0x36, 0xcb, 0x8a, 0x98, 0x8c, 0x1c, 0x4e, - 0x65, 0xbd, 0xb7, 0x76, 0xd9, 0x86, 0x2c, 0x9b, 0xc1, 0xd9, 0x23, 0x58, 0x1d, 0xf1, 0x81, 0xef, - 0xd9, 0x55, 0x90, 0xcb, 0x48, 0x04, 0x94, 0x4d, 0xcb, 0xc6, 0x56, 0x70, 0x16, 0x7e, 0x1e, 0x8e, - 0x8e, 0x7c, 0xb1, 0xb1, 0x09, 0x6f, 0x7a, 0xd5, 0xcd, 0xe1, 0xce, 0x1c, 0x34, 0x0f, 0x93, 0x70, - 0xac, 0x96, 0x7e, 0x1e, 0x5a, 0x22, 0x29, 0xe3, 0x11, 0xaf, 0xc3, 0x35, 0xa2, 0xd7, 0x97, 0xe1, - 0x38, 0x1c, 0x86, 0x27, 0x17, 0x96, 0x4d, 0xfc, 0xef, 0x4b, 0xb0, 0x64, 0xe5, 0xa6, 0x46, 0x31, - 0x39, 0xf0, 0x54, 0x10, 0x99, 0x20, 0xf1, 0x45, 0x63, 0x5b, 0x10, 0x05, 0xc5, 0x59, 0xc9, 0x2b, - 0x19, 0x57, 0xb6, 0x91, 0xde, 0x8c, 0x50, 0x1f, 0x0a, 0x7a, 0xef, 0xe4, 0xe9, 0x5d, 0x7e, 0xaf, - 0xee, 0x4c, 0xa8, 0x2a, 0x7e, 0x4b, 0x46, 0xd0, 0x0c, 0xe4, 0xa0, 0x2b, 0x76, 0xd4, 0x83, 0xe9, - 0x43, 0x51, 0x3d, 0xe8, 0x6b, 0x30, 0x76, 0x7e, 0x51, 0x02, 0x48, 0x7b, 0x47, 0x71, 0x17, 0x7a, - 0x6b, 0x13, 0xb7, 0x6f, 0x8d, 0x6d, 0xec, 0x43, 0x68, 0xe9, 0xa3, 0xf3, 0x74, 0xb7, 0x6c, 0x2a, - 0x0c, 0xb5, 0x8b, 0x3b, 0xb0, 0x70, 0x32, 0x0c, 0x8f, 0x48, 0x8b, 0xa1, 0x00, 0xd7, 0x58, 0x46, - 0x65, 0xce, 0x0b, 0xf8, 0x89, 0x44, 0xd3, 0xad, 0xb5, 0x6a, 0x6e, 0xad, 0xc5, 0x1b, 0xe5, 0x97, - 0x65, 0x7d, 0x7e, 0x99, 0xce, 0xc4, 0x3b, 0xb9, 0x9c, 0x3d, 0xcc, 0x89, 0xf5, 0x29, 0x47, 0x86, - 0xa4, 0xef, 0x1f, 0x5c, 0xea, 0x52, 0x7d, 0x0c, 0xf3, 0x91, 0x90, 0x99, 0x4a, 0xa0, 0x56, 0xdf, - 0x21, 0x50, 0xe7, 0x22, 0x6b, 0x67, 0xfe, 0x3a, 0xb4, 0xbd, 0xc1, 0x19, 0x8f, 0x12, 0x9f, 0x5c, - 0x4c, 0xa4, 0x46, 0x89, 0x01, 0x2e, 0x18, 0x38, 0x69, 0x2b, 0x77, 0x60, 0x41, 0xc6, 0xc8, 0xea, - 0x92, 0xf2, 0x2e, 0x5b, 0x0a, 0x63, 0x41, 0xe7, 0x1f, 0xa8, 0xe3, 0x52, 0x7b, 0x75, 0xdf, 0x3d, - 0x2b, 0xe6, 0x08, 0xcb, 0x99, 0x11, 0x7e, 0x4d, 0x1e, 0x5f, 0x0e, 0x94, 0x2f, 0xab, 0x62, 0xc4, - 0x62, 0x0d, 0xe4, 0x71, 0xb3, 0x3d, 0xad, 0xd5, 0xf7, 0x99, 0x56, 0xe7, 0x3f, 0x95, 0x60, 0x76, - 0x37, 0x1c, 0xef, 0xe2, 0x14, 0xa3, 0x8e, 0x83, 0x6c, 0xa2, 0x03, 0xd4, 0x55, 0xf2, 0x92, 0x98, - 0xb5, 0x42, 0xad, 0x64, 0x2e, 0xab, 0x95, 0xfc, 0x59, 0xb8, 0x4e, 0xde, 0xd4, 0x28, 0x1c, 0x87, - 0x11, 0xb2, 0xab, 0x37, 0x14, 0x2a, 0x48, 0x18, 0x24, 0xa7, 0x4a, 0x9c, 0xbe, 0xab, 0x08, 0xb9, - 0x38, 0xd0, 0xf2, 0x14, 0xd6, 0x8c, 0xd4, 0xa2, 0x84, 0x94, 0xcd, 0x67, 0x38, 0xbf, 0x09, 0x0d, - 0xb2, 0x30, 0x68, 0x68, 0x1f, 0x43, 0xe3, 0x34, 0x1c, 0xf7, 0x4e, 0xfd, 0x20, 0x51, 0xec, 0x3f, - 0x9f, 0xaa, 0xfe, 0xbb, 0x34, 0x29, 0xba, 0x80, 0xf3, 0xaf, 0x67, 0x60, 0xf6, 0x59, 0x70, 0x16, - 0xfa, 0x7d, 0x3a, 0xa2, 0x1d, 0xf1, 0x51, 0xa8, 0x42, 0xf6, 0xf1, 0x37, 0x4e, 0x07, 0xc5, 0xa7, - 0x8e, 0x05, 0xf1, 0xb6, 0x44, 0x28, 0x86, 0x84, 0xe8, 0xb2, 0x69, 0x7a, 0xdd, 0x4e, 0x30, 0x98, - 0x81, 0xa0, 0x75, 0x16, 0x99, 0xd7, 0xe5, 0x64, 0x2a, 0xbd, 0x12, 0x51, 0x33, 0xae, 0x44, 0x60, - 0x5b, 0x32, 0x92, 0x4e, 0x84, 0x5a, 0x89, 0xb6, 0x24, 0x44, 0x16, 0x65, 0xc4, 0x85, 0x37, 0x5c, - 0x2b, 0x5e, 0x68, 0x51, 0x9a, 0x20, 0x2a, 0x67, 0xe2, 0x03, 0x51, 0x46, 0x6c, 0x06, 0x26, 0x84, - 0xea, 0x69, 0xf6, 0x96, 0xa6, 0xb8, 0x25, 0x9b, 0x85, 0x51, 0x96, 0x0f, 0xb8, 0x16, 0xb9, 0x62, - 0x1c, 0x20, 0xae, 0x14, 0x66, 0x71, 0xc3, 0x0e, 0x15, 0xa1, 0xc4, 0xca, 0x0e, 0x45, 0x82, 0xf1, - 0x86, 0xc3, 0x23, 0xaf, 0xff, 0x86, 0x2e, 0xe9, 0xd2, 0xa1, 0x69, 0xc3, 0xb5, 0x41, 0x8a, 0x87, - 0x4b, 0x57, 0x95, 0x82, 0x56, 0xaa, 0xae, 0x09, 0xb1, 0x87, 0xd0, 0x24, 0x1b, 0x5d, 0xae, 0xeb, - 0x3c, 0xad, 0x6b, 0xdb, 0x34, 0xe2, 0x69, 0x65, 0xcd, 0x42, 0xe6, 0xf1, 0xf1, 0x42, 0x2e, 0xb8, - 0xd7, 0x1b, 0x0c, 0xe4, 0xa9, 0x7b, 0x5b, 0x5c, 0xab, 0xd3, 0x00, 0x79, 0x01, 0xc4, 0x84, 0x89, - 0x02, 0x8b, 0x54, 0xc0, 0xc2, 0xd8, 0x4d, 0xa8, 0xa3, 0xd5, 0x37, 0xf6, 0xfc, 0x01, 0xc5, 0xa9, - 0x08, 0xe3, 0x53, 0x63, 0x58, 0x87, 0xfa, 0x4d, 0xdb, 0xe6, 0x12, 0xcd, 0x8a, 0x85, 0xe1, 0xdc, - 0xe8, 0xf4, 0x28, 0x8d, 0x06, 0xb6, 0x41, 0xf6, 0x09, 0x9d, 0x7d, 0x26, 0x9c, 0x42, 0x7e, 0xe7, - 0x1f, 0x5e, 0x97, 0x63, 0x96, 0x44, 0xab, 0xfe, 0x1e, 0x62, 0x11, 0x57, 0x94, 0x44, 0xa5, 0x4d, - 0xb8, 0x9f, 0x57, 0x2c, 0xa5, 0x4d, 0x16, 0x25, 0xf7, 0xb3, 0x28, 0xe0, 0x6c, 0x40, 0xcb, 0xac, - 0x80, 0xd5, 0xa1, 0xfa, 0xe2, 0x60, 0x67, 0xbf, 0x7d, 0x85, 0x35, 0x61, 0xf6, 0x70, 0xe7, 0xe5, - 0xcb, 0xbd, 0x9d, 0xed, 0x76, 0x89, 0xb5, 0xa0, 0xae, 0xc3, 0x1c, 0xcb, 0x98, 0xda, 0xd8, 0xda, - 0xda, 0x39, 0x78, 0xb9, 0xb3, 0xdd, 0xae, 0x38, 0x7f, 0x50, 0x86, 0xa6, 0x51, 0xf3, 0x25, 0x7e, - 0x91, 0x9b, 0x00, 0x64, 0x49, 0xa4, 0x01, 0x0f, 0x55, 0xd7, 0x40, 0x50, 0x32, 0x6a, 0x1b, 0xbb, - 0x22, 0x6e, 0x17, 0xaa, 0x34, 0xcd, 0x17, 0x5d, 0xe3, 0x33, 0xbd, 0xfc, 0x35, 0xd7, 0x06, 0x91, - 0x96, 0x24, 0x40, 0x51, 0x77, 0x82, 0xc3, 0x4c, 0x08, 0xd7, 0x26, 0xe2, 0x71, 0x38, 0x3c, 0xe3, - 0xa2, 0x88, 0xd0, 0xc7, 0x2c, 0x0c, 0xdb, 0x92, 0x22, 0xc6, 0x88, 0x88, 0xad, 0xb9, 0x36, 0xc8, - 0xbe, 0xa9, 0xd6, 0xa6, 0x4e, 0x6b, 0xb3, 0x9a, 0x9f, 0x68, 0x73, 0x5d, 0x9c, 0x04, 0xd8, 0xc6, - 0x60, 0x20, 0x73, 0xcd, 0xbb, 0x8a, 0x91, 0x79, 0x31, 0x56, 0x09, 0x89, 0x02, 0x46, 0x2d, 0x17, - 0x33, 0xea, 0x3b, 0xc9, 0xd9, 0xd9, 0x81, 0xe6, 0x81, 0x71, 0xd5, 0x96, 0x64, 0x96, 0xba, 0x64, - 0x2b, 0x65, 0x9d, 0x81, 0x18, 0xdd, 0x29, 0x9b, 0xdd, 0x71, 0xfe, 0x7e, 0x49, 0xdc, 0x5e, 0xd2, - 0xdd, 0x17, 0x6d, 0x3b, 0xd0, 0xd2, 0x3e, 0xdc, 0x34, 0xe0, 0xdb, 0xc2, 0xb0, 0x0c, 0x75, 0xa5, - 0x17, 0x1e, 0x1f, 0xc7, 0x5c, 0x85, 0x66, 0x5a, 0x98, 0x52, 0x1c, 0x51, 0x15, 0xf5, 0x45, 0x0b, - 0xb1, 0x0c, 0xd1, 0xcc, 0xe1, 0x48, 0x24, 0xd2, 0x0d, 0xa8, 0x82, 0x52, 0x75, 0x5a, 0xc7, 0xa5, - 0x67, 0x67, 0xf9, 0x1e, 0xd4, 0x75, 0xbd, 0xf6, 0xae, 0xa0, 0x4a, 0xea, 0x7c, 0xdc, 0x7d, 0xc8, - 0xa8, 0xb4, 0x3a, 0x2d, 0x68, 0x35, 0x9f, 0xc1, 0xd6, 0x81, 0x1d, 0xfb, 0x51, 0xb6, 0xb8, 0x20, - 0xde, 0x82, 0x1c, 0xe7, 0x35, 0x2c, 0x29, 0x9e, 0x33, 0x34, 0x5a, 0x7b, 0x11, 0x4b, 0x97, 0xc9, - 0xa4, 0x72, 0x5e, 0x26, 0x39, 0x7f, 0x5c, 0x81, 0x59, 0xb9, 0xd2, 0xb9, 0xeb, 0xda, 0x62, 0x9d, - 0x2d, 0x8c, 0x75, 0xac, 0x8b, 0x79, 0x24, 0xc0, 0xe4, 0x4e, 0x94, 0xdb, 0x6b, 0x2a, 0x45, 0x7b, - 0x0d, 0x83, 0xea, 0xd8, 0x4b, 0x4e, 0xc9, 0xf5, 0xd2, 0x70, 0xe9, 0xb7, 0xf2, 0x52, 0xd6, 0x6c, - 0x2f, 0x65, 0xd1, 0xe5, 0x74, 0xa1, 0x4e, 0xe5, 0x2f, 0xa7, 0xdf, 0x80, 0x86, 0xb8, 0xd0, 0x9c, - 0x3a, 0x22, 0x53, 0x00, 0xa9, 0x57, 0x24, 0x48, 0x42, 0xc8, 0x3b, 0x32, 0x29, 0xf2, 0x15, 0x76, - 0xb7, 0x6f, 0xc3, 0x8c, 0xb8, 0xa4, 0x21, 0x43, 0x6f, 0x6f, 0xa8, 0x43, 0x3a, 0x51, 0x4e, 0xfd, - 0x15, 0x31, 0x3c, 0xae, 0x2c, 0x6b, 0x5e, 0xf3, 0x6c, 0xda, 0xd7, 0x3c, 0x4d, 0xff, 0x69, 0xcb, - 0xf6, 0x9f, 0x3a, 0x4f, 0x60, 0xce, 0xaa, 0x0e, 0xa5, 0xab, 0x0c, 0xdd, 0x6d, 0x5f, 0x61, 0x73, - 0xd0, 0x78, 0xb6, 0xdf, 0x7b, 0xb2, 0xf7, 0xec, 0xe9, 0xee, 0xcb, 0x76, 0x09, 0x93, 0x87, 0xaf, - 0xb6, 0xb6, 0x76, 0x76, 0xb6, 0x49, 0xda, 0x02, 0xcc, 0x3c, 0xd9, 0x78, 0xb6, 0x47, 0xb2, 0x76, - 0x5b, 0xd0, 0xb6, 0xac, 0x4b, 0x1f, 0x8c, 0x7c, 0x13, 0x98, 0xb2, 0xfb, 0x29, 0x84, 0x67, 0x3c, - 0xe4, 0x89, 0x8a, 0x2a, 0x5f, 0x94, 0x39, 0xcf, 0x74, 0x86, 0xba, 0x18, 0x91, 0xd6, 0x92, 0xb2, - 0x88, 0x9c, 0xa4, 0x2c, 0x8b, 0xc8, 0xa2, 0xae, 0xce, 0x77, 0xba, 0xd0, 0xd9, 0xe6, 0x58, 0xdb, - 0xc6, 0x70, 0x98, 0xe9, 0x0e, 0x1a, 0x6e, 0x05, 0x79, 0xd2, 0xaa, 0xfb, 0x3e, 0x5c, 0xdd, 0x10, - 0x01, 0xe4, 0xbf, 0xae, 0xf8, 0x42, 0xa7, 0x03, 0x2b, 0xd9, 0x2a, 0x65, 0x63, 0x4f, 0x60, 0x71, - 0x9b, 0x1f, 0x4d, 0x4e, 0xf6, 0xf8, 0x59, 0xda, 0x10, 0x83, 0x6a, 0x7c, 0x1a, 0x9e, 0xcb, 0xf9, - 0xa1, 0xdf, 0xec, 0x03, 0x80, 0x21, 0x96, 0xe9, 0xc5, 0x63, 0xde, 0x57, 0x97, 0x03, 0x09, 0x39, - 0x1c, 0xf3, 0xbe, 0xf3, 0x29, 0x30, 0xb3, 0x1e, 0x39, 0x5f, 0xa8, 0x6b, 0x4d, 0x8e, 0x7a, 0xf1, - 0x45, 0x9c, 0xf0, 0x91, 0xba, 0xf5, 0x68, 0x42, 0xce, 0x1d, 0x68, 0x1d, 0x78, 0x17, 0x2e, 0xff, - 0x99, 0x7c, 0xb6, 0x60, 0x15, 0x66, 0xc7, 0xde, 0x05, 0x92, 0xa0, 0x76, 0x06, 0x53, 0xb6, 0xf3, - 0xbf, 0xcb, 0x30, 0x23, 0x4a, 0x62, 0xad, 0x03, 0x1e, 0x27, 0x7e, 0x40, 0x9c, 0xa6, 0x6a, 0x35, - 0xa0, 0x1c, 0x6f, 0x97, 0x0b, 0x78, 0x5b, 0x7a, 0x28, 0xd4, 0x25, 0x2b, 0xc9, 0xc0, 0x16, 0x86, - 0x9c, 0x96, 0x06, 0x0a, 0x0b, 0x97, 0x61, 0x0a, 0x64, 0x4e, 0x16, 0x52, 0x8d, 0x4e, 0xf4, 0x4f, - 0x89, 0x2d, 0xc9, 0xc6, 0x26, 0x54, 0xa8, 0x37, 0xce, 0x0a, 0x6e, 0xcf, 0xe9, 0x8d, 0x39, 0xfd, - 0xb0, 0xfe, 0x1e, 0xfa, 0xa1, 0x70, 0x5b, 0xbc, 0x4b, 0x3f, 0x84, 0xf7, 0xd0, 0x0f, 0x1d, 0x06, - 0x6d, 0xba, 0xc1, 0x8d, 0x16, 0x88, 0xa2, 0xdd, 0xbf, 0x5d, 0x82, 0xb6, 0xa4, 0x22, 0x9d, 0xa7, - 0xce, 0xa8, 0xde, 0x75, 0xd5, 0xe7, 0x36, 0xcc, 0x91, 0xfd, 0xa3, 0x45, 0x80, 0x3c, 0xef, 0xb1, - 0x40, 0x1c, 0x87, 0x0a, 0x33, 0x19, 0xf9, 0x43, 0xb9, 0x28, 0x26, 0xa4, 0xa4, 0x48, 0xe4, 0xc9, - 0x80, 0xd7, 0x92, 0xab, 0xd3, 0xce, 0x1f, 0x95, 0x60, 0xd1, 0xe8, 0xb0, 0xa4, 0xc2, 0xc7, 0xd0, - 0xd2, 0x0f, 0x25, 0x70, 0xbd, 0xb9, 0xad, 0xda, 0x6c, 0x93, 0x7e, 0x66, 0x15, 0xa6, 0xc5, 0xf4, - 0x2e, 0xa8, 0x83, 0xf1, 0x64, 0x24, 0x77, 0x15, 0x13, 0x42, 0x42, 0x3a, 0xe7, 0xfc, 0x8d, 0x2e, - 0x22, 0xf6, 0x35, 0x0b, 0x23, 0xbf, 0x31, 0xda, 0x6d, 0xba, 0x50, 0x55, 0xfa, 0x8d, 0x4d, 0xd0, - 0xf9, 0x8b, 0x65, 0x58, 0x12, 0x86, 0xb8, 0x74, 0x80, 0xe8, 0xbb, 0xaa, 0x33, 0xc2, 0x27, 0x21, - 0x38, 0x72, 0xf7, 0x8a, 0x2b, 0xd3, 0xec, 0x3b, 0xef, 0xe9, 0x3c, 0xd0, 0x51, 0xb8, 0x53, 0xd6, - 0xa2, 0x52, 0xb4, 0x16, 0xef, 0x98, 0xe9, 0x22, 0x17, 0x7e, 0xad, 0xd8, 0x85, 0xff, 0x5e, 0x2e, - 0xf3, 0xcd, 0x59, 0xa8, 0xc5, 0xfd, 0x70, 0xcc, 0x9d, 0x15, 0x58, 0xb6, 0xa7, 0x40, 0x0a, 0xaa, - 0x5f, 0x94, 0xa0, 0xf3, 0x44, 0x9c, 0xc6, 0xf9, 0xc1, 0xc9, 0xae, 0x1f, 0x27, 0x61, 0xa4, 0x2f, - 0xfe, 0xdf, 0x04, 0x88, 0x13, 0x2f, 0x92, 0x0a, 0xad, 0x50, 0x0d, 0x0c, 0x04, 0x47, 0xc2, 0x83, - 0x81, 0xc8, 0x15, 0x2b, 0xa8, 0xd3, 0x39, 0xd5, 0x4b, 0x3a, 0x13, 0x2c, 0x05, 0xe6, 0x23, 0x11, - 0xbb, 0x8e, 0x5d, 0xe6, 0x67, 0x24, 0xfd, 0x85, 0x85, 0x9e, 0x41, 0x9d, 0xdf, 0x2b, 0xc3, 0x42, - 0xda, 0x49, 0x8a, 0xb1, 0xb0, 0x65, 0x88, 0xd4, 0x5a, 0x52, 0x19, 0x22, 0x1d, 0xff, 0x3d, 0x1f, - 0xd5, 0x18, 0xc3, 0x9f, 0x60, 0xa0, 0xec, 0x36, 0x34, 0x55, 0x2a, 0x9c, 0x24, 0xc6, 0x0d, 0x5c, - 0x13, 0x16, 0x11, 0xa9, 0xa8, 0x48, 0x49, 0xa5, 0x50, 0xa6, 0xe8, 0x36, 0xd0, 0x28, 0xa1, 0x2f, - 0xc5, 0xcc, 0xab, 0x24, 0x6b, 0x0b, 0x4d, 0x44, 0x3c, 0x86, 0x42, 0x5a, 0x88, 0xb9, 0x43, 0xd7, - 0xf5, 0xcb, 0x25, 0x9a, 0x33, 0x45, 0x8d, 0x69, 0x38, 0x71, 0xd5, 0x35, 0x21, 0x65, 0xd1, 0x85, - 0x13, 0x69, 0x9d, 0x88, 0xb7, 0x4f, 0x2c, 0xcc, 0xf9, 0xeb, 0x25, 0xb8, 0x56, 0xb0, 0x8c, 0x92, - 0x53, 0xb7, 0x61, 0xf1, 0x58, 0x67, 0xaa, 0xa9, 0x16, 0xec, 0xba, 0xa2, 0x42, 0x0e, 0xec, 0xe9, - 0x75, 0xf3, 0x1f, 0x68, 0xe5, 0x54, 0x2c, 0x9e, 0x15, 0x39, 0x9e, 0xcf, 0x70, 0x0e, 0xa0, 0xbb, - 0xf3, 0x16, 0x19, 0x7f, 0xcb, 0x7c, 0xbf, 0x4d, 0x51, 0xd6, 0xc3, 0x9c, 0x60, 0xbb, 0xdc, 0x8d, - 0x74, 0x0c, 0x73, 0x56, 0x5d, 0xec, 0x5b, 0xef, 0x5b, 0x89, 0xc9, 0xa3, 0x6b, 0x72, 0xd5, 0xc5, - 0x03, 0x74, 0x2a, 0x7e, 0xdd, 0x80, 0x9c, 0x33, 0x58, 0x78, 0x3e, 0x19, 0x26, 0x7e, 0xfa, 0x18, - 0x1d, 0xfb, 0x8e, 0xfc, 0x88, 0xaa, 0x50, 0x53, 0x57, 0xd8, 0x94, 0x59, 0x0e, 0x67, 0x6c, 0x84, - 0x35, 0xf5, 0xf2, 0x2d, 0xe6, 0x33, 0x9c, 0x6b, 0xb0, 0x9a, 0x36, 0x29, 0xe6, 0x4e, 0x6d, 0x0e, - 0xbf, 0x5f, 0x12, 0x81, 0x58, 0xf6, 0xdb, 0x78, 0xec, 0x29, 0x2c, 0xc5, 0x7e, 0x70, 0x32, 0xe4, - 0x66, 0x3d, 0xb1, 0x9c, 0x89, 0xab, 0x76, 0xf7, 0xe4, 0xfb, 0x79, 0x6e, 0xd1, 0x17, 0x48, 0x20, - 0xc5, 0x1d, 0x4d, 0x09, 0x24, 0x33, 0x25, 0x45, 0x03, 0xf8, 0x2e, 0xcc, 0xdb, 0x8d, 0xb1, 0x47, - 0x32, 0xf4, 0x3c, 0xed, 0x99, 0x79, 0xee, 0x63, 0x53, 0x86, 0x55, 0xd2, 0xf9, 0xb2, 0x04, 0x1d, - 0x97, 0x23, 0x19, 0x73, 0xa3, 0x51, 0x49, 0x3d, 0x8f, 0x73, 0xd5, 0x4e, 0x1f, 0xb0, 0x0e, 0x69, - 0x57, 0x63, 0x5d, 0x9f, 0xba, 0x28, 0xbb, 0x57, 0x0a, 0x46, 0xb5, 0x59, 0x87, 0x19, 0x39, 0xbe, - 0x55, 0xb8, 0x2a, 0xbb, 0xa4, 0xba, 0x93, 0x1e, 0x18, 0x58, 0x8d, 0x5a, 0x07, 0x06, 0x5d, 0xe8, - 0x88, 0xf7, 0x1d, 0xcc, 0x71, 0xc8, 0x0f, 0xb7, 0x81, 0x3d, 0xf7, 0xfa, 0x5e, 0x14, 0x86, 0xc1, - 0x01, 0x8f, 0x64, 0x50, 0x0d, 0x29, 0x40, 0xe4, 0x4f, 0x57, 0xba, 0x9a, 0x48, 0xa9, 0x27, 0x09, - 0xc2, 0x40, 0x3d, 0xfd, 0x20, 0x52, 0x8e, 0x0b, 0x4b, 0x9b, 0xde, 0x1b, 0xae, 0x6a, 0x4a, 0x67, - 0xa9, 0x39, 0xd6, 0x95, 0xaa, 0xb9, 0x57, 0x37, 0x4a, 0xf2, 0xcd, 0xba, 0x66, 0x69, 0xe7, 0x21, - 0x2c, 0xdb, 0x75, 0x4a, 0x51, 0xd2, 0x85, 0xfa, 0x48, 0x62, 0xb2, 0x77, 0x3a, 0x7d, 0xef, 0x0b, - 0x68, 0x1a, 0x6f, 0x76, 0xb0, 0x55, 0x58, 0x7a, 0xfd, 0xec, 0xe5, 0xfe, 0xce, 0xe1, 0x61, 0xef, - 0xe0, 0xd5, 0xe6, 0xf7, 0x76, 0x7e, 0xd8, 0xdb, 0xdd, 0x38, 0xdc, 0x6d, 0x5f, 0x61, 0x2b, 0xc0, - 0xf6, 0x77, 0x0e, 0x5f, 0xee, 0x6c, 0x5b, 0x78, 0x89, 0xdd, 0x84, 0xee, 0xab, 0xfd, 0x57, 0x87, - 0x3b, 0xdb, 0xbd, 0xa2, 0xef, 0xca, 0xec, 0x03, 0xb8, 0x26, 0xf3, 0x0b, 0x3e, 0xaf, 0xdc, 0x7b, - 0x0c, 0xed, 0xac, 0xff, 0xc3, 0xf2, 0x18, 0xbd, 0xcb, 0xb5, 0xf4, 0xf0, 0xcb, 0x0a, 0xcc, 0x8b, - 0xd0, 0x38, 0xf1, 0xba, 0x24, 0x8f, 0xd8, 0x73, 0x98, 0x95, 0xcf, 0x94, 0x32, 0x45, 0x5a, 0xf6, - 0xc3, 0xa8, 0xdd, 0x95, 0x2c, 0x2c, 0x97, 0x75, 0xe9, 0x2f, 0xfd, 0xc7, 0xff, 0xfe, 0x37, 0xcb, - 0x73, 0xac, 0x79, 0xff, 0xec, 0x93, 0xfb, 0x27, 0x3c, 0x88, 0xb1, 0x8e, 0xdf, 0x01, 0x48, 0x1f, - 0xdf, 0x64, 0x1d, 0xed, 0x03, 0xc8, 0xbc, 0x4c, 0xda, 0xbd, 0x56, 0x90, 0x23, 0xeb, 0xbd, 0x46, - 0xf5, 0x2e, 0x39, 0xf3, 0x58, 0xaf, 0x1f, 0xf8, 0x89, 0x78, 0x88, 0xf3, 0xb3, 0xd2, 0x3d, 0x36, - 0x80, 0x96, 0xf9, 0x2c, 0x26, 0x53, 0xe7, 0x3f, 0x05, 0x0f, 0x7b, 0x76, 0xaf, 0x17, 0xe6, 0x29, - 0x5a, 0xa6, 0x36, 0xae, 0x3a, 0x6d, 0x6c, 0x63, 0x42, 0x25, 0xd2, 0x56, 0x86, 0x82, 0xc3, 0xd3, - 0xd7, 0x2f, 0xd9, 0x0d, 0x83, 0xe9, 0x72, 0x6f, 0x6f, 0x76, 0x3f, 0x98, 0x92, 0x2b, 0xdb, 0xfa, - 0x80, 0xda, 0x5a, 0x75, 0x18, 0xb6, 0xd5, 0xa7, 0x32, 0xea, 0xed, 0xcd, 0xcf, 0x4a, 0xf7, 0x1e, - 0xfe, 0xbb, 0x3b, 0xd0, 0xd0, 0x67, 0xc3, 0xec, 0xa7, 0x30, 0x67, 0xc5, 0x2e, 0x32, 0x35, 0x8c, - 0xa2, 0x50, 0xc7, 0xee, 0x8d, 0xe2, 0x4c, 0xd9, 0xf0, 0x4d, 0x6a, 0xb8, 0xc3, 0x56, 0xb0, 0x61, - 0x19, 0xfc, 0x77, 0x9f, 0xa2, 0x70, 0xc5, 0x25, 0xbe, 0x37, 0x86, 0x24, 0x13, 0x8d, 0xdd, 0xc8, - 0x0a, 0x17, 0xab, 0xb5, 0x0f, 0xa6, 0xe4, 0xca, 0xe6, 0x6e, 0x50, 0x73, 0x2b, 0x6c, 0xd9, 0x6c, - 0x4e, 0x9f, 0xd7, 0x72, 0xba, 0xb9, 0x6a, 0x3e, 0x0c, 0xc9, 0x3e, 0xd0, 0x84, 0x55, 0xf4, 0x60, - 0xa4, 0x26, 0x91, 0xfc, 0xab, 0x91, 0x4e, 0x87, 0x9a, 0x62, 0x8c, 0x96, 0xcf, 0x7c, 0x17, 0x92, - 0x1d, 0x41, 0xd3, 0x78, 0x3e, 0x8a, 0x5d, 0x9b, 0xfa, 0xd4, 0x55, 0xb7, 0x5b, 0x94, 0x55, 0x34, - 0x14, 0xb3, 0xfe, 0xfb, 0xa8, 0xe8, 0xfc, 0x18, 0x1a, 0xfa, 0x41, 0x22, 0xb6, 0x6a, 0x3c, 0x10, - 0x65, 0x3e, 0xa0, 0xd4, 0xed, 0xe4, 0x33, 0x8a, 0x88, 0xcf, 0xac, 0x1d, 0x89, 0xef, 0x35, 0x34, - 0x8d, 0x47, 0x87, 0xf4, 0x00, 0xf2, 0x0f, 0x1b, 0xe9, 0x01, 0x14, 0xbc, 0x51, 0xe4, 0x2c, 0x52, - 0x13, 0x4d, 0xd6, 0x20, 0xfa, 0x4e, 0xde, 0x86, 0x31, 0xdb, 0x83, 0xab, 0x52, 0x62, 0x1f, 0xf1, - 0xaf, 0xb2, 0x0c, 0x05, 0x6f, 0x71, 0x3e, 0x28, 0xb1, 0xc7, 0x50, 0x57, 0x6f, 0x4b, 0xb1, 0x95, - 0xe2, 0x37, 0xb2, 0xba, 0xab, 0x39, 0x5c, 0x8a, 0xd7, 0x1f, 0x02, 0xa4, 0x2f, 0x1c, 0x69, 0x21, - 0x91, 0x7b, 0x31, 0x49, 0x53, 0x40, 0xfe, 0x39, 0x24, 0x67, 0x85, 0x06, 0xd8, 0x66, 0x24, 0x24, - 0x02, 0x7e, 0xae, 0x2e, 0xa9, 0xff, 0x04, 0x9a, 0xc6, 0x23, 0x47, 0x7a, 0xfa, 0xf2, 0x0f, 0x24, - 0xe9, 0xe9, 0x2b, 0x78, 0x13, 0xc9, 0xe9, 0x52, 0xed, 0xcb, 0xce, 0x02, 0xd6, 0x1e, 0xfb, 0x27, - 0xc1, 0x48, 0x14, 0xc0, 0x05, 0x3a, 0x85, 0x39, 0xeb, 0x25, 0x23, 0xcd, 0xa1, 0x45, 0xef, 0x24, - 0x69, 0x0e, 0x2d, 0x7c, 0xfc, 0x48, 0xd1, 0x99, 0xb3, 0x88, 0xed, 0x9c, 0x51, 0x11, 0xa3, 0xa5, - 0x1f, 0x41, 0xd3, 0x78, 0x95, 0x48, 0x8f, 0x25, 0xff, 0x00, 0x92, 0x1e, 0x4b, 0xd1, 0x23, 0x46, - 0xcb, 0xd4, 0xc6, 0xbc, 0x43, 0xa4, 0x40, 0xd7, 0xad, 0xb1, 0xee, 0x9f, 0xc2, 0xbc, 0xfd, 0x4e, - 0x91, 0xe6, 0xfd, 0xc2, 0x17, 0x8f, 0x34, 0xef, 0x4f, 0x79, 0xdc, 0x48, 0x92, 0xf4, 0xbd, 0x25, - 0xdd, 0xc8, 0xfd, 0xcf, 0x65, 0x74, 0xd9, 0x17, 0xec, 0xfb, 0x28, 0xe0, 0xe4, 0xfd, 0x77, 0xb6, - 0x6a, 0x50, 0xad, 0x79, 0x4b, 0x5e, 0xf3, 0x4b, 0xee, 0xaa, 0xbc, 0x4d, 0xcc, 0xe2, 0xc2, 0x38, - 0xed, 0x5a, 0x74, 0x0f, 0xde, 0xd8, 0xb5, 0xcc, 0xab, 0xf2, 0xc6, 0xae, 0x65, 0x5d, 0x97, 0xcf, - 0xee, 0x5a, 0x89, 0x8f, 0x75, 0x04, 0xb0, 0x90, 0xb9, 0x5f, 0xa1, 0xb9, 0xa2, 0xf8, 0x0a, 0x5c, - 0xf7, 0xe6, 0xbb, 0xaf, 0x65, 0xd8, 0x12, 0x44, 0x09, 0xc1, 0xfb, 0xea, 0xc2, 0xe1, 0xef, 0x42, - 0xcb, 0x7c, 0x3b, 0x85, 0x99, 0xac, 0x9c, 0x6d, 0xe9, 0x7a, 0x61, 0x9e, 0xbd, 0xb8, 0xac, 0x65, - 0x36, 0xc3, 0x7e, 0x00, 0x2b, 0x9a, 0xd5, 0xcd, 0x90, 0xfd, 0x98, 0xdd, 0x2a, 0x08, 0xe4, 0x37, - 0xf5, 0xb8, 0xee, 0xb5, 0xa9, 0x91, 0xfe, 0x0f, 0x4a, 0x48, 0x34, 0xf6, 0x83, 0x14, 0xe9, 0x86, - 0x51, 0xf4, 0x0e, 0x47, 0xba, 0x61, 0x14, 0xbe, 0x62, 0xa1, 0x88, 0x86, 0x2d, 0x59, 0x73, 0x24, - 0x0e, 0xe2, 0xd9, 0x8f, 0x60, 0xc1, 0xb8, 0x14, 0x75, 0x78, 0x11, 0xf4, 0x35, 0x03, 0xe4, 0xef, - 0xeb, 0x76, 0x8b, 0xac, 0x14, 0x67, 0x95, 0xea, 0x5f, 0x74, 0xac, 0xc9, 0x41, 0xe2, 0xdf, 0x82, - 0xa6, 0x79, 0xe1, 0xea, 0x1d, 0xf5, 0xae, 0x1a, 0x59, 0xe6, 0x75, 0xd3, 0x07, 0x25, 0x76, 0x20, - 0x02, 0xb2, 0xf4, 0xe3, 0x98, 0x61, 0x94, 0xdd, 0x3e, 0xed, 0x47, 0x33, 0xf5, 0x42, 0x16, 0x3d, - 0x97, 0x7a, 0xb7, 0xf4, 0xa0, 0xc4, 0xfe, 0x4e, 0x09, 0x5a, 0xd6, 0x85, 0x28, 0x2b, 0xbc, 0x25, - 0xd3, 0xb3, 0x8e, 0x99, 0x67, 0x76, 0xcd, 0x71, 0x69, 0xd8, 0x7b, 0xf7, 0xbe, 0x6b, 0x4d, 0xeb, - 0xe7, 0x96, 0x43, 0x6d, 0x3d, 0xfb, 0x42, 0xe6, 0x17, 0xd9, 0x02, 0xe6, 0x2d, 0xe9, 0x2f, 0x1e, - 0x94, 0xd8, 0x1f, 0x96, 0x60, 0xde, 0x76, 0x03, 0xeb, 0xe1, 0x16, 0x3a, 0x9c, 0xf5, 0xe2, 0x4f, - 0xf1, 0x1d, 0xff, 0x88, 0x7a, 0xf9, 0xf2, 0x9e, 0x6b, 0xf5, 0x52, 0x3e, 0x7e, 0xf2, 0xab, 0xf5, - 0x96, 0x7d, 0x26, 0x9e, 0x74, 0x56, 0x87, 0x35, 0x2c, 0xff, 0xb0, 0xb0, 0x26, 0x18, 0xf3, 0x29, - 0x60, 0x5a, 0x84, 0x9f, 0x88, 0x97, 0x21, 0xd5, 0x79, 0x02, 0xd2, 0xdd, 0xfb, 0x7e, 0xef, 0xdc, - 0xa6, 0x31, 0xdd, 0x74, 0xae, 0x59, 0x63, 0xca, 0xee, 0xf0, 0x1b, 0xa2, 0x77, 0xf2, 0x15, 0xdf, - 0x74, 0x8b, 0xca, 0xbd, 0xec, 0x3b, 0xbd, 0x93, 0x23, 0xd1, 0x49, 0x59, 0xdc, 0x62, 0x8e, 0xf7, - 0xac, 0xc6, 0xb9, 0x47, 0x7d, 0xbd, 0xed, 0xdc, 0x9a, 0xda, 0xd7, 0xfb, 0xe4, 0xcc, 0xc5, 0x1e, - 0x1f, 0x00, 0xa4, 0x07, 0xab, 0x2c, 0x73, 0xb0, 0xa7, 0x45, 0x46, 0xfe, 0xec, 0xd5, 0xe6, 0x40, - 0x75, 0xfe, 0x87, 0x35, 0xfe, 0x58, 0x08, 0xc0, 0x67, 0xea, 0x48, 0xd0, 0x54, 0x73, 0xec, 0x13, - 0x50, 0x4b, 0xcd, 0xc9, 0xd6, 0x6f, 0x89, 0x3f, 0x7d, 0xbe, 0xf8, 0x0a, 0xe6, 0xf6, 0xc2, 0xf0, - 0xcd, 0x64, 0xac, 0x23, 0x4f, 0xec, 0x73, 0x96, 0x5d, 0x2f, 0x3e, 0xed, 0x66, 0x46, 0xe1, 0xac, - 0x51, 0x55, 0x5d, 0xd6, 0x31, 0xaa, 0xba, 0xff, 0x79, 0x7a, 0x70, 0xfb, 0x05, 0xf3, 0x60, 0x51, - 0x4b, 0x55, 0xdd, 0xf1, 0xae, 0x5d, 0x8d, 0x25, 0x4b, 0xb3, 0x4d, 0x58, 0xfa, 0xb8, 0xea, 0xed, - 0xfd, 0x58, 0xd5, 0x49, 0x32, 0xa5, 0xb5, 0xcd, 0xfb, 0x74, 0xdd, 0x83, 0x0e, 0x2b, 0x96, 0xd2, - 0x8e, 0xeb, 0x53, 0x8e, 0xee, 0x9c, 0x05, 0xda, 0x3b, 0xcd, 0xd8, 0xbb, 0x88, 0xf8, 0xcf, 0xee, - 0x7f, 0x2e, 0x8f, 0x41, 0xbe, 0x50, 0x3b, 0x8d, 0x3a, 0x27, 0xb2, 0x76, 0x9a, 0xcc, 0xc1, 0x92, - 0xb5, 0xd3, 0xe4, 0x0e, 0x96, 0xac, 0xa9, 0x56, 0xe7, 0x54, 0x6c, 0x08, 0x8b, 0xb9, 0xb3, 0x28, - 0xbd, 0xc9, 0x4c, 0x3b, 0xc1, 0xea, 0xae, 0x4d, 0x2f, 0x60, 0xb7, 0x76, 0xcf, 0x6e, 0xed, 0x10, - 0xe6, 0xb6, 0xb9, 0x98, 0x2c, 0x11, 0x6a, 0x9b, 0xb9, 0x55, 0x67, 0x06, 0xf2, 0x66, 0xb7, 0x04, - 0xca, 0xb3, 0x55, 0x09, 0x8a, 0x71, 0x65, 0x3f, 0x86, 0xe6, 0x53, 0x9e, 0xa8, 0xd8, 0x5a, 0xad, - 0xcc, 0x66, 0x82, 0x6d, 0xbb, 0x05, 0xa1, 0xb9, 0x36, 0xcd, 0x50, 0x6d, 0xf7, 0xf9, 0xe0, 0x84, - 0x0b, 0xe1, 0xd4, 0xf3, 0x07, 0x5f, 0xb0, 0x3f, 0x47, 0x95, 0xeb, 0xcb, 0x05, 0x2b, 0x46, 0xa0, - 0xa4, 0x59, 0xf9, 0x42, 0x06, 0x2f, 0xaa, 0x39, 0x08, 0x07, 0xdc, 0x50, 0xaa, 0x02, 0x68, 0x1a, - 0x17, 0x71, 0x34, 0x03, 0xe5, 0xef, 0x75, 0x69, 0x06, 0x2a, 0xb8, 0xb7, 0xe3, 0xdc, 0xa5, 0x76, - 0x1c, 0xb6, 0x96, 0xb6, 0x23, 0xee, 0xea, 0xa4, 0x2d, 0xdd, 0xff, 0xdc, 0x1b, 0x25, 0x5f, 0xb0, - 0xd7, 0xf4, 0x18, 0x91, 0x19, 0x3b, 0x9c, 0x6a, 0xe7, 0xd9, 0x30, 0x63, 0x3d, 0x59, 0x46, 0x96, - 0xad, 0xb1, 0x8b, 0xa6, 0x48, 0xf7, 0xfa, 0x0e, 0xc0, 0x61, 0x12, 0x8e, 0xb7, 0x3d, 0x3e, 0x0a, - 0x83, 0x54, 0xd6, 0xa6, 0x91, 0xab, 0xa9, 0xfc, 0x32, 0xc2, 0x57, 0xd9, 0x6b, 0xc3, 0x9c, 0xb1, - 0xc2, 0xaf, 0x15, 0x71, 0x4d, 0x0d, 0x6e, 0xd5, 0x13, 0x52, 0x10, 0xe0, 0xfa, 0xa0, 0xc4, 0x36, - 0x00, 0xd2, 0xc3, 0x48, 0x6d, 0x9c, 0xe4, 0xce, 0x39, 0xb5, 0xd8, 0x2b, 0x38, 0xb9, 0x3c, 0x80, - 0x46, 0x7a, 0xba, 0xb5, 0x9a, 0x5e, 0x77, 0xb3, 0xce, 0xc2, 0xf4, 0x0e, 0x9e, 0x3b, 0x73, 0x72, - 0xda, 0x34, 0x55, 0xc0, 0xea, 0x38, 0x55, 0x74, 0x90, 0xe4, 0xc3, 0x92, 0xe8, 0xa0, 0x56, 0x70, - 0x28, 0xe2, 0x52, 0x8d, 0xa4, 0xe0, 0xdc, 0x47, 0x73, 0x73, 0xe1, 0x81, 0x88, 0xe5, 0x63, 0x41, - 0x6a, 0x15, 0xd1, 0x9e, 0x28, 0x9a, 0x47, 0xb0, 0x98, 0xf3, 0xb1, 0x6b, 0x96, 0x9e, 0x76, 0x88, - 0xa2, 0x59, 0x7a, 0xaa, 0x7b, 0xde, 0xb9, 0x4a, 0x4d, 0x2e, 0x38, 0x40, 0x36, 0xd5, 0xb9, 0x9f, - 0xf4, 0x4f, 0xb1, 0xb9, 0xdf, 0x2f, 0xc1, 0x52, 0x81, 0x0b, 0x9d, 0x7d, 0xa8, 0xcc, 0xf3, 0xa9, - 0xee, 0xf5, 0x6e, 0xa1, 0x87, 0xd5, 0x39, 0xa4, 0x76, 0x9e, 0xb3, 0xef, 0x59, 0x1b, 0x9b, 0x70, - 0x6e, 0x4a, 0xce, 0x7c, 0xa7, 0x52, 0x51, 0xa8, 0x51, 0xfc, 0x0c, 0x56, 0x45, 0x47, 0x36, 0x86, - 0xc3, 0x8c, 0xf7, 0xf7, 0x66, 0xee, 0xbf, 0xba, 0x58, 0x5e, 0xed, 0xee, 0xf4, 0xff, 0xfa, 0x32, - 0x45, 0x01, 0x16, 0x5d, 0x65, 0x13, 0x68, 0x67, 0x3d, 0xaa, 0x6c, 0x7a, 0x5d, 0xdd, 0x5b, 0x96, - 0xa1, 0x59, 0xe0, 0x85, 0xfd, 0x0d, 0x6a, 0xec, 0x96, 0xd3, 0x2d, 0x9a, 0x17, 0x61, 0x7b, 0xe2, - 0x7a, 0xfc, 0x05, 0xed, 0xfe, 0xcd, 0x8c, 0x53, 0x35, 0x30, 0xcd, 0x5f, 0xad, 0x4d, 0xdd, 0x62, - 0xef, 0xf1, 0x47, 0xd4, 0xfc, 0x9a, 0x73, 0xbd, 0xa8, 0xf9, 0x48, 0x7c, 0x22, 0x8c, 0xde, 0xd5, - 0x2c, 0x5f, 0xab, 0x1e, 0xac, 0x15, 0xad, 0xf7, 0x54, 0xeb, 0x25, 0x33, 0xd7, 0x57, 0x48, 0xb7, - 0x6b, 0x99, 0xee, 0x5e, 0xcd, 0x3e, 0x05, 0x7e, 0x65, 0xcd, 0x3e, 0x45, 0xfe, 0x61, 0x5b, 0xaf, - 0x51, 0x9e, 0xe1, 0xcf, 0x4a, 0xf7, 0x36, 0xef, 0xfc, 0xe8, 0x37, 0x4e, 0xfc, 0xe4, 0x74, 0x72, - 0xb4, 0xde, 0x0f, 0x47, 0xf7, 0x87, 0xca, 0xad, 0x27, 0x6f, 0x21, 0xdc, 0x1f, 0x06, 0x83, 0xfb, - 0x54, 0xed, 0xd1, 0x0c, 0xfd, 0x1b, 0xaa, 0x6f, 0xfd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8b, - 0x4e, 0x52, 0x4c, 0xb8, 0x6a, 0x00, 0x00, + // 8678 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7d, 0x5d, 0x6c, 0x24, 0x49, + 0xb6, 0x56, 0xd7, 0x9f, 0x5d, 0x75, 0xaa, 0x6c, 0x97, 0xc3, 0x6e, 0xbb, 0xba, 0xa6, 0xa7, 0xc7, + 0x93, 0xdb, 0x77, 0xba, 0xb7, 0x77, 0xd6, 0xdd, 0xe3, 0xdd, 0x1d, 0xe6, 0x4e, 0x73, 0xb9, 0xf8, + 0xaf, 0xdb, 0xbd, 0xe3, 0x76, 0x7b, 0xd3, 0xdd, 0xdb, 0xec, 0xee, 0xbd, 0xaa, 0x4d, 0x57, 0x85, + 0xed, 0xdc, 0xae, 0xca, 0xac, 0xcd, 0xcc, 0xb2, 0xdb, 0x3b, 0x0c, 0x12, 0x08, 0x21, 0xc4, 0x0b, + 0x1a, 0x78, 0x01, 0x04, 0xba, 0xd2, 0x5e, 0x24, 0xee, 0x85, 0x07, 0xe0, 0x01, 0x09, 0xd0, 0x95, + 0x78, 0xe0, 0x01, 0x09, 0x09, 0xf1, 0xc0, 0x03, 0x12, 0x0f, 0xac, 0x10, 0x48, 0x68, 0x85, 0x78, + 0x41, 0xe2, 0x1d, 0x9d, 0x13, 0x3f, 0x19, 0x91, 0x99, 0xd5, 0xee, 0xd9, 0x5d, 0xee, 0x93, 0x2b, + 0xbe, 0x88, 0x8c, 0xdf, 0x73, 0x4e, 0x9c, 0x73, 0xe2, 0x44, 0x18, 0x1a, 0xd1, 0xb8, 0xbf, 0x3e, + 0x8e, 0xc2, 0x24, 0x64, 0xb5, 0x61, 0x10, 0x8d, 0xfb, 0xdd, 0x9b, 0xa7, 0x61, 0x78, 0x3a, 0xe4, + 0xf7, 0xbd, 0xb1, 0x7f, 0xdf, 0x0b, 0x82, 0x30, 0xf1, 0x12, 0x3f, 0x0c, 0x62, 0x51, 0xc8, 0xf9, + 0x31, 0xcc, 0x3f, 0xe6, 0xc1, 0x11, 0xe7, 0x03, 0x97, 0xff, 0x74, 0xc2, 0xe3, 0x84, 0x7d, 0x03, + 0x16, 0x3d, 0xfe, 0x33, 0xce, 0x07, 0xbd, 0xb1, 0x17, 0xc7, 0xe3, 0xb3, 0xc8, 0x8b, 0x79, 0xa7, + 0xb4, 0x56, 0xba, 0xdb, 0x72, 0xdb, 0x22, 0xe3, 0x50, 0xe3, 0xec, 0x7d, 0x68, 0xc5, 0x58, 0x94, + 0x07, 0x49, 0x14, 0x8e, 0x2f, 0x3b, 0x65, 0x2a, 0xd7, 0x44, 0x6c, 0x57, 0x40, 0xce, 0x10, 0x16, + 0x74, 0x0b, 0xf1, 0x38, 0x0c, 0x62, 0xce, 0x1e, 0xc0, 0x72, 0xdf, 0x1f, 0x9f, 0xf1, 0xa8, 0x47, + 0x1f, 0x8f, 0x02, 0x3e, 0x0a, 0x03, 0xbf, 0xdf, 0x29, 0xad, 0x55, 0xee, 0x36, 0x5c, 0x26, 0xf2, + 0xf0, 0x8b, 0xa7, 0x32, 0x87, 0xdd, 0x81, 0x05, 0x1e, 0x08, 0x9c, 0x0f, 0xe8, 0x2b, 0xd9, 0xd4, + 0x7c, 0x0a, 0xe3, 0x07, 0xce, 0x5f, 0x2f, 0xc3, 0xe2, 0x93, 0xc0, 0x4f, 0x5e, 0x7a, 0xc3, 0x21, + 0x4f, 0xd4, 0x98, 0xee, 0xc0, 0xc2, 0x05, 0x01, 0x34, 0xa6, 0x8b, 0x30, 0x1a, 0xc8, 0x11, 0xcd, + 0x0b, 0xf8, 0x50, 0xa2, 0x53, 0x7b, 0x56, 0x9e, 0xda, 0xb3, 0xc2, 0xe9, 0xaa, 0x4c, 0x99, 0xae, + 0x3b, 0xb0, 0x10, 0xf1, 0x7e, 0x78, 0xce, 0xa3, 0xcb, 0xde, 0x85, 0x1f, 0x0c, 0xc2, 0x8b, 0x4e, + 0x75, 0xad, 0x74, 0xb7, 0xe6, 0xce, 0x2b, 0xf8, 0x25, 0xa1, 0x6c, 0x0b, 0x16, 0xfa, 0x67, 0x5e, + 0x10, 0xf0, 0x61, 0xef, 0xd8, 0xeb, 0xbf, 0x9a, 0x8c, 0xe3, 0x4e, 0x6d, 0xad, 0x74, 0xb7, 0xb9, + 0x71, 0x63, 0x9d, 0x56, 0x75, 0x7d, 0xfb, 0xcc, 0x0b, 0xb6, 0x28, 0xe7, 0x28, 0xf0, 0xc6, 0xf1, + 0x59, 0x98, 0xb8, 0xf3, 0xf2, 0x0b, 0x01, 0xc7, 0xce, 0x32, 0x30, 0x73, 0x26, 0xc4, 0xdc, 0x3b, + 0xff, 0xa4, 0x04, 0x4b, 0x2f, 0x82, 0x61, 0xd8, 0x7f, 0xf5, 0x2b, 0x4e, 0x51, 0xc1, 0x18, 0xca, + 0x6f, 0x3b, 0x86, 0xca, 0x57, 0x1d, 0xc3, 0x0a, 0x2c, 0xdb, 0x9d, 0x95, 0xa3, 0xe0, 0x70, 0x1d, + 0xbf, 0x3e, 0xe5, 0xaa, 0x5b, 0x6a, 0x18, 0x5f, 0x87, 0x76, 0x7f, 0x12, 0x45, 0x3c, 0xc8, 0x8d, + 0x63, 0x41, 0xe2, 0x7a, 0x20, 0xef, 0x43, 0x2b, 0xe0, 0x17, 0x69, 0x31, 0x49, 0xbb, 0x01, 0xbf, + 0x50, 0x45, 0x9c, 0x0e, 0xac, 0x64, 0x9b, 0x91, 0x1d, 0xf8, 0x6f, 0x25, 0xa8, 0xbe, 0x48, 0x5e, + 0x87, 0x6c, 0x1d, 0xaa, 0xc9, 0xe5, 0x58, 0x70, 0xc8, 0xfc, 0x06, 0x93, 0x43, 0xdb, 0x1c, 0x0c, + 0x22, 0x1e, 0xc7, 0xcf, 0x2f, 0xc7, 0xdc, 0x6d, 0x79, 0x22, 0xd1, 0xc3, 0x72, 0xac, 0x03, 0xb3, + 0x32, 0x4d, 0x0d, 0x36, 0x5c, 0x95, 0x64, 0xb7, 0x00, 0xbc, 0x51, 0x38, 0x09, 0x92, 0x5e, 0xec, + 0x25, 0x34, 0x55, 0x15, 0xd7, 0x40, 0xd8, 0x4d, 0x68, 0x8c, 0x5f, 0xf5, 0xe2, 0x7e, 0xe4, 0x8f, + 0x13, 0x22, 0x9b, 0x86, 0x9b, 0x02, 0xec, 0x1b, 0x50, 0x0f, 0x27, 0xc9, 0x38, 0xf4, 0x83, 0x44, + 0x92, 0xca, 0x82, 0xec, 0xcb, 0xb3, 0x49, 0x72, 0x88, 0xb0, 0xab, 0x0b, 0xb0, 0xdb, 0x30, 0xd7, + 0x0f, 0x83, 0x13, 0x3f, 0x1a, 0x09, 0x61, 0xd0, 0x99, 0xa1, 0xd6, 0x6c, 0xd0, 0xf9, 0x57, 0x65, + 0x68, 0x3e, 0x8f, 0xbc, 0x20, 0xf6, 0xfa, 0x08, 0x60, 0xd7, 0x93, 0xd7, 0xbd, 0x33, 0x2f, 0x3e, + 0xa3, 0xd1, 0x36, 0x5c, 0x95, 0x64, 0x2b, 0x30, 0x23, 0x3a, 0x4a, 0x63, 0xaa, 0xb8, 0x32, 0xc5, + 0x3e, 0x84, 0xc5, 0x60, 0x32, 0xea, 0xd9, 0x6d, 0x55, 0x88, 0x5a, 0xf2, 0x19, 0x38, 0x01, 0xc7, + 0xb8, 0xd6, 0xa2, 0x09, 0x31, 0x42, 0x03, 0x61, 0x0e, 0xb4, 0x64, 0x8a, 0xfb, 0xa7, 0x67, 0x62, + 0x98, 0x35, 0xd7, 0xc2, 0xb0, 0x8e, 0xc4, 0x1f, 0xf1, 0x5e, 0x9c, 0x78, 0xa3, 0xb1, 0x1c, 0x96, + 0x81, 0x50, 0x7e, 0x98, 0x78, 0xc3, 0xde, 0x09, 0xe7, 0x71, 0x67, 0x56, 0xe6, 0x6b, 0x84, 0x7d, + 0x00, 0xf3, 0x03, 0x1e, 0x27, 0x3d, 0xb9, 0x28, 0x3c, 0xee, 0xd4, 0x89, 0xf5, 0x33, 0x28, 0xd6, + 0x13, 0x79, 0x17, 0x3d, 0x9c, 0x00, 0xfe, 0xba, 0xd3, 0x10, 0x7d, 0x4d, 0x11, 0xa4, 0x9c, 0xc7, + 0x3c, 0x31, 0x66, 0x2f, 0x96, 0x14, 0xea, 0xec, 0x03, 0x33, 0xe0, 0x1d, 0x9e, 0x78, 0xfe, 0x30, + 0x66, 0x1f, 0x43, 0x2b, 0x31, 0x0a, 0x93, 0x28, 0x6c, 0x6a, 0x72, 0x32, 0x3e, 0x70, 0xad, 0x72, + 0xce, 0x63, 0xa8, 0x3f, 0xe2, 0x7c, 0xdf, 0x1f, 0xf9, 0x09, 0x5b, 0x81, 0xda, 0x89, 0xff, 0x9a, + 0x0b, 0x82, 0xaf, 0xec, 0x5d, 0x73, 0x45, 0x92, 0x75, 0x61, 0x76, 0xcc, 0xa3, 0x3e, 0x57, 0xcb, + 0xb3, 0x77, 0xcd, 0x55, 0xc0, 0xd6, 0x2c, 0xd4, 0x86, 0xf8, 0xb1, 0xf3, 0xbf, 0x2b, 0xd0, 0x3c, + 0xe2, 0x81, 0x66, 0x24, 0x06, 0x55, 0x1c, 0xb2, 0x64, 0x1e, 0xfa, 0xcd, 0xde, 0x83, 0x26, 0x4d, + 0x43, 0x9c, 0x44, 0x7e, 0x70, 0x2a, 0xe9, 0x17, 0x10, 0x3a, 0x22, 0x84, 0xb5, 0xa1, 0xe2, 0x8d, + 0x14, 0xed, 0xe2, 0x4f, 0x64, 0xb2, 0xb1, 0x77, 0x39, 0x42, 0x7e, 0xd4, 0xab, 0xda, 0x72, 0x9b, + 0x12, 0xdb, 0xc3, 0x65, 0x5d, 0x87, 0x25, 0xb3, 0x88, 0xaa, 0xbd, 0x46, 0xb5, 0x2f, 0x1a, 0x25, + 0x65, 0x23, 0x77, 0x60, 0x41, 0x95, 0x8f, 0x44, 0x67, 0x69, 0x9d, 0x1b, 0xee, 0xbc, 0x84, 0xd5, + 0x10, 0xee, 0x42, 0xfb, 0xc4, 0x0f, 0xbc, 0x61, 0xaf, 0x3f, 0x4c, 0xce, 0x7b, 0x03, 0x3e, 0x4c, + 0x3c, 0x5a, 0xf1, 0x9a, 0x3b, 0x4f, 0xf8, 0xf6, 0x30, 0x39, 0xdf, 0x41, 0x94, 0x7d, 0x08, 0x8d, + 0x13, 0xce, 0x7b, 0x34, 0x13, 0x9d, 0xba, 0xc5, 0x3d, 0x6a, 0x76, 0xdd, 0xfa, 0x89, 0x9a, 0xe7, + 0x0f, 0xa1, 0x1d, 0x4e, 0x92, 0xd3, 0xd0, 0x0f, 0x4e, 0x7b, 0x28, 0xaf, 0x7a, 0xfe, 0x80, 0x28, + 0xa0, 0xba, 0x55, 0x7e, 0x50, 0x72, 0xe7, 0x55, 0x1e, 0x4a, 0x8e, 0x27, 0x03, 0xf6, 0x2e, 0x00, + 0xb5, 0x2f, 0x2a, 0x87, 0xb5, 0xd2, 0xdd, 0x39, 0xb7, 0x81, 0x88, 0xa8, 0xec, 0x53, 0xa8, 0xd3, + 0x9c, 0x26, 0xc3, 0xf3, 0x4e, 0x93, 0x16, 0xfd, 0x3d, 0xd9, 0xb2, 0xb1, 0x1a, 0xeb, 0x3b, 0x3c, + 0x4e, 0x9e, 0x0f, 0xcf, 0x71, 0x4f, 0xbd, 0x74, 0x67, 0x07, 0x22, 0xd5, 0xfd, 0x14, 0x5a, 0x66, + 0x06, 0x4e, 0xff, 0x2b, 0x7e, 0x49, 0x4b, 0x56, 0x75, 0xf1, 0x27, 0x5b, 0x86, 0xda, 0xb9, 0x37, + 0x9c, 0x70, 0x29, 0xdc, 0x44, 0xe2, 0xd3, 0xf2, 0x27, 0x25, 0xe7, 0x5f, 0x96, 0xa0, 0x25, 0x5a, + 0x90, 0x9b, 0xf2, 0x6d, 0x98, 0x53, 0xd3, 0xca, 0xa3, 0x28, 0x8c, 0x24, 0x8f, 0xdb, 0x20, 0xbb, + 0x07, 0x6d, 0x05, 0x8c, 0x23, 0xee, 0x8f, 0xbc, 0x53, 0x55, 0x77, 0x0e, 0x67, 0x1b, 0x69, 0x8d, + 0x51, 0x38, 0x49, 0xb8, 0x14, 0xff, 0x2d, 0x39, 0x3e, 0x17, 0x31, 0xd7, 0x2e, 0x82, 0x3c, 0x5e, + 0x40, 0x2f, 0x16, 0xe6, 0x7c, 0x59, 0x02, 0x86, 0x5d, 0x7f, 0x1e, 0x8a, 0x2a, 0xe4, 0x72, 0x67, + 0x49, 0xad, 0xf4, 0xd6, 0xa4, 0x56, 0x9e, 0x46, 0x6a, 0x0e, 0xd4, 0x44, 0xcf, 0xab, 0x05, 0x3d, + 0x17, 0x59, 0xdf, 0xad, 0xd6, 0x2b, 0xed, 0xaa, 0xf3, 0x5f, 0x2a, 0xb0, 0xbc, 0x2d, 0xf6, 0xae, + 0xcd, 0x7e, 0x9f, 0x8f, 0x35, 0x11, 0xbe, 0x07, 0xcd, 0x20, 0x1c, 0xf0, 0xde, 0x78, 0x72, 0xac, + 0xd6, 0xa6, 0xe5, 0x02, 0x42, 0x87, 0x84, 0x10, 0x7d, 0x9c, 0x79, 0x7e, 0x20, 0x3a, 0x2d, 0xe6, + 0xb2, 0x41, 0x08, 0x75, 0xf9, 0x03, 0x58, 0x18, 0xf3, 0x60, 0x60, 0xd2, 0x9a, 0xd0, 0x2e, 0xe6, + 0x24, 0x2c, 0xc9, 0xec, 0x3d, 0x68, 0x9e, 0x4c, 0x44, 0x39, 0x64, 0xc1, 0x2a, 0xd1, 0x00, 0x48, + 0x68, 0x73, 0x94, 0xb0, 0x1b, 0x50, 0x1f, 0x4f, 0xe2, 0x33, 0xca, 0xad, 0x51, 0xee, 0x2c, 0xa6, + 0x31, 0xeb, 0x5d, 0x80, 0xc1, 0x24, 0x4e, 0x24, 0x89, 0xce, 0x50, 0x66, 0x03, 0x11, 0x41, 0xa2, + 0xdf, 0x84, 0xa5, 0x91, 0xf7, 0xba, 0x47, 0xb4, 0xd3, 0xf3, 0x83, 0xde, 0xc9, 0x90, 0xc4, 0xef, + 0x2c, 0x95, 0x6b, 0x8f, 0xbc, 0xd7, 0xdf, 0xc7, 0x9c, 0x27, 0xc1, 0x23, 0xc2, 0x91, 0x3f, 0xd5, + 0xbe, 0x1f, 0xf1, 0x98, 0x47, 0xe7, 0x9c, 0x58, 0xaa, 0xaa, 0x37, 0x77, 0x57, 0xa0, 0xd8, 0xa3, + 0x11, 0x8e, 0x3b, 0x19, 0xf6, 0x05, 0xff, 0xb8, 0xb3, 0x23, 0x3f, 0xd8, 0x4b, 0x86, 0x7d, 0x76, + 0x13, 0x00, 0x19, 0x72, 0xcc, 0xa3, 0xde, 0xab, 0x0b, 0x62, 0x9a, 0x2a, 0x31, 0xe0, 0x21, 0x8f, + 0x3e, 0xbb, 0x60, 0xef, 0x40, 0xa3, 0x1f, 0x13, 0x47, 0x7b, 0x97, 0x9d, 0x26, 0x71, 0x54, 0xbd, + 0x1f, 0x23, 0x2f, 0x7b, 0x97, 0xec, 0x43, 0x60, 0xd8, 0x5b, 0x8f, 0x56, 0x81, 0x0f, 0xa8, 0xfa, + 0xb8, 0xd3, 0xa2, 0x52, 0xd8, 0xd9, 0x4d, 0x99, 0x81, 0xed, 0xc4, 0xec, 0x6b, 0x30, 0xa7, 0x3a, + 0x7b, 0x32, 0xf4, 0x4e, 0xe3, 0xce, 0x1c, 0x15, 0x6c, 0x49, 0xf0, 0x11, 0x62, 0xce, 0x4b, 0xa1, + 0x6d, 0x18, 0x6b, 0x2b, 0x79, 0x06, 0xf7, 0x3d, 0x42, 0x68, 0x5d, 0xeb, 0xae, 0x4c, 0x15, 0x2d, + 0x5a, 0xb9, 0x60, 0xd1, 0x9c, 0x9f, 0x97, 0xa0, 0x25, 0x6b, 0xa6, 0x2d, 0x9a, 0x3d, 0x00, 0xa6, + 0x56, 0x31, 0x79, 0xed, 0x0f, 0x7a, 0xc7, 0x97, 0x09, 0x8f, 0x05, 0xd1, 0xec, 0x5d, 0x73, 0x0b, + 0xf2, 0x50, 0x18, 0x59, 0x68, 0x9c, 0x44, 0x82, 0x9e, 0xf7, 0xae, 0xb9, 0xb9, 0x1c, 0x64, 0x2f, + 0x54, 0x02, 0x26, 0x49, 0xcf, 0x0f, 0x06, 0xfc, 0x35, 0x91, 0xd2, 0x9c, 0x6b, 0x61, 0x5b, 0xf3, + 0xd0, 0x32, 0xbf, 0x73, 0x7e, 0x02, 0x75, 0xa5, 0x42, 0xd0, 0xf6, 0x99, 0xe9, 0x97, 0x6b, 0x20, + 0xac, 0x0b, 0x75, 0xbb, 0x17, 0x6e, 0xfd, 0xab, 0xb4, 0xed, 0xfc, 0x39, 0x68, 0xef, 0x23, 0x11, + 0x05, 0x48, 0xb4, 0x52, 0x2f, 0x5a, 0x81, 0x19, 0x83, 0x79, 0x1a, 0xae, 0x4c, 0xe1, 0x0e, 0x75, + 0x16, 0xc6, 0x89, 0x6c, 0x87, 0x7e, 0x3b, 0xff, 0xae, 0x04, 0x6c, 0x37, 0x4e, 0xfc, 0x91, 0x97, + 0xf0, 0x47, 0x5c, 0x8b, 0x86, 0x67, 0xd0, 0xc2, 0xda, 0x9e, 0x87, 0x9b, 0x42, 0x4b, 0x11, 0xbb, + 0xeb, 0x37, 0x24, 0x3b, 0xe7, 0x3f, 0x58, 0x37, 0x4b, 0x0b, 0xa1, 0x6b, 0x55, 0x80, 0xdc, 0x96, + 0x78, 0xd1, 0x29, 0x4f, 0x48, 0x85, 0x91, 0x0a, 0x30, 0x08, 0x68, 0x3b, 0x0c, 0x4e, 0xba, 0xbf, + 0x0b, 0x8b, 0xb9, 0x3a, 0x4c, 0xf9, 0xdc, 0x28, 0x90, 0xcf, 0x15, 0x53, 0x3e, 0xf7, 0x61, 0xc9, + 0xea, 0x97, 0xa4, 0xb8, 0x0e, 0xcc, 0x22, 0x63, 0xa0, 0x86, 0x48, 0xbb, 0xbc, 0xab, 0x92, 0x6c, + 0x03, 0x96, 0x4f, 0x38, 0x8f, 0xbc, 0x84, 0x92, 0xc4, 0x3a, 0xb8, 0x26, 0xb2, 0xe6, 0xc2, 0x3c, + 0xe7, 0xbf, 0x97, 0x60, 0x01, 0x25, 0xe9, 0x53, 0x2f, 0xb8, 0x54, 0x73, 0xb5, 0x5f, 0x38, 0x57, + 0x77, 0x8d, 0x4d, 0xc9, 0x28, 0xfd, 0x55, 0x27, 0xaa, 0x92, 0x9d, 0x28, 0xb6, 0x06, 0x2d, 0xab, + 0xbb, 0x35, 0xa1, 0x92, 0xc5, 0x5e, 0x72, 0xc8, 0xa3, 0xad, 0xcb, 0x84, 0xff, 0xfa, 0x53, 0xf9, + 0x01, 0xb4, 0xd3, 0x6e, 0xcb, 0x79, 0x64, 0x50, 0x45, 0xc2, 0x94, 0x15, 0xd0, 0x6f, 0xe7, 0xef, + 0x97, 0x44, 0xc1, 0xed, 0xd0, 0xd7, 0xea, 0x1a, 0x16, 0x44, 0xad, 0x4f, 0x15, 0xc4, 0xdf, 0x53, + 0xd5, 0xdd, 0x5f, 0x7f, 0xb0, 0x28, 0x13, 0x63, 0x1e, 0x0c, 0x7a, 0xde, 0x70, 0x48, 0x82, 0xb8, + 0xee, 0xce, 0x62, 0x7a, 0x73, 0x38, 0x74, 0xee, 0xc0, 0xa2, 0xd1, 0xbb, 0x37, 0x8c, 0xe3, 0x00, + 0xd8, 0xbe, 0x1f, 0x27, 0x2f, 0x82, 0x78, 0x6c, 0x68, 0x43, 0xef, 0x40, 0x03, 0xa5, 0x2d, 0xf6, + 0x4c, 0x70, 0x6e, 0xcd, 0x45, 0xf1, 0x8b, 0xfd, 0x8a, 0x29, 0xd3, 0x7b, 0x2d, 0x33, 0xcb, 0x32, + 0xd3, 0x7b, 0x4d, 0x99, 0xce, 0x27, 0xb0, 0x64, 0xd5, 0x27, 0x9b, 0x7e, 0x1f, 0x6a, 0x93, 0xe4, + 0x75, 0xa8, 0x74, 0xd5, 0xa6, 0xa4, 0x10, 0xb4, 0x8a, 0x5c, 0x91, 0xe3, 0x3c, 0x84, 0xc5, 0x03, + 0x7e, 0x21, 0x19, 0x59, 0x75, 0xe4, 0x83, 0x2b, 0x2d, 0x26, 0xca, 0x77, 0xd6, 0x81, 0x99, 0x1f, + 0xa7, 0x0c, 0xa0, 0xec, 0xa7, 0x92, 0x65, 0x3f, 0x39, 0x1f, 0x00, 0x3b, 0xf2, 0x4f, 0x83, 0xa7, + 0x3c, 0x8e, 0xbd, 0x53, 0xcd, 0xfa, 0x6d, 0xa8, 0x8c, 0xe2, 0x53, 0x29, 0xaa, 0xf0, 0xa7, 0xf3, + 0x2d, 0x58, 0xb2, 0xca, 0xc9, 0x8a, 0x6f, 0x42, 0x23, 0xf6, 0x4f, 0x03, 0x2f, 0x99, 0x44, 0x5c, + 0x56, 0x9d, 0x02, 0xce, 0x23, 0x58, 0xfe, 0x3e, 0x8f, 0xfc, 0x93, 0xcb, 0xab, 0xaa, 0xb7, 0xeb, + 0x29, 0x67, 0xeb, 0xd9, 0x85, 0xeb, 0x99, 0x7a, 0x64, 0xf3, 0x82, 0x7c, 0xe5, 0x4a, 0xd6, 0x5d, + 0x91, 0x30, 0x64, 0x5f, 0xd9, 0x94, 0x7d, 0xce, 0x0b, 0x60, 0xdb, 0x61, 0x10, 0xf0, 0x7e, 0x72, + 0xc8, 0x79, 0x94, 0xba, 0x6e, 0x52, 0x5a, 0x6d, 0x6e, 0xac, 0xca, 0x99, 0xcd, 0x0a, 0x54, 0x49, + 0xc4, 0x0c, 0xaa, 0x63, 0x1e, 0x8d, 0xa8, 0xe2, 0xba, 0x4b, 0xbf, 0x9d, 0xeb, 0xb0, 0x64, 0x55, + 0x2b, 0x8d, 0xdd, 0x8f, 0xe0, 0xfa, 0x8e, 0x1f, 0xf7, 0xf3, 0x0d, 0x76, 0x60, 0x76, 0x3c, 0x39, + 0xee, 0xa5, 0x9c, 0xa8, 0x92, 0x68, 0xff, 0x64, 0x3f, 0x91, 0x95, 0xfd, 0xb5, 0x12, 0x54, 0xf7, + 0x9e, 0xef, 0x6f, 0xe3, 0x5e, 0xe1, 0x07, 0xfd, 0x70, 0x84, 0x1a, 0x98, 0x18, 0xb4, 0x4e, 0x4f, + 0xe5, 0xb0, 0x9b, 0xd0, 0x20, 0xc5, 0x0d, 0x4d, 0x3e, 0xa9, 0x07, 0xa5, 0x00, 0x9a, 0x9b, 0xfc, + 0xf5, 0xd8, 0x8f, 0xc8, 0x9e, 0x54, 0x56, 0x62, 0x95, 0xb6, 0x99, 0x7c, 0x86, 0xf3, 0xf3, 0x59, + 0x98, 0x95, 0x9b, 0xaf, 0xd8, 0xc8, 0x13, 0xff, 0x9c, 0xa7, 0x1b, 0x39, 0xa6, 0x50, 0x29, 0x8e, + 0xf8, 0x28, 0x4c, 0xb4, 0xfe, 0x26, 0x96, 0xc1, 0x06, 0xc9, 0x9c, 0x96, 0x4a, 0x84, 0x30, 0xc0, + 0x2b, 0xa2, 0x94, 0x05, 0xb2, 0x9b, 0x30, 0xab, 0x94, 0x81, 0xaa, 0xb6, 0x16, 0x14, 0x84, 0xb3, + 0xd1, 0xf7, 0xc6, 0x5e, 0xdf, 0x4f, 0x2e, 0xa5, 0x58, 0xd0, 0x69, 0xac, 0x7f, 0x18, 0xf6, 0xbd, + 0x61, 0xef, 0xd8, 0x1b, 0x7a, 0x41, 0x9f, 0x2b, 0x73, 0xdd, 0x02, 0xd1, 0x74, 0x95, 0xdd, 0x52, + 0xc5, 0x84, 0x79, 0x9b, 0x41, 0x71, 0x0f, 0xef, 0x87, 0xa3, 0x91, 0x9f, 0xa0, 0xc5, 0x4b, 0xaa, + 0x59, 0xc5, 0x35, 0x10, 0xe1, 0x1c, 0xa0, 0xd4, 0x85, 0x98, 0xc1, 0x86, 0x72, 0x0e, 0x18, 0x20, + 0xd6, 0x92, 0xd1, 0xd0, 0x2a, 0xae, 0x81, 0xe0, 0x5a, 0x4c, 0x82, 0x98, 0x27, 0xc9, 0x90, 0x0f, + 0x74, 0x87, 0x9a, 0x54, 0x2c, 0x9f, 0xc1, 0x1e, 0xc0, 0x92, 0x30, 0xc2, 0x63, 0x2f, 0x09, 0xe3, + 0x33, 0x3f, 0xee, 0xc5, 0x68, 0xae, 0xb6, 0xa8, 0x7c, 0x51, 0x16, 0xfb, 0x04, 0x56, 0x33, 0x70, + 0xc4, 0xfb, 0xdc, 0x3f, 0xe7, 0x03, 0x52, 0xe1, 0x2a, 0xee, 0xb4, 0x6c, 0xb6, 0x06, 0xcd, 0x60, + 0x32, 0xea, 0x4d, 0xc6, 0x03, 0x0f, 0x95, 0x98, 0x79, 0x52, 0x2e, 0x4d, 0x88, 0x7d, 0x04, 0x4a, + 0x4f, 0x93, 0xda, 0xe3, 0x82, 0x25, 0xe1, 0x90, 0x7a, 0x5d, 0xbb, 0x04, 0x12, 0x66, 0xaa, 0x92, + 0xb6, 0xa5, 0x91, 0xa7, 0x00, 0xe2, 0x93, 0xc8, 0x3f, 0xf7, 0x12, 0xde, 0x59, 0x14, 0x42, 0x5d, + 0x26, 0xf1, 0x3b, 0x3f, 0xf0, 0x13, 0xdf, 0x4b, 0xc2, 0xa8, 0xc3, 0x28, 0x2f, 0x05, 0x70, 0x12, + 0x89, 0x3e, 0xe2, 0xc4, 0x4b, 0x26, 0xb1, 0xd4, 0x50, 0x97, 0x84, 0xb5, 0x92, 0xcb, 0x60, 0x1f, + 0xc3, 0x8a, 0xa0, 0x08, 0xca, 0x92, 0xba, 0x37, 0xa9, 0x0a, 0xcb, 0x34, 0x23, 0x53, 0x72, 0x71, + 0x2a, 0x25, 0x89, 0xe4, 0x3e, 0xbc, 0x2e, 0xa6, 0x72, 0x4a, 0x36, 0xf6, 0x0f, 0x7b, 0xe0, 0xf7, + 0x7b, 0xb2, 0x04, 0xb2, 0xc8, 0x0a, 0x8d, 0x22, 0x9f, 0x81, 0x24, 0x3e, 0xf4, 0x4f, 0x78, 0xe2, + 0x8f, 0x78, 0x67, 0x55, 0x90, 0xb8, 0x4a, 0x23, 0x03, 0x4e, 0xc6, 0x94, 0xd3, 0x11, 0x0c, 0x2f, + 0x52, 0xce, 0x1f, 0x94, 0xc4, 0xe6, 0x23, 0x19, 0x35, 0x36, 0xcc, 0x2a, 0xc1, 0xa2, 0xbd, 0x30, + 0x18, 0x5e, 0x4a, 0xae, 0x05, 0x01, 0x3d, 0x0b, 0x86, 0x97, 0xa8, 0xd8, 0xfb, 0x81, 0x59, 0x44, + 0xc8, 0xb9, 0x96, 0x02, 0xa9, 0xd0, 0x7b, 0xd0, 0x1c, 0x4f, 0x8e, 0x87, 0x7e, 0x5f, 0x14, 0xa9, + 0x88, 0x5a, 0x04, 0x44, 0x05, 0xd0, 0xa6, 0x14, 0x2b, 0x25, 0x4a, 0x54, 0xa9, 0x44, 0x53, 0x62, + 0x58, 0xc4, 0xd9, 0x82, 0x65, 0xbb, 0x83, 0x52, 0xa0, 0xdf, 0x83, 0xba, 0xe4, 0xff, 0x58, 0x1a, + 0xf6, 0xf3, 0x86, 0xdf, 0x13, 0xcd, 0x20, 0x9d, 0xef, 0xfc, 0xeb, 0x2a, 0x2c, 0x49, 0x74, 0x7b, + 0x18, 0xc6, 0xfc, 0x68, 0x32, 0x1a, 0x79, 0x51, 0x81, 0x60, 0x29, 0x5d, 0x21, 0x58, 0xca, 0x79, + 0xc1, 0x72, 0xcb, 0xb2, 0x2f, 0x85, 0x64, 0x32, 0x10, 0x76, 0x17, 0x16, 0xfa, 0xc3, 0x30, 0x16, + 0xea, 0xbe, 0xe9, 0x7a, 0xcb, 0xc2, 0x79, 0x61, 0x58, 0x2b, 0x12, 0x86, 0xa6, 0x20, 0x9b, 0xc9, + 0x08, 0x32, 0x07, 0x5a, 0x58, 0x29, 0x57, 0xb2, 0x79, 0x56, 0x1a, 0x5b, 0x06, 0x86, 0xfd, 0xc9, + 0x8a, 0x0d, 0x21, 0xa3, 0x16, 0x8a, 0x84, 0x86, 0x3f, 0xe2, 0x24, 0xfb, 0x8d, 0xd2, 0x0d, 0x29, + 0x34, 0xf2, 0x59, 0xec, 0x11, 0x80, 0x68, 0x8b, 0x14, 0x10, 0x20, 0x05, 0xe4, 0x03, 0x7b, 0x55, + 0xcc, 0xf9, 0x5f, 0xc7, 0xc4, 0x24, 0xe2, 0xa4, 0x94, 0x18, 0x5f, 0x3a, 0x7f, 0xa3, 0x04, 0x4d, + 0x23, 0x8f, 0x5d, 0x87, 0xc5, 0xed, 0x67, 0xcf, 0x0e, 0x77, 0xdd, 0xcd, 0xe7, 0x4f, 0xbe, 0xbf, + 0xdb, 0xdb, 0xde, 0x7f, 0x76, 0xb4, 0xdb, 0xbe, 0x86, 0xf0, 0xfe, 0xb3, 0xed, 0xcd, 0xfd, 0xde, + 0xa3, 0x67, 0xee, 0xb6, 0x82, 0x4b, 0x6c, 0x05, 0x98, 0xbb, 0xfb, 0xf4, 0xd9, 0xf3, 0x5d, 0x0b, + 0x2f, 0xb3, 0x36, 0xb4, 0xb6, 0xdc, 0xdd, 0xcd, 0xed, 0x3d, 0x89, 0x54, 0xd8, 0x32, 0xb4, 0x1f, + 0xbd, 0x38, 0xd8, 0x79, 0x72, 0xf0, 0xb8, 0xb7, 0xbd, 0x79, 0xb0, 0xbd, 0xbb, 0xbf, 0xbb, 0xd3, + 0xae, 0xb2, 0x39, 0x68, 0x6c, 0x6e, 0x6d, 0x1e, 0xec, 0x3c, 0x3b, 0xd8, 0xdd, 0x69, 0xd7, 0x9c, + 0xff, 0x5a, 0x82, 0xeb, 0xd4, 0xeb, 0x41, 0x96, 0x49, 0xd6, 0xa0, 0xd9, 0x0f, 0xc3, 0x31, 0x2a, + 0xfe, 0xe9, 0xd6, 0x66, 0x42, 0xc8, 0x00, 0x42, 0x28, 0x9c, 0x84, 0x51, 0x9f, 0x4b, 0x1e, 0x01, + 0x82, 0x1e, 0x21, 0x82, 0x0c, 0x20, 0x97, 0x57, 0x94, 0x10, 0x2c, 0xd2, 0x14, 0x98, 0x28, 0xb2, + 0x02, 0x33, 0xc7, 0x11, 0xf7, 0xfa, 0x67, 0x92, 0x3b, 0x64, 0x8a, 0x7d, 0x3d, 0xb5, 0x4c, 0xfb, + 0x38, 0xfb, 0x43, 0x3e, 0x20, 0x8a, 0xa9, 0xbb, 0x0b, 0x12, 0xdf, 0x96, 0x30, 0x4a, 0x41, 0xef, + 0xd8, 0x0b, 0x06, 0x61, 0xc0, 0x07, 0x52, 0xed, 0x4d, 0x01, 0xe7, 0x10, 0x56, 0xb2, 0xe3, 0x93, + 0x3c, 0xf6, 0xb1, 0xc1, 0x63, 0x42, 0x0b, 0xed, 0x4e, 0x5f, 0x4d, 0x83, 0xdf, 0x7e, 0x51, 0x86, + 0x2a, 0x2a, 0x25, 0xd3, 0x15, 0x18, 0x53, 0xcf, 0xac, 0xe4, 0xfc, 0xf4, 0x64, 0xec, 0x8a, 0x2d, + 0x4a, 0x3a, 0x5a, 0x52, 0x24, 0xcd, 0x8f, 0x78, 0xff, 0x5c, 0xba, 0x5a, 0x0c, 0x04, 0x19, 0x04, + 0x8d, 0x00, 0xfa, 0x5a, 0x32, 0x88, 0x4a, 0xab, 0x3c, 0xfa, 0x72, 0x36, 0xcd, 0xa3, 0xef, 0x3a, + 0x30, 0xeb, 0x07, 0xc7, 0xe1, 0x24, 0x18, 0x10, 0x43, 0xd4, 0x5d, 0x95, 0xa4, 0x93, 0x01, 0x62, + 0x54, 0x94, 0x9f, 0x82, 0xfc, 0x53, 0x80, 0x6d, 0x40, 0x23, 0xbe, 0x0c, 0xfa, 0x26, 0xcd, 0x2f, + 0xcb, 0x59, 0xc2, 0x39, 0x58, 0x3f, 0xba, 0x0c, 0xfa, 0x44, 0xe1, 0x69, 0x31, 0xe7, 0x77, 0xa1, + 0xae, 0x60, 0x24, 0xcb, 0x17, 0x07, 0x9f, 0x1d, 0x3c, 0x7b, 0x79, 0xd0, 0x3b, 0xfa, 0xc1, 0xc1, + 0x76, 0xfb, 0x1a, 0x5b, 0x80, 0xe6, 0xe6, 0x36, 0x51, 0x3a, 0x01, 0x25, 0x2c, 0x72, 0xb8, 0x79, + 0x74, 0xa4, 0x91, 0xb2, 0xc3, 0xd0, 0x90, 0x8f, 0x49, 0xf3, 0xd3, 0x9e, 0xef, 0x8f, 0x61, 0xd1, + 0xc0, 0x52, 0x2b, 0x62, 0x8c, 0x40, 0xc6, 0x8a, 0x20, 0x95, 0x51, 0xe4, 0x38, 0x6d, 0x98, 0x7f, + 0xcc, 0x93, 0x27, 0xc1, 0x49, 0xa8, 0x6a, 0xfa, 0x9f, 0x55, 0x58, 0xd0, 0x90, 0xac, 0xe8, 0x2e, + 0x2c, 0xf8, 0x03, 0x1e, 0x24, 0x7e, 0x72, 0xd9, 0xb3, 0xfc, 0x05, 0x59, 0x18, 0x55, 0x6d, 0x6f, + 0xe8, 0x7b, 0xea, 0x00, 0x46, 0x24, 0xd0, 0x7e, 0x46, 0x1d, 0xc0, 0xf4, 0xdb, 0x10, 0x5d, 0x09, + 0x37, 0x45, 0x61, 0x1e, 0x4a, 0x20, 0xc4, 0xe5, 0x36, 0xa3, 0x3f, 0x11, 0x2a, 0x67, 0x51, 0x16, + 0x2e, 0x95, 0xa8, 0x09, 0x87, 0x5c, 0x13, 0x7a, 0x82, 0x06, 0x72, 0x27, 0x1c, 0x33, 0x42, 0x3e, + 0x66, 0x4f, 0x38, 0x8c, 0x53, 0x92, 0x7a, 0xee, 0x94, 0x04, 0xe5, 0xe7, 0x65, 0xd0, 0xe7, 0x83, + 0x5e, 0x12, 0xf6, 0x48, 0xce, 0x13, 0x49, 0xd4, 0xdd, 0x2c, 0x8c, 0xfb, 0x46, 0xc2, 0xe3, 0x24, + 0xe0, 0xc2, 0x2d, 0x5d, 0xdf, 0x2a, 0x77, 0x4a, 0xae, 0x82, 0xd0, 0x3e, 0x98, 0x44, 0x7e, 0xdc, + 0x69, 0xd1, 0xf9, 0x07, 0xfd, 0x66, 0xdf, 0x86, 0xeb, 0xc7, 0x3c, 0x4e, 0x7a, 0x67, 0xdc, 0x1b, + 0xf0, 0x88, 0xc8, 0x4b, 0x1c, 0xb4, 0x08, 0x95, 0xab, 0x38, 0x13, 0x09, 0xf7, 0x9c, 0x47, 0xb1, + 0x1f, 0x06, 0xa4, 0x6c, 0x35, 0x5c, 0x95, 0xc4, 0xfa, 0x70, 0xf0, 0x7a, 0xa3, 0xd6, 0x33, 0xb8, + 0x40, 0x03, 0x2f, 0xce, 0x64, 0xb7, 0x61, 0x86, 0x06, 0x10, 0x77, 0xda, 0x44, 0x33, 0xad, 0x94, + 0xe7, 0xfd, 0xc0, 0x95, 0x79, 0xb8, 0xca, 0xfd, 0x70, 0x18, 0x46, 0xa4, 0x71, 0x35, 0x5c, 0x91, + 0xb0, 0x67, 0xe7, 0x34, 0xf2, 0xc6, 0x67, 0x52, 0xeb, 0xca, 0xc2, 0xdf, 0xad, 0xd6, 0x9b, 0xed, + 0x96, 0xf3, 0x67, 0xa0, 0x46, 0xd5, 0x52, 0x75, 0x34, 0x99, 0x25, 0x59, 0x1d, 0xa1, 0x1d, 0x98, + 0x0d, 0x78, 0x72, 0x11, 0x46, 0xaf, 0xd4, 0x69, 0x9e, 0x4c, 0x3a, 0x3f, 0x23, 0x0b, 0x4d, 0x9f, + 0x6e, 0xbd, 0x20, 0xd5, 0x12, 0xed, 0x6c, 0xb1, 0x54, 0xf1, 0x99, 0x27, 0x8d, 0xc6, 0x3a, 0x01, + 0x47, 0x67, 0x1e, 0xca, 0x5a, 0x6b, 0xf5, 0x85, 0x1d, 0xde, 0x24, 0x6c, 0x4f, 0x2c, 0xfe, 0x6d, + 0x98, 0x57, 0xe7, 0x66, 0x71, 0x6f, 0xc8, 0x4f, 0x12, 0xe5, 0x45, 0x0b, 0x26, 0x23, 0x32, 0xd6, + 0xf7, 0xf9, 0x49, 0xe2, 0x1c, 0xc0, 0xa2, 0x94, 0x7f, 0xcf, 0xc6, 0x5c, 0x35, 0xfd, 0xdb, 0x45, + 0xba, 0x44, 0x73, 0x63, 0xc9, 0x16, 0x98, 0xe2, 0xa4, 0xd0, 0x2e, 0xe9, 0xb8, 0xc0, 0x4c, 0x79, + 0x2a, 0x2b, 0x94, 0x9b, 0xb9, 0xf2, 0x13, 0xca, 0xe1, 0x58, 0x18, 0xce, 0x4f, 0x3c, 0xe9, 0xf7, + 0xd5, 0x69, 0x67, 0xdd, 0x55, 0x49, 0xe7, 0x8f, 0x4a, 0xb0, 0x44, 0xb5, 0x29, 0x6d, 0x48, 0xee, + 0x59, 0x9f, 0x7c, 0x85, 0x6e, 0x2a, 0x2f, 0xad, 0xf0, 0x4d, 0x2e, 0x43, 0xcd, 0xdc, 0xc5, 0x44, + 0xe2, 0xab, 0xfb, 0x64, 0xaa, 0x59, 0x9f, 0x8c, 0xf3, 0x77, 0x4a, 0xb0, 0x28, 0x36, 0x12, 0xd2, + 0xb6, 0xe5, 0xf0, 0xff, 0x2c, 0xcc, 0x09, 0x8d, 0x40, 0x4a, 0x05, 0xd9, 0xd1, 0x54, 0xb4, 0x12, + 0x2a, 0x0a, 0xef, 0x5d, 0x73, 0xed, 0xc2, 0xec, 0x21, 0x69, 0x65, 0x41, 0x8f, 0xd0, 0x82, 0x73, + 0x71, 0x7b, 0xae, 0xf7, 0xae, 0xb9, 0x46, 0xf1, 0xad, 0x3a, 0x2a, 0xcb, 0x88, 0x3b, 0x8f, 0x61, + 0xce, 0x6a, 0xc8, 0xf2, 0x07, 0xb5, 0x84, 0x3f, 0x28, 0xe7, 0x78, 0x2d, 0x17, 0x38, 0x5e, 0xff, + 0x79, 0x05, 0x18, 0x12, 0x4b, 0x66, 0x35, 0xd6, 0xec, 0xd3, 0x0b, 0x75, 0x44, 0x9e, 0x42, 0x6c, + 0x1d, 0x98, 0x91, 0x54, 0x27, 0x2a, 0x62, 0xcb, 0x2c, 0xc8, 0x41, 0x31, 0x2b, 0x35, 0x0e, 0x7d, + 0x5a, 0x41, 0x76, 0xbe, 0x98, 0xf6, 0xc2, 0x3c, 0xdc, 0x15, 0xe9, 0xe8, 0x02, 0x2d, 0x12, 0x69, + 0x1b, 0xab, 0x74, 0x76, 0x7d, 0x67, 0xae, 0x5c, 0xdf, 0xd9, 0x9c, 0xcf, 0xcd, 0xb0, 0xce, 0xea, + 0xb6, 0x75, 0x76, 0x1b, 0xe6, 0xd4, 0x09, 0x45, 0x6f, 0x84, 0xad, 0x4b, 0x53, 0xd8, 0x02, 0xd9, + 0x3d, 0x68, 0x2b, 0x03, 0x49, 0x9b, 0x80, 0xe2, 0x9c, 0x2f, 0x87, 0xa3, 0xfc, 0x4f, 0xbd, 0x70, + 0x4d, 0xea, 0x6c, 0x0a, 0x90, 0x3d, 0x85, 0x14, 0xd2, 0x9b, 0x04, 0xf2, 0x68, 0x9c, 0x0f, 0xc8, + 0x08, 0x46, 0x7b, 0x2a, 0x9b, 0xe1, 0xfc, 0xad, 0x12, 0xb4, 0x71, 0xcd, 0x2c, 0xb2, 0xfc, 0x14, + 0x88, 0x2b, 0xde, 0x92, 0x2a, 0xad, 0xb2, 0xec, 0x13, 0x68, 0x50, 0x3a, 0x1c, 0xf3, 0x40, 0xd2, + 0x64, 0xc7, 0xa6, 0xc9, 0x54, 0x9e, 0xec, 0x5d, 0x73, 0xd3, 0xc2, 0x06, 0x45, 0xfe, 0xc7, 0x12, + 0x34, 0x65, 0x2b, 0xbf, 0xb2, 0x97, 0xa7, 0x6b, 0xc4, 0x32, 0x08, 0x4a, 0x4a, 0x43, 0x17, 0xee, + 0xc2, 0xc2, 0xc8, 0x4b, 0x26, 0x11, 0xee, 0xe7, 0x96, 0x87, 0x27, 0x0b, 0xe3, 0xe6, 0x4c, 0xa2, + 0x33, 0xee, 0x25, 0xfe, 0xb0, 0xa7, 0x72, 0x65, 0xd4, 0x40, 0x51, 0x16, 0x4a, 0x90, 0x38, 0xf1, + 0x4e, 0xb9, 0xdc, 0x77, 0x45, 0xc2, 0xe9, 0xc0, 0xca, 0x61, 0x7a, 0x6a, 0x63, 0xe8, 0xd7, 0xce, + 0x3f, 0x9d, 0x83, 0xd5, 0x5c, 0x96, 0x8e, 0x71, 0x92, 0x6e, 0x8b, 0xa1, 0x3f, 0x3a, 0x0e, 0xb5, + 0x71, 0x52, 0x32, 0x3d, 0x1a, 0x56, 0x16, 0x3b, 0x85, 0xeb, 0x4a, 0xc1, 0xc0, 0x39, 0x4d, 0x37, + 0xc3, 0x32, 0xed, 0x72, 0x1f, 0xd9, 0x4b, 0x98, 0x6d, 0x50, 0xe1, 0x26, 0x13, 0x17, 0xd7, 0xc7, + 0xce, 0xa0, 0xa3, 0x35, 0x19, 0x29, 0xac, 0x0d, 0x6d, 0x07, 0xdb, 0xfa, 0xf0, 0x8a, 0xb6, 0x2c, + 0x75, 0xdc, 0x9d, 0x5a, 0x1b, 0xbb, 0x84, 0x5b, 0x2a, 0x8f, 0xa4, 0x71, 0xbe, 0xbd, 0xea, 0x5b, + 0x8d, 0x8d, 0x0c, 0x0d, 0xbb, 0xd1, 0x2b, 0x2a, 0x66, 0x3f, 0x81, 0x95, 0x0b, 0xcf, 0x4f, 0x54, + 0xb7, 0x0c, 0xdd, 0xa2, 0x46, 0x4d, 0x6e, 0x5c, 0xd1, 0xe4, 0x4b, 0xf1, 0xb1, 0xb5, 0x45, 0x4d, + 0xa9, 0xb1, 0xfb, 0x27, 0x65, 0x98, 0xb7, 0xeb, 0x41, 0x32, 0x95, 0xbc, 0xaf, 0x64, 0xa0, 0xd2, + 0x46, 0x33, 0x70, 0xde, 0xc6, 0x2f, 0x17, 0xd9, 0xf8, 0xa6, 0x55, 0x5d, 0xb9, 0xca, 0x3d, 0x58, + 0x7d, 0x3b, 0xf7, 0x60, 0xad, 0xd0, 0x3d, 0x38, 0xdd, 0x8b, 0x34, 0xf3, 0xab, 0x7a, 0x91, 0x66, + 0xdf, 0xe8, 0x45, 0xea, 0xfe, 0xdf, 0x12, 0xb0, 0x3c, 0xf5, 0xb2, 0xc7, 0xc2, 0xad, 0x11, 0xf0, + 0xa1, 0x14, 0x62, 0xdf, 0x7c, 0x3b, 0x0e, 0x50, 0xab, 0xa5, 0xbe, 0x46, 0x56, 0x34, 0x03, 0x8d, + 0x4c, 0xf5, 0x6a, 0xce, 0x2d, 0xca, 0xca, 0xb8, 0x48, 0xab, 0x57, 0xbb, 0x48, 0x6b, 0x57, 0xbb, + 0x48, 0x67, 0xb2, 0x2e, 0xd2, 0xee, 0x5f, 0x2d, 0xc1, 0x52, 0x01, 0x99, 0xfd, 0xe6, 0x06, 0x8e, + 0x84, 0x61, 0x49, 0x9f, 0xb2, 0x24, 0x0c, 0x13, 0xec, 0xfe, 0x45, 0x98, 0xb3, 0x58, 0xeb, 0x37, + 0xd7, 0x7e, 0x56, 0x43, 0x14, 0x94, 0x6d, 0x61, 0xdd, 0xff, 0x55, 0x06, 0x96, 0x67, 0xef, 0x3f, + 0xd5, 0x3e, 0xe4, 0xe7, 0xa9, 0x52, 0x30, 0x4f, 0xff, 0x5f, 0x77, 0x9e, 0x0f, 0x61, 0x51, 0x46, + 0x4f, 0x1a, 0x8e, 0x2c, 0x41, 0x31, 0xf9, 0x0c, 0xd4, 0x91, 0x6d, 0xff, 0x74, 0xdd, 0x8a, 0x16, + 0x33, 0xb6, 0xdf, 0x8c, 0x9b, 0xda, 0xe9, 0x42, 0x47, 0xce, 0xd0, 0xee, 0x39, 0x0f, 0x92, 0xa3, + 0xc9, 0xb1, 0x08, 0x1f, 0xf4, 0xc3, 0xc0, 0xf9, 0x17, 0x15, 0xad, 0xe6, 0x53, 0xa6, 0x54, 0x28, + 0xbe, 0x0d, 0x2d, 0x73, 0xfb, 0x90, 0xcb, 0x91, 0xf1, 0x65, 0xa2, 0x2a, 0x61, 0x96, 0x62, 0x3b, + 0x30, 0x4f, 0x42, 0x72, 0xa0, 0xbf, 0x2b, 0xd3, 0x77, 0x6f, 0xf0, 0xcf, 0xec, 0x5d, 0x73, 0x33, + 0xdf, 0xb0, 0xdf, 0x81, 0x79, 0xdb, 0xf8, 0x93, 0x5a, 0x49, 0x91, 0x35, 0x80, 0x9f, 0xdb, 0x85, + 0xd9, 0x26, 0xb4, 0xb3, 0xd6, 0xa3, 0x8c, 0xe4, 0x99, 0x52, 0x41, 0xae, 0x38, 0xfb, 0x44, 0x1e, + 0x56, 0xd6, 0xc8, 0x6f, 0x72, 0xdb, 0xfe, 0xcc, 0x98, 0xa6, 0x75, 0xf1, 0xc7, 0x38, 0xbe, 0xfc, + 0x3d, 0x80, 0x14, 0x63, 0x6d, 0x68, 0x3d, 0x3b, 0xdc, 0x3d, 0xe8, 0x6d, 0xef, 0x6d, 0x1e, 0x1c, + 0xec, 0xee, 0xb7, 0xaf, 0x31, 0x06, 0xf3, 0xe4, 0xe6, 0xdb, 0xd1, 0x58, 0x09, 0x31, 0xe9, 0x58, + 0x51, 0x58, 0x99, 0x2d, 0x43, 0xfb, 0xc9, 0x41, 0x06, 0xad, 0x6c, 0x35, 0x34, 0x7f, 0x38, 0x2b, + 0xb0, 0x2c, 0xa2, 0x63, 0xb7, 0x04, 0x79, 0x28, 0xed, 0xe4, 0x1f, 0x94, 0xe0, 0x7a, 0x26, 0x23, + 0x0d, 0xf5, 0x12, 0x0a, 0x88, 0xad, 0x95, 0xd8, 0x20, 0x1d, 0x3e, 0x28, 0x5d, 0x33, 0x23, 0x41, + 0xf2, 0x19, 0x48, 0xf3, 0x86, 0x6e, 0x9a, 0xe1, 0xa4, 0xa2, 0x2c, 0x67, 0x55, 0x47, 0xd5, 0x64, + 0x3a, 0x7e, 0x22, 0xa2, 0x6e, 0xcd, 0x8c, 0xf4, 0xf0, 0xd7, 0xee, 0xb2, 0x4a, 0xa2, 0x59, 0x61, + 0x29, 0x3b, 0x76, 0x7f, 0x0b, 0xf3, 0x9c, 0x7f, 0x5c, 0x01, 0xf6, 0xbd, 0x09, 0x8f, 0x2e, 0x29, + 0x9e, 0x4b, 0x7b, 0x4d, 0x57, 0xb3, 0x3e, 0xc1, 0x99, 0xf1, 0xe4, 0xf8, 0x33, 0x7e, 0xa9, 0xa2, + 0x1b, 0xcb, 0x69, 0x74, 0x63, 0x51, 0x84, 0x61, 0xf5, 0xea, 0x08, 0xc3, 0xda, 0x55, 0x11, 0x86, + 0x5f, 0x83, 0x39, 0xff, 0x34, 0x08, 0x91, 0xe7, 0x51, 0x4f, 0x88, 0x3b, 0x33, 0x6b, 0x15, 0xb4, + 0xad, 0x25, 0x78, 0x80, 0x18, 0x7b, 0x98, 0x16, 0xe2, 0x83, 0x53, 0x8a, 0x66, 0x35, 0xa5, 0xc0, + 0xee, 0xe0, 0x94, 0xef, 0x87, 0x7d, 0x2f, 0x09, 0x23, 0x72, 0xec, 0xa8, 0x8f, 0x11, 0x8f, 0xd9, + 0x6d, 0x98, 0x8f, 0xc3, 0x09, 0x6a, 0x4e, 0x6a, 0xac, 0xc2, 0x93, 0xd4, 0x12, 0xe8, 0xa1, 0x18, + 0xf1, 0x3a, 0x2c, 0x4d, 0x62, 0xde, 0x1b, 0xf9, 0x71, 0x8c, 0xbb, 0x63, 0x3f, 0x0c, 0x92, 0x28, + 0x1c, 0x4a, 0x7f, 0xd2, 0xe2, 0x24, 0xe6, 0x4f, 0x45, 0xce, 0xb6, 0xc8, 0x60, 0xdf, 0x4e, 0xbb, + 0x34, 0xf6, 0xfc, 0x28, 0xee, 0x00, 0x75, 0x49, 0x8d, 0x14, 0xfb, 0x7d, 0xe8, 0xf9, 0x91, 0xee, + 0x0b, 0x26, 0xe2, 0x4c, 0x84, 0x64, 0x33, 0x13, 0x21, 0x29, 0x03, 0xec, 0xd6, 0xa1, 0xae, 0x3e, + 0x47, 0x23, 0xf7, 0x24, 0x0a, 0x47, 0xca, 0xc8, 0xc5, 0xdf, 0x6c, 0x1e, 0xca, 0x49, 0x28, 0x0d, + 0xd4, 0x72, 0x12, 0x3a, 0xbf, 0x0f, 0x4d, 0x63, 0x06, 0xd8, 0xfb, 0xc2, 0xde, 0x46, 0x85, 0x4a, + 0x5a, 0xc7, 0xe2, 0x98, 0xa4, 0x21, 0xd1, 0x27, 0x03, 0xf6, 0x0d, 0x58, 0x1c, 0xf8, 0x11, 0xa7, + 0xc0, 0xda, 0x5e, 0xc4, 0xcf, 0x79, 0x14, 0x2b, 0x5f, 0x42, 0x5b, 0x67, 0xb8, 0x02, 0x77, 0x7a, + 0xb0, 0x64, 0x91, 0x8e, 0xe6, 0xac, 0x19, 0x8a, 0x0a, 0x54, 0xee, 0x4c, 0x3b, 0x62, 0x50, 0xe6, + 0xe1, 0x9e, 0x24, 0xdd, 0x20, 0xbd, 0x71, 0x14, 0x1e, 0x53, 0x23, 0x25, 0xd7, 0xc2, 0x9c, 0x5f, + 0x94, 0xa1, 0xb2, 0x17, 0x8e, 0xcd, 0xc3, 0x9d, 0x52, 0xfe, 0x70, 0x47, 0x2a, 0x8f, 0x3d, 0xad, + 0x1b, 0xca, 0x1d, 0xde, 0x02, 0xd9, 0x3d, 0x98, 0xf7, 0x46, 0x49, 0x2f, 0x09, 0x51, 0x59, 0xbe, + 0xf0, 0x22, 0x11, 0x42, 0x58, 0x21, 0xb2, 0xc8, 0xe4, 0xb0, 0x65, 0xa8, 0x68, 0x9d, 0x87, 0x0a, + 0x60, 0x12, 0x2d, 0x35, 0x3a, 0x40, 0xbf, 0x94, 0x3e, 0x4b, 0x99, 0x42, 0xae, 0xb7, 0xbf, 0x17, + 0x66, 0xb2, 0xd8, 0xb9, 0x8a, 0xb2, 0x50, 0x91, 0x45, 0x46, 0x18, 0xa5, 0x7a, 0xa1, 0x4e, 0x9b, + 0xde, 0xf8, 0xba, 0xed, 0x8d, 0x5f, 0x83, 0x66, 0x32, 0x3c, 0xef, 0x8d, 0xbd, 0xcb, 0x61, 0xe8, + 0x0d, 0x24, 0x01, 0x9a, 0x10, 0x7b, 0x00, 0x30, 0x1a, 0x8f, 0x7b, 0xb8, 0x59, 0x46, 0x03, 0x32, + 0xbf, 0x9b, 0x1b, 0x6d, 0x39, 0xfb, 0x4f, 0x0f, 0x0f, 0x5d, 0xc2, 0x5d, 0xa3, 0x8c, 0xf3, 0x12, + 0x1a, 0x3a, 0xc3, 0x8c, 0x3b, 0xa5, 0x10, 0x8a, 0xa6, 0x1d, 0x77, 0x4a, 0x11, 0x13, 0x1f, 0xc0, + 0xbc, 0x90, 0x90, 0x38, 0x2e, 0x1a, 0x80, 0x38, 0xf6, 0xce, 0xa0, 0xce, 0x2f, 0x4b, 0x50, 0xa3, + 0x05, 0x47, 0x95, 0x41, 0xe4, 0xe9, 0xc3, 0x28, 0x5a, 0xc4, 0x39, 0x37, 0x0b, 0x33, 0xc7, 0x8a, + 0x4b, 0x2f, 0xeb, 0xd9, 0x37, 0x63, 0xd3, 0xd7, 0xa0, 0xa1, 0x5b, 0x32, 0x56, 0x30, 0x05, 0xd9, + 0x2d, 0xa8, 0x9e, 0x85, 0x63, 0x65, 0x55, 0x81, 0x3a, 0xaf, 0x0e, 0xc7, 0x2e, 0xe1, 0x69, 0x7f, + 0xb0, 0x3e, 0x31, 0x04, 0xa1, 0xb9, 0x66, 0xe1, 0x82, 0xb1, 0xce, 0x14, 0x8e, 0xf5, 0x05, 0x2c, + 0x20, 0x5b, 0x1a, 0xce, 0xf9, 0xe9, 0xf2, 0xf3, 0xeb, 0xb8, 0x1d, 0xf7, 0x87, 0x93, 0x01, 0x37, + 0x6d, 0x5b, 0x72, 0xbe, 0x4a, 0x5c, 0x69, 0x75, 0xce, 0x3f, 0x2b, 0x09, 0x76, 0xc7, 0x7a, 0xd9, + 0x5d, 0xa8, 0xa2, 0x14, 0xcc, 0xb8, 0x32, 0x74, 0x58, 0x0b, 0x96, 0x73, 0xa9, 0x04, 0xae, 0x22, + 0xb9, 0x47, 0xcd, 0xda, 0x85, 0x73, 0x34, 0x35, 0x0c, 0xf5, 0xc8, 0x32, 0xf6, 0x54, 0x06, 0x65, + 0xeb, 0xc6, 0xd9, 0x52, 0xd5, 0x92, 0xac, 0x6a, 0xf7, 0x1f, 0x9c, 0x72, 0xe3, 0x4c, 0xe9, 0x8f, + 0x4b, 0x30, 0x67, 0xf5, 0x09, 0x89, 0x76, 0xe8, 0xc5, 0x89, 0x0c, 0x2b, 0x90, 0x2b, 0x6f, 0x42, + 0x26, 0xc1, 0x97, 0x6d, 0x82, 0xd7, 0x67, 0x14, 0x15, 0xf3, 0x8c, 0xe2, 0x01, 0x34, 0xd2, 0x8b, + 0x09, 0x76, 0xa7, 0xb0, 0x45, 0x15, 0xe0, 0x93, 0x16, 0x4a, 0xbd, 0xe0, 0x35, 0xc3, 0x0b, 0xee, + 0x3c, 0x84, 0xa6, 0x51, 0xde, 0xf4, 0x62, 0x97, 0x2c, 0x2f, 0xb6, 0x8e, 0x7e, 0x2b, 0xa7, 0xd1, + 0x6f, 0xce, 0x97, 0x65, 0x98, 0x43, 0xf2, 0xf6, 0x83, 0xd3, 0xc3, 0x70, 0xe8, 0xf7, 0x2f, 0x89, + 0xac, 0x14, 0x25, 0xcb, 0x5d, 0x50, 0x91, 0xb9, 0x0d, 0x23, 0xf7, 0xeb, 0x90, 0x5f, 0x21, 0xaa, + 0x74, 0x1a, 0x65, 0x19, 0x4a, 0x82, 0x63, 0x2f, 0x96, 0xe2, 0x41, 0x6a, 0xe1, 0x16, 0x88, 0x12, + 0x07, 0x01, 0x8a, 0x65, 0x1c, 0xf9, 0xc3, 0xa1, 0x2f, 0xca, 0x0a, 0x1b, 0xad, 0x28, 0x0b, 0xdb, + 0x1c, 0xf8, 0xb1, 0x77, 0x9c, 0x9e, 0x3f, 0xea, 0x34, 0x39, 0xf8, 0xbc, 0xd7, 0x86, 0x83, 0x4f, + 0x04, 0x3f, 0xdb, 0x60, 0x76, 0x21, 0x67, 0x73, 0x0b, 0xe9, 0xfc, 0xdb, 0x32, 0x34, 0x0d, 0xb2, + 0x40, 0x76, 0x2e, 0xdc, 0x6e, 0x0c, 0x54, 0x1e, 0xcc, 0x07, 0x96, 0xd5, 0x6f, 0x20, 0xec, 0xb6, + 0xdd, 0x2a, 0x39, 0xfa, 0x89, 0xe1, 0x2d, 0x12, 0xba, 0x09, 0x0d, 0x24, 0xfd, 0x8f, 0xc8, 0xc5, + 0x20, 0x6f, 0x05, 0x69, 0x40, 0xe5, 0x6e, 0x50, 0x6e, 0x2d, 0xcd, 0x25, 0xe0, 0x8d, 0x47, 0xf5, + 0x9f, 0x40, 0x4b, 0x56, 0x43, 0x6b, 0x4c, 0x83, 0x4e, 0x99, 0xcf, 0x5a, 0x7f, 0xd7, 0x2a, 0xa9, + 0xbe, 0xdc, 0x50, 0x5f, 0xd6, 0xaf, 0xfa, 0x52, 0x95, 0x74, 0x1e, 0xeb, 0x28, 0x88, 0xc7, 0x91, + 0x37, 0x3e, 0x53, 0x02, 0xe5, 0x01, 0x2c, 0x29, 0xb9, 0x31, 0x09, 0xbc, 0x20, 0x08, 0x27, 0x41, + 0x9f, 0xab, 0x40, 0xb9, 0xa2, 0x2c, 0x67, 0xa0, 0xc3, 0xaa, 0xa9, 0x22, 0x76, 0x0f, 0x6a, 0x42, + 0x8f, 0x12, 0xbb, 0x72, 0xb1, 0x08, 0x11, 0x45, 0xd8, 0x5d, 0xa8, 0x09, 0x75, 0xaa, 0x3c, 0x95, + 0xe9, 0x45, 0x01, 0x67, 0x1d, 0x16, 0x28, 0x8e, 0xdb, 0x90, 0x7d, 0xef, 0x14, 0xed, 0xd6, 0x33, + 0x7d, 0x11, 0xed, 0xbd, 0x0c, 0xec, 0x40, 0xf0, 0x95, 0x79, 0x96, 0xf9, 0xcb, 0x0a, 0x34, 0x0d, + 0x18, 0xe5, 0x13, 0x1d, 0x40, 0xf5, 0x06, 0xbe, 0x37, 0xe2, 0x09, 0x8f, 0x24, 0x2f, 0x65, 0x50, + 0x2c, 0xe7, 0x9d, 0x9f, 0xf6, 0xc2, 0x49, 0xd2, 0x1b, 0xf0, 0xd3, 0x88, 0x73, 0xa9, 0x46, 0x64, + 0x50, 0x2c, 0x87, 0xd4, 0x6c, 0x94, 0x13, 0x47, 0x46, 0x19, 0x54, 0x9d, 0x4c, 0x8a, 0x79, 0xaa, + 0xa6, 0x27, 0x93, 0x62, 0x56, 0xb2, 0x92, 0xb5, 0x56, 0x20, 0x59, 0x3f, 0x86, 0x15, 0x21, 0x43, + 0xa5, 0xf4, 0xe8, 0x65, 0x88, 0x6b, 0x4a, 0x2e, 0xbb, 0x07, 0x6d, 0xec, 0xb3, 0x62, 0x8d, 0xd8, + 0xff, 0x99, 0xe0, 0xb1, 0x92, 0x9b, 0xc3, 0xb1, 0x2c, 0xb9, 0xcb, 0xcd, 0xb2, 0x22, 0x3c, 0x24, + 0x87, 0x53, 0x59, 0xef, 0xb5, 0x5d, 0xb6, 0x21, 0xcb, 0x66, 0x70, 0xf6, 0x09, 0xac, 0x8e, 0xf8, + 0xc0, 0xf7, 0xec, 0x2a, 0x7a, 0xe9, 0x26, 0x3f, 0x2d, 0x1b, 0x5b, 0xc1, 0x59, 0xf8, 0x59, 0x38, + 0x3a, 0xf6, 0xc5, 0xc6, 0x26, 0x1c, 0xfb, 0x55, 0x37, 0x87, 0x3b, 0x73, 0xd0, 0x3c, 0x4a, 0xc2, + 0xb1, 0x5a, 0xfa, 0x79, 0x68, 0x89, 0xa4, 0x0c, 0x8d, 0x7c, 0x07, 0x6e, 0x10, 0xbd, 0x3e, 0x0f, + 0xc7, 0xe1, 0x30, 0x3c, 0xbd, 0xb4, 0xcc, 0xf3, 0xff, 0x50, 0x82, 0x25, 0x2b, 0x37, 0xb5, 0xcf, + 0xc9, 0x97, 0xa8, 0xe2, 0xd9, 0x04, 0x89, 0x2f, 0x1a, 0xdb, 0x82, 0x28, 0x28, 0x8e, 0x6d, 0x5e, + 0xc8, 0x10, 0xb7, 0xcd, 0xf4, 0x92, 0x86, 0xfa, 0x50, 0xd0, 0x7b, 0x27, 0x4f, 0xef, 0xf2, 0x7b, + 0x75, 0x7d, 0x43, 0x55, 0xf1, 0x3b, 0x32, 0x98, 0x67, 0x20, 0x07, 0x5d, 0xb1, 0x03, 0x30, 0x4c, + 0x77, 0x8e, 0xea, 0x41, 0x5f, 0x83, 0xb1, 0xf3, 0xf3, 0x12, 0x40, 0xda, 0x3b, 0x0a, 0x01, 0xd1, + 0x5b, 0x9b, 0xb8, 0x08, 0x6c, 0x6c, 0x63, 0xef, 0x43, 0x4b, 0x9f, 0xe2, 0xa7, 0xbb, 0x65, 0x53, + 0x61, 0xa8, 0x5d, 0xdc, 0x81, 0x85, 0xd3, 0x61, 0x78, 0x4c, 0x5a, 0x0c, 0xc5, 0xda, 0xc6, 0x32, + 0x40, 0x74, 0x5e, 0xc0, 0x8f, 0x24, 0x9a, 0x6e, 0xad, 0x55, 0x73, 0x6b, 0x2d, 0xde, 0x28, 0xbf, + 0x2c, 0xeb, 0xa3, 0xd4, 0x74, 0x26, 0xde, 0xc8, 0xe5, 0x6c, 0x23, 0x27, 0xd6, 0xa7, 0x9c, 0x5e, + 0x92, 0xe9, 0x71, 0x78, 0xa5, 0x77, 0xf7, 0x21, 0xcc, 0x47, 0x42, 0x66, 0x2a, 0x81, 0x5a, 0x7d, + 0x83, 0x40, 0x9d, 0x8b, 0xac, 0x9d, 0xf9, 0xeb, 0xd0, 0xf6, 0x06, 0xe7, 0x3c, 0x4a, 0x7c, 0xf2, + 0x76, 0x91, 0x1a, 0x25, 0x06, 0xb8, 0x60, 0xe0, 0xa4, 0xad, 0xdc, 0x81, 0x05, 0x19, 0xae, 0xab, + 0x4b, 0xca, 0x6b, 0x75, 0x29, 0x8c, 0x05, 0x9d, 0x7f, 0xa4, 0x4e, 0x6e, 0xed, 0xd5, 0x7d, 0xf3, + 0xac, 0x98, 0x23, 0x2c, 0x67, 0x46, 0xf8, 0x35, 0x79, 0x92, 0x3a, 0x50, 0x6e, 0xb5, 0x8a, 0x11, + 0x16, 0x36, 0x90, 0x27, 0xdf, 0xf6, 0xb4, 0x56, 0xdf, 0x66, 0x5a, 0x9d, 0xff, 0x5c, 0x82, 0xd9, + 0xbd, 0x70, 0xbc, 0x87, 0x53, 0x8c, 0x3a, 0x0e, 0xb2, 0x89, 0x8e, 0x95, 0x57, 0xc9, 0x2b, 0xc2, + 0xe7, 0x0a, 0xb5, 0x92, 0xb9, 0xac, 0x56, 0xf2, 0xe7, 0xe1, 0x1d, 0x72, 0xec, 0x46, 0xe1, 0x38, + 0x8c, 0x90, 0x5d, 0xbd, 0xa1, 0x50, 0x41, 0xc2, 0x20, 0x39, 0x53, 0xe2, 0xf4, 0x4d, 0x45, 0xc8, + 0xdb, 0x82, 0x46, 0xb0, 0x30, 0xac, 0xa4, 0x16, 0x25, 0xa4, 0x6c, 0x3e, 0xc3, 0xf9, 0x6d, 0x68, + 0x90, 0x85, 0x41, 0x43, 0xfb, 0x10, 0x1a, 0x67, 0xe1, 0xb8, 0x77, 0xe6, 0x07, 0x89, 0x62, 0xff, + 0xf9, 0x54, 0xf5, 0xdf, 0xa3, 0x49, 0xd1, 0x05, 0x9c, 0x7f, 0x33, 0x03, 0xb3, 0x4f, 0x82, 0xf3, + 0xd0, 0xef, 0xd3, 0x69, 0xf1, 0x88, 0x8f, 0x42, 0x75, 0x7b, 0x00, 0x7f, 0xe3, 0x74, 0x50, 0xa8, + 0xec, 0x58, 0x10, 0x6f, 0x4b, 0x44, 0x85, 0x48, 0x88, 0xee, 0xbd, 0xa6, 0x37, 0xff, 0x04, 0x83, + 0x19, 0x08, 0x1a, 0x8a, 0x91, 0x79, 0x73, 0x4f, 0xa6, 0xd2, 0xdb, 0x19, 0x35, 0xe3, 0x76, 0x06, + 0xb6, 0x25, 0x83, 0xfa, 0x44, 0xd4, 0x97, 0x68, 0x4b, 0x42, 0x64, 0xdc, 0x46, 0x5c, 0x38, 0xe6, + 0xb5, 0xe2, 0x85, 0xc6, 0xad, 0x09, 0xa2, 0x72, 0x26, 0x3e, 0x10, 0x65, 0xc4, 0x66, 0x60, 0x42, + 0xa8, 0x9e, 0x66, 0x2f, 0x8c, 0x8a, 0x0b, 0xbb, 0x59, 0x18, 0x65, 0xf9, 0x80, 0x6b, 0x91, 0x2b, + 0xc6, 0x01, 0xe2, 0x76, 0x63, 0x16, 0x37, 0x4c, 0x62, 0x11, 0xd5, 0xac, 0x4c, 0x62, 0x24, 0x18, + 0x6f, 0x38, 0x3c, 0xf6, 0xfa, 0xaf, 0x84, 0x29, 0xd9, 0x12, 0xe7, 0x39, 0x16, 0x48, 0xa1, 0x79, + 0xe9, 0xaa, 0x52, 0xfc, 0x4c, 0xd5, 0x35, 0x21, 0xb6, 0x01, 0x4d, 0x72, 0x17, 0xc8, 0x75, 0x9d, + 0xa7, 0x75, 0x6d, 0x9b, 0xfe, 0x04, 0x5a, 0x59, 0xb3, 0x90, 0x79, 0x92, 0xbd, 0x90, 0x8b, 0x33, + 0xf6, 0x06, 0x03, 0x19, 0x00, 0xd0, 0x16, 0x37, 0xfc, 0x34, 0x40, 0x0e, 0x09, 0x31, 0x61, 0xa2, + 0xc0, 0x22, 0x15, 0xb0, 0x30, 0x76, 0x0b, 0xea, 0x68, 0xf5, 0x8d, 0x3d, 0x7f, 0x40, 0x21, 0x33, + 0xc2, 0xf8, 0xd4, 0x18, 0xd6, 0xa1, 0x7e, 0xd3, 0xb6, 0xb9, 0x44, 0xb3, 0x62, 0x61, 0x38, 0x37, + 0x3a, 0x3d, 0x4a, 0x03, 0x93, 0x6d, 0x90, 0x7d, 0x44, 0xc7, 0xb0, 0x09, 0xa7, 0xe8, 0xe3, 0xf9, + 0x8d, 0x77, 0xe4, 0x98, 0x25, 0xd1, 0xaa, 0xbf, 0x47, 0x58, 0xc4, 0x15, 0x25, 0x51, 0x69, 0x13, + 0x9e, 0xf0, 0x15, 0x4b, 0x69, 0x93, 0x45, 0xc9, 0x13, 0x2e, 0x0a, 0x38, 0x9b, 0xd0, 0x32, 0x2b, + 0x60, 0x75, 0xa8, 0x3e, 0x3b, 0xdc, 0x3d, 0x68, 0x5f, 0x63, 0x4d, 0x98, 0x3d, 0xda, 0x7d, 0xfe, + 0x7c, 0x7f, 0x77, 0xa7, 0x5d, 0x62, 0x2d, 0xa8, 0xeb, 0x88, 0xcb, 0x32, 0xa6, 0x36, 0xb7, 0xb7, + 0x77, 0x0f, 0x9f, 0xef, 0xee, 0xb4, 0x2b, 0xce, 0x1f, 0x95, 0xa1, 0x69, 0xd4, 0x7c, 0x85, 0x8b, + 0xe6, 0x16, 0x00, 0x59, 0x12, 0x69, 0xec, 0x45, 0xd5, 0x35, 0x10, 0x94, 0x8c, 0xda, 0xc6, 0xae, + 0x88, 0x8b, 0x8e, 0x2a, 0x4d, 0xf3, 0x45, 0x37, 0x0a, 0xcd, 0x03, 0x87, 0x9a, 0x6b, 0x83, 0x48, + 0x4b, 0x12, 0xa0, 0x00, 0x40, 0xc1, 0x61, 0x26, 0x84, 0x6b, 0x13, 0xf1, 0x38, 0x1c, 0x9e, 0x73, + 0x51, 0x44, 0xe8, 0x63, 0x16, 0x86, 0x6d, 0x49, 0x11, 0x63, 0x04, 0xe7, 0xd6, 0x5c, 0x1b, 0x64, + 0xdf, 0x54, 0x6b, 0x53, 0xa7, 0xb5, 0x59, 0xcd, 0x4f, 0xb4, 0xb9, 0x2e, 0x4e, 0x02, 0x6c, 0x73, + 0x30, 0x90, 0xb9, 0xe6, 0xb5, 0xc9, 0xc8, 0xbc, 0xa3, 0xab, 0x84, 0x44, 0x01, 0xa3, 0x96, 0x8b, + 0x19, 0xf5, 0x8d, 0xe4, 0xec, 0xec, 0x42, 0xf3, 0xd0, 0xb8, 0xf5, 0x4b, 0x32, 0x4b, 0xdd, 0xf7, + 0x95, 0xb2, 0xce, 0x40, 0x8c, 0xee, 0x94, 0xcd, 0xee, 0x38, 0xff, 0xb0, 0x24, 0x2e, 0x52, 0xe9, + 0xee, 0x8b, 0xb6, 0x1d, 0x68, 0x69, 0x77, 0x72, 0x1a, 0x7b, 0x6e, 0x61, 0x58, 0x86, 0xba, 0xd2, + 0x0b, 0x4f, 0x4e, 0x62, 0xae, 0xa2, 0x44, 0x2d, 0x4c, 0x29, 0x8e, 0xa8, 0x8a, 0xfa, 0xa2, 0x85, + 0x58, 0x46, 0x8b, 0xe6, 0x70, 0x24, 0x12, 0xe9, 0x91, 0x54, 0xf1, 0xb1, 0x3a, 0xad, 0x43, 0xe4, + 0xb3, 0xb3, 0x7c, 0x0f, 0xea, 0xba, 0x5e, 0x7b, 0x57, 0x50, 0x25, 0x75, 0x3e, 0xee, 0x3e, 0x64, + 0x54, 0x5a, 0x9d, 0x16, 0xb4, 0x9a, 0xcf, 0x60, 0xeb, 0xc0, 0x4e, 0xfc, 0x28, 0x5b, 0x5c, 0x10, + 0x6f, 0x41, 0x8e, 0xf3, 0x12, 0x96, 0x14, 0xcf, 0x19, 0x1a, 0xad, 0xbd, 0x88, 0xa5, 0xab, 0x64, + 0x52, 0x39, 0x2f, 0x93, 0x9c, 0x5f, 0x54, 0x60, 0x56, 0xae, 0x74, 0xee, 0xe6, 0xb8, 0x58, 0x67, + 0x0b, 0x63, 0x1d, 0xeb, 0x8e, 0x20, 0x09, 0x30, 0xb9, 0x13, 0xe5, 0xf6, 0x9a, 0x4a, 0xd1, 0x5e, + 0xc3, 0xa0, 0x3a, 0xf6, 0x92, 0x33, 0x72, 0xbd, 0x34, 0x5c, 0xfa, 0xad, 0x1c, 0xa6, 0x35, 0xdb, + 0x61, 0x5a, 0x74, 0x4f, 0x5e, 0xa8, 0x53, 0xf9, 0x7b, 0xf2, 0x37, 0xa1, 0x21, 0xee, 0x56, 0xa7, + 0x3e, 0xd1, 0x14, 0x40, 0xea, 0x15, 0x09, 0x92, 0x10, 0xf2, 0xba, 0x4e, 0x8a, 0x7c, 0x85, 0xdd, + 0xed, 0xdb, 0x30, 0x23, 0xee, 0x8b, 0xc8, 0x28, 0xe0, 0x9b, 0xea, 0xbc, 0x50, 0x94, 0x53, 0x7f, + 0x45, 0x38, 0x91, 0x2b, 0xcb, 0x9a, 0x37, 0x4e, 0x9b, 0xf6, 0x8d, 0x53, 0xd3, 0x95, 0xdb, 0xb2, + 0x5d, 0xb9, 0xce, 0x23, 0x98, 0xb3, 0xaa, 0x43, 0xe9, 0x2a, 0xa3, 0x88, 0xdb, 0xd7, 0xd8, 0x1c, + 0x34, 0x9e, 0x1c, 0xf4, 0x1e, 0xed, 0x3f, 0x79, 0xbc, 0xf7, 0xbc, 0x5d, 0xc2, 0xe4, 0xd1, 0x8b, + 0xed, 0xed, 0xdd, 0xdd, 0x1d, 0x92, 0xb6, 0x00, 0x33, 0x8f, 0x36, 0x9f, 0xec, 0x93, 0xac, 0xdd, + 0x11, 0xb4, 0x2d, 0xeb, 0xd2, 0x67, 0x34, 0xdf, 0x04, 0xa6, 0xec, 0x7e, 0x8a, 0x26, 0x1a, 0x0f, + 0x79, 0xa2, 0x02, 0xdc, 0x17, 0x65, 0xce, 0x13, 0x9d, 0xa1, 0xee, 0x68, 0xa4, 0xb5, 0xa4, 0x2c, + 0x22, 0x27, 0x29, 0xcb, 0x22, 0xb2, 0xa8, 0xab, 0xf3, 0x9d, 0x2e, 0x74, 0x76, 0x38, 0xd6, 0xb6, + 0x39, 0x1c, 0x66, 0xba, 0x83, 0x86, 0x5b, 0x41, 0x9e, 0xb4, 0xea, 0xbe, 0x07, 0xd7, 0x37, 0x45, + 0x2c, 0xfb, 0x6f, 0x2a, 0xd4, 0xd1, 0xe9, 0xc0, 0x4a, 0xb6, 0x4a, 0xd9, 0xd8, 0x23, 0x58, 0xdc, + 0xe1, 0xc7, 0x93, 0xd3, 0x7d, 0x7e, 0x9e, 0x36, 0xc4, 0xa0, 0x1a, 0x9f, 0x85, 0x17, 0x72, 0x7e, + 0xe8, 0x37, 0x7b, 0x17, 0x60, 0x88, 0x65, 0x7a, 0xf1, 0x98, 0xf7, 0xd5, 0x3d, 0x45, 0x42, 0x8e, + 0xc6, 0xbc, 0xef, 0x7c, 0x0c, 0xcc, 0xac, 0x47, 0xce, 0x17, 0xea, 0x5a, 0x93, 0xe3, 0x5e, 0x7c, + 0x19, 0x27, 0x7c, 0xa4, 0x2e, 0x60, 0x9a, 0x90, 0x73, 0x07, 0x5a, 0x87, 0xde, 0xa5, 0xcb, 0x7f, + 0x2a, 0x5f, 0x50, 0x58, 0x85, 0xd9, 0xb1, 0x77, 0x89, 0x24, 0xa8, 0x9d, 0xc1, 0x94, 0xed, 0xfc, + 0x9f, 0x32, 0xcc, 0x88, 0x92, 0x58, 0xeb, 0x80, 0xc7, 0x89, 0x1f, 0x10, 0xa7, 0xa9, 0x5a, 0x0d, + 0x28, 0xc7, 0xdb, 0xe5, 0x02, 0xde, 0x96, 0x1e, 0x0a, 0x75, 0xdf, 0x4b, 0x32, 0xb0, 0x85, 0x21, + 0xa7, 0xa5, 0x31, 0xcb, 0xc2, 0x65, 0x98, 0x02, 0x99, 0x43, 0x8e, 0x54, 0xa3, 0x13, 0xfd, 0x53, + 0x62, 0x4b, 0xb2, 0xb1, 0x09, 0x15, 0xea, 0x8d, 0xb3, 0x82, 0xdb, 0x73, 0x7a, 0x63, 0x4e, 0x3f, + 0xac, 0xbf, 0x85, 0x7e, 0x28, 0xdc, 0x16, 0x6f, 0xd2, 0x0f, 0xe1, 0x2d, 0xf4, 0x43, 0x87, 0x41, + 0x9b, 0x2e, 0x93, 0xa3, 0x05, 0xa2, 0x68, 0xf7, 0xef, 0x96, 0xa0, 0x2d, 0xa9, 0x48, 0xe7, 0xa9, + 0xe3, 0xb2, 0x37, 0xdd, 0x3a, 0xba, 0x0d, 0x73, 0x64, 0xff, 0x68, 0x11, 0x20, 0x8f, 0x9e, 0x2c, + 0x10, 0xc7, 0xa1, 0x22, 0x5e, 0x46, 0xfe, 0x50, 0x2e, 0x8a, 0x09, 0x29, 0x29, 0x12, 0x79, 0x32, + 0xf6, 0xb6, 0xe4, 0xea, 0xb4, 0xf3, 0x27, 0x25, 0x58, 0x34, 0x3a, 0x2c, 0xa9, 0xf0, 0x21, 0xb4, + 0xf4, 0x9b, 0x0d, 0x5c, 0x6f, 0x6e, 0xab, 0x36, 0xdb, 0xa4, 0x9f, 0x59, 0x85, 0x69, 0x31, 0xbd, + 0x4b, 0xea, 0x60, 0x3c, 0x19, 0xc9, 0x5d, 0xc5, 0x84, 0x90, 0x90, 0x2e, 0x38, 0x7f, 0xa5, 0x8b, + 0x88, 0x7d, 0xcd, 0xc2, 0xc8, 0x6f, 0x8c, 0x76, 0x9b, 0x2e, 0x54, 0x95, 0x7e, 0x63, 0x13, 0x74, + 0xfe, 0x72, 0x19, 0x96, 0x84, 0x21, 0x2e, 0x1d, 0x20, 0xfa, 0xda, 0xec, 0x8c, 0xf0, 0x49, 0x08, + 0x8e, 0xdc, 0xbb, 0xe6, 0xca, 0x34, 0xfb, 0xce, 0x5b, 0x3a, 0x0f, 0x74, 0x40, 0xf0, 0x94, 0xb5, + 0xa8, 0x14, 0xad, 0xc5, 0x1b, 0x66, 0xba, 0xc8, 0x85, 0x5f, 0x2b, 0x76, 0xe1, 0xbf, 0x95, 0xcb, + 0x7c, 0x6b, 0x16, 0x6a, 0x71, 0x3f, 0x1c, 0x73, 0x67, 0x05, 0x96, 0xed, 0x29, 0x90, 0x82, 0xea, + 0xe7, 0x25, 0xe8, 0x3c, 0x12, 0x07, 0x83, 0x7e, 0x70, 0xba, 0xe7, 0xc7, 0x49, 0x18, 0xe9, 0x37, + 0x08, 0x6e, 0x01, 0xc4, 0x89, 0x17, 0x49, 0x85, 0x56, 0xa8, 0x06, 0x06, 0x82, 0x23, 0xe1, 0xc1, + 0x40, 0xe4, 0x8a, 0x15, 0xd4, 0xe9, 0x9c, 0xea, 0x25, 0x9d, 0x09, 0x96, 0x02, 0xf3, 0x81, 0x08, + 0xa3, 0xc7, 0x2e, 0xf3, 0x73, 0x92, 0xfe, 0xc2, 0x42, 0xcf, 0xa0, 0xce, 0x1f, 0x94, 0x61, 0x21, + 0xed, 0x24, 0x85, 0x7b, 0xd8, 0x32, 0x44, 0x6a, 0x2d, 0xa9, 0x0c, 0x91, 0x8e, 0xff, 0x9e, 0x8f, + 0x6a, 0x8c, 0xe1, 0x4f, 0x30, 0x50, 0x76, 0x1b, 0x9a, 0x2a, 0x15, 0x4e, 0x12, 0xe3, 0x32, 0xb0, + 0x09, 0x8b, 0xe0, 0x58, 0x54, 0xa4, 0xa4, 0x52, 0x28, 0x53, 0x74, 0x31, 0x69, 0x94, 0xd0, 0x97, + 0x62, 0xe6, 0x55, 0x92, 0xb5, 0x85, 0x26, 0x22, 0xde, 0x65, 0x21, 0x2d, 0xc4, 0xdc, 0xa1, 0xeb, + 0xfa, 0x11, 0x15, 0xcd, 0x99, 0xa2, 0xc6, 0x34, 0xb2, 0xb9, 0xea, 0x9a, 0x90, 0xb2, 0xe8, 0xc2, + 0x89, 0x71, 0xda, 0x59, 0x75, 0x2d, 0xcc, 0xf9, 0x9b, 0x25, 0xb8, 0x51, 0xb0, 0x8c, 0x92, 0x53, + 0x77, 0x60, 0xf1, 0x44, 0x67, 0xaa, 0xa9, 0x16, 0xec, 0xba, 0xa2, 0xa2, 0x1f, 0xec, 0xe9, 0x75, + 0xf3, 0x1f, 0x68, 0xe5, 0x54, 0x2c, 0x9e, 0x15, 0xc4, 0x9e, 0xcf, 0x70, 0x0e, 0xa1, 0xbb, 0xfb, + 0x1a, 0x19, 0x7f, 0xdb, 0x7c, 0x4a, 0x4e, 0x51, 0xd6, 0x46, 0x4e, 0xb0, 0x5d, 0xed, 0x46, 0x3a, + 0x81, 0x39, 0xab, 0x2e, 0xf6, 0xad, 0xb7, 0xad, 0xc4, 0xe4, 0xd1, 0x35, 0xb9, 0xea, 0xe2, 0x2d, + 0x3c, 0x15, 0x4a, 0x6f, 0x40, 0xce, 0x39, 0x2c, 0x3c, 0x9d, 0x0c, 0x13, 0x3f, 0x7d, 0x17, 0x8f, + 0x7d, 0x47, 0x7e, 0x44, 0x55, 0xa8, 0xa9, 0x2b, 0x6c, 0xca, 0x2c, 0x87, 0x33, 0x36, 0xc2, 0x9a, + 0x7a, 0xf9, 0x16, 0xf3, 0x19, 0xce, 0x0d, 0x58, 0x4d, 0x9b, 0x14, 0x73, 0xa7, 0x36, 0x87, 0x3f, + 0x2c, 0x89, 0x98, 0x30, 0xfb, 0x99, 0x3e, 0xf6, 0x18, 0x96, 0x62, 0x3f, 0x38, 0x1d, 0x72, 0xb3, + 0x9e, 0x58, 0xce, 0xc4, 0x75, 0xbb, 0x7b, 0xf2, 0x29, 0x3f, 0xb7, 0xe8, 0x0b, 0x24, 0x90, 0xe2, + 0x8e, 0xa6, 0x04, 0x92, 0x99, 0x92, 0xa2, 0x01, 0x7c, 0x17, 0xe6, 0xed, 0xc6, 0xd8, 0x27, 0x32, + 0x0a, 0x3e, 0xed, 0x99, 0x79, 0xee, 0x63, 0x53, 0x86, 0x55, 0xd2, 0xf9, 0xb2, 0x04, 0x1d, 0x97, + 0x23, 0x19, 0x73, 0xa3, 0x51, 0x49, 0x3d, 0x0f, 0x73, 0xd5, 0x4e, 0x1f, 0xb0, 0x8e, 0xae, 0x57, + 0x63, 0x5d, 0x9f, 0xba, 0x28, 0x7b, 0xd7, 0x0a, 0x46, 0xb5, 0x55, 0x87, 0x19, 0x39, 0xbe, 0x55, + 0xb8, 0x2e, 0xbb, 0xa4, 0xba, 0x93, 0x1e, 0x18, 0x58, 0x8d, 0x5a, 0x07, 0x06, 0x5d, 0xe8, 0x88, + 0xa7, 0x26, 0xcc, 0x71, 0xc8, 0x0f, 0x77, 0x80, 0x3d, 0xf5, 0xfa, 0x5e, 0x14, 0x86, 0xc1, 0x21, + 0x8f, 0x64, 0x7c, 0x0f, 0x29, 0x40, 0xe4, 0x4f, 0x57, 0xba, 0x9a, 0x48, 0xa9, 0xd7, 0x11, 0xc2, + 0x40, 0xbd, 0x42, 0x21, 0x52, 0x8e, 0x0b, 0x4b, 0x5b, 0xde, 0x2b, 0xae, 0x6a, 0x4a, 0x67, 0xa9, + 0x39, 0xd6, 0x95, 0xaa, 0xb9, 0x57, 0x97, 0x5b, 0xf2, 0xcd, 0xba, 0x66, 0x69, 0x67, 0x03, 0x96, + 0xed, 0x3a, 0xa5, 0x28, 0xe9, 0x42, 0x7d, 0x24, 0x31, 0xd9, 0x3b, 0x9d, 0xbe, 0xf7, 0x05, 0x34, + 0x8d, 0xe7, 0x43, 0xd8, 0x2a, 0x2c, 0xbd, 0x7c, 0xf2, 0xfc, 0x60, 0xf7, 0xe8, 0xa8, 0x77, 0xf8, + 0x62, 0xeb, 0xb3, 0xdd, 0x1f, 0xf4, 0xf6, 0x36, 0x8f, 0xf6, 0xda, 0xd7, 0xd8, 0x0a, 0xb0, 0x83, + 0xdd, 0xa3, 0xe7, 0xbb, 0x3b, 0x16, 0x5e, 0x62, 0xb7, 0xa0, 0xfb, 0xe2, 0xe0, 0xc5, 0xd1, 0xee, + 0x4e, 0xaf, 0xe8, 0xbb, 0x32, 0x7b, 0x17, 0x6e, 0xc8, 0xfc, 0x82, 0xcf, 0x2b, 0xf7, 0x1e, 0x42, + 0x3b, 0xeb, 0xff, 0xb0, 0x3c, 0x46, 0x6f, 0x72, 0x2d, 0x6d, 0x7c, 0x59, 0x81, 0x79, 0x11, 0xa5, + 0x27, 0x1e, 0xba, 0xe4, 0x11, 0x7b, 0x0a, 0xb3, 0xf2, 0xc5, 0x54, 0xa6, 0x48, 0xcb, 0x7e, 0xa3, + 0xb5, 0xbb, 0x92, 0x85, 0xe5, 0xb2, 0x2e, 0xfd, 0x95, 0xff, 0xf4, 0x3f, 0xfe, 0x76, 0x79, 0x8e, + 0x35, 0xef, 0x9f, 0x7f, 0x74, 0xff, 0x94, 0x07, 0x31, 0xd6, 0xf1, 0x7b, 0x00, 0xe9, 0x3b, 0xa0, + 0xac, 0xa3, 0x7d, 0x00, 0x99, 0x47, 0x52, 0xbb, 0x37, 0x0a, 0x72, 0x64, 0xbd, 0x37, 0xa8, 0xde, + 0x25, 0x67, 0x1e, 0xeb, 0xf5, 0x03, 0x3f, 0x11, 0x6f, 0x82, 0x7e, 0x5a, 0xba, 0xc7, 0x06, 0xd0, + 0x32, 0x5f, 0xe8, 0x64, 0xea, 0xfc, 0xa7, 0xe0, 0x8d, 0xd1, 0xee, 0x3b, 0x85, 0x79, 0x8a, 0x96, + 0xa9, 0x8d, 0xeb, 0x4e, 0x1b, 0xdb, 0x98, 0x50, 0x89, 0xb4, 0x95, 0xa1, 0xe0, 0xf0, 0xf4, 0x21, + 0x4e, 0x76, 0xd3, 0x60, 0xba, 0xdc, 0x33, 0xa0, 0xdd, 0x77, 0xa7, 0xe4, 0xca, 0xb6, 0xde, 0xa5, + 0xb6, 0x56, 0x1d, 0x86, 0x6d, 0xf5, 0xa9, 0x8c, 0x7a, 0x06, 0xf4, 0xd3, 0xd2, 0xbd, 0x8d, 0x7f, + 0x7f, 0x07, 0x1a, 0xfa, 0x6c, 0x98, 0xfd, 0x04, 0xe6, 0xac, 0x30, 0x4a, 0xa6, 0x86, 0x51, 0x14, + 0x75, 0xd9, 0xbd, 0x59, 0x9c, 0x29, 0x1b, 0xbe, 0x45, 0x0d, 0x77, 0xd8, 0x0a, 0x36, 0x2c, 0xe3, + 0x10, 0xef, 0x53, 0x40, 0xb0, 0xb8, 0x4f, 0xf8, 0xca, 0x90, 0x64, 0xa2, 0xb1, 0x9b, 0x59, 0xe1, + 0x62, 0xb5, 0xf6, 0xee, 0x94, 0x5c, 0xd9, 0xdc, 0x4d, 0x6a, 0x6e, 0x85, 0x2d, 0x9b, 0xcd, 0xe9, + 0xf3, 0x5a, 0x4e, 0x97, 0x68, 0xcd, 0x37, 0x2a, 0xd9, 0xbb, 0x9a, 0xb0, 0x8a, 0xde, 0xae, 0xd4, + 0x24, 0x92, 0x7f, 0xc0, 0xd2, 0xe9, 0x50, 0x53, 0x8c, 0xd1, 0xf2, 0x99, 0x4f, 0x54, 0xb2, 0x63, + 0x68, 0x1a, 0x2f, 0x59, 0xb1, 0x1b, 0x53, 0x5f, 0xdd, 0xea, 0x76, 0x8b, 0xb2, 0x8a, 0x86, 0x62, + 0xd6, 0x7f, 0x1f, 0x15, 0x9d, 0x1f, 0x41, 0x43, 0xbf, 0x8d, 0xc4, 0x56, 0x8d, 0xb7, 0xaa, 0xcc, + 0xb7, 0x9c, 0xba, 0x9d, 0x7c, 0x46, 0x11, 0xf1, 0x99, 0xb5, 0x23, 0xf1, 0xbd, 0x84, 0xa6, 0xf1, + 0xfe, 0x91, 0x1e, 0x40, 0xfe, 0x8d, 0x25, 0x3d, 0x80, 0x82, 0xe7, 0x92, 0x9c, 0x45, 0x6a, 0xa2, + 0xc9, 0x1a, 0x44, 0xdf, 0xc9, 0xeb, 0x30, 0x66, 0xfb, 0x70, 0x5d, 0x4a, 0xec, 0x63, 0xfe, 0x55, + 0x96, 0xa1, 0xe0, 0x59, 0xd0, 0x07, 0x25, 0xf6, 0x10, 0xea, 0xea, 0x99, 0x2b, 0xb6, 0x52, 0xfc, + 0x5c, 0x57, 0x77, 0x35, 0x87, 0x4b, 0xf1, 0xfa, 0x03, 0x80, 0xf4, 0xb1, 0x25, 0x2d, 0x24, 0x72, + 0x8f, 0x37, 0x69, 0x0a, 0xc8, 0xbf, 0xcc, 0xe4, 0xac, 0xd0, 0x00, 0xdb, 0x8c, 0x84, 0x44, 0xc0, + 0x2f, 0xd4, 0x7d, 0xf9, 0x1f, 0x43, 0xd3, 0x78, 0x6f, 0x49, 0x4f, 0x5f, 0xfe, 0xad, 0x26, 0x3d, + 0x7d, 0x05, 0xcf, 0x33, 0x39, 0x5d, 0xaa, 0x7d, 0xd9, 0x59, 0xc0, 0xda, 0x63, 0xff, 0x34, 0x18, + 0x89, 0x02, 0xb8, 0x40, 0x67, 0x30, 0x67, 0x3d, 0xaa, 0xa4, 0x39, 0xb4, 0xe8, 0xc9, 0x26, 0xcd, + 0xa1, 0x85, 0xef, 0x30, 0x29, 0x3a, 0x73, 0x16, 0xb1, 0x9d, 0x73, 0x2a, 0x62, 0xb4, 0xf4, 0x43, + 0x68, 0x1a, 0x0f, 0x24, 0xe9, 0xb1, 0xe4, 0xdf, 0x62, 0xd2, 0x63, 0x29, 0x7a, 0x4f, 0x69, 0x99, + 0xda, 0x98, 0x77, 0x88, 0x14, 0xe8, 0xe6, 0x37, 0xd6, 0xfd, 0x13, 0x98, 0xb7, 0x9f, 0x4c, 0xd2, + 0xbc, 0x5f, 0xf8, 0xf8, 0x92, 0xe6, 0xfd, 0x29, 0xef, 0x2c, 0x49, 0x92, 0xbe, 0xb7, 0xa4, 0x1b, + 0xb9, 0xff, 0xb9, 0x8c, 0x2e, 0xfb, 0x82, 0x7d, 0x0f, 0x05, 0x9c, 0xbc, 0x8a, 0xcf, 0x56, 0x0d, + 0xaa, 0x35, 0x2f, 0xec, 0x6b, 0x7e, 0xc9, 0xdd, 0xda, 0xb7, 0x89, 0x59, 0xdc, 0x5d, 0xa7, 0x5d, + 0x8b, 0xae, 0xe4, 0x1b, 0xbb, 0x96, 0x79, 0x6b, 0xdf, 0xd8, 0xb5, 0xac, 0x9b, 0xfb, 0xd9, 0x5d, + 0x2b, 0xf1, 0xb1, 0x8e, 0x00, 0x16, 0x32, 0x57, 0x3d, 0x34, 0x57, 0x14, 0xdf, 0xc6, 0xeb, 0xde, + 0x7a, 0xf3, 0x0d, 0x11, 0x5b, 0x82, 0x28, 0x21, 0x78, 0x5f, 0xdd, 0x7d, 0xfc, 0x7d, 0x68, 0x99, + 0xcf, 0xb8, 0x30, 0x93, 0x95, 0xb3, 0x2d, 0xbd, 0x53, 0x98, 0x67, 0x2f, 0x2e, 0x6b, 0x99, 0xcd, + 0xb0, 0xef, 0xc3, 0x8a, 0x66, 0x75, 0xf3, 0xf6, 0x40, 0xcc, 0xde, 0x2b, 0xb8, 0x53, 0x60, 0xea, + 0x71, 0xdd, 0x1b, 0x53, 0x2f, 0x1d, 0x3c, 0x28, 0x21, 0xd1, 0xd8, 0x6f, 0x63, 0xa4, 0x1b, 0x46, + 0xd1, 0x93, 0x20, 0xe9, 0x86, 0x51, 0xf8, 0xa0, 0x86, 0x22, 0x1a, 0xb6, 0x64, 0xcd, 0x91, 0x38, + 0x88, 0x67, 0x3f, 0x84, 0x05, 0xe3, 0x7e, 0xd6, 0xd1, 0x65, 0xd0, 0xd7, 0x0c, 0x90, 0xbf, 0x3a, + 0xdc, 0x2d, 0xb2, 0x52, 0x9c, 0x55, 0xaa, 0x7f, 0xd1, 0xb1, 0x26, 0x07, 0x89, 0x7f, 0x1b, 0x9a, + 0xe6, 0xdd, 0xaf, 0x37, 0xd4, 0xbb, 0x6a, 0x64, 0x99, 0x37, 0x5f, 0x1f, 0x94, 0xd8, 0xa1, 0x08, + 0xc8, 0xd2, 0xef, 0x74, 0x86, 0x51, 0x76, 0xfb, 0xb4, 0xdf, 0xef, 0xd4, 0x0b, 0x59, 0xf4, 0x72, + 0xeb, 0xdd, 0xd2, 0x83, 0x12, 0xfb, 0x7b, 0x25, 0x68, 0x59, 0x77, 0xb3, 0xac, 0xf0, 0x96, 0x4c, + 0xcf, 0x3a, 0x66, 0x9e, 0xd9, 0x35, 0xc7, 0xa5, 0x61, 0xef, 0xdf, 0xfb, 0xae, 0x35, 0xad, 0x9f, + 0x5b, 0x0e, 0xb5, 0xf5, 0xec, 0x63, 0x9d, 0x5f, 0x64, 0x0b, 0x98, 0x17, 0xb6, 0xbf, 0x78, 0x50, + 0x62, 0x7f, 0x5c, 0x82, 0x79, 0xdb, 0x0d, 0xac, 0x87, 0x5b, 0xe8, 0x70, 0xd6, 0x8b, 0x3f, 0xc5, + 0x77, 0xfc, 0x43, 0xea, 0xe5, 0xf3, 0x7b, 0xae, 0xd5, 0x4b, 0xf9, 0x0e, 0xcb, 0xaf, 0xd7, 0x5b, + 0xf6, 0xa9, 0x78, 0x5d, 0x5a, 0x1d, 0xd6, 0xb0, 0xfc, 0x1b, 0xc7, 0x9a, 0x60, 0xcc, 0x57, 0x89, + 0x69, 0x11, 0x7e, 0x2c, 0x1e, 0xa9, 0x54, 0xe7, 0x09, 0x48, 0x77, 0x6f, 0xfb, 0xbd, 0x73, 0x9b, + 0xc6, 0x74, 0xcb, 0xb9, 0x61, 0x8d, 0x29, 0xbb, 0xc3, 0x6f, 0x8a, 0xde, 0xc9, 0x07, 0x85, 0xd3, + 0x2d, 0x2a, 0xf7, 0xc8, 0xf0, 0xf4, 0x4e, 0x8e, 0x44, 0x27, 0x65, 0x71, 0x8b, 0x39, 0xde, 0xb2, + 0x1a, 0xe7, 0x1e, 0xf5, 0xf5, 0xb6, 0xf3, 0xde, 0xd4, 0xbe, 0xde, 0x27, 0x67, 0x2e, 0xf6, 0xf8, + 0x10, 0x20, 0x3d, 0x58, 0x65, 0x99, 0x83, 0x3d, 0x2d, 0x32, 0xf2, 0x67, 0xaf, 0x36, 0x07, 0xaa, + 0xf3, 0x3f, 0xac, 0xf1, 0x47, 0x42, 0x00, 0x3e, 0x51, 0x47, 0x82, 0xa6, 0x9a, 0x63, 0x9f, 0x80, + 0x5a, 0x6a, 0x4e, 0xb6, 0x7e, 0x4b, 0xfc, 0xe9, 0xf3, 0xc5, 0x17, 0x30, 0xb7, 0x1f, 0x86, 0xaf, + 0x26, 0x63, 0x1d, 0x79, 0x62, 0x9f, 0xb3, 0xec, 0x79, 0xf1, 0x59, 0x37, 0x33, 0x0a, 0x67, 0x8d, + 0xaa, 0xea, 0xb2, 0x8e, 0x51, 0xd5, 0xfd, 0xcf, 0xd3, 0x83, 0xdb, 0x2f, 0x98, 0x07, 0x8b, 0x5a, + 0xaa, 0xea, 0x8e, 0x77, 0xed, 0x6a, 0x2c, 0x59, 0x9a, 0x6d, 0xc2, 0xd2, 0xc7, 0x55, 0x6f, 0xef, + 0xc7, 0xaa, 0x4e, 0x92, 0x29, 0xad, 0x1d, 0xde, 0xa7, 0x9b, 0x27, 0x74, 0x58, 0xb1, 0x94, 0x76, + 0x5c, 0x9f, 0x72, 0x74, 0xe7, 0x2c, 0xd0, 0xde, 0x69, 0xc6, 0xde, 0x65, 0xc4, 0x7f, 0x7a, 0xff, + 0x73, 0x79, 0x0c, 0xf2, 0x85, 0xda, 0x69, 0xd4, 0x39, 0x91, 0xb5, 0xd3, 0x64, 0x0e, 0x96, 0xac, + 0x9d, 0x26, 0x77, 0xb0, 0x64, 0x4d, 0xb5, 0x3a, 0xa7, 0x62, 0x43, 0x58, 0xcc, 0x9d, 0x45, 0xe9, + 0x4d, 0x66, 0xda, 0x09, 0x56, 0x77, 0x6d, 0x7a, 0x01, 0xbb, 0xb5, 0x7b, 0x76, 0x6b, 0x47, 0x30, + 0xb7, 0xc3, 0xc5, 0x64, 0x89, 0x50, 0xdb, 0xcc, 0x05, 0x3f, 0x33, 0x90, 0x37, 0xbb, 0x25, 0x50, + 0x9e, 0xad, 0x4a, 0x50, 0x8c, 0x2b, 0xfb, 0x11, 0x34, 0x1f, 0xf3, 0x44, 0xc5, 0xd6, 0x6a, 0x65, + 0x36, 0x13, 0x6c, 0xdb, 0x2d, 0x08, 0xcd, 0xb5, 0x69, 0x86, 0x6a, 0xbb, 0xcf, 0x07, 0xa7, 0x5c, + 0x08, 0xa7, 0x9e, 0x3f, 0xf8, 0x82, 0xfd, 0x05, 0xaa, 0x5c, 0x5f, 0x2e, 0x58, 0x31, 0x02, 0x25, + 0xcd, 0xca, 0x17, 0x32, 0x78, 0x51, 0xcd, 0x41, 0x38, 0xe0, 0x86, 0x52, 0x15, 0x40, 0xd3, 0xb8, + 0x13, 0xa4, 0x19, 0x28, 0x7f, 0xc5, 0x4c, 0x33, 0x50, 0xc1, 0x15, 0x22, 0xe7, 0x2e, 0xb5, 0xe3, + 0xb0, 0xb5, 0xb4, 0x1d, 0x71, 0x6d, 0x28, 0x6d, 0xe9, 0xfe, 0xe7, 0xde, 0x28, 0xf9, 0x82, 0xbd, + 0xa4, 0x77, 0x91, 0xcc, 0xd8, 0xe1, 0x54, 0x3b, 0xcf, 0x86, 0x19, 0xeb, 0xc9, 0x32, 0xb2, 0x6c, + 0x8d, 0x5d, 0x34, 0x45, 0xba, 0xd7, 0x77, 0x00, 0x8e, 0x92, 0x70, 0xbc, 0xe3, 0xf1, 0x51, 0x18, + 0xa4, 0xb2, 0x36, 0x8d, 0x5c, 0x4d, 0xe5, 0x97, 0x11, 0xbe, 0xca, 0x5e, 0x1a, 0xe6, 0x8c, 0x15, + 0x7e, 0xad, 0x88, 0x6b, 0x6a, 0x70, 0xab, 0x9e, 0x90, 0x82, 0x00, 0xd7, 0x07, 0x25, 0xb6, 0x09, + 0x90, 0x1e, 0x46, 0x6a, 0xe3, 0x24, 0x77, 0xce, 0xa9, 0xc5, 0x5e, 0xc1, 0xc9, 0xe5, 0x21, 0x34, + 0xd2, 0xd3, 0xad, 0xd5, 0xf4, 0xe6, 0x9d, 0x75, 0x16, 0xa6, 0x77, 0xf0, 0xdc, 0x99, 0x93, 0xd3, + 0xa6, 0xa9, 0x02, 0x56, 0xc7, 0xa9, 0xa2, 0x83, 0x24, 0x1f, 0x96, 0x44, 0x07, 0xb5, 0x82, 0x43, + 0x11, 0x97, 0x6a, 0x24, 0x05, 0xe7, 0x3e, 0x9a, 0x9b, 0x0b, 0x0f, 0x44, 0x2c, 0x1f, 0x0b, 0x52, + 0xab, 0x88, 0xf6, 0x44, 0xd1, 0x3c, 0x82, 0xc5, 0x9c, 0x8f, 0x5d, 0xb3, 0xf4, 0xb4, 0x43, 0x14, + 0xcd, 0xd2, 0x53, 0xdd, 0xf3, 0xce, 0x75, 0x6a, 0x72, 0xc1, 0x01, 0xb2, 0xa9, 0x2e, 0xfc, 0xa4, + 0x7f, 0x86, 0xcd, 0xfd, 0x61, 0x09, 0x96, 0x0a, 0x5c, 0xe8, 0xec, 0x7d, 0x65, 0x9e, 0x4f, 0x75, + 0xaf, 0x77, 0x0b, 0x3d, 0xac, 0xce, 0x11, 0xb5, 0xf3, 0x94, 0x7d, 0x66, 0x6d, 0x6c, 0xc2, 0xb9, + 0x29, 0x39, 0xf3, 0x8d, 0x4a, 0x45, 0xa1, 0x46, 0xf1, 0x53, 0x58, 0x15, 0x1d, 0xd9, 0x1c, 0x0e, + 0x33, 0xde, 0xdf, 0x5b, 0xb9, 0x7f, 0x30, 0x63, 0x79, 0xb5, 0xbb, 0xd3, 0xff, 0x01, 0xcd, 0x14, + 0x05, 0x58, 0x74, 0x95, 0x4d, 0xa0, 0x9d, 0xf5, 0xa8, 0xb2, 0xe9, 0x75, 0x75, 0xdf, 0xb3, 0x0c, + 0xcd, 0x02, 0x2f, 0xec, 0x6f, 0x51, 0x63, 0xef, 0x39, 0xdd, 0xa2, 0x79, 0x11, 0xb6, 0x27, 0xae, + 0xc7, 0x5f, 0xd2, 0xee, 0xdf, 0xcc, 0x38, 0x55, 0x03, 0xd3, 0xfc, 0xd5, 0xda, 0xd4, 0x2d, 0xf6, + 0x1e, 0x7f, 0x40, 0xcd, 0xaf, 0x39, 0xef, 0x14, 0x35, 0x1f, 0x89, 0x4f, 0x84, 0xd1, 0xbb, 0x9a, + 0xe5, 0x6b, 0xd5, 0x83, 0xb5, 0xa2, 0xf5, 0x9e, 0x6a, 0xbd, 0x64, 0xe6, 0xfa, 0x1a, 0xe9, 0x76, + 0x2d, 0xd3, 0xdd, 0xab, 0xd9, 0xa7, 0xc0, 0xaf, 0xac, 0xd9, 0xa7, 0xc8, 0x3f, 0x6c, 0xeb, 0x35, + 0xca, 0x33, 0xfc, 0x69, 0xe9, 0xde, 0xd6, 0x9d, 0x1f, 0xfe, 0xd6, 0xa9, 0x9f, 0x9c, 0x4d, 0x8e, + 0xd7, 0xfb, 0xe1, 0xe8, 0xfe, 0x50, 0xb9, 0xf5, 0xe4, 0x2d, 0x84, 0xfb, 0xc3, 0x60, 0x70, 0x9f, + 0xaa, 0x3d, 0x9e, 0xa1, 0xff, 0x88, 0xf5, 0xad, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x95, 0x82, + 0x58, 0xe9, 0x43, 0x6b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index c1347e692..e0240da52 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -1836,6 +1836,32 @@ message Hop { TLV format. */ bool tlv_payload = 9 [json_name = "tlv_payload"]; + + /** + An optional TLV record tha singals the use of an MPP payment. If present, + the receiver will enforce that that the same mpp_record is included in the + final hop payload of all non-zero payments in the HTLC set. If empty, a + regular single-shot payment is or was attempted. + */ + MPPRecord mpp_record = 10 [json_name = "mpp_record"]; +} + +message MPPRecord { + /** + A unique, random identifier used to authenticate the sender as the intended + payer of a multi-path payment. The payment_addr must be the same for all + subpayments, and match the payment_addr provided in the receiver's invoice. + The same payment_addr must be used on all subpayments. + */ + bytes payment_addr = 11 [json_name = "payment_addr"]; + + /** + The total amount in milli-satoshis being sent as part of a larger multi-path + payment. The caller is responsible for ensuring subpayments to the same node + and payment_hash sum exactly to total_amt_msat. The same + total_amt_msat must be used on all subpayments. + */ + int64 total_amt_msat = 10 [json_name = "total_amt_msat"]; } /** diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index 90254a177..a366b9c89 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -2530,6 +2530,10 @@ "type": "boolean", "format": "boolean", "description": "* \nIf set to true, then this hop will be encoded using the new variable length\nTLV format." + }, + "mpp_record": { + "$ref": "#/definitions/lnrpcMPPRecord", + "description": "*\nAn optional TLV record tha singals the use of an MPP payment. If present,\nthe receiver will enforce that that the same mpp_record is included in the\nfinal hop payload of all non-zero payments in the HTLC set. If empty, a\nregular single-shot payment is or was attempted." } } }, @@ -2873,6 +2877,21 @@ } } }, + "lnrpcMPPRecord": { + "type": "object", + "properties": { + "payment_addr": { + "type": "string", + "format": "byte", + "description": "*\nA unique, random identifier used to authenticate the sender as the intended\npayer of a multi-path payment. The payment_addr must be the same for all\nsubpayments, and match the payment_addr provided in the receiver's invoice.\nThe same payment_addr must be used on all subpayments." + }, + "total_amt_msat": { + "type": "string", + "format": "int64", + "description": "*\nThe total amount in milli-satoshis being sent as part of a larger multi-path\npayment. The caller is responsible for ensuring subpayments to the same node\nand payment_hash sum exactly to total_amt_msat. The same\ntotal_amt_msat must be used on all subpayments." + } + } + }, "lnrpcMacaroonPermission": { "type": "object", "properties": { From 8cb17d5c1f88def8e63a2c43ee3d78c6b125d882 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 15:11:23 -0800 Subject: [PATCH 09/11] lnrpc/routerrpc/router_backend: populate and unmarshal mpp fields This commit parses mpp_total_amt_msat and mpp_payment_addr from the SendToRoute rpc and populates an MPP record on the internal hop reprsentation. When the router goes to encode the onion packet, these fields will be serialized for the destination. We also populate the mpp fields when marshalling routes in rpc responses. --- lnrpc/routerrpc/router_backend.go | 68 ++++++++++++++ lnrpc/routerrpc/router_backend_test.go | 120 +++++++++++++++++++++++++ 2 files changed, 188 insertions(+) diff --git a/lnrpc/routerrpc/router_backend.go b/lnrpc/routerrpc/router_backend.go index 99942b0d5..c90e55132 100644 --- a/lnrpc/routerrpc/router_backend.go +++ b/lnrpc/routerrpc/router_backend.go @@ -13,7 +13,9 @@ import ( "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/lnrpc" + "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/tlv" @@ -352,6 +354,17 @@ func (r *RouterBackend) MarshallRoute(route *route.Route) (*lnrpc.Route, error) chanCapacity = incomingAmt.ToSatoshis() } + // Extract the MPP fields if present on this hop. + var mpp *lnrpc.MPPRecord + if hop.MPP != nil { + addr := hop.MPP.PaymentAddr() + + mpp = &lnrpc.MPPRecord{ + PaymentAddr: addr[:], + TotalAmtMsat: int64(hop.MPP.TotalMsat()), + } + } + resp.Hops[i] = &lnrpc.Hop{ ChanId: hop.ChannelID, ChanCapacity: int64(chanCapacity), @@ -364,6 +377,7 @@ func (r *RouterBackend) MarshallRoute(route *route.Route) (*lnrpc.Route, error) hop.PubKeyBytes[:], ), TlvPayload: !hop.LegacyPayload, + MppRecord: mpp, } incomingAmt = hop.AmtToForward } @@ -396,6 +410,11 @@ func (r *RouterBackend) UnmarshallHopByChannelLookup(hop *lnrpc.Hop, var tlvRecords []tlv.Record + mpp, err := UnmarshalMPP(hop.MppRecord) + if err != nil { + return nil, err + } + return &route.Hop{ OutgoingTimeLock: hop.Expiry, AmtToForward: lnwire.MilliSatoshi(hop.AmtToForwardMsat), @@ -403,6 +422,7 @@ func (r *RouterBackend) UnmarshallHopByChannelLookup(hop *lnrpc.Hop, ChannelID: hop.ChanId, TLVRecords: tlvRecords, LegacyPayload: !hop.TlvPayload, + MPP: mpp, }, nil } @@ -420,6 +440,11 @@ func UnmarshallKnownPubkeyHop(hop *lnrpc.Hop) (*route.Hop, error) { var tlvRecords []tlv.Record + mpp, err := UnmarshalMPP(hop.MppRecord) + if err != nil { + return nil, err + } + return &route.Hop{ OutgoingTimeLock: hop.Expiry, AmtToForward: lnwire.MilliSatoshi(hop.AmtToForwardMsat), @@ -427,6 +452,7 @@ func UnmarshallKnownPubkeyHop(hop *lnrpc.Hop) (*route.Hop, error) { ChannelID: hop.ChanId, TLVRecords: tlvRecords, LegacyPayload: !hop.TlvPayload, + MPP: mpp, }, nil } @@ -712,3 +738,45 @@ func ValidateCLTVLimit(val, max uint32) (uint32, error) { return val, nil } } + +// UnmarshalMPP accepts the mpp_total_amt_msat and mpp_payment_addr fields from +// an RPC request and converts into an record.MPP object. An error is returned +// if the payment address is not 0 or 32 bytes. If the total amount and payment +// address are zero-value, the return value will be nil signaling there is no +// MPP record to attach to this hop. Otherwise, a non-nil reocrd will be +// contained combining the provided values. +func UnmarshalMPP(reqMPP *lnrpc.MPPRecord) (*record.MPP, error) { + // If no MPP record was submitted, assume the user wants to send a + // regular payment. + if reqMPP == nil { + return nil, nil + } + + reqTotal := reqMPP.TotalAmtMsat + reqAddr := reqMPP.PaymentAddr + + switch { + + // No MPP fields were provided. + case reqTotal == 0 && len(reqAddr) == 0: + return nil, fmt.Errorf("missing total_msat and payment_addr") + + // Total is present, but payment address is missing. + case reqTotal > 0 && len(reqAddr) == 0: + return nil, fmt.Errorf("missing payment_addr") + + // Payment address is present, but total is missing. + case reqTotal == 0 && len(reqAddr) > 0: + return nil, fmt.Errorf("missing total_msat") + } + + addr, err := lntypes.MakeHash(reqAddr) + if err != nil { + return nil, fmt.Errorf("unable to parse "+ + "payment_addr: %v", err) + } + + total := lnwire.MilliSatoshi(reqTotal) + + return record.NewMPP(total, addr), nil +} diff --git a/lnrpc/routerrpc/router_backend_test.go b/lnrpc/routerrpc/router_backend_test.go index 48e5b8fdb..779231f87 100644 --- a/lnrpc/routerrpc/router_backend_test.go +++ b/lnrpc/routerrpc/router_backend_test.go @@ -180,3 +180,123 @@ func (m *mockMissionControl) GetPairHistorySnapshot(fromNode, return routing.TimedPairResult{} } + +type mppOutcome byte + +const ( + valid mppOutcome = iota + invalid + nompp +) + +type unmarshalMPPTest struct { + name string + mpp *lnrpc.MPPRecord + outcome mppOutcome +} + +// TestUnmarshalMPP checks both positive and negative cases of UnmarshalMPP to +// assert that an MPP record is only returned when both fields are properly +// specified. It also asserts that zero-values for both inputs is also valid, +// but returns a nil record. +func TestUnmarshalMPP(t *testing.T) { + tests := []unmarshalMPPTest{ + { + name: "nil record", + mpp: nil, + outcome: nompp, + }, + { + name: "invalid total or addr", + mpp: &lnrpc.MPPRecord{ + PaymentAddr: nil, + TotalAmtMsat: 0, + }, + outcome: invalid, + }, + { + name: "valid total only", + mpp: &lnrpc.MPPRecord{ + PaymentAddr: nil, + TotalAmtMsat: 8, + }, + outcome: invalid, + }, + { + name: "valid addr only", + mpp: &lnrpc.MPPRecord{ + PaymentAddr: bytes.Repeat([]byte{0x02}, 32), + TotalAmtMsat: 0, + }, + outcome: invalid, + }, + { + name: "valid total and invalid addr", + mpp: &lnrpc.MPPRecord{ + PaymentAddr: []byte{0x02}, + TotalAmtMsat: 8, + }, + outcome: invalid, + }, + { + name: "valid total and valid addr", + mpp: &lnrpc.MPPRecord{ + PaymentAddr: bytes.Repeat([]byte{0x02}, 32), + TotalAmtMsat: 8, + }, + outcome: valid, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + testUnmarshalMPP(t, test) + }) + } +} + +func testUnmarshalMPP(t *testing.T, test unmarshalMPPTest) { + mpp, err := UnmarshalMPP(test.mpp) + switch test.outcome { + + // Valid arguments should result in no error, a non-nil MPP record, and + // the fields should be set correctly. + case valid: + if err != nil { + t.Fatalf("unable to parse mpp record: %v", err) + } + if mpp == nil { + t.Fatalf("mpp payload should be non-nil") + } + if int64(mpp.TotalMsat()) != test.mpp.TotalAmtMsat { + t.Fatalf("incorrect total msat") + } + addr := mpp.PaymentAddr() + if !bytes.Equal(addr[:], test.mpp.PaymentAddr) { + t.Fatalf("incorrect payment addr") + } + + // Invalid arguments should produce a failure and nil MPP record. + case invalid: + if err == nil { + t.Fatalf("expected failure for invalid mpp") + } + if mpp != nil { + t.Fatalf("mpp payload should be nil for failure") + } + + // Arguments that produce no MPP field should return no error and no MPP + // record. + case nompp: + if err != nil { + t.Fatalf("failure for args resulting for no-mpp") + } + if mpp != nil { + t.Fatalf("mpp payload should be nil for no-mpp") + } + + default: + t.Fatalf("test case has non-standard outcome") + } +} From 18a06b0ed3b495793e5a3c3c4cc603761750dc51 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 15:11:39 -0800 Subject: [PATCH 10/11] lntest: remove unnecessary wait from single-hop sendtoroute We already wait for all channels to open before creating the payment requests. --- lntest/itest/lnd_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lntest/itest/lnd_test.go b/lntest/itest/lnd_test.go index f96241798..eb13a36a0 100644 --- a/lntest/itest/lnd_test.go +++ b/lntest/itest/lnd_test.go @@ -4488,16 +4488,6 @@ func testSingleHopSendToRoute(net *lntest.NetworkHarness, t *harnessTest) { t.Fatalf("unable to create pay reqs: %v", err) } - // We'll wait for all parties to recognize the new channels within the - // network. - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - err = net.Bob.WaitForNetworkChannelOpen(ctxt, chanPointAlice) - if err != nil { - t.Fatalf("alice didn't advertise her channel in time: %v", err) - } - - time.Sleep(time.Millisecond * 50) - // Using Alice as the source, pay to the 5 invoices from Carol created // above. ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) From 540e44e186ee0c6460b9a20eaa9e1d4d3481fb7b Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 4 Nov 2019 15:11:55 -0800 Subject: [PATCH 11/11] lntest/itest: expand testSingleHopSendToRoute matrix In this commit, we refactor the testSingleHopSendToRoute test to support table driven tests for various endpoints and payment types. Currently only the main rpcserver's SendToRoute is tested, so we also add support the SendToRouteSync and the routerrpc's SendToRoute. The tests are also modified to have each endpoint perform a single-hop, single-shot MPP payment. This asserts that the Hop messages are being properly unmarshalled and that setting correctly yields a successful payment. At the momemnt the receiver does not actually verify or use the MPP fields presented in the onion, though this test will be expanded later as those pieces are assembled. --- lntest/itest/lnd_test.go | 387 +++++++++++++++++++++++++++++++-------- 1 file changed, 309 insertions(+), 78 deletions(-) diff --git a/lntest/itest/lnd_test.go b/lntest/itest/lnd_test.go index eb13a36a0..5817e85db 100644 --- a/lntest/itest/lnd_test.go +++ b/lntest/itest/lnd_test.go @@ -106,7 +106,6 @@ func (h *harnessTest) Fatalf(format string, a ...interface{}) { // RunTestCase executes a harness test case. Any errors or panics will be // represented as fatal. func (h *harnessTest) RunTestCase(testCase *testCase) { - h.testCase = testCase defer func() { h.testCase = nil @@ -4406,43 +4405,135 @@ func testMultiHopPayments(net *lntest.NetworkHarness, t *harnessTest) { closeChannelAndAssert(ctxt, t, net, carol, chanPointCarol, false) } -// testSingleHopSendToRoute tests that payments are properly processed -// through a provided route with a single hop. We'll create the -// following network topology: -// Alice --100k--> Bob -// We'll query the daemon for routes from Alice to Bob and then -// send payments through the route. +type singleHopSendToRouteCase struct { + name string + + // streaming tests streaming SendToRoute if true, otherwise tests + // synchronous SenToRoute. + streaming bool + + // routerrpc submits the request to the routerrpc subserver if true, + // otherwise submits to the main rpc server. + routerrpc bool + + // mpp sets the MPP fields on the request if true, otherwise submits a + // regular payment. + mpp bool +} + +var singleHopSendToRouteCases = []singleHopSendToRouteCase{ + { + name: "regular main sync", + }, + { + name: "regular main stream", + streaming: true, + }, + { + name: "regular routerrpc sync", + routerrpc: true, + }, + { + name: "mpp main sync", + mpp: true, + }, + { + name: "mpp main stream", + streaming: true, + mpp: true, + }, + { + name: "mpp routerrpc sync", + routerrpc: true, + mpp: true, + }, +} + +// testSingleHopSendToRoute tests that payments are properly processed through a +// provided route with a single hop. We'll create the following network +// topology: +// Carol --100k--> Dave +// We'll query the daemon for routes from Carol to Dave and then send payments +// by feeding the route back into the various SendToRoute RPC methods. Here we +// test all three SendToRoute endpoints, forcing each to perform both a regular +// payment and an MPP payment. func testSingleHopSendToRoute(net *lntest.NetworkHarness, t *harnessTest) { - ctxb := context.Background() + for _, test := range singleHopSendToRouteCases { + test := test + + t.t.Run(test.name, func(t1 *testing.T) { + ht := newHarnessTest(t1, t.lndHarness) + ht.RunTestCase(&testCase{ + name: test.name, + test: func(_ *lntest.NetworkHarness, tt *harnessTest) { + testSingleHopSendToRouteCase(net, tt, test) + }, + }) + }) + } +} + +func testSingleHopSendToRouteCase(net *lntest.NetworkHarness, t *harnessTest, + test singleHopSendToRouteCase) { const chanAmt = btcutil.Amount(100000) + const paymentAmtSat = 1000 + const numPayments = 5 + const amountPaid = int64(numPayments * paymentAmtSat) + + ctxb := context.Background() var networkChans []*lnrpc.ChannelPoint - // Open a channel with 100k satoshis between Alice and Bob with Alice + // Create Carol and Dave, then establish a channel between them. Carol + // is the sole funder of the channel with 100k satoshis. The network + // topology should look like: + // Carol -> 100k -> Dave + carol, err := net.NewNode("Carol", nil) + if err != nil { + t.Fatalf("unable to create new nodes: %v", err) + } + defer shutdownAndAssert(net, t, carol) + + dave, err := net.NewNode("Dave", nil) + if err != nil { + t.Fatalf("unable to create new nodes: %v", err) + } + defer shutdownAndAssert(net, t, dave) + + ctxt, _ := context.WithTimeout(ctxb, defaultTimeout) + if err := net.ConnectNodes(ctxt, carol, dave); err != nil { + t.Fatalf("unable to connect carol to dave: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + err = net.SendCoins(ctxt, btcutil.SatoshiPerBitcoin, carol) + if err != nil { + t.Fatalf("unable to send coins to carol: %v", err) + } + + // Open a channel with 100k satoshis between Carol and Dave with Carol // being the sole funder of the channel. - ctxt, _ := context.WithTimeout(ctxb, channelOpenTimeout) - chanPointAlice := openChannelAndAssert( - ctxt, t, net, net.Alice, net.Bob, + ctxt, _ = context.WithTimeout(ctxb, channelOpenTimeout) + chanPointCarol := openChannelAndAssert( + ctxt, t, net, carol, dave, lntest.OpenChannelParams{ Amt: chanAmt, }, ) - networkChans = append(networkChans, chanPointAlice) + networkChans = append(networkChans, chanPointCarol) - aliceChanTXID, err := lnd.GetChanPointFundingTxid(chanPointAlice) + carolChanTXID, err := lnd.GetChanPointFundingTxid(chanPointCarol) if err != nil { t.Fatalf("unable to get txid: %v", err) } - aliceFundPoint := wire.OutPoint{ - Hash: *aliceChanTXID, - Index: chanPointAlice.OutputIndex, + carolFundPoint := wire.OutPoint{ + Hash: *carolChanTXID, + Index: chanPointCarol.OutputIndex, } // Wait for all nodes to have seen all channels. - nodes := []*lntest.HarnessNode{net.Alice, net.Bob} - nodeNames := []string{"Alice", "Bob"} + nodes := []*lntest.HarnessNode{carol, dave} for _, chanPoint := range networkChans { - for i, node := range nodes { + for _, node := range nodes { txid, err := lnd.GetChanPointFundingTxid(chanPoint) if err != nil { t.Fatalf("unable to get txid: %v", err) @@ -4456,101 +4547,241 @@ func testSingleHopSendToRoute(net *lntest.NetworkHarness, t *harnessTest) { err = node.WaitForNetworkChannelOpen(ctxt, chanPoint) if err != nil { t.Fatalf("%s(%d): timeout waiting for "+ - "channel(%s) open: %v", nodeNames[i], + "channel(%s) open: %v", node.Name(), node.NodeID, point, err) } } } - // Query for routes to pay from Alice to Bob. - // We set FinalCltvDelta to 40 since by default QueryRoutes returns - // the last hop with a final cltv delta of 9 where as the default in - // htlcswitch is 40. - const paymentAmt = 1000 - routesReq := &lnrpc.QueryRoutesRequest{ - PubKey: net.Bob.PubKeyStr, - Amt: paymentAmt, - FinalCltvDelta: lnd.DefaultBitcoinTimeLockDelta, - } - ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - routes, err := net.Alice.QueryRoutes(ctxt, routesReq) - if err != nil { - t.Fatalf("unable to get route: %v", err) - } - - // Create 5 invoices for Bob, which expect a payment from Alice for 1k - // satoshis with a different preimage each time. - const numPayments = 5 + // Create invoices for Dave, which expect a payment from Carol. _, rHashes, _, err := createPayReqs( - net.Bob, paymentAmt, numPayments, + dave, paymentAmtSat, numPayments, ) if err != nil { t.Fatalf("unable to create pay reqs: %v", err) } - // Using Alice as the source, pay to the 5 invoices from Carol created - // above. + // Query for routes to pay from Carol to Dave. + // We set FinalCltvDelta to 40 since by default QueryRoutes returns + // the last hop with a final cltv delta of 9 where as the default in + // htlcswitch is 40. + routesReq := &lnrpc.QueryRoutesRequest{ + PubKey: dave.PubKeyStr, + Amt: paymentAmtSat, + FinalCltvDelta: lnd.DefaultBitcoinTimeLockDelta, + } ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) - alicePayStream, err := net.Alice.SendToRoute(ctxt) + routes, err := carol.QueryRoutes(ctxt, routesReq) if err != nil { - t.Fatalf("unable to create payment stream for alice: %v", err) + t.Fatalf("unable to get route from %s: %v", + carol.Name(), err) } - for _, rHash := range rHashes { - sendReq := &lnrpc.SendToRouteRequest{ - PaymentHash: rHash, - Route: routes.Routes[0], - } - err := alicePayStream.Send(sendReq) + // There should only be one route to try, so take the first item. + r := routes.Routes[0] + // Construct a closure that will set MPP fields on the route, which + // allows us to test MPP payments. + setMPPFields := func(i int) { + addr := [32]byte{byte(i)} + + hop := r.Hops[len(r.Hops)-1] + hop.TlvPayload = true + hop.MppRecord = &lnrpc.MPPRecord{ + PaymentAddr: addr[:], + TotalAmtMsat: paymentAmtSat * 1000, + } + } + + // Construct closures for each of the payment types covered: + // - main rpc server sync + // - main rpc server streaming + // - routerrpc server sync + sendToRouteSync := func() { + for i, rHash := range rHashes { + // Populate the MPP fields for the final hop if we are + // testing MPP payments. + if test.mpp { + setMPPFields(i) + } + + sendReq := &lnrpc.SendToRouteRequest{ + PaymentHash: rHash, + Route: r, + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + resp, err := carol.SendToRouteSync( + ctxt, sendReq, + ) + if err != nil { + t.Fatalf("unable to send to route for "+ + "%s: %v", carol.Name(), err) + } + if resp.PaymentError != "" { + t.Fatalf("received payment error from %s: %v", + carol.Name(), resp.PaymentError) + } + } + } + sendToRouteStream := func() { + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + alicePayStream, err := carol.SendToRoute(ctxt) if err != nil { - t.Fatalf("unable to send payment: %v", err) + t.Fatalf("unable to create payment stream for "+ + "carol: %v", err) + } + + for i, rHash := range rHashes { + // Populate the MPP fields for the final hop if we are + // testing MPP payments. + if test.mpp { + setMPPFields(i) + } + + sendReq := &lnrpc.SendToRouteRequest{ + PaymentHash: rHash, + Route: routes.Routes[0], + } + err := alicePayStream.Send(sendReq) + + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + + resp, err := alicePayStream.Recv() + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + if resp.PaymentError != "" { + t.Fatalf("received payment error: %v", + resp.PaymentError) + } + } + } + sendToRouteRouterRPC := func() { + for i, rHash := range rHashes { + // Populate the MPP fields for the final hop if we are + // testing MPP payments. + if test.mpp { + setMPPFields(i) + } + + sendReq := &routerrpc.SendToRouteRequest{ + PaymentHash: rHash, + Route: r, + } + ctxt, _ = context.WithTimeout(ctxb, defaultTimeout) + resp, err := carol.RouterClient.SendToRoute( + ctxt, sendReq, + ) + if err != nil { + t.Fatalf("unable to send to route for "+ + "%s: %v", carol.Name(), err) + } + if resp.Failure != nil { + t.Fatalf("received payment error from %s: %v", + carol.Name(), resp.Failure) + } } } - for range rHashes { - resp, err := alicePayStream.Recv() - if err != nil { - t.Fatalf("unable to send payment: %v", err) - } - if resp.PaymentError != "" { - t.Fatalf("received payment error: %v", resp.PaymentError) - } + // Using Carol as the node as the source, send the payments + // synchronously via the the routerrpc's SendToRoute, or via the main RPC + // server's SendToRoute streaming or sync calls. + switch { + case !test.routerrpc && test.streaming: + sendToRouteStream() + case !test.routerrpc && !test.streaming: + sendToRouteSync() + case test.routerrpc && !test.streaming: + sendToRouteRouterRPC() + default: + t.Fatalf("routerrpc does not support streaming send_to_route") } - req := &lnrpc.ListPaymentsRequest{} + // Verify that the payment's from Carol's PoV have the correct payment + // hash and amount. ctxt, _ = context.WithTimeout(ctxt, defaultTimeout) - paymentsResp, err := net.Alice.ListPayments(ctxt, req) + paymentsResp, err := carol.ListPayments( + ctxt, &lnrpc.ListPaymentsRequest{}, + ) if err != nil { - t.Fatalf("error when obtaining Alice payments: %v", err) + t.Fatalf("error when obtaining %s payments: %v", + carol.Name(), err) } - if len(paymentsResp.Payments) != 5 { + if len(paymentsResp.Payments) != numPayments { t.Fatalf("incorrect number of payments, got %v, want %v", - len(paymentsResp.Payments), 5) + len(paymentsResp.Payments), numPayments) } - // Verify that the ListPayments displays the payment without an invoice - // since the payment was completed with SendToRoute. - for _, p := range paymentsResp.Payments { + for i, p := range paymentsResp.Payments { + // Assert that the payment hashes for each payment match up. + rHashHex := hex.EncodeToString(rHashes[i]) + if p.PaymentHash != rHashHex { + t.Fatalf("incorrect payment hash for payment %d, "+ + "want: %s got: %s", + i, rHashHex, p.PaymentHash) + } + + // Assert that each payment has no invoice since the payment was + // completed using SendToRoute. if p.PaymentRequest != "" { - t.Fatalf("incorrect payreq, want: \"\", got: %v", - p.PaymentRequest) + t.Fatalf("incorrect payment request for payment: %d, "+ + "want: \"\", got: %s", + i, p.PaymentRequest) + } + + // Assert the payment ammount is correct. + if p.ValueSat != paymentAmtSat { + t.Fatalf("incorrect payment amt for payment %d, "+ + "want: %d, got: %d", + i, paymentAmtSat, p.ValueSat) + } + } + + // Verify that the invoices's from Dave's PoV have the correct payment + // hash and amount. + ctxt, _ = context.WithTimeout(ctxt, defaultTimeout) + invoicesResp, err := dave.ListInvoices( + ctxt, &lnrpc.ListInvoiceRequest{}, + ) + if err != nil { + t.Fatalf("error when obtaining %s payments: %v", + dave.Name(), err) + } + if len(invoicesResp.Invoices) != numPayments { + t.Fatalf("incorrect number of invoices, got %v, want %v", + len(invoicesResp.Invoices), numPayments) + } + + for i, inv := range invoicesResp.Invoices { + // Assert that the payment hashes match up. + if !bytes.Equal(inv.RHash, rHashes[i]) { + t.Fatalf("incorrect payment hash for invoice %d, "+ + "want: %x got: %x", + i, rHashes[i], inv.RHash) + } + + // Assert that the amount paid to the invoice is correct. + if inv.AmtPaidSat != paymentAmtSat { + t.Fatalf("incorrect payment amt for invoice %d, "+ + "want: %d, got %d", + i, paymentAmtSat, inv.AmtPaidSat) } } // At this point all the channels within our proto network should be - // shifted by 5k satoshis in the direction of Bob, the sink within the + // shifted by 5k satoshis in the direction of Dave, the sink within the // payment flow generated above. The order of asserts corresponds to // increasing of time is needed to embed the HTLC in commitment - // transaction, in channel Alice->Bob, order is Bob and then Alice. - const amountPaid = int64(5000) - assertAmountPaid(t, "Alice(local) => Bob(remote)", net.Bob, - aliceFundPoint, int64(0), amountPaid) - assertAmountPaid(t, "Alice(local) => Bob(remote)", net.Alice, - aliceFundPoint, amountPaid, int64(0)) + // transaction, in channel Carol->Dave, order is Dave and then Carol. + assertAmountPaid(t, "Carol(local) => Dave(remote)", dave, + carolFundPoint, int64(0), amountPaid) + assertAmountPaid(t, "Carol(local) => Dave(remote)", carol, + carolFundPoint, amountPaid, int64(0)) ctxt, _ = context.WithTimeout(ctxb, channelCloseTimeout) - closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAlice, false) + closeChannelAndAssert(ctxt, t, net, carol, chanPointCarol, false) } // testMultiHopSendToRoute tests that payments are properly processed