Merge pull request #2497 from joostjager/querysingleroute

lnrpc: deprecate QueryRoutes with more than one route
This commit is contained in:
Olaoluwa Osuntokun 2019-03-12 21:15:18 -07:00 committed by GitHub
commit ad8849056b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1458 additions and 1107 deletions

@ -0,0 +1,229 @@
package routerrpc
import (
"encoding/hex"
"errors"
"fmt"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
context "golang.org/x/net/context"
)
// RouterBackend contains the backend implementation of the router rpc sub
// server calls.
type RouterBackend struct {
MaxPaymentMSat lnwire.MilliSatoshi
SelfNode routing.Vertex
FetchChannelCapacity func(chanID uint64) (btcutil.Amount, error)
FindRoutes func(source, target routing.Vertex,
amt lnwire.MilliSatoshi, restrictions *routing.RestrictParams,
numPaths uint32, finalExpiry ...uint16) (
[]*routing.Route, error)
}
// QueryRoutes attempts to query the daemons' Channel Router for a possible
// route to a target destination capable of carrying a specific amount of
// satoshis within the route's flow. The retuned route contains the full
// details required to craft and send an HTLC, also including the necessary
// information that should be present within the Sphinx packet encapsulated
// within the HTLC.
//
// TODO(roasbeef): should return a slice of routes in reality
// * create separate PR to send based on well formatted route
func (r *RouterBackend) QueryRoutes(ctx context.Context,
in *lnrpc.QueryRoutesRequest) (*lnrpc.QueryRoutesResponse, error) {
parsePubKey := func(key string) (routing.Vertex, error) {
pubKeyBytes, err := hex.DecodeString(key)
if err != nil {
return routing.Vertex{}, err
}
if len(pubKeyBytes) != 33 {
return routing.Vertex{},
errors.New("invalid key length")
}
var v routing.Vertex
copy(v[:], pubKeyBytes)
return v, nil
}
// Parse the hex-encoded source and target public keys into full public
// key objects we can properly manipulate.
targetPubKey, err := parsePubKey(in.PubKey)
if err != nil {
return nil, err
}
var sourcePubKey routing.Vertex
if in.SourcePubKey != "" {
var err error
sourcePubKey, err = parsePubKey(in.SourcePubKey)
if err != nil {
return nil, err
}
} else {
// If no source is specified, use self.
sourcePubKey = r.SelfNode
}
// Currently, within the bootstrap phase of the network, we limit the
// largest payment size allotted to (2^32) - 1 mSAT or 4.29 million
// satoshis.
amt := btcutil.Amount(in.Amt)
amtMSat := lnwire.NewMSatFromSatoshis(amt)
if amtMSat > r.MaxPaymentMSat {
return nil, fmt.Errorf("payment of %v is too large, max payment "+
"allowed is %v", amt, r.MaxPaymentMSat.ToSatoshis())
}
// Unmarshall restrictions from request.
feeLimit := calculateFeeLimit(in.FeeLimit, amtMSat)
ignoredNodes := make(map[routing.Vertex]struct{})
for _, ignorePubKey := range in.IgnoredNodes {
if len(ignorePubKey) != 33 {
return nil, fmt.Errorf("invalid ignore node pubkey")
}
var ignoreVertex routing.Vertex
copy(ignoreVertex[:], ignorePubKey)
ignoredNodes[ignoreVertex] = struct{}{}
}
ignoredEdges := make(map[routing.EdgeLocator]struct{})
for _, ignoredEdge := range in.IgnoredEdges {
locator := routing.EdgeLocator{
ChannelID: ignoredEdge.ChannelId,
}
if ignoredEdge.DirectionReverse {
locator.Direction = 1
}
ignoredEdges[locator] = struct{}{}
}
restrictions := &routing.RestrictParams{
FeeLimit: feeLimit,
IgnoredNodes: ignoredNodes,
IgnoredEdges: ignoredEdges,
}
// numRoutes will default to 10 if not specified explicitly.
numRoutesIn := uint32(in.NumRoutes)
if numRoutesIn == 0 {
numRoutesIn = 10
}
// Query the channel router for a possible path to the destination that
// can carry `in.Amt` satoshis _including_ the total fee required on
// the route.
var (
routes []*routing.Route
findErr error
)
if in.FinalCltvDelta == 0 {
routes, findErr = r.FindRoutes(
sourcePubKey, targetPubKey, amtMSat, restrictions, numRoutesIn,
)
} else {
routes, findErr = r.FindRoutes(
sourcePubKey, targetPubKey, amtMSat, restrictions, numRoutesIn,
uint16(in.FinalCltvDelta),
)
}
if findErr != nil {
return nil, findErr
}
// As the number of returned routes can be less than the number of
// requested routes, we'll clamp down the length of the response to the
// minimum of the two.
numRoutes := uint32(len(routes))
if numRoutesIn < numRoutes {
numRoutes = numRoutesIn
}
// For each valid route, we'll convert the result into the format
// required by the RPC system.
routeResp := &lnrpc.QueryRoutesResponse{
Routes: make([]*lnrpc.Route, 0, in.NumRoutes),
}
for i := uint32(0); i < numRoutes; i++ {
routeResp.Routes = append(
routeResp.Routes,
r.MarshallRoute(routes[i]),
)
}
return routeResp, nil
}
// calculateFeeLimit returns the fee limit in millisatoshis. If a percentage
// based fee limit has been requested, we'll factor in the ratio provided with
// the amount of the payment.
func calculateFeeLimit(feeLimit *lnrpc.FeeLimit,
amount lnwire.MilliSatoshi) lnwire.MilliSatoshi {
switch feeLimit.GetLimit().(type) {
case *lnrpc.FeeLimit_Fixed:
return lnwire.NewMSatFromSatoshis(
btcutil.Amount(feeLimit.GetFixed()),
)
case *lnrpc.FeeLimit_Percent:
return amount * lnwire.MilliSatoshi(feeLimit.GetPercent()) / 100
default:
// If a fee limit was not specified, we'll use the payment's
// amount as an upper bound in order to avoid payment attempts
// from incurring fees higher than the payment amount itself.
return amount
}
}
// MarshallRoute marshalls an internal route to an rpc route struct.
func (r *RouterBackend) MarshallRoute(route *routing.Route) *lnrpc.Route {
resp := &lnrpc.Route{
TotalTimeLock: route.TotalTimeLock,
TotalFees: int64(route.TotalFees.ToSatoshis()),
TotalFeesMsat: int64(route.TotalFees),
TotalAmt: int64(route.TotalAmount.ToSatoshis()),
TotalAmtMsat: int64(route.TotalAmount),
Hops: make([]*lnrpc.Hop, len(route.Hops)),
}
incomingAmt := route.TotalAmount
for i, hop := range route.Hops {
fee := route.HopFee(i)
// Channel capacity is not a defining property of a route. For
// backwards RPC compatibility, we retrieve it here from the
// graph.
chanCapacity, err := r.FetchChannelCapacity(hop.ChannelID)
if err != nil {
// If capacity cannot be retrieved, this may be a
// not-yet-received or private channel. Then report
// amount that is sent through the channel as capacity.
chanCapacity = incomingAmt.ToSatoshis()
}
resp.Hops[i] = &lnrpc.Hop{
ChanId: hop.ChannelID,
ChanCapacity: int64(chanCapacity),
AmtToForward: int64(hop.AmtToForward.ToSatoshis()),
AmtToForwardMsat: int64(hop.AmtToForward),
Fee: int64(fee.ToSatoshis()),
FeeMsat: int64(fee),
Expiry: uint32(hop.OutgoingTimeLock),
PubKey: hex.EncodeToString(
hop.PubKeyBytes[:]),
}
incomingAmt = hop.AmtToForward
}
return resp
}

@ -0,0 +1,126 @@
package routerrpc
import (
"bytes"
"context"
"encoding/hex"
"testing"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/lnrpc"
)
const (
destKey = "0286098b97bc843372b4426d4b276cea9aa2f48f0428d6f5b66ae101befc14f8b4"
ignoreNodeKey = "02f274f48f3c0d590449a6776e3ce8825076ac376e470e992246eebc565ef8bb2a"
)
var (
sourceKey = routing.Vertex{1, 2, 3}
)
// TestQueryRoutes asserts that query routes rpc parameters are properly parsed
// and passed onto path finding.
func TestQueryRoutes(t *testing.T) {
ignoreNodeBytes, err := hex.DecodeString(ignoreNodeKey)
if err != nil {
t.Fatal(err)
}
var ignoreNodeVertex routing.Vertex
copy(ignoreNodeVertex[:], ignoreNodeBytes)
destNodeBytes, err := hex.DecodeString(destKey)
if err != nil {
t.Fatal(err)
}
request := &lnrpc.QueryRoutesRequest{
PubKey: destKey,
Amt: 100000,
NumRoutes: 1,
FinalCltvDelta: 100,
FeeLimit: &lnrpc.FeeLimit{
Limit: &lnrpc.FeeLimit_Fixed{
Fixed: 250,
},
},
IgnoredNodes: [][]byte{ignoreNodeBytes},
IgnoredEdges: []*lnrpc.EdgeLocator{&lnrpc.EdgeLocator{
ChannelId: 555,
DirectionReverse: true,
}},
}
route := &routing.Route{}
findRoutes := func(source, target routing.Vertex,
amt lnwire.MilliSatoshi, restrictions *routing.RestrictParams,
numPaths uint32, finalExpiry ...uint16) (
[]*routing.Route, error) {
if int64(amt) != request.Amt*1000 {
t.Fatal("unexpected amount")
}
if numPaths != 1 {
t.Fatal("unexpected number of routes")
}
if source != sourceKey {
t.Fatal("unexpected source key")
}
if !bytes.Equal(target[:], destNodeBytes) {
t.Fatal("unexpected target key")
}
if restrictions.FeeLimit != 250*1000 {
t.Fatal("unexpected fee limit")
}
if len(restrictions.IgnoredEdges) != 1 {
t.Fatal("unexpected ignored edges map size")
}
if _, ok := restrictions.IgnoredEdges[routing.EdgeLocator{
ChannelID: 555, Direction: 1,
}]; !ok {
t.Fatal("unexpected ignored edge")
}
if len(restrictions.IgnoredNodes) != 1 {
t.Fatal("unexpected ignored nodes map size")
}
if _, ok := restrictions.IgnoredNodes[ignoreNodeVertex]; !ok {
t.Fatal("unexpected ignored node")
}
return []*routing.Route{
route,
}, nil
}
backend := &RouterBackend{
MaxPaymentMSat: lnwire.NewMSatFromSatoshis(1000000),
FindRoutes: findRoutes,
SelfNode: routing.Vertex{1, 2, 3},
FetchChannelCapacity: func(chanID uint64) (
btcutil.Amount, error) {
return 1, nil
},
}
resp, err := backend.QueryRoutes(context.Background(), request)
if err != nil {
t.Fatal(err)
}
if len(resp.Routes) != 1 {
t.Fatal("expected a single route response")
}
}

@ -55,7 +55,7 @@ func (x AddressType) String() string {
return proto.EnumName(AddressType_name, int32(x)) return proto.EnumName(AddressType_name, int32(x))
} }
func (AddressType) EnumDescriptor() ([]byte, []int) { func (AddressType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{0} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{0}
} }
type ChannelCloseSummary_ClosureType int32 type ChannelCloseSummary_ClosureType int32
@ -90,7 +90,7 @@ func (x ChannelCloseSummary_ClosureType) String() string {
return proto.EnumName(ChannelCloseSummary_ClosureType_name, int32(x)) return proto.EnumName(ChannelCloseSummary_ClosureType_name, int32(x))
} }
func (ChannelCloseSummary_ClosureType) EnumDescriptor() ([]byte, []int) { func (ChannelCloseSummary_ClosureType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{39, 0} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{39, 0}
} }
type ChannelEventUpdate_UpdateType int32 type ChannelEventUpdate_UpdateType int32
@ -119,7 +119,7 @@ func (x ChannelEventUpdate_UpdateType) String() string {
return proto.EnumName(ChannelEventUpdate_UpdateType_name, int32(x)) return proto.EnumName(ChannelEventUpdate_UpdateType_name, int32(x))
} }
func (ChannelEventUpdate_UpdateType) EnumDescriptor() ([]byte, []int) { func (ChannelEventUpdate_UpdateType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{60, 0} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{60, 0}
} }
type Invoice_InvoiceState int32 type Invoice_InvoiceState int32
@ -145,7 +145,7 @@ func (x Invoice_InvoiceState) String() string {
return proto.EnumName(Invoice_InvoiceState_name, int32(x)) return proto.EnumName(Invoice_InvoiceState_name, int32(x))
} }
func (Invoice_InvoiceState) EnumDescriptor() ([]byte, []int) { func (Invoice_InvoiceState) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{89, 0} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{90, 0}
} }
type GenSeedRequest struct { type GenSeedRequest struct {
@ -166,7 +166,7 @@ func (m *GenSeedRequest) Reset() { *m = GenSeedRequest{} }
func (m *GenSeedRequest) String() string { return proto.CompactTextString(m) } func (m *GenSeedRequest) String() string { return proto.CompactTextString(m) }
func (*GenSeedRequest) ProtoMessage() {} func (*GenSeedRequest) ProtoMessage() {}
func (*GenSeedRequest) Descriptor() ([]byte, []int) { func (*GenSeedRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{0} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{0}
} }
func (m *GenSeedRequest) XXX_Unmarshal(b []byte) error { func (m *GenSeedRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GenSeedRequest.Unmarshal(m, b) return xxx_messageInfo_GenSeedRequest.Unmarshal(m, b)
@ -221,7 +221,7 @@ func (m *GenSeedResponse) Reset() { *m = GenSeedResponse{} }
func (m *GenSeedResponse) String() string { return proto.CompactTextString(m) } func (m *GenSeedResponse) String() string { return proto.CompactTextString(m) }
func (*GenSeedResponse) ProtoMessage() {} func (*GenSeedResponse) ProtoMessage() {}
func (*GenSeedResponse) Descriptor() ([]byte, []int) { func (*GenSeedResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{1} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{1}
} }
func (m *GenSeedResponse) XXX_Unmarshal(b []byte) error { func (m *GenSeedResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GenSeedResponse.Unmarshal(m, b) return xxx_messageInfo_GenSeedResponse.Unmarshal(m, b)
@ -286,7 +286,7 @@ func (m *InitWalletRequest) Reset() { *m = InitWalletRequest{} }
func (m *InitWalletRequest) String() string { return proto.CompactTextString(m) } func (m *InitWalletRequest) String() string { return proto.CompactTextString(m) }
func (*InitWalletRequest) ProtoMessage() {} func (*InitWalletRequest) ProtoMessage() {}
func (*InitWalletRequest) Descriptor() ([]byte, []int) { func (*InitWalletRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{2} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{2}
} }
func (m *InitWalletRequest) XXX_Unmarshal(b []byte) error { func (m *InitWalletRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_InitWalletRequest.Unmarshal(m, b) return xxx_messageInfo_InitWalletRequest.Unmarshal(m, b)
@ -344,7 +344,7 @@ func (m *InitWalletResponse) Reset() { *m = InitWalletResponse{} }
func (m *InitWalletResponse) String() string { return proto.CompactTextString(m) } func (m *InitWalletResponse) String() string { return proto.CompactTextString(m) }
func (*InitWalletResponse) ProtoMessage() {} func (*InitWalletResponse) ProtoMessage() {}
func (*InitWalletResponse) Descriptor() ([]byte, []int) { func (*InitWalletResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{3} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{3}
} }
func (m *InitWalletResponse) XXX_Unmarshal(b []byte) error { func (m *InitWalletResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_InitWalletResponse.Unmarshal(m, b) return xxx_messageInfo_InitWalletResponse.Unmarshal(m, b)
@ -386,7 +386,7 @@ func (m *UnlockWalletRequest) Reset() { *m = UnlockWalletRequest{} }
func (m *UnlockWalletRequest) String() string { return proto.CompactTextString(m) } func (m *UnlockWalletRequest) String() string { return proto.CompactTextString(m) }
func (*UnlockWalletRequest) ProtoMessage() {} func (*UnlockWalletRequest) ProtoMessage() {}
func (*UnlockWalletRequest) Descriptor() ([]byte, []int) { func (*UnlockWalletRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{4} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{4}
} }
func (m *UnlockWalletRequest) XXX_Unmarshal(b []byte) error { func (m *UnlockWalletRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UnlockWalletRequest.Unmarshal(m, b) return xxx_messageInfo_UnlockWalletRequest.Unmarshal(m, b)
@ -430,7 +430,7 @@ func (m *UnlockWalletResponse) Reset() { *m = UnlockWalletResponse{} }
func (m *UnlockWalletResponse) String() string { return proto.CompactTextString(m) } func (m *UnlockWalletResponse) String() string { return proto.CompactTextString(m) }
func (*UnlockWalletResponse) ProtoMessage() {} func (*UnlockWalletResponse) ProtoMessage() {}
func (*UnlockWalletResponse) Descriptor() ([]byte, []int) { func (*UnlockWalletResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{5} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{5}
} }
func (m *UnlockWalletResponse) XXX_Unmarshal(b []byte) error { func (m *UnlockWalletResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UnlockWalletResponse.Unmarshal(m, b) return xxx_messageInfo_UnlockWalletResponse.Unmarshal(m, b)
@ -468,7 +468,7 @@ func (m *ChangePasswordRequest) Reset() { *m = ChangePasswordRequest{} }
func (m *ChangePasswordRequest) String() string { return proto.CompactTextString(m) } func (m *ChangePasswordRequest) String() string { return proto.CompactTextString(m) }
func (*ChangePasswordRequest) ProtoMessage() {} func (*ChangePasswordRequest) ProtoMessage() {}
func (*ChangePasswordRequest) Descriptor() ([]byte, []int) { func (*ChangePasswordRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{6} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{6}
} }
func (m *ChangePasswordRequest) XXX_Unmarshal(b []byte) error { func (m *ChangePasswordRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChangePasswordRequest.Unmarshal(m, b) return xxx_messageInfo_ChangePasswordRequest.Unmarshal(m, b)
@ -512,7 +512,7 @@ func (m *ChangePasswordResponse) Reset() { *m = ChangePasswordResponse{}
func (m *ChangePasswordResponse) String() string { return proto.CompactTextString(m) } func (m *ChangePasswordResponse) String() string { return proto.CompactTextString(m) }
func (*ChangePasswordResponse) ProtoMessage() {} func (*ChangePasswordResponse) ProtoMessage() {}
func (*ChangePasswordResponse) Descriptor() ([]byte, []int) { func (*ChangePasswordResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{7} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{7}
} }
func (m *ChangePasswordResponse) XXX_Unmarshal(b []byte) error { func (m *ChangePasswordResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChangePasswordResponse.Unmarshal(m, b) return xxx_messageInfo_ChangePasswordResponse.Unmarshal(m, b)
@ -554,7 +554,7 @@ func (m *Utxo) Reset() { *m = Utxo{} }
func (m *Utxo) String() string { return proto.CompactTextString(m) } func (m *Utxo) String() string { return proto.CompactTextString(m) }
func (*Utxo) ProtoMessage() {} func (*Utxo) ProtoMessage() {}
func (*Utxo) Descriptor() ([]byte, []int) { func (*Utxo) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{8} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{8}
} }
func (m *Utxo) XXX_Unmarshal(b []byte) error { func (m *Utxo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Utxo.Unmarshal(m, b) return xxx_messageInfo_Utxo.Unmarshal(m, b)
@ -642,7 +642,7 @@ func (m *Transaction) Reset() { *m = Transaction{} }
func (m *Transaction) String() string { return proto.CompactTextString(m) } func (m *Transaction) String() string { return proto.CompactTextString(m) }
func (*Transaction) ProtoMessage() {} func (*Transaction) ProtoMessage() {}
func (*Transaction) Descriptor() ([]byte, []int) { func (*Transaction) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{9} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{9}
} }
func (m *Transaction) XXX_Unmarshal(b []byte) error { func (m *Transaction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Transaction.Unmarshal(m, b) return xxx_messageInfo_Transaction.Unmarshal(m, b)
@ -728,7 +728,7 @@ func (m *GetTransactionsRequest) Reset() { *m = GetTransactionsRequest{}
func (m *GetTransactionsRequest) String() string { return proto.CompactTextString(m) } func (m *GetTransactionsRequest) String() string { return proto.CompactTextString(m) }
func (*GetTransactionsRequest) ProtoMessage() {} func (*GetTransactionsRequest) ProtoMessage() {}
func (*GetTransactionsRequest) Descriptor() ([]byte, []int) { func (*GetTransactionsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{10} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{10}
} }
func (m *GetTransactionsRequest) XXX_Unmarshal(b []byte) error { func (m *GetTransactionsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetTransactionsRequest.Unmarshal(m, b) return xxx_messageInfo_GetTransactionsRequest.Unmarshal(m, b)
@ -760,7 +760,7 @@ func (m *TransactionDetails) Reset() { *m = TransactionDetails{} }
func (m *TransactionDetails) String() string { return proto.CompactTextString(m) } func (m *TransactionDetails) String() string { return proto.CompactTextString(m) }
func (*TransactionDetails) ProtoMessage() {} func (*TransactionDetails) ProtoMessage() {}
func (*TransactionDetails) Descriptor() ([]byte, []int) { func (*TransactionDetails) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{11} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{11}
} }
func (m *TransactionDetails) XXX_Unmarshal(b []byte) error { func (m *TransactionDetails) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_TransactionDetails.Unmarshal(m, b) return xxx_messageInfo_TransactionDetails.Unmarshal(m, b)
@ -801,7 +801,7 @@ func (m *FeeLimit) Reset() { *m = FeeLimit{} }
func (m *FeeLimit) String() string { return proto.CompactTextString(m) } func (m *FeeLimit) String() string { return proto.CompactTextString(m) }
func (*FeeLimit) ProtoMessage() {} func (*FeeLimit) ProtoMessage() {}
func (*FeeLimit) Descriptor() ([]byte, []int) { func (*FeeLimit) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{12} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{12}
} }
func (m *FeeLimit) XXX_Unmarshal(b []byte) error { func (m *FeeLimit) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FeeLimit.Unmarshal(m, b) return xxx_messageInfo_FeeLimit.Unmarshal(m, b)
@ -961,7 +961,7 @@ func (m *SendRequest) Reset() { *m = SendRequest{} }
func (m *SendRequest) String() string { return proto.CompactTextString(m) } func (m *SendRequest) String() string { return proto.CompactTextString(m) }
func (*SendRequest) ProtoMessage() {} func (*SendRequest) ProtoMessage() {}
func (*SendRequest) Descriptor() ([]byte, []int) { func (*SendRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{13} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{13}
} }
func (m *SendRequest) XXX_Unmarshal(b []byte) error { func (m *SendRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SendRequest.Unmarshal(m, b) return xxx_messageInfo_SendRequest.Unmarshal(m, b)
@ -1058,7 +1058,7 @@ func (m *SendResponse) Reset() { *m = SendResponse{} }
func (m *SendResponse) String() string { return proto.CompactTextString(m) } func (m *SendResponse) String() string { return proto.CompactTextString(m) }
func (*SendResponse) ProtoMessage() {} func (*SendResponse) ProtoMessage() {}
func (*SendResponse) Descriptor() ([]byte, []int) { func (*SendResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{14} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{14}
} }
func (m *SendResponse) XXX_Unmarshal(b []byte) error { func (m *SendResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SendResponse.Unmarshal(m, b) return xxx_messageInfo_SendResponse.Unmarshal(m, b)
@ -1128,7 +1128,7 @@ func (m *SendToRouteRequest) Reset() { *m = SendToRouteRequest{} }
func (m *SendToRouteRequest) String() string { return proto.CompactTextString(m) } func (m *SendToRouteRequest) String() string { return proto.CompactTextString(m) }
func (*SendToRouteRequest) ProtoMessage() {} func (*SendToRouteRequest) ProtoMessage() {}
func (*SendToRouteRequest) Descriptor() ([]byte, []int) { func (*SendToRouteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{15} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{15}
} }
func (m *SendToRouteRequest) XXX_Unmarshal(b []byte) error { func (m *SendToRouteRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SendToRouteRequest.Unmarshal(m, b) return xxx_messageInfo_SendToRouteRequest.Unmarshal(m, b)
@ -1193,7 +1193,7 @@ func (m *ChannelPoint) Reset() { *m = ChannelPoint{} }
func (m *ChannelPoint) String() string { return proto.CompactTextString(m) } func (m *ChannelPoint) String() string { return proto.CompactTextString(m) }
func (*ChannelPoint) ProtoMessage() {} func (*ChannelPoint) ProtoMessage() {}
func (*ChannelPoint) Descriptor() ([]byte, []int) { func (*ChannelPoint) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{16} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{16}
} }
func (m *ChannelPoint) XXX_Unmarshal(b []byte) error { func (m *ChannelPoint) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelPoint.Unmarshal(m, b) return xxx_messageInfo_ChannelPoint.Unmarshal(m, b)
@ -1339,7 +1339,7 @@ func (m *OutPoint) Reset() { *m = OutPoint{} }
func (m *OutPoint) String() string { return proto.CompactTextString(m) } func (m *OutPoint) String() string { return proto.CompactTextString(m) }
func (*OutPoint) ProtoMessage() {} func (*OutPoint) ProtoMessage() {}
func (*OutPoint) Descriptor() ([]byte, []int) { func (*OutPoint) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{17} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{17}
} }
func (m *OutPoint) XXX_Unmarshal(b []byte) error { func (m *OutPoint) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_OutPoint.Unmarshal(m, b) return xxx_messageInfo_OutPoint.Unmarshal(m, b)
@ -1394,7 +1394,7 @@ func (m *LightningAddress) Reset() { *m = LightningAddress{} }
func (m *LightningAddress) String() string { return proto.CompactTextString(m) } func (m *LightningAddress) String() string { return proto.CompactTextString(m) }
func (*LightningAddress) ProtoMessage() {} func (*LightningAddress) ProtoMessage() {}
func (*LightningAddress) Descriptor() ([]byte, []int) { func (*LightningAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{18} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{18}
} }
func (m *LightningAddress) XXX_Unmarshal(b []byte) error { func (m *LightningAddress) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LightningAddress.Unmarshal(m, b) return xxx_messageInfo_LightningAddress.Unmarshal(m, b)
@ -1444,7 +1444,7 @@ func (m *SendManyRequest) Reset() { *m = SendManyRequest{} }
func (m *SendManyRequest) String() string { return proto.CompactTextString(m) } func (m *SendManyRequest) String() string { return proto.CompactTextString(m) }
func (*SendManyRequest) ProtoMessage() {} func (*SendManyRequest) ProtoMessage() {}
func (*SendManyRequest) Descriptor() ([]byte, []int) { func (*SendManyRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{19} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{19}
} }
func (m *SendManyRequest) XXX_Unmarshal(b []byte) error { func (m *SendManyRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SendManyRequest.Unmarshal(m, b) return xxx_messageInfo_SendManyRequest.Unmarshal(m, b)
@ -1497,7 +1497,7 @@ func (m *SendManyResponse) Reset() { *m = SendManyResponse{} }
func (m *SendManyResponse) String() string { return proto.CompactTextString(m) } func (m *SendManyResponse) String() string { return proto.CompactTextString(m) }
func (*SendManyResponse) ProtoMessage() {} func (*SendManyResponse) ProtoMessage() {}
func (*SendManyResponse) Descriptor() ([]byte, []int) { func (*SendManyResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{20} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{20}
} }
func (m *SendManyResponse) XXX_Unmarshal(b []byte) error { func (m *SendManyResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SendManyResponse.Unmarshal(m, b) return xxx_messageInfo_SendManyResponse.Unmarshal(m, b)
@ -1547,7 +1547,7 @@ func (m *SendCoinsRequest) Reset() { *m = SendCoinsRequest{} }
func (m *SendCoinsRequest) String() string { return proto.CompactTextString(m) } func (m *SendCoinsRequest) String() string { return proto.CompactTextString(m) }
func (*SendCoinsRequest) ProtoMessage() {} func (*SendCoinsRequest) ProtoMessage() {}
func (*SendCoinsRequest) Descriptor() ([]byte, []int) { func (*SendCoinsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{21} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{21}
} }
func (m *SendCoinsRequest) XXX_Unmarshal(b []byte) error { func (m *SendCoinsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SendCoinsRequest.Unmarshal(m, b) return xxx_messageInfo_SendCoinsRequest.Unmarshal(m, b)
@ -1614,7 +1614,7 @@ func (m *SendCoinsResponse) Reset() { *m = SendCoinsResponse{} }
func (m *SendCoinsResponse) String() string { return proto.CompactTextString(m) } func (m *SendCoinsResponse) String() string { return proto.CompactTextString(m) }
func (*SendCoinsResponse) ProtoMessage() {} func (*SendCoinsResponse) ProtoMessage() {}
func (*SendCoinsResponse) Descriptor() ([]byte, []int) { func (*SendCoinsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{22} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{22}
} }
func (m *SendCoinsResponse) XXX_Unmarshal(b []byte) error { func (m *SendCoinsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SendCoinsResponse.Unmarshal(m, b) return xxx_messageInfo_SendCoinsResponse.Unmarshal(m, b)
@ -1655,7 +1655,7 @@ func (m *ListUnspentRequest) Reset() { *m = ListUnspentRequest{} }
func (m *ListUnspentRequest) String() string { return proto.CompactTextString(m) } func (m *ListUnspentRequest) String() string { return proto.CompactTextString(m) }
func (*ListUnspentRequest) ProtoMessage() {} func (*ListUnspentRequest) ProtoMessage() {}
func (*ListUnspentRequest) Descriptor() ([]byte, []int) { func (*ListUnspentRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{23} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{23}
} }
func (m *ListUnspentRequest) XXX_Unmarshal(b []byte) error { func (m *ListUnspentRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListUnspentRequest.Unmarshal(m, b) return xxx_messageInfo_ListUnspentRequest.Unmarshal(m, b)
@ -1701,7 +1701,7 @@ func (m *ListUnspentResponse) Reset() { *m = ListUnspentResponse{} }
func (m *ListUnspentResponse) String() string { return proto.CompactTextString(m) } func (m *ListUnspentResponse) String() string { return proto.CompactTextString(m) }
func (*ListUnspentResponse) ProtoMessage() {} func (*ListUnspentResponse) ProtoMessage() {}
func (*ListUnspentResponse) Descriptor() ([]byte, []int) { func (*ListUnspentResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{24} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{24}
} }
func (m *ListUnspentResponse) XXX_Unmarshal(b []byte) error { func (m *ListUnspentResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListUnspentResponse.Unmarshal(m, b) return xxx_messageInfo_ListUnspentResponse.Unmarshal(m, b)
@ -1740,7 +1740,7 @@ func (m *NewAddressRequest) Reset() { *m = NewAddressRequest{} }
func (m *NewAddressRequest) String() string { return proto.CompactTextString(m) } func (m *NewAddressRequest) String() string { return proto.CompactTextString(m) }
func (*NewAddressRequest) ProtoMessage() {} func (*NewAddressRequest) ProtoMessage() {}
func (*NewAddressRequest) Descriptor() ([]byte, []int) { func (*NewAddressRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{25} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{25}
} }
func (m *NewAddressRequest) XXX_Unmarshal(b []byte) error { func (m *NewAddressRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NewAddressRequest.Unmarshal(m, b) return xxx_messageInfo_NewAddressRequest.Unmarshal(m, b)
@ -1779,7 +1779,7 @@ func (m *NewAddressResponse) Reset() { *m = NewAddressResponse{} }
func (m *NewAddressResponse) String() string { return proto.CompactTextString(m) } func (m *NewAddressResponse) String() string { return proto.CompactTextString(m) }
func (*NewAddressResponse) ProtoMessage() {} func (*NewAddressResponse) ProtoMessage() {}
func (*NewAddressResponse) Descriptor() ([]byte, []int) { func (*NewAddressResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{26} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{26}
} }
func (m *NewAddressResponse) XXX_Unmarshal(b []byte) error { func (m *NewAddressResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NewAddressResponse.Unmarshal(m, b) return xxx_messageInfo_NewAddressResponse.Unmarshal(m, b)
@ -1818,7 +1818,7 @@ func (m *SignMessageRequest) Reset() { *m = SignMessageRequest{} }
func (m *SignMessageRequest) String() string { return proto.CompactTextString(m) } func (m *SignMessageRequest) String() string { return proto.CompactTextString(m) }
func (*SignMessageRequest) ProtoMessage() {} func (*SignMessageRequest) ProtoMessage() {}
func (*SignMessageRequest) Descriptor() ([]byte, []int) { func (*SignMessageRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{27} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{27}
} }
func (m *SignMessageRequest) XXX_Unmarshal(b []byte) error { func (m *SignMessageRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SignMessageRequest.Unmarshal(m, b) return xxx_messageInfo_SignMessageRequest.Unmarshal(m, b)
@ -1857,7 +1857,7 @@ func (m *SignMessageResponse) Reset() { *m = SignMessageResponse{} }
func (m *SignMessageResponse) String() string { return proto.CompactTextString(m) } func (m *SignMessageResponse) String() string { return proto.CompactTextString(m) }
func (*SignMessageResponse) ProtoMessage() {} func (*SignMessageResponse) ProtoMessage() {}
func (*SignMessageResponse) Descriptor() ([]byte, []int) { func (*SignMessageResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{28} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{28}
} }
func (m *SignMessageResponse) XXX_Unmarshal(b []byte) error { func (m *SignMessageResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SignMessageResponse.Unmarshal(m, b) return xxx_messageInfo_SignMessageResponse.Unmarshal(m, b)
@ -1898,7 +1898,7 @@ func (m *VerifyMessageRequest) Reset() { *m = VerifyMessageRequest{} }
func (m *VerifyMessageRequest) String() string { return proto.CompactTextString(m) } func (m *VerifyMessageRequest) String() string { return proto.CompactTextString(m) }
func (*VerifyMessageRequest) ProtoMessage() {} func (*VerifyMessageRequest) ProtoMessage() {}
func (*VerifyMessageRequest) Descriptor() ([]byte, []int) { func (*VerifyMessageRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{29} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{29}
} }
func (m *VerifyMessageRequest) XXX_Unmarshal(b []byte) error { func (m *VerifyMessageRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VerifyMessageRequest.Unmarshal(m, b) return xxx_messageInfo_VerifyMessageRequest.Unmarshal(m, b)
@ -1946,7 +1946,7 @@ func (m *VerifyMessageResponse) Reset() { *m = VerifyMessageResponse{} }
func (m *VerifyMessageResponse) String() string { return proto.CompactTextString(m) } func (m *VerifyMessageResponse) String() string { return proto.CompactTextString(m) }
func (*VerifyMessageResponse) ProtoMessage() {} func (*VerifyMessageResponse) ProtoMessage() {}
func (*VerifyMessageResponse) Descriptor() ([]byte, []int) { func (*VerifyMessageResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{30} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{30}
} }
func (m *VerifyMessageResponse) XXX_Unmarshal(b []byte) error { func (m *VerifyMessageResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_VerifyMessageResponse.Unmarshal(m, b) return xxx_messageInfo_VerifyMessageResponse.Unmarshal(m, b)
@ -1995,7 +1995,7 @@ func (m *ConnectPeerRequest) Reset() { *m = ConnectPeerRequest{} }
func (m *ConnectPeerRequest) String() string { return proto.CompactTextString(m) } func (m *ConnectPeerRequest) String() string { return proto.CompactTextString(m) }
func (*ConnectPeerRequest) ProtoMessage() {} func (*ConnectPeerRequest) ProtoMessage() {}
func (*ConnectPeerRequest) Descriptor() ([]byte, []int) { func (*ConnectPeerRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{31} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{31}
} }
func (m *ConnectPeerRequest) XXX_Unmarshal(b []byte) error { func (m *ConnectPeerRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ConnectPeerRequest.Unmarshal(m, b) return xxx_messageInfo_ConnectPeerRequest.Unmarshal(m, b)
@ -2039,7 +2039,7 @@ func (m *ConnectPeerResponse) Reset() { *m = ConnectPeerResponse{} }
func (m *ConnectPeerResponse) String() string { return proto.CompactTextString(m) } func (m *ConnectPeerResponse) String() string { return proto.CompactTextString(m) }
func (*ConnectPeerResponse) ProtoMessage() {} func (*ConnectPeerResponse) ProtoMessage() {}
func (*ConnectPeerResponse) Descriptor() ([]byte, []int) { func (*ConnectPeerResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{32} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{32}
} }
func (m *ConnectPeerResponse) XXX_Unmarshal(b []byte) error { func (m *ConnectPeerResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ConnectPeerResponse.Unmarshal(m, b) return xxx_messageInfo_ConnectPeerResponse.Unmarshal(m, b)
@ -2071,7 +2071,7 @@ func (m *DisconnectPeerRequest) Reset() { *m = DisconnectPeerRequest{} }
func (m *DisconnectPeerRequest) String() string { return proto.CompactTextString(m) } func (m *DisconnectPeerRequest) String() string { return proto.CompactTextString(m) }
func (*DisconnectPeerRequest) ProtoMessage() {} func (*DisconnectPeerRequest) ProtoMessage() {}
func (*DisconnectPeerRequest) Descriptor() ([]byte, []int) { func (*DisconnectPeerRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{33} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{33}
} }
func (m *DisconnectPeerRequest) XXX_Unmarshal(b []byte) error { func (m *DisconnectPeerRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DisconnectPeerRequest.Unmarshal(m, b) return xxx_messageInfo_DisconnectPeerRequest.Unmarshal(m, b)
@ -2108,7 +2108,7 @@ func (m *DisconnectPeerResponse) Reset() { *m = DisconnectPeerResponse{}
func (m *DisconnectPeerResponse) String() string { return proto.CompactTextString(m) } func (m *DisconnectPeerResponse) String() string { return proto.CompactTextString(m) }
func (*DisconnectPeerResponse) ProtoMessage() {} func (*DisconnectPeerResponse) ProtoMessage() {}
func (*DisconnectPeerResponse) Descriptor() ([]byte, []int) { func (*DisconnectPeerResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{34} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{34}
} }
func (m *DisconnectPeerResponse) XXX_Unmarshal(b []byte) error { func (m *DisconnectPeerResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DisconnectPeerResponse.Unmarshal(m, b) return xxx_messageInfo_DisconnectPeerResponse.Unmarshal(m, b)
@ -2142,7 +2142,7 @@ func (m *HTLC) Reset() { *m = HTLC{} }
func (m *HTLC) String() string { return proto.CompactTextString(m) } func (m *HTLC) String() string { return proto.CompactTextString(m) }
func (*HTLC) ProtoMessage() {} func (*HTLC) ProtoMessage() {}
func (*HTLC) Descriptor() ([]byte, []int) { func (*HTLC) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{35} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{35}
} }
func (m *HTLC) XXX_Unmarshal(b []byte) error { func (m *HTLC) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HTLC.Unmarshal(m, b) return xxx_messageInfo_HTLC.Unmarshal(m, b)
@ -2256,7 +2256,7 @@ func (m *Channel) Reset() { *m = Channel{} }
func (m *Channel) String() string { return proto.CompactTextString(m) } func (m *Channel) String() string { return proto.CompactTextString(m) }
func (*Channel) ProtoMessage() {} func (*Channel) ProtoMessage() {}
func (*Channel) Descriptor() ([]byte, []int) { func (*Channel) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{36} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{36}
} }
func (m *Channel) XXX_Unmarshal(b []byte) error { func (m *Channel) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Channel.Unmarshal(m, b) return xxx_messageInfo_Channel.Unmarshal(m, b)
@ -2416,7 +2416,7 @@ func (m *ListChannelsRequest) Reset() { *m = ListChannelsRequest{} }
func (m *ListChannelsRequest) String() string { return proto.CompactTextString(m) } func (m *ListChannelsRequest) String() string { return proto.CompactTextString(m) }
func (*ListChannelsRequest) ProtoMessage() {} func (*ListChannelsRequest) ProtoMessage() {}
func (*ListChannelsRequest) Descriptor() ([]byte, []int) { func (*ListChannelsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{37} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{37}
} }
func (m *ListChannelsRequest) XXX_Unmarshal(b []byte) error { func (m *ListChannelsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListChannelsRequest.Unmarshal(m, b) return xxx_messageInfo_ListChannelsRequest.Unmarshal(m, b)
@ -2476,7 +2476,7 @@ func (m *ListChannelsResponse) Reset() { *m = ListChannelsResponse{} }
func (m *ListChannelsResponse) String() string { return proto.CompactTextString(m) } func (m *ListChannelsResponse) String() string { return proto.CompactTextString(m) }
func (*ListChannelsResponse) ProtoMessage() {} func (*ListChannelsResponse) ProtoMessage() {}
func (*ListChannelsResponse) Descriptor() ([]byte, []int) { func (*ListChannelsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{38} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{38}
} }
func (m *ListChannelsResponse) XXX_Unmarshal(b []byte) error { func (m *ListChannelsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListChannelsResponse.Unmarshal(m, b) return xxx_messageInfo_ListChannelsResponse.Unmarshal(m, b)
@ -2533,7 +2533,7 @@ func (m *ChannelCloseSummary) Reset() { *m = ChannelCloseSummary{} }
func (m *ChannelCloseSummary) String() string { return proto.CompactTextString(m) } func (m *ChannelCloseSummary) String() string { return proto.CompactTextString(m) }
func (*ChannelCloseSummary) ProtoMessage() {} func (*ChannelCloseSummary) ProtoMessage() {}
func (*ChannelCloseSummary) Descriptor() ([]byte, []int) { func (*ChannelCloseSummary) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{39} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{39}
} }
func (m *ChannelCloseSummary) XXX_Unmarshal(b []byte) error { func (m *ChannelCloseSummary) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelCloseSummary.Unmarshal(m, b) return xxx_messageInfo_ChannelCloseSummary.Unmarshal(m, b)
@ -2639,7 +2639,7 @@ func (m *ClosedChannelsRequest) Reset() { *m = ClosedChannelsRequest{} }
func (m *ClosedChannelsRequest) String() string { return proto.CompactTextString(m) } func (m *ClosedChannelsRequest) String() string { return proto.CompactTextString(m) }
func (*ClosedChannelsRequest) ProtoMessage() {} func (*ClosedChannelsRequest) ProtoMessage() {}
func (*ClosedChannelsRequest) Descriptor() ([]byte, []int) { func (*ClosedChannelsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{40} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{40}
} }
func (m *ClosedChannelsRequest) XXX_Unmarshal(b []byte) error { func (m *ClosedChannelsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ClosedChannelsRequest.Unmarshal(m, b) return xxx_messageInfo_ClosedChannelsRequest.Unmarshal(m, b)
@ -2712,7 +2712,7 @@ func (m *ClosedChannelsResponse) Reset() { *m = ClosedChannelsResponse{}
func (m *ClosedChannelsResponse) String() string { return proto.CompactTextString(m) } func (m *ClosedChannelsResponse) String() string { return proto.CompactTextString(m) }
func (*ClosedChannelsResponse) ProtoMessage() {} func (*ClosedChannelsResponse) ProtoMessage() {}
func (*ClosedChannelsResponse) Descriptor() ([]byte, []int) { func (*ClosedChannelsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{41} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{41}
} }
func (m *ClosedChannelsResponse) XXX_Unmarshal(b []byte) error { func (m *ClosedChannelsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ClosedChannelsResponse.Unmarshal(m, b) return xxx_messageInfo_ClosedChannelsResponse.Unmarshal(m, b)
@ -2765,7 +2765,7 @@ func (m *Peer) Reset() { *m = Peer{} }
func (m *Peer) String() string { return proto.CompactTextString(m) } func (m *Peer) String() string { return proto.CompactTextString(m) }
func (*Peer) ProtoMessage() {} func (*Peer) ProtoMessage() {}
func (*Peer) Descriptor() ([]byte, []int) { func (*Peer) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{42} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{42}
} }
func (m *Peer) XXX_Unmarshal(b []byte) error { func (m *Peer) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Peer.Unmarshal(m, b) return xxx_messageInfo_Peer.Unmarshal(m, b)
@ -2851,7 +2851,7 @@ func (m *ListPeersRequest) Reset() { *m = ListPeersRequest{} }
func (m *ListPeersRequest) String() string { return proto.CompactTextString(m) } func (m *ListPeersRequest) String() string { return proto.CompactTextString(m) }
func (*ListPeersRequest) ProtoMessage() {} func (*ListPeersRequest) ProtoMessage() {}
func (*ListPeersRequest) Descriptor() ([]byte, []int) { func (*ListPeersRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{43} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{43}
} }
func (m *ListPeersRequest) XXX_Unmarshal(b []byte) error { func (m *ListPeersRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListPeersRequest.Unmarshal(m, b) return xxx_messageInfo_ListPeersRequest.Unmarshal(m, b)
@ -2883,7 +2883,7 @@ func (m *ListPeersResponse) Reset() { *m = ListPeersResponse{} }
func (m *ListPeersResponse) String() string { return proto.CompactTextString(m) } func (m *ListPeersResponse) String() string { return proto.CompactTextString(m) }
func (*ListPeersResponse) ProtoMessage() {} func (*ListPeersResponse) ProtoMessage() {}
func (*ListPeersResponse) Descriptor() ([]byte, []int) { func (*ListPeersResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{44} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{44}
} }
func (m *ListPeersResponse) XXX_Unmarshal(b []byte) error { func (m *ListPeersResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListPeersResponse.Unmarshal(m, b) return xxx_messageInfo_ListPeersResponse.Unmarshal(m, b)
@ -2920,7 +2920,7 @@ func (m *GetInfoRequest) Reset() { *m = GetInfoRequest{} }
func (m *GetInfoRequest) String() string { return proto.CompactTextString(m) } func (m *GetInfoRequest) String() string { return proto.CompactTextString(m) }
func (*GetInfoRequest) ProtoMessage() {} func (*GetInfoRequest) ProtoMessage() {}
func (*GetInfoRequest) Descriptor() ([]byte, []int) { func (*GetInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{45} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{45}
} }
func (m *GetInfoRequest) XXX_Unmarshal(b []byte) error { func (m *GetInfoRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetInfoRequest.Unmarshal(m, b) return xxx_messageInfo_GetInfoRequest.Unmarshal(m, b)
@ -2980,7 +2980,7 @@ func (m *GetInfoResponse) Reset() { *m = GetInfoResponse{} }
func (m *GetInfoResponse) String() string { return proto.CompactTextString(m) } func (m *GetInfoResponse) String() string { return proto.CompactTextString(m) }
func (*GetInfoResponse) ProtoMessage() {} func (*GetInfoResponse) ProtoMessage() {}
func (*GetInfoResponse) Descriptor() ([]byte, []int) { func (*GetInfoResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{46} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{46}
} }
func (m *GetInfoResponse) XXX_Unmarshal(b []byte) error { func (m *GetInfoResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetInfoResponse.Unmarshal(m, b) return xxx_messageInfo_GetInfoResponse.Unmarshal(m, b)
@ -3113,7 +3113,7 @@ func (m *Chain) Reset() { *m = Chain{} }
func (m *Chain) String() string { return proto.CompactTextString(m) } func (m *Chain) String() string { return proto.CompactTextString(m) }
func (*Chain) ProtoMessage() {} func (*Chain) ProtoMessage() {}
func (*Chain) Descriptor() ([]byte, []int) { func (*Chain) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{47} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{47}
} }
func (m *Chain) XXX_Unmarshal(b []byte) error { func (m *Chain) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Chain.Unmarshal(m, b) return xxx_messageInfo_Chain.Unmarshal(m, b)
@ -3160,7 +3160,7 @@ func (m *ConfirmationUpdate) Reset() { *m = ConfirmationUpdate{} }
func (m *ConfirmationUpdate) String() string { return proto.CompactTextString(m) } func (m *ConfirmationUpdate) String() string { return proto.CompactTextString(m) }
func (*ConfirmationUpdate) ProtoMessage() {} func (*ConfirmationUpdate) ProtoMessage() {}
func (*ConfirmationUpdate) Descriptor() ([]byte, []int) { func (*ConfirmationUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{48} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{48}
} }
func (m *ConfirmationUpdate) XXX_Unmarshal(b []byte) error { func (m *ConfirmationUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ConfirmationUpdate.Unmarshal(m, b) return xxx_messageInfo_ConfirmationUpdate.Unmarshal(m, b)
@ -3212,7 +3212,7 @@ func (m *ChannelOpenUpdate) Reset() { *m = ChannelOpenUpdate{} }
func (m *ChannelOpenUpdate) String() string { return proto.CompactTextString(m) } func (m *ChannelOpenUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelOpenUpdate) ProtoMessage() {} func (*ChannelOpenUpdate) ProtoMessage() {}
func (*ChannelOpenUpdate) Descriptor() ([]byte, []int) { func (*ChannelOpenUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{49} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{49}
} }
func (m *ChannelOpenUpdate) XXX_Unmarshal(b []byte) error { func (m *ChannelOpenUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelOpenUpdate.Unmarshal(m, b) return xxx_messageInfo_ChannelOpenUpdate.Unmarshal(m, b)
@ -3251,7 +3251,7 @@ func (m *ChannelCloseUpdate) Reset() { *m = ChannelCloseUpdate{} }
func (m *ChannelCloseUpdate) String() string { return proto.CompactTextString(m) } func (m *ChannelCloseUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelCloseUpdate) ProtoMessage() {} func (*ChannelCloseUpdate) ProtoMessage() {}
func (*ChannelCloseUpdate) Descriptor() ([]byte, []int) { func (*ChannelCloseUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{50} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{50}
} }
func (m *ChannelCloseUpdate) XXX_Unmarshal(b []byte) error { func (m *ChannelCloseUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelCloseUpdate.Unmarshal(m, b) return xxx_messageInfo_ChannelCloseUpdate.Unmarshal(m, b)
@ -3306,7 +3306,7 @@ func (m *CloseChannelRequest) Reset() { *m = CloseChannelRequest{} }
func (m *CloseChannelRequest) String() string { return proto.CompactTextString(m) } func (m *CloseChannelRequest) String() string { return proto.CompactTextString(m) }
func (*CloseChannelRequest) ProtoMessage() {} func (*CloseChannelRequest) ProtoMessage() {}
func (*CloseChannelRequest) Descriptor() ([]byte, []int) { func (*CloseChannelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{51} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{51}
} }
func (m *CloseChannelRequest) XXX_Unmarshal(b []byte) error { func (m *CloseChannelRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CloseChannelRequest.Unmarshal(m, b) return xxx_messageInfo_CloseChannelRequest.Unmarshal(m, b)
@ -3368,7 +3368,7 @@ func (m *CloseStatusUpdate) Reset() { *m = CloseStatusUpdate{} }
func (m *CloseStatusUpdate) String() string { return proto.CompactTextString(m) } func (m *CloseStatusUpdate) String() string { return proto.CompactTextString(m) }
func (*CloseStatusUpdate) ProtoMessage() {} func (*CloseStatusUpdate) ProtoMessage() {}
func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { func (*CloseStatusUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{52} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{52}
} }
func (m *CloseStatusUpdate) XXX_Unmarshal(b []byte) error { func (m *CloseStatusUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CloseStatusUpdate.Unmarshal(m, b) return xxx_messageInfo_CloseStatusUpdate.Unmarshal(m, b)
@ -3511,7 +3511,7 @@ func (m *PendingUpdate) Reset() { *m = PendingUpdate{} }
func (m *PendingUpdate) String() string { return proto.CompactTextString(m) } func (m *PendingUpdate) String() string { return proto.CompactTextString(m) }
func (*PendingUpdate) ProtoMessage() {} func (*PendingUpdate) ProtoMessage() {}
func (*PendingUpdate) Descriptor() ([]byte, []int) { func (*PendingUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{53} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{53}
} }
func (m *PendingUpdate) XXX_Unmarshal(b []byte) error { func (m *PendingUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingUpdate.Unmarshal(m, b) return xxx_messageInfo_PendingUpdate.Unmarshal(m, b)
@ -3577,7 +3577,7 @@ func (m *OpenChannelRequest) Reset() { *m = OpenChannelRequest{} }
func (m *OpenChannelRequest) String() string { return proto.CompactTextString(m) } func (m *OpenChannelRequest) String() string { return proto.CompactTextString(m) }
func (*OpenChannelRequest) ProtoMessage() {} func (*OpenChannelRequest) ProtoMessage() {}
func (*OpenChannelRequest) Descriptor() ([]byte, []int) { func (*OpenChannelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{54} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{54}
} }
func (m *OpenChannelRequest) XXX_Unmarshal(b []byte) error { func (m *OpenChannelRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_OpenChannelRequest.Unmarshal(m, b) return xxx_messageInfo_OpenChannelRequest.Unmarshal(m, b)
@ -3688,7 +3688,7 @@ func (m *OpenStatusUpdate) Reset() { *m = OpenStatusUpdate{} }
func (m *OpenStatusUpdate) String() string { return proto.CompactTextString(m) } func (m *OpenStatusUpdate) String() string { return proto.CompactTextString(m) }
func (*OpenStatusUpdate) ProtoMessage() {} func (*OpenStatusUpdate) ProtoMessage() {}
func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { func (*OpenStatusUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{55} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{55}
} }
func (m *OpenStatusUpdate) XXX_Unmarshal(b []byte) error { func (m *OpenStatusUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_OpenStatusUpdate.Unmarshal(m, b) return xxx_messageInfo_OpenStatusUpdate.Unmarshal(m, b)
@ -3844,7 +3844,7 @@ func (m *PendingHTLC) Reset() { *m = PendingHTLC{} }
func (m *PendingHTLC) String() string { return proto.CompactTextString(m) } func (m *PendingHTLC) String() string { return proto.CompactTextString(m) }
func (*PendingHTLC) ProtoMessage() {} func (*PendingHTLC) ProtoMessage() {}
func (*PendingHTLC) Descriptor() ([]byte, []int) { func (*PendingHTLC) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{56} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{56}
} }
func (m *PendingHTLC) XXX_Unmarshal(b []byte) error { func (m *PendingHTLC) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingHTLC.Unmarshal(m, b) return xxx_messageInfo_PendingHTLC.Unmarshal(m, b)
@ -3916,7 +3916,7 @@ func (m *PendingChannelsRequest) Reset() { *m = PendingChannelsRequest{}
func (m *PendingChannelsRequest) String() string { return proto.CompactTextString(m) } func (m *PendingChannelsRequest) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsRequest) ProtoMessage() {} func (*PendingChannelsRequest) ProtoMessage() {}
func (*PendingChannelsRequest) Descriptor() ([]byte, []int) { func (*PendingChannelsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{57} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{57}
} }
func (m *PendingChannelsRequest) XXX_Unmarshal(b []byte) error { func (m *PendingChannelsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingChannelsRequest.Unmarshal(m, b) return xxx_messageInfo_PendingChannelsRequest.Unmarshal(m, b)
@ -3956,7 +3956,7 @@ func (m *PendingChannelsResponse) Reset() { *m = PendingChannelsResponse
func (m *PendingChannelsResponse) String() string { return proto.CompactTextString(m) } func (m *PendingChannelsResponse) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsResponse) ProtoMessage() {} func (*PendingChannelsResponse) ProtoMessage() {}
func (*PendingChannelsResponse) Descriptor() ([]byte, []int) { func (*PendingChannelsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{58} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{58}
} }
func (m *PendingChannelsResponse) XXX_Unmarshal(b []byte) error { func (m *PendingChannelsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingChannelsResponse.Unmarshal(m, b) return xxx_messageInfo_PendingChannelsResponse.Unmarshal(m, b)
@ -4028,7 +4028,7 @@ func (m *PendingChannelsResponse_PendingChannel) Reset() {
func (m *PendingChannelsResponse_PendingChannel) String() string { return proto.CompactTextString(m) } func (m *PendingChannelsResponse_PendingChannel) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsResponse_PendingChannel) ProtoMessage() {} func (*PendingChannelsResponse_PendingChannel) ProtoMessage() {}
func (*PendingChannelsResponse_PendingChannel) Descriptor() ([]byte, []int) { func (*PendingChannelsResponse_PendingChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{58, 0} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{58, 0}
} }
func (m *PendingChannelsResponse_PendingChannel) XXX_Unmarshal(b []byte) error { func (m *PendingChannelsResponse_PendingChannel) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingChannelsResponse_PendingChannel.Unmarshal(m, b) return xxx_messageInfo_PendingChannelsResponse_PendingChannel.Unmarshal(m, b)
@ -4115,7 +4115,7 @@ func (m *PendingChannelsResponse_PendingOpenChannel) String() string {
} }
func (*PendingChannelsResponse_PendingOpenChannel) ProtoMessage() {} func (*PendingChannelsResponse_PendingOpenChannel) ProtoMessage() {}
func (*PendingChannelsResponse_PendingOpenChannel) Descriptor() ([]byte, []int) { func (*PendingChannelsResponse_PendingOpenChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{58, 1} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{58, 1}
} }
func (m *PendingChannelsResponse_PendingOpenChannel) XXX_Unmarshal(b []byte) error { func (m *PendingChannelsResponse_PendingOpenChannel) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingChannelsResponse_PendingOpenChannel.Unmarshal(m, b) return xxx_messageInfo_PendingChannelsResponse_PendingOpenChannel.Unmarshal(m, b)
@ -4188,7 +4188,7 @@ func (m *PendingChannelsResponse_WaitingCloseChannel) String() string {
} }
func (*PendingChannelsResponse_WaitingCloseChannel) ProtoMessage() {} func (*PendingChannelsResponse_WaitingCloseChannel) ProtoMessage() {}
func (*PendingChannelsResponse_WaitingCloseChannel) Descriptor() ([]byte, []int) { func (*PendingChannelsResponse_WaitingCloseChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{58, 2} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{58, 2}
} }
func (m *PendingChannelsResponse_WaitingCloseChannel) XXX_Unmarshal(b []byte) error { func (m *PendingChannelsResponse_WaitingCloseChannel) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingChannelsResponse_WaitingCloseChannel.Unmarshal(m, b) return xxx_messageInfo_PendingChannelsResponse_WaitingCloseChannel.Unmarshal(m, b)
@ -4236,7 +4236,7 @@ func (m *PendingChannelsResponse_ClosedChannel) Reset() { *m = PendingCh
func (m *PendingChannelsResponse_ClosedChannel) String() string { return proto.CompactTextString(m) } func (m *PendingChannelsResponse_ClosedChannel) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsResponse_ClosedChannel) ProtoMessage() {} func (*PendingChannelsResponse_ClosedChannel) ProtoMessage() {}
func (*PendingChannelsResponse_ClosedChannel) Descriptor() ([]byte, []int) { func (*PendingChannelsResponse_ClosedChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{58, 3} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{58, 3}
} }
func (m *PendingChannelsResponse_ClosedChannel) XXX_Unmarshal(b []byte) error { func (m *PendingChannelsResponse_ClosedChannel) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingChannelsResponse_ClosedChannel.Unmarshal(m, b) return xxx_messageInfo_PendingChannelsResponse_ClosedChannel.Unmarshal(m, b)
@ -4300,7 +4300,7 @@ func (m *PendingChannelsResponse_ForceClosedChannel) String() string {
} }
func (*PendingChannelsResponse_ForceClosedChannel) ProtoMessage() {} func (*PendingChannelsResponse_ForceClosedChannel) ProtoMessage() {}
func (*PendingChannelsResponse_ForceClosedChannel) Descriptor() ([]byte, []int) { func (*PendingChannelsResponse_ForceClosedChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{58, 4} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{58, 4}
} }
func (m *PendingChannelsResponse_ForceClosedChannel) XXX_Unmarshal(b []byte) error { func (m *PendingChannelsResponse_ForceClosedChannel) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PendingChannelsResponse_ForceClosedChannel.Unmarshal(m, b) return xxx_messageInfo_PendingChannelsResponse_ForceClosedChannel.Unmarshal(m, b)
@ -4379,7 +4379,7 @@ func (m *ChannelEventSubscription) Reset() { *m = ChannelEventSubscripti
func (m *ChannelEventSubscription) String() string { return proto.CompactTextString(m) } func (m *ChannelEventSubscription) String() string { return proto.CompactTextString(m) }
func (*ChannelEventSubscription) ProtoMessage() {} func (*ChannelEventSubscription) ProtoMessage() {}
func (*ChannelEventSubscription) Descriptor() ([]byte, []int) { func (*ChannelEventSubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{59} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{59}
} }
func (m *ChannelEventSubscription) XXX_Unmarshal(b []byte) error { func (m *ChannelEventSubscription) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelEventSubscription.Unmarshal(m, b) return xxx_messageInfo_ChannelEventSubscription.Unmarshal(m, b)
@ -4416,7 +4416,7 @@ func (m *ChannelEventUpdate) Reset() { *m = ChannelEventUpdate{} }
func (m *ChannelEventUpdate) String() string { return proto.CompactTextString(m) } func (m *ChannelEventUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelEventUpdate) ProtoMessage() {} func (*ChannelEventUpdate) ProtoMessage() {}
func (*ChannelEventUpdate) Descriptor() ([]byte, []int) { func (*ChannelEventUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{60} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{60}
} }
func (m *ChannelEventUpdate) XXX_Unmarshal(b []byte) error { func (m *ChannelEventUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelEventUpdate.Unmarshal(m, b) return xxx_messageInfo_ChannelEventUpdate.Unmarshal(m, b)
@ -4628,7 +4628,7 @@ func (m *WalletBalanceRequest) Reset() { *m = WalletBalanceRequest{} }
func (m *WalletBalanceRequest) String() string { return proto.CompactTextString(m) } func (m *WalletBalanceRequest) String() string { return proto.CompactTextString(m) }
func (*WalletBalanceRequest) ProtoMessage() {} func (*WalletBalanceRequest) ProtoMessage() {}
func (*WalletBalanceRequest) Descriptor() ([]byte, []int) { func (*WalletBalanceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{61} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{61}
} }
func (m *WalletBalanceRequest) XXX_Unmarshal(b []byte) error { func (m *WalletBalanceRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WalletBalanceRequest.Unmarshal(m, b) return xxx_messageInfo_WalletBalanceRequest.Unmarshal(m, b)
@ -4664,7 +4664,7 @@ func (m *WalletBalanceResponse) Reset() { *m = WalletBalanceResponse{} }
func (m *WalletBalanceResponse) String() string { return proto.CompactTextString(m) } func (m *WalletBalanceResponse) String() string { return proto.CompactTextString(m) }
func (*WalletBalanceResponse) ProtoMessage() {} func (*WalletBalanceResponse) ProtoMessage() {}
func (*WalletBalanceResponse) Descriptor() ([]byte, []int) { func (*WalletBalanceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{62} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{62}
} }
func (m *WalletBalanceResponse) XXX_Unmarshal(b []byte) error { func (m *WalletBalanceResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WalletBalanceResponse.Unmarshal(m, b) return xxx_messageInfo_WalletBalanceResponse.Unmarshal(m, b)
@ -4715,7 +4715,7 @@ func (m *ChannelBalanceRequest) Reset() { *m = ChannelBalanceRequest{} }
func (m *ChannelBalanceRequest) String() string { return proto.CompactTextString(m) } func (m *ChannelBalanceRequest) String() string { return proto.CompactTextString(m) }
func (*ChannelBalanceRequest) ProtoMessage() {} func (*ChannelBalanceRequest) ProtoMessage() {}
func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) { func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{63} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{63}
} }
func (m *ChannelBalanceRequest) XXX_Unmarshal(b []byte) error { func (m *ChannelBalanceRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelBalanceRequest.Unmarshal(m, b) return xxx_messageInfo_ChannelBalanceRequest.Unmarshal(m, b)
@ -4749,7 +4749,7 @@ func (m *ChannelBalanceResponse) Reset() { *m = ChannelBalanceResponse{}
func (m *ChannelBalanceResponse) String() string { return proto.CompactTextString(m) } func (m *ChannelBalanceResponse) String() string { return proto.CompactTextString(m) }
func (*ChannelBalanceResponse) ProtoMessage() {} func (*ChannelBalanceResponse) ProtoMessage() {}
func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) { func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{64} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{64}
} }
func (m *ChannelBalanceResponse) XXX_Unmarshal(b []byte) error { func (m *ChannelBalanceResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelBalanceResponse.Unmarshal(m, b) return xxx_messageInfo_ChannelBalanceResponse.Unmarshal(m, b)
@ -4788,8 +4788,10 @@ type QueryRoutesRequest struct {
PubKey string `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"` PubKey string `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key,omitempty"`
// / The amount to send expressed in satoshis // / The amount to send expressed in satoshis
Amt int64 `protobuf:"varint,2,opt,name=amt,proto3" json:"amt,omitempty"` Amt int64 `protobuf:"varint,2,opt,name=amt,proto3" json:"amt,omitempty"`
// / The max number of routes to return. // *
NumRoutes int32 `protobuf:"varint,3,opt,name=num_routes,json=numRoutes,proto3" json:"num_routes,omitempty"` // Deprecated. The max number of routes to return. In the future, QueryRoutes
// will only return a single route.
NumRoutes int32 `protobuf:"varint,3,opt,name=num_routes,json=numRoutes,proto3" json:"num_routes,omitempty"` // Deprecated: Do not use.
// / An optional CLTV delta from the current height that should be used for the timelock of the final hop // / An optional CLTV delta from the current height that should be used for the timelock of the final hop
FinalCltvDelta int32 `protobuf:"varint,4,opt,name=final_cltv_delta,json=finalCltvDelta,proto3" json:"final_cltv_delta,omitempty"` FinalCltvDelta int32 `protobuf:"varint,4,opt,name=final_cltv_delta,json=finalCltvDelta,proto3" json:"final_cltv_delta,omitempty"`
// * // *
@ -4798,6 +4800,16 @@ type QueryRoutesRequest struct {
// sent, or as a fixed amount of the maximum fee the user is willing the pay to // sent, or as a fixed amount of the maximum fee the user is willing the pay to
// send the payment. // send the payment.
FeeLimit *FeeLimit `protobuf:"bytes,5,opt,name=fee_limit,json=feeLimit,proto3" json:"fee_limit,omitempty"` FeeLimit *FeeLimit `protobuf:"bytes,5,opt,name=fee_limit,json=feeLimit,proto3" json:"fee_limit,omitempty"`
// *
// A list of nodes to ignore during path finding.
IgnoredNodes [][]byte `protobuf:"bytes,6,rep,name=ignored_nodes,json=ignoredNodes,proto3" json:"ignored_nodes,omitempty"`
// *
// A list of edges to ignore during path finding.
IgnoredEdges []*EdgeLocator `protobuf:"bytes,7,rep,name=ignored_edges,json=ignoredEdges,proto3" json:"ignored_edges,omitempty"`
// *
// The source node where the request route should originated from. If empty,
// self is assumed.
SourcePubKey string `protobuf:"bytes,8,opt,name=source_pub_key,json=sourcePubKey,proto3" json:"source_pub_key,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -4807,7 +4819,7 @@ func (m *QueryRoutesRequest) Reset() { *m = QueryRoutesRequest{} }
func (m *QueryRoutesRequest) String() string { return proto.CompactTextString(m) } func (m *QueryRoutesRequest) String() string { return proto.CompactTextString(m) }
func (*QueryRoutesRequest) ProtoMessage() {} func (*QueryRoutesRequest) ProtoMessage() {}
func (*QueryRoutesRequest) Descriptor() ([]byte, []int) { func (*QueryRoutesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{65} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{65}
} }
func (m *QueryRoutesRequest) XXX_Unmarshal(b []byte) error { func (m *QueryRoutesRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_QueryRoutesRequest.Unmarshal(m, b) return xxx_messageInfo_QueryRoutesRequest.Unmarshal(m, b)
@ -4841,6 +4853,7 @@ func (m *QueryRoutesRequest) GetAmt() int64 {
return 0 return 0
} }
// Deprecated: Do not use.
func (m *QueryRoutesRequest) GetNumRoutes() int32 { func (m *QueryRoutesRequest) GetNumRoutes() int32 {
if m != nil { if m != nil {
return m.NumRoutes return m.NumRoutes
@ -4862,6 +4875,79 @@ func (m *QueryRoutesRequest) GetFeeLimit() *FeeLimit {
return nil return nil
} }
func (m *QueryRoutesRequest) GetIgnoredNodes() [][]byte {
if m != nil {
return m.IgnoredNodes
}
return nil
}
func (m *QueryRoutesRequest) GetIgnoredEdges() []*EdgeLocator {
if m != nil {
return m.IgnoredEdges
}
return nil
}
func (m *QueryRoutesRequest) GetSourcePubKey() string {
if m != nil {
return m.SourcePubKey
}
return ""
}
type EdgeLocator struct {
// / The short channel id of this edge.
ChannelId uint64 `protobuf:"varint,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
// *
// The direction of this edge. If direction_reverse is false, the direction
// of this edge is from the channel endpoint with the lexicographically smaller
// pub key to the endpoint with the larger pub key. If direction_reverse is
// is true, the edge goes the other way.
DirectionReverse bool `protobuf:"varint,2,opt,name=direction_reverse,json=directionReverse,proto3" json:"direction_reverse,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EdgeLocator) Reset() { *m = EdgeLocator{} }
func (m *EdgeLocator) String() string { return proto.CompactTextString(m) }
func (*EdgeLocator) ProtoMessage() {}
func (*EdgeLocator) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{66}
}
func (m *EdgeLocator) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EdgeLocator.Unmarshal(m, b)
}
func (m *EdgeLocator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EdgeLocator.Marshal(b, m, deterministic)
}
func (dst *EdgeLocator) XXX_Merge(src proto.Message) {
xxx_messageInfo_EdgeLocator.Merge(dst, src)
}
func (m *EdgeLocator) XXX_Size() int {
return xxx_messageInfo_EdgeLocator.Size(m)
}
func (m *EdgeLocator) XXX_DiscardUnknown() {
xxx_messageInfo_EdgeLocator.DiscardUnknown(m)
}
var xxx_messageInfo_EdgeLocator proto.InternalMessageInfo
func (m *EdgeLocator) GetChannelId() uint64 {
if m != nil {
return m.ChannelId
}
return 0
}
func (m *EdgeLocator) GetDirectionReverse() bool {
if m != nil {
return m.DirectionReverse
}
return false
}
type QueryRoutesResponse struct { type QueryRoutesResponse struct {
Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"` Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
@ -4873,7 +4959,7 @@ func (m *QueryRoutesResponse) Reset() { *m = QueryRoutesResponse{} }
func (m *QueryRoutesResponse) String() string { return proto.CompactTextString(m) } func (m *QueryRoutesResponse) String() string { return proto.CompactTextString(m) }
func (*QueryRoutesResponse) ProtoMessage() {} func (*QueryRoutesResponse) ProtoMessage() {}
func (*QueryRoutesResponse) Descriptor() ([]byte, []int) { func (*QueryRoutesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{66} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{67}
} }
func (m *QueryRoutesResponse) XXX_Unmarshal(b []byte) error { func (m *QueryRoutesResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_QueryRoutesResponse.Unmarshal(m, b) return xxx_messageInfo_QueryRoutesResponse.Unmarshal(m, b)
@ -4925,7 +5011,7 @@ func (m *Hop) Reset() { *m = Hop{} }
func (m *Hop) String() string { return proto.CompactTextString(m) } func (m *Hop) String() string { return proto.CompactTextString(m) }
func (*Hop) ProtoMessage() {} func (*Hop) ProtoMessage() {}
func (*Hop) Descriptor() ([]byte, []int) { func (*Hop) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{67} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{68}
} }
func (m *Hop) XXX_Unmarshal(b []byte) error { func (m *Hop) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Hop.Unmarshal(m, b) return xxx_messageInfo_Hop.Unmarshal(m, b)
@ -5046,7 +5132,7 @@ func (m *Route) Reset() { *m = Route{} }
func (m *Route) String() string { return proto.CompactTextString(m) } func (m *Route) String() string { return proto.CompactTextString(m) }
func (*Route) ProtoMessage() {} func (*Route) ProtoMessage() {}
func (*Route) Descriptor() ([]byte, []int) { func (*Route) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{68} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{69}
} }
func (m *Route) XXX_Unmarshal(b []byte) error { func (m *Route) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Route.Unmarshal(m, b) return xxx_messageInfo_Route.Unmarshal(m, b)
@ -5122,7 +5208,7 @@ func (m *NodeInfoRequest) Reset() { *m = NodeInfoRequest{} }
func (m *NodeInfoRequest) String() string { return proto.CompactTextString(m) } func (m *NodeInfoRequest) String() string { return proto.CompactTextString(m) }
func (*NodeInfoRequest) ProtoMessage() {} func (*NodeInfoRequest) ProtoMessage() {}
func (*NodeInfoRequest) Descriptor() ([]byte, []int) { func (*NodeInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{69} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{70}
} }
func (m *NodeInfoRequest) XXX_Unmarshal(b []byte) error { func (m *NodeInfoRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NodeInfoRequest.Unmarshal(m, b) return xxx_messageInfo_NodeInfoRequest.Unmarshal(m, b)
@ -5167,7 +5253,7 @@ func (m *NodeInfo) Reset() { *m = NodeInfo{} }
func (m *NodeInfo) String() string { return proto.CompactTextString(m) } func (m *NodeInfo) String() string { return proto.CompactTextString(m) }
func (*NodeInfo) ProtoMessage() {} func (*NodeInfo) ProtoMessage() {}
func (*NodeInfo) Descriptor() ([]byte, []int) { func (*NodeInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{70} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{71}
} }
func (m *NodeInfo) XXX_Unmarshal(b []byte) error { func (m *NodeInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NodeInfo.Unmarshal(m, b) return xxx_messageInfo_NodeInfo.Unmarshal(m, b)
@ -5228,7 +5314,7 @@ func (m *LightningNode) Reset() { *m = LightningNode{} }
func (m *LightningNode) String() string { return proto.CompactTextString(m) } func (m *LightningNode) String() string { return proto.CompactTextString(m) }
func (*LightningNode) ProtoMessage() {} func (*LightningNode) ProtoMessage() {}
func (*LightningNode) Descriptor() ([]byte, []int) { func (*LightningNode) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{71} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{72}
} }
func (m *LightningNode) XXX_Unmarshal(b []byte) error { func (m *LightningNode) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LightningNode.Unmarshal(m, b) return xxx_messageInfo_LightningNode.Unmarshal(m, b)
@ -5295,7 +5381,7 @@ func (m *NodeAddress) Reset() { *m = NodeAddress{} }
func (m *NodeAddress) String() string { return proto.CompactTextString(m) } func (m *NodeAddress) String() string { return proto.CompactTextString(m) }
func (*NodeAddress) ProtoMessage() {} func (*NodeAddress) ProtoMessage() {}
func (*NodeAddress) Descriptor() ([]byte, []int) { func (*NodeAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{72} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{73}
} }
func (m *NodeAddress) XXX_Unmarshal(b []byte) error { func (m *NodeAddress) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NodeAddress.Unmarshal(m, b) return xxx_messageInfo_NodeAddress.Unmarshal(m, b)
@ -5345,7 +5431,7 @@ func (m *RoutingPolicy) Reset() { *m = RoutingPolicy{} }
func (m *RoutingPolicy) String() string { return proto.CompactTextString(m) } func (m *RoutingPolicy) String() string { return proto.CompactTextString(m) }
func (*RoutingPolicy) ProtoMessage() {} func (*RoutingPolicy) ProtoMessage() {}
func (*RoutingPolicy) Descriptor() ([]byte, []int) { func (*RoutingPolicy) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{73} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{74}
} }
func (m *RoutingPolicy) XXX_Unmarshal(b []byte) error { func (m *RoutingPolicy) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RoutingPolicy.Unmarshal(m, b) return xxx_messageInfo_RoutingPolicy.Unmarshal(m, b)
@ -5435,7 +5521,7 @@ func (m *ChannelEdge) Reset() { *m = ChannelEdge{} }
func (m *ChannelEdge) String() string { return proto.CompactTextString(m) } func (m *ChannelEdge) String() string { return proto.CompactTextString(m) }
func (*ChannelEdge) ProtoMessage() {} func (*ChannelEdge) ProtoMessage() {}
func (*ChannelEdge) Descriptor() ([]byte, []int) { func (*ChannelEdge) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{74} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{75}
} }
func (m *ChannelEdge) XXX_Unmarshal(b []byte) error { func (m *ChannelEdge) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelEdge.Unmarshal(m, b) return xxx_messageInfo_ChannelEdge.Unmarshal(m, b)
@ -5526,7 +5612,7 @@ func (m *ChannelGraphRequest) Reset() { *m = ChannelGraphRequest{} }
func (m *ChannelGraphRequest) String() string { return proto.CompactTextString(m) } func (m *ChannelGraphRequest) String() string { return proto.CompactTextString(m) }
func (*ChannelGraphRequest) ProtoMessage() {} func (*ChannelGraphRequest) ProtoMessage() {}
func (*ChannelGraphRequest) Descriptor() ([]byte, []int) { func (*ChannelGraphRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{75} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{76}
} }
func (m *ChannelGraphRequest) XXX_Unmarshal(b []byte) error { func (m *ChannelGraphRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelGraphRequest.Unmarshal(m, b) return xxx_messageInfo_ChannelGraphRequest.Unmarshal(m, b)
@ -5568,7 +5654,7 @@ func (m *ChannelGraph) Reset() { *m = ChannelGraph{} }
func (m *ChannelGraph) String() string { return proto.CompactTextString(m) } func (m *ChannelGraph) String() string { return proto.CompactTextString(m) }
func (*ChannelGraph) ProtoMessage() {} func (*ChannelGraph) ProtoMessage() {}
func (*ChannelGraph) Descriptor() ([]byte, []int) { func (*ChannelGraph) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{76} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{77}
} }
func (m *ChannelGraph) XXX_Unmarshal(b []byte) error { func (m *ChannelGraph) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelGraph.Unmarshal(m, b) return xxx_messageInfo_ChannelGraph.Unmarshal(m, b)
@ -5617,7 +5703,7 @@ func (m *ChanInfoRequest) Reset() { *m = ChanInfoRequest{} }
func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) } func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) }
func (*ChanInfoRequest) ProtoMessage() {} func (*ChanInfoRequest) ProtoMessage() {}
func (*ChanInfoRequest) Descriptor() ([]byte, []int) { func (*ChanInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{77} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{78}
} }
func (m *ChanInfoRequest) XXX_Unmarshal(b []byte) error { func (m *ChanInfoRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChanInfoRequest.Unmarshal(m, b) return xxx_messageInfo_ChanInfoRequest.Unmarshal(m, b)
@ -5654,7 +5740,7 @@ func (m *NetworkInfoRequest) Reset() { *m = NetworkInfoRequest{} }
func (m *NetworkInfoRequest) String() string { return proto.CompactTextString(m) } func (m *NetworkInfoRequest) String() string { return proto.CompactTextString(m) }
func (*NetworkInfoRequest) ProtoMessage() {} func (*NetworkInfoRequest) ProtoMessage() {}
func (*NetworkInfoRequest) Descriptor() ([]byte, []int) { func (*NetworkInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{78} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{79}
} }
func (m *NetworkInfoRequest) XXX_Unmarshal(b []byte) error { func (m *NetworkInfoRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NetworkInfoRequest.Unmarshal(m, b) return xxx_messageInfo_NetworkInfoRequest.Unmarshal(m, b)
@ -5693,7 +5779,7 @@ func (m *NetworkInfo) Reset() { *m = NetworkInfo{} }
func (m *NetworkInfo) String() string { return proto.CompactTextString(m) } func (m *NetworkInfo) String() string { return proto.CompactTextString(m) }
func (*NetworkInfo) ProtoMessage() {} func (*NetworkInfo) ProtoMessage() {}
func (*NetworkInfo) Descriptor() ([]byte, []int) { func (*NetworkInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{79} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{80}
} }
func (m *NetworkInfo) XXX_Unmarshal(b []byte) error { func (m *NetworkInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NetworkInfo.Unmarshal(m, b) return xxx_messageInfo_NetworkInfo.Unmarshal(m, b)
@ -5786,7 +5872,7 @@ func (m *StopRequest) Reset() { *m = StopRequest{} }
func (m *StopRequest) String() string { return proto.CompactTextString(m) } func (m *StopRequest) String() string { return proto.CompactTextString(m) }
func (*StopRequest) ProtoMessage() {} func (*StopRequest) ProtoMessage() {}
func (*StopRequest) Descriptor() ([]byte, []int) { func (*StopRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{80} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{81}
} }
func (m *StopRequest) XXX_Unmarshal(b []byte) error { func (m *StopRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StopRequest.Unmarshal(m, b) return xxx_messageInfo_StopRequest.Unmarshal(m, b)
@ -5816,7 +5902,7 @@ func (m *StopResponse) Reset() { *m = StopResponse{} }
func (m *StopResponse) String() string { return proto.CompactTextString(m) } func (m *StopResponse) String() string { return proto.CompactTextString(m) }
func (*StopResponse) ProtoMessage() {} func (*StopResponse) ProtoMessage() {}
func (*StopResponse) Descriptor() ([]byte, []int) { func (*StopResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{81} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{82}
} }
func (m *StopResponse) XXX_Unmarshal(b []byte) error { func (m *StopResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StopResponse.Unmarshal(m, b) return xxx_messageInfo_StopResponse.Unmarshal(m, b)
@ -5846,7 +5932,7 @@ func (m *GraphTopologySubscription) Reset() { *m = GraphTopologySubscrip
func (m *GraphTopologySubscription) String() string { return proto.CompactTextString(m) } func (m *GraphTopologySubscription) String() string { return proto.CompactTextString(m) }
func (*GraphTopologySubscription) ProtoMessage() {} func (*GraphTopologySubscription) ProtoMessage() {}
func (*GraphTopologySubscription) Descriptor() ([]byte, []int) { func (*GraphTopologySubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{82} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{83}
} }
func (m *GraphTopologySubscription) XXX_Unmarshal(b []byte) error { func (m *GraphTopologySubscription) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GraphTopologySubscription.Unmarshal(m, b) return xxx_messageInfo_GraphTopologySubscription.Unmarshal(m, b)
@ -5879,7 +5965,7 @@ func (m *GraphTopologyUpdate) Reset() { *m = GraphTopologyUpdate{} }
func (m *GraphTopologyUpdate) String() string { return proto.CompactTextString(m) } func (m *GraphTopologyUpdate) String() string { return proto.CompactTextString(m) }
func (*GraphTopologyUpdate) ProtoMessage() {} func (*GraphTopologyUpdate) ProtoMessage() {}
func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) { func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{83} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{84}
} }
func (m *GraphTopologyUpdate) XXX_Unmarshal(b []byte) error { func (m *GraphTopologyUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GraphTopologyUpdate.Unmarshal(m, b) return xxx_messageInfo_GraphTopologyUpdate.Unmarshal(m, b)
@ -5934,7 +6020,7 @@ func (m *NodeUpdate) Reset() { *m = NodeUpdate{} }
func (m *NodeUpdate) String() string { return proto.CompactTextString(m) } func (m *NodeUpdate) String() string { return proto.CompactTextString(m) }
func (*NodeUpdate) ProtoMessage() {} func (*NodeUpdate) ProtoMessage() {}
func (*NodeUpdate) Descriptor() ([]byte, []int) { func (*NodeUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{84} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{85}
} }
func (m *NodeUpdate) XXX_Unmarshal(b []byte) error { func (m *NodeUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NodeUpdate.Unmarshal(m, b) return xxx_messageInfo_NodeUpdate.Unmarshal(m, b)
@ -6002,7 +6088,7 @@ func (m *ChannelEdgeUpdate) Reset() { *m = ChannelEdgeUpdate{} }
func (m *ChannelEdgeUpdate) String() string { return proto.CompactTextString(m) } func (m *ChannelEdgeUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelEdgeUpdate) ProtoMessage() {} func (*ChannelEdgeUpdate) ProtoMessage() {}
func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) { func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{85} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{86}
} }
func (m *ChannelEdgeUpdate) XXX_Unmarshal(b []byte) error { func (m *ChannelEdgeUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelEdgeUpdate.Unmarshal(m, b) return xxx_messageInfo_ChannelEdgeUpdate.Unmarshal(m, b)
@ -6082,7 +6168,7 @@ func (m *ClosedChannelUpdate) Reset() { *m = ClosedChannelUpdate{} }
func (m *ClosedChannelUpdate) String() string { return proto.CompactTextString(m) } func (m *ClosedChannelUpdate) String() string { return proto.CompactTextString(m) }
func (*ClosedChannelUpdate) ProtoMessage() {} func (*ClosedChannelUpdate) ProtoMessage() {}
func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) { func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{86} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{87}
} }
func (m *ClosedChannelUpdate) XXX_Unmarshal(b []byte) error { func (m *ClosedChannelUpdate) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ClosedChannelUpdate.Unmarshal(m, b) return xxx_messageInfo_ClosedChannelUpdate.Unmarshal(m, b)
@ -6152,7 +6238,7 @@ func (m *HopHint) Reset() { *m = HopHint{} }
func (m *HopHint) String() string { return proto.CompactTextString(m) } func (m *HopHint) String() string { return proto.CompactTextString(m) }
func (*HopHint) ProtoMessage() {} func (*HopHint) ProtoMessage() {}
func (*HopHint) Descriptor() ([]byte, []int) { func (*HopHint) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{87} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{88}
} }
func (m *HopHint) XXX_Unmarshal(b []byte) error { func (m *HopHint) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HopHint.Unmarshal(m, b) return xxx_messageInfo_HopHint.Unmarshal(m, b)
@ -6221,7 +6307,7 @@ func (m *RouteHint) Reset() { *m = RouteHint{} }
func (m *RouteHint) String() string { return proto.CompactTextString(m) } func (m *RouteHint) String() string { return proto.CompactTextString(m) }
func (*RouteHint) ProtoMessage() {} func (*RouteHint) ProtoMessage() {}
func (*RouteHint) Descriptor() ([]byte, []int) { func (*RouteHint) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{88} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{89}
} }
func (m *RouteHint) XXX_Unmarshal(b []byte) error { func (m *RouteHint) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RouteHint.Unmarshal(m, b) return xxx_messageInfo_RouteHint.Unmarshal(m, b)
@ -6336,7 +6422,7 @@ func (m *Invoice) Reset() { *m = Invoice{} }
func (m *Invoice) String() string { return proto.CompactTextString(m) } func (m *Invoice) String() string { return proto.CompactTextString(m) }
func (*Invoice) ProtoMessage() {} func (*Invoice) ProtoMessage() {}
func (*Invoice) Descriptor() ([]byte, []int) { func (*Invoice) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{89} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{90}
} }
func (m *Invoice) XXX_Unmarshal(b []byte) error { func (m *Invoice) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Invoice.Unmarshal(m, b) return xxx_messageInfo_Invoice.Unmarshal(m, b)
@ -6528,7 +6614,7 @@ func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} }
func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) } func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*AddInvoiceResponse) ProtoMessage() {} func (*AddInvoiceResponse) ProtoMessage() {}
func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { func (*AddInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{90} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{91}
} }
func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error { func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AddInvoiceResponse.Unmarshal(m, b) return xxx_messageInfo_AddInvoiceResponse.Unmarshal(m, b)
@ -6585,7 +6671,7 @@ func (m *PaymentHash) Reset() { *m = PaymentHash{} }
func (m *PaymentHash) String() string { return proto.CompactTextString(m) } func (m *PaymentHash) String() string { return proto.CompactTextString(m) }
func (*PaymentHash) ProtoMessage() {} func (*PaymentHash) ProtoMessage() {}
func (*PaymentHash) Descriptor() ([]byte, []int) { func (*PaymentHash) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{91} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{92}
} }
func (m *PaymentHash) XXX_Unmarshal(b []byte) error { func (m *PaymentHash) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PaymentHash.Unmarshal(m, b) return xxx_messageInfo_PaymentHash.Unmarshal(m, b)
@ -6641,7 +6727,7 @@ func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} }
func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) } func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) }
func (*ListInvoiceRequest) ProtoMessage() {} func (*ListInvoiceRequest) ProtoMessage() {}
func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { func (*ListInvoiceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{92} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{93}
} }
func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error { func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListInvoiceRequest.Unmarshal(m, b) return xxx_messageInfo_ListInvoiceRequest.Unmarshal(m, b)
@ -6711,7 +6797,7 @@ func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} }
func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) } func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*ListInvoiceResponse) ProtoMessage() {} func (*ListInvoiceResponse) ProtoMessage() {}
func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { func (*ListInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{93} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{94}
} }
func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error { func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListInvoiceResponse.Unmarshal(m, b) return xxx_messageInfo_ListInvoiceResponse.Unmarshal(m, b)
@ -6774,7 +6860,7 @@ func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} }
func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) } func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) }
func (*InvoiceSubscription) ProtoMessage() {} func (*InvoiceSubscription) ProtoMessage() {}
func (*InvoiceSubscription) Descriptor() ([]byte, []int) { func (*InvoiceSubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{94} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{95}
} }
func (m *InvoiceSubscription) XXX_Unmarshal(b []byte) error { func (m *InvoiceSubscription) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_InvoiceSubscription.Unmarshal(m, b) return xxx_messageInfo_InvoiceSubscription.Unmarshal(m, b)
@ -6834,7 +6920,7 @@ func (m *Payment) Reset() { *m = Payment{} }
func (m *Payment) String() string { return proto.CompactTextString(m) } func (m *Payment) String() string { return proto.CompactTextString(m) }
func (*Payment) ProtoMessage() {} func (*Payment) ProtoMessage() {}
func (*Payment) Descriptor() ([]byte, []int) { func (*Payment) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{95} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{96}
} }
func (m *Payment) XXX_Unmarshal(b []byte) error { func (m *Payment) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Payment.Unmarshal(m, b) return xxx_messageInfo_Payment.Unmarshal(m, b)
@ -6921,7 +7007,7 @@ func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} }
func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) } func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) }
func (*ListPaymentsRequest) ProtoMessage() {} func (*ListPaymentsRequest) ProtoMessage() {}
func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { func (*ListPaymentsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{96} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{97}
} }
func (m *ListPaymentsRequest) XXX_Unmarshal(b []byte) error { func (m *ListPaymentsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListPaymentsRequest.Unmarshal(m, b) return xxx_messageInfo_ListPaymentsRequest.Unmarshal(m, b)
@ -6953,7 +7039,7 @@ func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} }
func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) } func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) }
func (*ListPaymentsResponse) ProtoMessage() {} func (*ListPaymentsResponse) ProtoMessage() {}
func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { func (*ListPaymentsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{97} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{98}
} }
func (m *ListPaymentsResponse) XXX_Unmarshal(b []byte) error { func (m *ListPaymentsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListPaymentsResponse.Unmarshal(m, b) return xxx_messageInfo_ListPaymentsResponse.Unmarshal(m, b)
@ -6990,7 +7076,7 @@ func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsReque
func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) } func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) }
func (*DeleteAllPaymentsRequest) ProtoMessage() {} func (*DeleteAllPaymentsRequest) ProtoMessage() {}
func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{98} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{99}
} }
func (m *DeleteAllPaymentsRequest) XXX_Unmarshal(b []byte) error { func (m *DeleteAllPaymentsRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DeleteAllPaymentsRequest.Unmarshal(m, b) return xxx_messageInfo_DeleteAllPaymentsRequest.Unmarshal(m, b)
@ -7020,7 +7106,7 @@ func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResp
func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) } func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) }
func (*DeleteAllPaymentsResponse) ProtoMessage() {} func (*DeleteAllPaymentsResponse) ProtoMessage() {}
func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{99} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{100}
} }
func (m *DeleteAllPaymentsResponse) XXX_Unmarshal(b []byte) error { func (m *DeleteAllPaymentsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DeleteAllPaymentsResponse.Unmarshal(m, b) return xxx_messageInfo_DeleteAllPaymentsResponse.Unmarshal(m, b)
@ -7051,7 +7137,7 @@ func (m *AbandonChannelRequest) Reset() { *m = AbandonChannelRequest{} }
func (m *AbandonChannelRequest) String() string { return proto.CompactTextString(m) } func (m *AbandonChannelRequest) String() string { return proto.CompactTextString(m) }
func (*AbandonChannelRequest) ProtoMessage() {} func (*AbandonChannelRequest) ProtoMessage() {}
func (*AbandonChannelRequest) Descriptor() ([]byte, []int) { func (*AbandonChannelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{100} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{101}
} }
func (m *AbandonChannelRequest) XXX_Unmarshal(b []byte) error { func (m *AbandonChannelRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AbandonChannelRequest.Unmarshal(m, b) return xxx_messageInfo_AbandonChannelRequest.Unmarshal(m, b)
@ -7088,7 +7174,7 @@ func (m *AbandonChannelResponse) Reset() { *m = AbandonChannelResponse{}
func (m *AbandonChannelResponse) String() string { return proto.CompactTextString(m) } func (m *AbandonChannelResponse) String() string { return proto.CompactTextString(m) }
func (*AbandonChannelResponse) ProtoMessage() {} func (*AbandonChannelResponse) ProtoMessage() {}
func (*AbandonChannelResponse) Descriptor() ([]byte, []int) { func (*AbandonChannelResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{101} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{102}
} }
func (m *AbandonChannelResponse) XXX_Unmarshal(b []byte) error { func (m *AbandonChannelResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AbandonChannelResponse.Unmarshal(m, b) return xxx_messageInfo_AbandonChannelResponse.Unmarshal(m, b)
@ -7120,7 +7206,7 @@ func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} }
func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) } func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) }
func (*DebugLevelRequest) ProtoMessage() {} func (*DebugLevelRequest) ProtoMessage() {}
func (*DebugLevelRequest) Descriptor() ([]byte, []int) { func (*DebugLevelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{102} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{103}
} }
func (m *DebugLevelRequest) XXX_Unmarshal(b []byte) error { func (m *DebugLevelRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DebugLevelRequest.Unmarshal(m, b) return xxx_messageInfo_DebugLevelRequest.Unmarshal(m, b)
@ -7165,7 +7251,7 @@ func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} }
func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) } func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) }
func (*DebugLevelResponse) ProtoMessage() {} func (*DebugLevelResponse) ProtoMessage() {}
func (*DebugLevelResponse) Descriptor() ([]byte, []int) { func (*DebugLevelResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{103} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{104}
} }
func (m *DebugLevelResponse) XXX_Unmarshal(b []byte) error { func (m *DebugLevelResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DebugLevelResponse.Unmarshal(m, b) return xxx_messageInfo_DebugLevelResponse.Unmarshal(m, b)
@ -7204,7 +7290,7 @@ func (m *PayReqString) Reset() { *m = PayReqString{} }
func (m *PayReqString) String() string { return proto.CompactTextString(m) } func (m *PayReqString) String() string { return proto.CompactTextString(m) }
func (*PayReqString) ProtoMessage() {} func (*PayReqString) ProtoMessage() {}
func (*PayReqString) Descriptor() ([]byte, []int) { func (*PayReqString) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{104} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{105}
} }
func (m *PayReqString) XXX_Unmarshal(b []byte) error { func (m *PayReqString) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PayReqString.Unmarshal(m, b) return xxx_messageInfo_PayReqString.Unmarshal(m, b)
@ -7251,7 +7337,7 @@ func (m *PayReq) Reset() { *m = PayReq{} }
func (m *PayReq) String() string { return proto.CompactTextString(m) } func (m *PayReq) String() string { return proto.CompactTextString(m) }
func (*PayReq) ProtoMessage() {} func (*PayReq) ProtoMessage() {}
func (*PayReq) Descriptor() ([]byte, []int) { func (*PayReq) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{105} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{106}
} }
func (m *PayReq) XXX_Unmarshal(b []byte) error { func (m *PayReq) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PayReq.Unmarshal(m, b) return xxx_messageInfo_PayReq.Unmarshal(m, b)
@ -7351,7 +7437,7 @@ func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} }
func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) } func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) }
func (*FeeReportRequest) ProtoMessage() {} func (*FeeReportRequest) ProtoMessage() {}
func (*FeeReportRequest) Descriptor() ([]byte, []int) { func (*FeeReportRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{106} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{107}
} }
func (m *FeeReportRequest) XXX_Unmarshal(b []byte) error { func (m *FeeReportRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FeeReportRequest.Unmarshal(m, b) return xxx_messageInfo_FeeReportRequest.Unmarshal(m, b)
@ -7389,7 +7475,7 @@ func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} }
func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) } func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) }
func (*ChannelFeeReport) ProtoMessage() {} func (*ChannelFeeReport) ProtoMessage() {}
func (*ChannelFeeReport) Descriptor() ([]byte, []int) { func (*ChannelFeeReport) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{107} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{108}
} }
func (m *ChannelFeeReport) XXX_Unmarshal(b []byte) error { func (m *ChannelFeeReport) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ChannelFeeReport.Unmarshal(m, b) return xxx_messageInfo_ChannelFeeReport.Unmarshal(m, b)
@ -7455,7 +7541,7 @@ func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} }
func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) } func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) }
func (*FeeReportResponse) ProtoMessage() {} func (*FeeReportResponse) ProtoMessage() {}
func (*FeeReportResponse) Descriptor() ([]byte, []int) { func (*FeeReportResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{108} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{109}
} }
func (m *FeeReportResponse) XXX_Unmarshal(b []byte) error { func (m *FeeReportResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FeeReportResponse.Unmarshal(m, b) return xxx_messageInfo_FeeReportResponse.Unmarshal(m, b)
@ -7523,7 +7609,7 @@ func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} }
func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) } func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) }
func (*PolicyUpdateRequest) ProtoMessage() {} func (*PolicyUpdateRequest) ProtoMessage() {}
func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{109} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{110}
} }
func (m *PolicyUpdateRequest) XXX_Unmarshal(b []byte) error { func (m *PolicyUpdateRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PolicyUpdateRequest.Unmarshal(m, b) return xxx_messageInfo_PolicyUpdateRequest.Unmarshal(m, b)
@ -7684,7 +7770,7 @@ func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} }
func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) } func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) }
func (*PolicyUpdateResponse) ProtoMessage() {} func (*PolicyUpdateResponse) ProtoMessage() {}
func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{110} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{111}
} }
func (m *PolicyUpdateResponse) XXX_Unmarshal(b []byte) error { func (m *PolicyUpdateResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PolicyUpdateResponse.Unmarshal(m, b) return xxx_messageInfo_PolicyUpdateResponse.Unmarshal(m, b)
@ -7722,7 +7808,7 @@ func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryReque
func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) } func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) }
func (*ForwardingHistoryRequest) ProtoMessage() {} func (*ForwardingHistoryRequest) ProtoMessage() {}
func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{111} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{112}
} }
func (m *ForwardingHistoryRequest) XXX_Unmarshal(b []byte) error { func (m *ForwardingHistoryRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ForwardingHistoryRequest.Unmarshal(m, b) return xxx_messageInfo_ForwardingHistoryRequest.Unmarshal(m, b)
@ -7794,7 +7880,7 @@ func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} }
func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) } func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) }
func (*ForwardingEvent) ProtoMessage() {} func (*ForwardingEvent) ProtoMessage() {}
func (*ForwardingEvent) Descriptor() ([]byte, []int) { func (*ForwardingEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{112} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{113}
} }
func (m *ForwardingEvent) XXX_Unmarshal(b []byte) error { func (m *ForwardingEvent) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ForwardingEvent.Unmarshal(m, b) return xxx_messageInfo_ForwardingEvent.Unmarshal(m, b)
@ -7877,7 +7963,7 @@ func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResp
func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) } func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) }
func (*ForwardingHistoryResponse) ProtoMessage() {} func (*ForwardingHistoryResponse) ProtoMessage() {}
func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_rpc_61aed0266ec39391, []int{113} return fileDescriptor_rpc_3ef4d8a7aac1a994, []int{114}
} }
func (m *ForwardingHistoryResponse) XXX_Unmarshal(b []byte) error { func (m *ForwardingHistoryResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ForwardingHistoryResponse.Unmarshal(m, b) return xxx_messageInfo_ForwardingHistoryResponse.Unmarshal(m, b)
@ -7984,6 +8070,7 @@ func init() {
proto.RegisterType((*ChannelBalanceRequest)(nil), "lnrpc.ChannelBalanceRequest") proto.RegisterType((*ChannelBalanceRequest)(nil), "lnrpc.ChannelBalanceRequest")
proto.RegisterType((*ChannelBalanceResponse)(nil), "lnrpc.ChannelBalanceResponse") proto.RegisterType((*ChannelBalanceResponse)(nil), "lnrpc.ChannelBalanceResponse")
proto.RegisterType((*QueryRoutesRequest)(nil), "lnrpc.QueryRoutesRequest") proto.RegisterType((*QueryRoutesRequest)(nil), "lnrpc.QueryRoutesRequest")
proto.RegisterType((*EdgeLocator)(nil), "lnrpc.EdgeLocator")
proto.RegisterType((*QueryRoutesResponse)(nil), "lnrpc.QueryRoutesResponse") proto.RegisterType((*QueryRoutesResponse)(nil), "lnrpc.QueryRoutesResponse")
proto.RegisterType((*Hop)(nil), "lnrpc.Hop") proto.RegisterType((*Hop)(nil), "lnrpc.Hop")
proto.RegisterType((*Route)(nil), "lnrpc.Route") proto.RegisterType((*Route)(nil), "lnrpc.Route")
@ -10377,448 +10464,455 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{
Metadata: "rpc.proto", Metadata: "rpc.proto",
} }
func init() { proto.RegisterFile("rpc.proto", fileDescriptor_rpc_61aed0266ec39391) } func init() { proto.RegisterFile("rpc.proto", fileDescriptor_rpc_3ef4d8a7aac1a994) }
var fileDescriptor_rpc_61aed0266ec39391 = []byte{ var fileDescriptor_rpc_3ef4d8a7aac1a994 = []byte{
// 7040 bytes of a gzipped FileDescriptorProto // 7142 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0x5f, 0x6c, 0x24, 0xd9, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0x5d, 0x6c, 0x24, 0xd9,
0x59, 0xef, 0x54, 0xff, 0xb1, 0xbb, 0xbf, 0x6e, 0xb7, 0xdb, 0xc7, 0x7f, 0xa6, 0xa7, 0x77, 0x76, 0x5d, 0xef, 0x54, 0x7f, 0xd8, 0xdd, 0xff, 0x6e, 0xb7, 0xdb, 0xc7, 0x5f, 0x3d, 0xbd, 0xb3, 0xb3,
0x76, 0xb6, 0x32, 0x77, 0xc7, 0x71, 0xf6, 0x8e, 0x67, 0x27, 0xc9, 0xde, 0xcd, 0xee, 0xcd, 0xbd, 0xde, 0xca, 0xdc, 0x1d, 0xc7, 0xd9, 0x3b, 0x9e, 0x9d, 0x24, 0x9b, 0xcd, 0xee, 0xcd, 0xbd, 0xd7,
0x78, 0x6c, 0xcf, 0x78, 0x12, 0xaf, 0xc7, 0x29, 0xcf, 0x64, 0xc8, 0x26, 0xa8, 0x53, 0xee, 0x3e, 0x63, 0x7b, 0xc6, 0x93, 0x78, 0x3d, 0x4e, 0x79, 0x26, 0x73, 0xb3, 0xc9, 0x55, 0xa7, 0xdc, 0x7d,
0x6e, 0xd7, 0x4e, 0x75, 0x55, 0xa7, 0xaa, 0xda, 0x9e, 0xce, 0x32, 0x12, 0x02, 0x44, 0x24, 0x04, 0xdc, 0xae, 0x9d, 0xea, 0xaa, 0x4e, 0x55, 0xb5, 0x3d, 0xce, 0x32, 0x12, 0x02, 0x44, 0x24, 0x04,
0x42, 0xc0, 0x0b, 0x41, 0x41, 0x48, 0x01, 0x09, 0xf2, 0xc8, 0x43, 0x22, 0x24, 0xe0, 0x0d, 0xf1, 0x42, 0xc0, 0x0b, 0x41, 0x41, 0x48, 0x01, 0x09, 0xf2, 0xc8, 0x43, 0x10, 0x12, 0x1f, 0x4f, 0x88,
0x80, 0x84, 0x10, 0xe4, 0x11, 0x09, 0x09, 0xc1, 0x0b, 0xf0, 0x80, 0x84, 0xc4, 0x23, 0x12, 0x3a, 0x07, 0x24, 0x84, 0x20, 0x8f, 0x48, 0x48, 0x08, 0x5e, 0x80, 0x07, 0x24, 0x24, 0x1e, 0x91, 0xd0,
0xdf, 0xf9, 0x53, 0xe7, 0x54, 0x55, 0x8f, 0x67, 0x93, 0xc0, 0x93, 0x7d, 0x7e, 0xe7, 0xab, 0xf3, 0xf9, 0x9f, 0x8f, 0x3a, 0xa7, 0xaa, 0x7a, 0x3c, 0x9b, 0x04, 0x9e, 0xec, 0xf3, 0x3b, 0xff, 0x3a,
0xf7, 0xfb, 0x77, 0xbe, 0xf3, 0x9d, 0x86, 0x7a, 0x34, 0xee, 0xdf, 0x1a, 0x47, 0x61, 0x12, 0x92, 0x9f, 0xff, 0xaf, 0xf3, 0x3f, 0xff, 0xd3, 0x50, 0x8f, 0xc6, 0xfd, 0x5b, 0xe3, 0x28, 0x4c, 0x42,
0xaa, 0x1f, 0x44, 0xe3, 0x7e, 0xf7, 0xea, 0x30, 0x0c, 0x87, 0x3e, 0xdd, 0x74, 0xc7, 0xde, 0xa6, 0x52, 0xf5, 0x83, 0x68, 0xdc, 0xef, 0x5e, 0x1b, 0x86, 0xe1, 0xd0, 0xa7, 0x9b, 0xee, 0xd8, 0xdb,
0x1b, 0x04, 0x61, 0xe2, 0x26, 0x5e, 0x18, 0xc4, 0x9c, 0xc8, 0xfe, 0x3a, 0xb4, 0xee, 0xd3, 0xe0, 0x74, 0x83, 0x20, 0x4c, 0xdc, 0xc4, 0x0b, 0x83, 0x98, 0x13, 0xd9, 0xdf, 0x80, 0xd6, 0x7d, 0x1a,
0x88, 0xd2, 0x81, 0x43, 0xbf, 0x31, 0xa1, 0x71, 0x42, 0x3e, 0x05, 0x4b, 0x2e, 0xfd, 0x26, 0xa5, 0x1c, 0x51, 0x3a, 0x70, 0xe8, 0x37, 0x27, 0x34, 0x4e, 0xc8, 0xa7, 0x60, 0xc1, 0xa5, 0xdf, 0xa2,
0x83, 0xde, 0xd8, 0x8d, 0xe3, 0xf1, 0x69, 0xe4, 0xc6, 0xb4, 0x63, 0x5d, 0xb7, 0xd6, 0x9b, 0x4e, 0x74, 0xd0, 0x1b, 0xbb, 0x71, 0x3c, 0x3e, 0x8d, 0xdc, 0x98, 0x76, 0xac, 0x35, 0x6b, 0xbd, 0xe9,
0x9b, 0x57, 0x1c, 0x2a, 0x9c, 0xbc, 0x0e, 0xcd, 0x98, 0x91, 0xd2, 0x20, 0x89, 0xc2, 0xf1, 0xb4, 0xb4, 0x79, 0xc5, 0xa1, 0xc2, 0xc9, 0xeb, 0xd0, 0x8c, 0x19, 0x29, 0x0d, 0x92, 0x28, 0x1c, 0x5f,
0x53, 0x42, 0xba, 0x06, 0xc3, 0x76, 0x39, 0x64, 0xfb, 0xb0, 0xa8, 0x7a, 0x88, 0xc7, 0x61, 0x10, 0x74, 0x4a, 0x48, 0xd7, 0x60, 0xd8, 0x2e, 0x87, 0x6c, 0x1f, 0xe6, 0x55, 0x0f, 0xf1, 0x38, 0x0c,
0x53, 0x72, 0x1b, 0x56, 0xfa, 0xde, 0xf8, 0x94, 0x46, 0x3d, 0xfc, 0x78, 0x14, 0xd0, 0x51, 0x18, 0x62, 0x4a, 0x6e, 0xc3, 0x52, 0xdf, 0x1b, 0x9f, 0xd2, 0xa8, 0x87, 0x1f, 0x8f, 0x02, 0x3a, 0x0a,
0x78, 0xfd, 0x8e, 0x75, 0xbd, 0xbc, 0x5e, 0x77, 0x08, 0xaf, 0x63, 0x5f, 0xbc, 0x2f, 0x6a, 0xc8, 0x03, 0xaf, 0xdf, 0xb1, 0xd6, 0xca, 0xeb, 0x75, 0x87, 0xf0, 0x3a, 0xf6, 0xc5, 0xfb, 0xa2, 0x86,
0x4d, 0x58, 0xa4, 0x01, 0xc7, 0xe9, 0x00, 0xbf, 0x12, 0x5d, 0xb5, 0x52, 0x98, 0x7d, 0x60, 0xff, 0xdc, 0x84, 0x79, 0x1a, 0x70, 0x9c, 0x0e, 0xf0, 0x2b, 0xd1, 0x55, 0x2b, 0x85, 0xd9, 0x07, 0xf6,
0xb9, 0x05, 0x4b, 0x0f, 0x02, 0x2f, 0x79, 0xe2, 0xfa, 0x3e, 0x4d, 0xe4, 0x9c, 0x6e, 0xc2, 0xe2, 0x9f, 0x59, 0xb0, 0xf0, 0x20, 0xf0, 0x92, 0x27, 0xae, 0xef, 0xd3, 0x44, 0xce, 0xe9, 0x26, 0xcc,
0x39, 0x02, 0x38, 0xa7, 0xf3, 0x30, 0x1a, 0x88, 0x19, 0xb5, 0x38, 0x7c, 0x28, 0xd0, 0x99, 0x23, 0x9f, 0x23, 0x80, 0x73, 0x3a, 0x0f, 0xa3, 0x81, 0x98, 0x51, 0x8b, 0xc3, 0x87, 0x02, 0x9d, 0x3a,
0x2b, 0xcd, 0x1c, 0x59, 0xe1, 0x72, 0x95, 0x67, 0x2c, 0xd7, 0x4d, 0x58, 0x8c, 0x68, 0x3f, 0x3c, 0xb2, 0xd2, 0xd4, 0x91, 0x15, 0x2e, 0x57, 0x79, 0xca, 0x72, 0xdd, 0x84, 0xf9, 0x88, 0xf6, 0xc3,
0xa3, 0xd1, 0xb4, 0x77, 0xee, 0x05, 0x83, 0xf0, 0xbc, 0x53, 0xb9, 0x6e, 0xad, 0x57, 0x9d, 0x96, 0x33, 0x1a, 0x5d, 0xf4, 0xce, 0xbd, 0x60, 0x10, 0x9e, 0x77, 0x2a, 0x6b, 0xd6, 0x7a, 0xd5, 0x69,
0x84, 0x9f, 0x20, 0x6a, 0xaf, 0x00, 0xd1, 0x67, 0xc1, 0xd7, 0xcd, 0x1e, 0xc2, 0xf2, 0xe3, 0xc0, 0x49, 0xf8, 0x09, 0xa2, 0xf6, 0x12, 0x10, 0x7d, 0x16, 0x7c, 0xdd, 0xec, 0x21, 0x2c, 0x3e, 0x0e,
0x0f, 0xfb, 0x4f, 0x7f, 0xc4, 0xd9, 0x15, 0x74, 0x5f, 0x2a, 0xec, 0x7e, 0x0d, 0x56, 0xcc, 0x8e, 0xfc, 0xb0, 0xff, 0xf4, 0x47, 0x9c, 0x5d, 0x41, 0xf7, 0xa5, 0xc2, 0xee, 0x57, 0x60, 0xc9, 0xec,
0xc4, 0x00, 0x28, 0xac, 0x6e, 0x9f, 0xba, 0xc1, 0x90, 0xca, 0x26, 0xe5, 0x10, 0x3e, 0x09, 0xed, 0x48, 0x0c, 0x80, 0xc2, 0xf2, 0xf6, 0xa9, 0x1b, 0x0c, 0xa9, 0x6c, 0x52, 0x0e, 0xe1, 0x93, 0xd0,
0xfe, 0x24, 0x8a, 0x68, 0x90, 0x1b, 0xc3, 0xa2, 0xc0, 0xd5, 0x20, 0x5e, 0x87, 0x66, 0x40, 0xcf, 0xee, 0x4f, 0xa2, 0x88, 0x06, 0xb9, 0x31, 0xcc, 0x0b, 0x5c, 0x0d, 0xe2, 0x75, 0x68, 0x06, 0xf4,
0x53, 0x32, 0xc1, 0x32, 0x01, 0x3d, 0x97, 0x24, 0x76, 0x07, 0xd6, 0xb2, 0xdd, 0x88, 0x01, 0xfc, 0x3c, 0x25, 0x13, 0x2c, 0x13, 0xd0, 0x73, 0x49, 0x62, 0x77, 0x60, 0x25, 0xdb, 0x8d, 0x18, 0xc0,
0x83, 0x05, 0x95, 0xc7, 0xc9, 0xb3, 0x90, 0xdc, 0x82, 0x4a, 0x32, 0x1d, 0x73, 0xc6, 0x6c, 0xdd, 0xdf, 0x5b, 0x50, 0x79, 0x9c, 0x3c, 0x0b, 0xc9, 0x2d, 0xa8, 0x24, 0x17, 0x63, 0xce, 0x98, 0xad,
0x21, 0xb7, 0x90, 0xd7, 0x6f, 0x6d, 0x0d, 0x06, 0x11, 0x8d, 0xe3, 0x47, 0xd3, 0x31, 0x75, 0x9a, 0x3b, 0xe4, 0x16, 0xf2, 0xfa, 0xad, 0xad, 0xc1, 0x20, 0xa2, 0x71, 0xfc, 0xe8, 0x62, 0x4c, 0x9d,
0x2e, 0x2f, 0xf4, 0x18, 0x1d, 0xe9, 0xc0, 0xbc, 0x28, 0x63, 0x87, 0x75, 0x47, 0x16, 0xc9, 0x35, 0xa6, 0xcb, 0x0b, 0x3d, 0x46, 0x47, 0x3a, 0x30, 0x2b, 0xca, 0xd8, 0x61, 0xdd, 0x91, 0x45, 0x72,
0x00, 0x77, 0x14, 0x4e, 0x82, 0xa4, 0x17, 0xbb, 0x09, 0xee, 0x5c, 0xd9, 0xd1, 0x10, 0x72, 0x15, 0x1d, 0xc0, 0x1d, 0x85, 0x93, 0x20, 0xe9, 0xc5, 0x6e, 0x82, 0x3b, 0x57, 0x76, 0x34, 0x84, 0x5c,
0xea, 0xe3, 0xa7, 0xbd, 0xb8, 0x1f, 0x79, 0xe3, 0x04, 0x77, 0xab, 0xee, 0xa4, 0x00, 0xf9, 0x14, 0x83, 0xfa, 0xf8, 0x69, 0x2f, 0xee, 0x47, 0xde, 0x38, 0xc1, 0xdd, 0xaa, 0x3b, 0x29, 0x40, 0x3e,
0xd4, 0xc2, 0x49, 0x32, 0x0e, 0xbd, 0x20, 0xe9, 0x54, 0xaf, 0x5b, 0xeb, 0x8d, 0x3b, 0x8b, 0x62, 0x05, 0xb5, 0x70, 0x92, 0x8c, 0x43, 0x2f, 0x48, 0x3a, 0xd5, 0x35, 0x6b, 0xbd, 0x71, 0x67, 0x5e,
0x2c, 0x0f, 0x27, 0xc9, 0x21, 0x83, 0x1d, 0x45, 0x40, 0x6e, 0xc0, 0x42, 0x3f, 0x0c, 0x4e, 0xbc, 0x8c, 0xe5, 0xe1, 0x24, 0x39, 0x64, 0xb0, 0xa3, 0x08, 0xc8, 0x0d, 0x98, 0xeb, 0x87, 0xc1, 0x89,
0x68, 0xc4, 0x65, 0xb0, 0x33, 0x87, 0xbd, 0x99, 0xa0, 0xfd, 0xed, 0x12, 0x34, 0x1e, 0x45, 0x6e, 0x17, 0x8d, 0xb8, 0x0c, 0x76, 0x66, 0xb0, 0x37, 0x13, 0xb4, 0xbf, 0x53, 0x82, 0xc6, 0xa3, 0xc8,
0x10, 0xbb, 0x7d, 0x06, 0xb0, 0xa1, 0x27, 0xcf, 0x7a, 0xa7, 0x6e, 0x7c, 0x8a, 0xb3, 0xad, 0x3b, 0x0d, 0x62, 0xb7, 0xcf, 0x00, 0x36, 0xf4, 0xe4, 0x59, 0xef, 0xd4, 0x8d, 0x4f, 0x71, 0xb6, 0x75,
0xb2, 0x48, 0xd6, 0x60, 0x8e, 0x0f, 0x14, 0xe7, 0x54, 0x76, 0x44, 0x89, 0xbc, 0x09, 0x4b, 0xc1, 0x47, 0x16, 0xc9, 0x0a, 0xcc, 0xf0, 0x81, 0xe2, 0x9c, 0xca, 0x8e, 0x28, 0x91, 0x37, 0x61, 0x21,
0x64, 0xd4, 0x33, 0xfb, 0x2a, 0xe3, 0x4e, 0xe7, 0x2b, 0xd8, 0x02, 0x1c, 0xb3, 0xbd, 0xe6, 0x5d, 0x98, 0x8c, 0x7a, 0x66, 0x5f, 0x65, 0xdc, 0xe9, 0x7c, 0x05, 0x5b, 0x80, 0x63, 0xb6, 0xd7, 0xbc,
0xf0, 0x19, 0x6a, 0x08, 0xb1, 0xa1, 0x29, 0x4a, 0xd4, 0x1b, 0x9e, 0xf2, 0x69, 0x56, 0x1d, 0x03, 0x0b, 0x3e, 0x43, 0x0d, 0x21, 0x36, 0x34, 0x45, 0x89, 0x7a, 0xc3, 0x53, 0x3e, 0xcd, 0xaa, 0x63,
0x63, 0x6d, 0x24, 0xde, 0x88, 0xf6, 0xe2, 0xc4, 0x1d, 0x8d, 0xc5, 0xb4, 0x34, 0x04, 0xeb, 0xc3, 0x60, 0xac, 0x8d, 0xc4, 0x1b, 0xd1, 0x5e, 0x9c, 0xb8, 0xa3, 0xb1, 0x98, 0x96, 0x86, 0x60, 0x7d,
0xc4, 0xf5, 0x7b, 0x27, 0x94, 0xc6, 0x9d, 0x79, 0x51, 0xaf, 0x10, 0xf2, 0x06, 0xb4, 0x06, 0x34, 0x98, 0xb8, 0x7e, 0xef, 0x84, 0xd2, 0xb8, 0x33, 0x2b, 0xea, 0x15, 0x42, 0xde, 0x80, 0xd6, 0x80,
0x4e, 0x7a, 0x62, 0x53, 0x68, 0xdc, 0xa9, 0xa1, 0xc4, 0x65, 0x50, 0xc6, 0x19, 0xf7, 0x69, 0xa2, 0xc6, 0x49, 0x4f, 0x6c, 0x0a, 0x8d, 0x3b, 0x35, 0x94, 0xb8, 0x0c, 0xca, 0x38, 0xe3, 0x3e, 0x4d,
0xad, 0x4e, 0x2c, 0x38, 0xd0, 0xde, 0x07, 0xa2, 0xc1, 0x3b, 0x34, 0x71, 0x3d, 0x3f, 0x26, 0x6f, 0xb4, 0xd5, 0x89, 0x05, 0x07, 0xda, 0xfb, 0x40, 0x34, 0x78, 0x87, 0x26, 0xae, 0xe7, 0xc7, 0xe4,
0x43, 0x33, 0xd1, 0x88, 0x51, 0xc3, 0x34, 0x14, 0xbb, 0x68, 0x1f, 0x38, 0x06, 0x9d, 0x7d, 0x1f, 0x6d, 0x68, 0x26, 0x1a, 0x31, 0x6a, 0x98, 0x86, 0x62, 0x17, 0xed, 0x03, 0xc7, 0xa0, 0xb3, 0xef,
0x6a, 0xf7, 0x28, 0xdd, 0xf7, 0x46, 0x5e, 0x42, 0xd6, 0xa0, 0x7a, 0xe2, 0x3d, 0xa3, 0x9c, 0xa1, 0x43, 0xed, 0x1e, 0xa5, 0xfb, 0xde, 0xc8, 0x4b, 0xc8, 0x0a, 0x54, 0x4f, 0xbc, 0x67, 0x94, 0x33,
0xcb, 0x7b, 0x97, 0x1c, 0x5e, 0x24, 0x5d, 0x98, 0x1f, 0xd3, 0xa8, 0x4f, 0xe5, 0xf2, 0xef, 0x5d, 0x74, 0x79, 0xef, 0x8a, 0xc3, 0x8b, 0xa4, 0x0b, 0xb3, 0x63, 0x1a, 0xf5, 0xa9, 0x5c, 0xfe, 0xbd,
0x72, 0x24, 0x70, 0x77, 0x1e, 0xaa, 0x3e, 0xfb, 0xd8, 0xfe, 0xdb, 0x12, 0x34, 0x8e, 0x68, 0xa0, 0x2b, 0x8e, 0x04, 0xee, 0xce, 0x42, 0xd5, 0x67, 0x1f, 0xdb, 0x7f, 0x53, 0x82, 0xc6, 0x11, 0x0d,
0x04, 0x85, 0x40, 0x85, 0x4d, 0x49, 0x08, 0x07, 0xfe, 0x4f, 0x5e, 0x83, 0x06, 0x4e, 0x33, 0x4e, 0x94, 0xa0, 0x10, 0xa8, 0xb0, 0x29, 0x09, 0xe1, 0xc0, 0xff, 0xc9, 0x6b, 0xd0, 0xc0, 0x69, 0xc6,
0x22, 0x2f, 0x18, 0x0a, 0xfe, 0x04, 0x06, 0x1d, 0x21, 0x42, 0xda, 0x50, 0x76, 0x47, 0x92, 0x37, 0x49, 0xe4, 0x05, 0x43, 0xc1, 0x9f, 0xc0, 0xa0, 0x23, 0x44, 0x48, 0x1b, 0xca, 0xee, 0x48, 0xf2,
0xd9, 0xbf, 0x4c, 0x88, 0xc6, 0xee, 0x74, 0xc4, 0xe4, 0x4d, 0xed, 0x5a, 0xd3, 0x69, 0x08, 0x6c, 0x26, 0xfb, 0x97, 0x09, 0xd1, 0xd8, 0xbd, 0x18, 0x31, 0x79, 0x53, 0xbb, 0xd6, 0x74, 0x1a, 0x02,
0x8f, 0x6d, 0xdb, 0x2d, 0x58, 0xd6, 0x49, 0x64, 0xeb, 0x55, 0x6c, 0x7d, 0x49, 0xa3, 0x14, 0x9d, 0xdb, 0x63, 0xdb, 0x76, 0x0b, 0x16, 0x75, 0x12, 0xd9, 0x7a, 0x15, 0x5b, 0x5f, 0xd0, 0x28, 0x45,
0xdc, 0x84, 0x45, 0x49, 0x1f, 0xf1, 0xc1, 0xe2, 0x3e, 0xd6, 0x9d, 0x96, 0x80, 0xe5, 0x14, 0xd6, 0x27, 0x37, 0x61, 0x5e, 0xd2, 0x47, 0x7c, 0xb0, 0xb8, 0x8f, 0x75, 0xa7, 0x25, 0x60, 0x39, 0x85,
0xa1, 0x7d, 0xe2, 0x05, 0xae, 0xdf, 0xeb, 0xfb, 0xc9, 0x59, 0x6f, 0x40, 0xfd, 0xc4, 0xc5, 0x1d, 0x75, 0x68, 0x9f, 0x78, 0x81, 0xeb, 0xf7, 0xfa, 0x7e, 0x72, 0xd6, 0x1b, 0x50, 0x3f, 0x71, 0x71,
0xad, 0x3a, 0x2d, 0xc4, 0xb7, 0xfd, 0xe4, 0x6c, 0x87, 0xa1, 0xe4, 0x4d, 0xa8, 0x9f, 0x50, 0xda, 0x47, 0xab, 0x4e, 0x0b, 0xf1, 0x6d, 0x3f, 0x39, 0xdb, 0x61, 0x28, 0x79, 0x13, 0xea, 0x27, 0x94,
0xc3, 0x95, 0xe8, 0xd4, 0x0c, 0xe9, 0x90, 0xab, 0xeb, 0xd4, 0x4e, 0xe4, 0x3a, 0xaf, 0x43, 0x3b, 0xf6, 0x70, 0x25, 0x3a, 0x35, 0x43, 0x3a, 0xe4, 0xea, 0x3a, 0xb5, 0x13, 0xb9, 0xce, 0xeb, 0xd0,
0x9c, 0x24, 0xc3, 0xd0, 0x0b, 0x86, 0xbd, 0xfe, 0xa9, 0x1b, 0xf4, 0xbc, 0x41, 0xa7, 0x7e, 0xdd, 0x0e, 0x27, 0xc9, 0x30, 0xf4, 0x82, 0x61, 0xaf, 0x7f, 0xea, 0x06, 0x3d, 0x6f, 0xd0, 0xa9, 0xaf,
0x5a, 0xaf, 0x38, 0x2d, 0x89, 0x33, 0xad, 0xf0, 0x60, 0x60, 0xff, 0xb1, 0x05, 0x4d, 0xbe, 0xa8, 0x59, 0xeb, 0x15, 0xa7, 0x25, 0x71, 0xa6, 0x15, 0x1e, 0x0c, 0xec, 0x3f, 0xb4, 0xa0, 0xc9, 0x17,
0xc2, 0xa0, 0xdc, 0x80, 0x05, 0x39, 0x76, 0x1a, 0x45, 0x61, 0x24, 0x04, 0xc5, 0x04, 0xc9, 0x06, 0x55, 0x18, 0x94, 0x1b, 0x30, 0x27, 0xc7, 0x4e, 0xa3, 0x28, 0x8c, 0x84, 0xa0, 0x98, 0x20, 0xd9,
0xb4, 0x25, 0x30, 0x8e, 0xa8, 0x37, 0x72, 0x87, 0x54, 0x68, 0x9f, 0x1c, 0x4e, 0xee, 0xa4, 0x2d, 0x80, 0xb6, 0x04, 0xc6, 0x11, 0xf5, 0x46, 0xee, 0x90, 0x0a, 0xed, 0x93, 0xc3, 0xc9, 0x9d, 0xb4,
0x46, 0xe1, 0x24, 0xe1, 0x2a, 0xbd, 0x71, 0xa7, 0x29, 0x86, 0xef, 0x30, 0xcc, 0x31, 0x49, 0x98, 0xc5, 0x28, 0x9c, 0x24, 0x5c, 0xa5, 0x37, 0xee, 0x34, 0xc5, 0xf0, 0x1d, 0x86, 0x39, 0x26, 0x09,
0xa0, 0x14, 0x6c, 0x8a, 0x81, 0xd9, 0xdf, 0xb7, 0x80, 0xb0, 0xa1, 0x3f, 0x0a, 0x79, 0x13, 0x62, 0x13, 0x94, 0x82, 0x4d, 0x31, 0x30, 0xfb, 0x07, 0x16, 0x10, 0x36, 0xf4, 0x47, 0x21, 0x6f, 0x42,
0x4d, 0xb3, 0xfb, 0x69, 0xbd, 0xf4, 0x7e, 0x96, 0x66, 0xed, 0xe7, 0x3a, 0xcc, 0xe1, 0xb0, 0x98, 0xac, 0x69, 0x76, 0x3f, 0xad, 0x97, 0xde, 0xcf, 0xd2, 0xb4, 0xfd, 0x5c, 0x87, 0x19, 0x1c, 0x16,
0xe4, 0x97, 0xb3, 0x43, 0xbf, 0x5b, 0xea, 0x58, 0x8e, 0xa8, 0x27, 0x36, 0x54, 0xf9, 0x1c, 0x2b, 0x93, 0xfc, 0x72, 0x76, 0xe8, 0x77, 0x4b, 0x1d, 0xcb, 0x11, 0xf5, 0xc4, 0x86, 0x2a, 0x9f, 0x63,
0x05, 0x73, 0xe4, 0x55, 0xf6, 0x77, 0x2d, 0x68, 0xb2, 0xd5, 0x0f, 0xa8, 0x8f, 0x5a, 0x8d, 0xdc, 0xa5, 0x60, 0x8e, 0xbc, 0xca, 0xfe, 0x9e, 0x05, 0x4d, 0xb6, 0xfa, 0x01, 0xf5, 0x51, 0xab, 0x91,
0x06, 0x72, 0x32, 0x09, 0x06, 0x6c, 0xb3, 0x92, 0x67, 0xde, 0xa0, 0x77, 0x3c, 0x65, 0x5d, 0xe1, 0xdb, 0x40, 0x4e, 0x26, 0xc1, 0x80, 0x6d, 0x56, 0xf2, 0xcc, 0x1b, 0xf4, 0x8e, 0x2f, 0x58, 0x57,
0xb8, 0xf7, 0x2e, 0x39, 0x05, 0x75, 0xe4, 0x4d, 0x68, 0x1b, 0x68, 0x9c, 0x44, 0x7c, 0xf4, 0x7b, 0x38, 0xee, 0xbd, 0x2b, 0x4e, 0x41, 0x1d, 0x79, 0x13, 0xda, 0x06, 0x1a, 0x27, 0x11, 0x1f, 0xfd,
0x97, 0x9c, 0x5c, 0x0d, 0x5b, 0x4c, 0xa6, 0x37, 0x27, 0x49, 0xcf, 0x0b, 0x06, 0xf4, 0x19, 0xae, 0xde, 0x15, 0x27, 0x57, 0xc3, 0x16, 0x93, 0xe9, 0xcd, 0x49, 0xd2, 0xf3, 0x82, 0x01, 0x7d, 0x86,
0xff, 0x82, 0x63, 0x60, 0x77, 0x5b, 0xd0, 0xd4, 0xbf, 0xb3, 0x3f, 0x84, 0x9a, 0xd4, 0xba, 0xa8, 0xeb, 0x3f, 0xe7, 0x18, 0xd8, 0xdd, 0x16, 0x34, 0xf5, 0xef, 0xec, 0x0f, 0xa1, 0x26, 0xb5, 0x2e,
0x71, 0x32, 0xe3, 0x72, 0x34, 0x84, 0x74, 0xa1, 0x66, 0x8e, 0xc2, 0xa9, 0x7d, 0x9c, 0xbe, 0xed, 0x6a, 0x9c, 0xcc, 0xb8, 0x1c, 0x0d, 0x21, 0x5d, 0xa8, 0x99, 0xa3, 0x70, 0x6a, 0x1f, 0xa7, 0x6f,
0xff, 0x07, 0xed, 0x7d, 0xa6, 0xfa, 0x02, 0x2f, 0x18, 0x0a, 0xb3, 0xc3, 0xf4, 0xf1, 0x78, 0x72, 0xfb, 0x7f, 0x43, 0x7b, 0x9f, 0xa9, 0xbe, 0xc0, 0x0b, 0x86, 0xc2, 0xec, 0x30, 0x7d, 0x3c, 0x9e,
0xfc, 0x94, 0x4e, 0x05, 0xff, 0x89, 0x12, 0x13, 0xfa, 0xd3, 0x30, 0x4e, 0x44, 0x3f, 0xf8, 0xbf, 0x1c, 0x3f, 0xa5, 0x17, 0x82, 0xff, 0x44, 0x89, 0x09, 0xfd, 0x69, 0x18, 0x27, 0xa2, 0x1f, 0xfc,
0xfd, 0x8f, 0x16, 0x2c, 0x32, 0x46, 0x78, 0xdf, 0x0d, 0xa6, 0x92, 0x0b, 0xf6, 0xa1, 0xc9, 0x9a, 0xdf, 0xfe, 0x07, 0x0b, 0xe6, 0x19, 0x23, 0xbc, 0xef, 0x06, 0x17, 0x92, 0x0b, 0xf6, 0xa1, 0xc9,
0x7a, 0x14, 0x6e, 0x71, 0xad, 0xce, 0xb5, 0xd5, 0xba, 0xd8, 0x8f, 0x0c, 0xf5, 0x2d, 0x9d, 0x94, 0x9a, 0x7a, 0x14, 0x6e, 0x71, 0xad, 0xce, 0xb5, 0xd5, 0xba, 0xd8, 0x8f, 0x0c, 0xf5, 0x2d, 0x9d,
0x39, 0x5b, 0x53, 0xc7, 0xf8, 0x9a, 0xa9, 0x95, 0xc4, 0x8d, 0x86, 0x34, 0x41, 0x7d, 0x2f, 0xf4, 0x94, 0x39, 0x5b, 0x17, 0x8e, 0xf1, 0x35, 0x53, 0x2b, 0x89, 0x1b, 0x0d, 0x69, 0x82, 0xfa, 0x5e,
0x3f, 0x70, 0x68, 0x3b, 0x0c, 0x4e, 0xc8, 0x75, 0x68, 0xc6, 0x6e, 0xd2, 0x1b, 0xd3, 0x08, 0xd7, 0xe8, 0x7f, 0xe0, 0xd0, 0x76, 0x18, 0x9c, 0x90, 0x35, 0x68, 0xc6, 0x6e, 0xd2, 0x1b, 0xd3, 0x08,
0x04, 0x55, 0x43, 0xd9, 0x81, 0xd8, 0x4d, 0x0e, 0x69, 0x74, 0x77, 0x9a, 0xd0, 0xee, 0xff, 0x87, 0xd7, 0x04, 0x55, 0x43, 0xd9, 0x81, 0xd8, 0x4d, 0x0e, 0x69, 0x74, 0xf7, 0x22, 0xa1, 0xdd, 0xff,
0xa5, 0x5c, 0x2f, 0x4c, 0x1b, 0xa5, 0x53, 0x64, 0xff, 0x92, 0x15, 0xa8, 0x9e, 0xb9, 0xfe, 0x84, 0x03, 0x0b, 0xb9, 0x5e, 0x98, 0x36, 0x4a, 0xa7, 0xc8, 0xfe, 0x25, 0x4b, 0x50, 0x3d, 0x73, 0xfd,
0x0a, 0x33, 0xc4, 0x0b, 0xef, 0x96, 0xde, 0xb1, 0xec, 0x37, 0xa0, 0x9d, 0x0e, 0x5b, 0x08, 0x2b, 0x09, 0x15, 0x66, 0x88, 0x17, 0xde, 0x2d, 0xbd, 0x63, 0xd9, 0x6f, 0x40, 0x3b, 0x1d, 0xb6, 0x10,
0x81, 0x0a, 0x5b, 0x69, 0xd1, 0x00, 0xfe, 0x6f, 0x7f, 0xc7, 0xe2, 0x84, 0xdb, 0xa1, 0xa7, 0x54, 0x56, 0x02, 0x15, 0xb6, 0xd2, 0xa2, 0x01, 0xfc, 0xdf, 0xfe, 0xae, 0xc5, 0x09, 0xb7, 0x43, 0x4f,
0x3a, 0x23, 0x64, 0x9a, 0x5f, 0x12, 0xb2, 0xff, 0x67, 0x9a, 0xbc, 0x1f, 0x7f, 0xb2, 0xe4, 0x0a, 0xa9, 0x74, 0x46, 0xc8, 0x34, 0xbf, 0x24, 0x64, 0xff, 0x4f, 0x35, 0x79, 0x3f, 0xfe, 0x64, 0xc9,
0xd4, 0x62, 0x1a, 0x0c, 0x7a, 0xae, 0xef, 0xa3, 0xe6, 0xab, 0x39, 0xf3, 0xac, 0xbc, 0xe5, 0xfb, 0x55, 0xa8, 0xc5, 0x34, 0x18, 0xf4, 0x5c, 0xdf, 0x47, 0xcd, 0x57, 0x73, 0x66, 0x59, 0x79, 0xcb,
0xf6, 0x4d, 0x58, 0xd2, 0x46, 0xf7, 0x82, 0x79, 0x1c, 0x00, 0xd9, 0xf7, 0xe2, 0xe4, 0x71, 0x10, 0xf7, 0xed, 0x9b, 0xb0, 0xa0, 0x8d, 0xee, 0x05, 0xf3, 0x38, 0x00, 0xb2, 0xef, 0xc5, 0xc9, 0xe3,
0x8f, 0x35, 0x8d, 0xf9, 0x0a, 0xd4, 0x47, 0x5e, 0x80, 0x23, 0xe3, 0xac, 0x58, 0x75, 0x6a, 0x23, 0x20, 0x1e, 0x6b, 0x1a, 0xf3, 0x15, 0xa8, 0x8f, 0xbc, 0x00, 0x47, 0xc6, 0x59, 0xb1, 0xea, 0xd4,
0x2f, 0x60, 0xe3, 0x8a, 0xb1, 0xd2, 0x7d, 0x26, 0x2a, 0x4b, 0xa2, 0xd2, 0x7d, 0x86, 0x95, 0xf6, 0x46, 0x5e, 0xc0, 0xc6, 0x15, 0x63, 0xa5, 0xfb, 0x4c, 0x54, 0x96, 0x44, 0xa5, 0xfb, 0x0c, 0x2b,
0x3b, 0xb0, 0x6c, 0xb4, 0x27, 0xba, 0x7e, 0x1d, 0xaa, 0x93, 0xe4, 0x59, 0x28, 0xed, 0x59, 0x43, 0xed, 0x77, 0x60, 0xd1, 0x68, 0x4f, 0x74, 0xfd, 0x3a, 0x54, 0x27, 0xc9, 0xb3, 0x50, 0xda, 0xb3,
0x70, 0x08, 0xf3, 0x8c, 0x1c, 0x5e, 0x63, 0xbf, 0x07, 0x4b, 0x07, 0xf4, 0x5c, 0x70, 0xa6, 0x1c, 0x86, 0xe0, 0x10, 0xe6, 0x19, 0x39, 0xbc, 0xc6, 0x7e, 0x0f, 0x16, 0x0e, 0xe8, 0xb9, 0xe0, 0x4c,
0xc8, 0x1b, 0x17, 0x7a, 0x4d, 0x58, 0x6f, 0xdf, 0x02, 0xa2, 0x7f, 0x2c, 0x7a, 0xd5, 0x7c, 0x28, 0x39, 0x90, 0x37, 0x2e, 0xf5, 0x9a, 0xb0, 0xde, 0xbe, 0x05, 0x44, 0xff, 0x58, 0xf4, 0xaa, 0xf9,
0xcb, 0xf0, 0xa1, 0xec, 0x37, 0x80, 0x1c, 0x79, 0xc3, 0xe0, 0x7d, 0x1a, 0xc7, 0xee, 0x50, 0x29, 0x50, 0x96, 0xe1, 0x43, 0xd9, 0x6f, 0x00, 0x39, 0xf2, 0x86, 0xc1, 0xfb, 0x34, 0x8e, 0xdd, 0xa1,
0xb5, 0x36, 0x94, 0x47, 0xf1, 0x50, 0xc8, 0x1e, 0xfb, 0xd7, 0xfe, 0x34, 0x2c, 0x1b, 0x74, 0xa2, 0x52, 0x6a, 0x6d, 0x28, 0x8f, 0xe2, 0xa1, 0x90, 0x3d, 0xf6, 0xaf, 0xfd, 0x69, 0x58, 0x34, 0xe8,
0xe1, 0xab, 0x50, 0x8f, 0xbd, 0x61, 0xe0, 0x26, 0x93, 0x88, 0x8a, 0xa6, 0x53, 0xc0, 0xbe, 0x07, 0x44, 0xc3, 0xd7, 0xa0, 0x1e, 0x7b, 0xc3, 0xc0, 0x4d, 0x26, 0x11, 0x15, 0x4d, 0xa7, 0x80, 0x7d,
0x2b, 0x5f, 0xa6, 0x91, 0x77, 0x32, 0xbd, 0xa8, 0x79, 0xb3, 0x9d, 0x52, 0xb6, 0x9d, 0x5d, 0x58, 0x0f, 0x96, 0xbe, 0x42, 0x23, 0xef, 0xe4, 0xe2, 0xb2, 0xe6, 0xcd, 0x76, 0x4a, 0xd9, 0x76, 0x76,
0xcd, 0xb4, 0x23, 0xba, 0xe7, 0xec, 0x2b, 0x76, 0xb2, 0xe6, 0xf0, 0x82, 0x26, 0xcc, 0x25, 0x5d, 0x61, 0x39, 0xd3, 0x8e, 0xe8, 0x9e, 0xb3, 0xaf, 0xd8, 0xc9, 0x9a, 0xc3, 0x0b, 0x9a, 0x30, 0x97,
0x98, 0xed, 0xc7, 0x40, 0xb6, 0xc3, 0x20, 0xa0, 0xfd, 0xe4, 0x90, 0xd2, 0x28, 0x3d, 0x35, 0xa5, 0x74, 0x61, 0xb6, 0x1f, 0x03, 0xd9, 0x0e, 0x83, 0x80, 0xf6, 0x93, 0x43, 0x4a, 0xa3, 0xf4, 0xd4,
0xbc, 0xda, 0xb8, 0x73, 0x59, 0xac, 0x6c, 0x56, 0x43, 0x08, 0x26, 0x26, 0x50, 0x19, 0xd3, 0x68, 0x94, 0xf2, 0x6a, 0xe3, 0xce, 0xaa, 0x58, 0xd9, 0xac, 0x86, 0x10, 0x4c, 0x4c, 0xa0, 0x32, 0xa6,
0x84, 0x0d, 0xd7, 0x1c, 0xfc, 0xdf, 0x5e, 0x85, 0x65, 0xa3, 0x59, 0xe1, 0xf0, 0xbe, 0x05, 0xab, 0xd1, 0x08, 0x1b, 0xae, 0x39, 0xf8, 0xbf, 0xbd, 0x0c, 0x8b, 0x46, 0xb3, 0xc2, 0xe1, 0x7d, 0x0b,
0x3b, 0x5e, 0xdc, 0xcf, 0x77, 0xd8, 0x81, 0xf9, 0xf1, 0xe4, 0xb8, 0x97, 0x4a, 0xa2, 0x2c, 0x32, 0x96, 0x77, 0xbc, 0xb8, 0x9f, 0xef, 0xb0, 0x03, 0xb3, 0xe3, 0xc9, 0x71, 0x2f, 0x95, 0x44, 0x59,
0x1f, 0x29, 0xfb, 0x89, 0x68, 0xec, 0x97, 0x2c, 0xa8, 0xec, 0x3d, 0xda, 0xdf, 0x66, 0xca, 0xcf, 0x64, 0x3e, 0x52, 0xf6, 0x13, 0xd1, 0xd8, 0xcf, 0x5b, 0x50, 0xd9, 0x7b, 0xb4, 0xbf, 0xcd, 0x94,
0x0b, 0xfa, 0xe1, 0x88, 0x19, 0x10, 0x3e, 0x69, 0x55, 0x9e, 0x29, 0x61, 0x57, 0xa1, 0x8e, 0x76, 0x9f, 0x17, 0xf4, 0xc3, 0x11, 0x33, 0x20, 0x7c, 0xd2, 0xaa, 0x3c, 0x55, 0xc2, 0xae, 0x41, 0x1d,
0x87, 0xb9, 0x7d, 0xe2, 0x80, 0x93, 0x02, 0xcc, 0xe5, 0xa4, 0xcf, 0xc6, 0x5e, 0x84, 0x3e, 0xa5, 0xed, 0x0e, 0x73, 0xfb, 0xc4, 0x01, 0x27, 0x05, 0x98, 0xcb, 0x49, 0x9f, 0x8d, 0xbd, 0x08, 0x7d,
0xf4, 0x14, 0x2b, 0xa8, 0x37, 0xf3, 0x15, 0xf6, 0x77, 0xaa, 0x30, 0x2f, 0xac, 0x09, 0xf6, 0xd7, 0x4a, 0xe9, 0x29, 0x56, 0x50, 0x6f, 0xe6, 0x2b, 0xec, 0xef, 0x56, 0x61, 0x56, 0x58, 0x13, 0xec,
0x4f, 0xbc, 0x33, 0x2a, 0x46, 0x22, 0x4a, 0xcc, 0xa6, 0x47, 0x74, 0x14, 0x26, 0xb4, 0x67, 0x6c, 0xaf, 0x9f, 0x78, 0x67, 0x54, 0x8c, 0x44, 0x94, 0x98, 0x4d, 0x8f, 0xe8, 0x28, 0x4c, 0x68, 0xcf,
0x83, 0x09, 0xa2, 0x4b, 0xcd, 0x1b, 0xea, 0x71, 0x27, 0xbc, 0xcc, 0xa9, 0x0c, 0x90, 0x2d, 0x96, 0xd8, 0x06, 0x13, 0x44, 0x97, 0x9a, 0x37, 0xd4, 0xe3, 0x4e, 0x78, 0x99, 0x53, 0x19, 0x20, 0x5b,
0xf4, 0x28, 0x2a, 0xe8, 0x51, 0xc8, 0x22, 0x5b, 0x89, 0xbe, 0x3b, 0x76, 0xfb, 0x5e, 0x32, 0x15, 0x2c, 0xe9, 0x51, 0x54, 0xd0, 0xa3, 0x90, 0x45, 0xb6, 0x12, 0x7d, 0x77, 0xec, 0xf6, 0xbd, 0xe4,
0x2a, 0x41, 0x95, 0x59, 0xdb, 0x7e, 0xd8, 0x77, 0xfd, 0xde, 0xb1, 0xeb, 0xbb, 0x41, 0x9f, 0x4a, 0x42, 0xa8, 0x04, 0x55, 0x66, 0x6d, 0xfb, 0x61, 0xdf, 0xf5, 0x7b, 0xc7, 0xae, 0xef, 0x06, 0x7d,
0x77, 0xdd, 0x00, 0x99, 0xeb, 0x2a, 0x86, 0x24, 0xc9, 0xb8, 0x7b, 0x9b, 0x41, 0x99, 0x41, 0xea, 0x2a, 0xdd, 0x75, 0x03, 0x64, 0xae, 0xab, 0x18, 0x92, 0x24, 0xe3, 0xee, 0x6d, 0x06, 0x65, 0x06,
0x87, 0xa3, 0x91, 0x97, 0x30, 0x8f, 0x17, 0xbd, 0xa1, 0xb2, 0xa3, 0x21, 0xfc, 0x70, 0x80, 0xa5, 0xa9, 0x1f, 0x8e, 0x46, 0x5e, 0xc2, 0x3c, 0x5e, 0xf4, 0x86, 0xca, 0x8e, 0x86, 0xf0, 0xc3, 0x01,
0x73, 0xbe, 0x7a, 0x75, 0x79, 0x38, 0xd0, 0x40, 0xd6, 0x0a, 0x73, 0xa9, 0x98, 0x1a, 0x7b, 0x7a, 0x96, 0xce, 0xf9, 0xea, 0xd5, 0xe5, 0xe1, 0x40, 0x03, 0x59, 0x2b, 0xcc, 0xa5, 0x62, 0x6a, 0xec,
0xde, 0x01, 0xde, 0x4a, 0x8a, 0xb0, 0x7d, 0x98, 0x04, 0x31, 0x4d, 0x12, 0x9f, 0x0e, 0xd4, 0x80, 0xe9, 0x79, 0x07, 0x78, 0x2b, 0x29, 0xc2, 0xf6, 0x61, 0x12, 0xc4, 0x34, 0x49, 0x7c, 0x3a, 0x50,
0x1a, 0x48, 0x96, 0xaf, 0x20, 0xb7, 0x61, 0x99, 0x3b, 0xe1, 0xb1, 0x9b, 0x84, 0xf1, 0xa9, 0x17, 0x03, 0x6a, 0x20, 0x59, 0xbe, 0x82, 0xdc, 0x86, 0x45, 0xee, 0x84, 0xc7, 0x6e, 0x12, 0xc6, 0xa7,
0xf7, 0x62, 0xe6, 0xce, 0x36, 0x91, 0xbe, 0xa8, 0x8a, 0xbc, 0x03, 0x97, 0x33, 0x70, 0x44, 0xfb, 0x5e, 0xdc, 0x8b, 0x99, 0x3b, 0xdb, 0x44, 0xfa, 0xa2, 0x2a, 0xf2, 0x0e, 0xac, 0x66, 0xe0, 0x88,
0xd4, 0x3b, 0xa3, 0x83, 0xce, 0x02, 0x7e, 0x35, 0xab, 0x9a, 0x5c, 0x87, 0x06, 0x3b, 0x7b, 0x4c, 0xf6, 0xa9, 0x77, 0x46, 0x07, 0x9d, 0x39, 0xfc, 0x6a, 0x5a, 0x35, 0x59, 0x83, 0x06, 0x3b, 0x7b,
0xc6, 0x03, 0x97, 0x59, 0xe4, 0x16, 0xee, 0x83, 0x0e, 0x91, 0xb7, 0x60, 0x61, 0x4c, 0xb9, 0x39, 0x4c, 0xc6, 0x03, 0x97, 0x59, 0xe4, 0x16, 0xee, 0x83, 0x0e, 0x91, 0xb7, 0x60, 0x6e, 0x4c, 0xb9,
0x3f, 0x4d, 0xfc, 0x7e, 0xdc, 0x59, 0x34, 0xb4, 0x1b, 0xe3, 0x5c, 0xc7, 0xa4, 0x60, 0x4c, 0xd9, 0x39, 0x3f, 0x4d, 0xfc, 0x7e, 0xdc, 0x99, 0x37, 0xb4, 0x1b, 0xe3, 0x5c, 0xc7, 0xa4, 0x60, 0x4c,
0x8f, 0xd1, 0x09, 0x75, 0xa7, 0x9d, 0x36, 0xb2, 0x5b, 0x0a, 0xa0, 0x8c, 0x44, 0xde, 0x99, 0x9b, 0xd9, 0x8f, 0xd1, 0x09, 0x75, 0x2f, 0x3a, 0x6d, 0x64, 0xb7, 0x14, 0x40, 0x19, 0x89, 0xbc, 0x33,
0xd0, 0xce, 0x12, 0x57, 0xe8, 0xa2, 0xc8, 0xbe, 0xf3, 0x02, 0x2f, 0xf1, 0xdc, 0x24, 0x8c, 0x3a, 0x37, 0xa1, 0x9d, 0x05, 0xae, 0xd0, 0x45, 0x91, 0x7d, 0xe7, 0x05, 0x5e, 0xe2, 0xb9, 0x49, 0x18,
0x04, 0xeb, 0x52, 0xc0, 0xfe, 0x5d, 0x8b, 0xab, 0x5d, 0xc1, 0xa2, 0x4a, 0x7d, 0xbe, 0x06, 0x0d, 0x75, 0x08, 0xd6, 0xa5, 0x80, 0xfd, 0x5b, 0x16, 0x57, 0xbb, 0x82, 0x45, 0x95, 0xfa, 0x7c, 0x0d,
0xce, 0x9c, 0xbd, 0x30, 0xf0, 0xa7, 0x82, 0x5f, 0x81, 0x43, 0x0f, 0x03, 0x7f, 0x4a, 0x3e, 0x01, 0x1a, 0x9c, 0x39, 0x7b, 0x61, 0xe0, 0x5f, 0x08, 0x7e, 0x05, 0x0e, 0x3d, 0x0c, 0xfc, 0x0b, 0xf2,
0x0b, 0x5e, 0xa0, 0x93, 0x70, 0x09, 0x6f, 0x4a, 0x10, 0x89, 0x5e, 0x83, 0xc6, 0x78, 0x72, 0xec, 0x09, 0x98, 0xf3, 0x02, 0x9d, 0x84, 0x4b, 0x78, 0x53, 0x82, 0x48, 0xf4, 0x1a, 0x34, 0xc6, 0x93,
0x7b, 0x7d, 0x4e, 0x52, 0xe6, 0xad, 0x70, 0x08, 0x09, 0x98, 0x33, 0xc8, 0xc7, 0xc9, 0x29, 0x2a, 0x63, 0xdf, 0xeb, 0x73, 0x92, 0x32, 0x6f, 0x85, 0x43, 0x48, 0xc0, 0x9c, 0x41, 0x3e, 0x4e, 0x4e,
0x48, 0xd1, 0x10, 0x18, 0x23, 0xb1, 0xef, 0xc2, 0x8a, 0x39, 0x40, 0xa1, 0xca, 0x36, 0xa0, 0x26, 0x51, 0x41, 0x8a, 0x86, 0xc0, 0x18, 0x89, 0x7d, 0x17, 0x96, 0xcc, 0x01, 0x0a, 0x55, 0xb6, 0x01,
0x38, 0x3f, 0xee, 0x34, 0x70, 0xf5, 0x5a, 0x62, 0xf5, 0x04, 0xa9, 0xa3, 0xea, 0xed, 0x1f, 0x54, 0x35, 0xc1, 0xf9, 0x71, 0xa7, 0x81, 0xab, 0xd7, 0x12, 0xab, 0x27, 0x48, 0x1d, 0x55, 0x6f, 0xff,
0x60, 0x59, 0xa0, 0xdb, 0x7e, 0x18, 0xd3, 0xa3, 0xc9, 0x68, 0xe4, 0x46, 0x05, 0x22, 0x65, 0x5d, 0x41, 0x05, 0x16, 0x05, 0xba, 0xed, 0x87, 0x31, 0x3d, 0x9a, 0x8c, 0x46, 0x6e, 0x54, 0x20, 0x52,
0x20, 0x52, 0x25, 0x53, 0xa4, 0x18, 0xa3, 0x9f, 0xba, 0x5e, 0xc0, 0x3d, 0x59, 0x2e, 0x8f, 0x1a, 0xd6, 0x25, 0x22, 0x55, 0x32, 0x45, 0x8a, 0x31, 0xfa, 0xa9, 0xeb, 0x05, 0xdc, 0x93, 0xe5, 0xf2,
0x42, 0xd6, 0x61, 0xb1, 0xef, 0x87, 0x31, 0xf7, 0xda, 0xf4, 0x43, 0x67, 0x16, 0xce, 0xab, 0x80, 0xa8, 0x21, 0x64, 0x1d, 0xe6, 0xfb, 0x7e, 0x18, 0x73, 0xaf, 0x4d, 0x3f, 0x74, 0x66, 0xe1, 0xbc,
0x6a, 0x91, 0x0a, 0xd0, 0x45, 0x78, 0x2e, 0x23, 0xc2, 0x36, 0x34, 0x59, 0xa3, 0x54, 0x6a, 0xa4, 0x0a, 0xa8, 0x16, 0xa9, 0x00, 0x5d, 0x84, 0x67, 0x32, 0x22, 0x6c, 0x43, 0x93, 0x35, 0x4a, 0xa5,
0x79, 0xee, 0xc9, 0xe9, 0x18, 0x1b, 0x4f, 0x56, 0x60, 0xb8, 0x74, 0x2e, 0x16, 0x89, 0x0b, 0x3b, 0x46, 0x9a, 0xe5, 0x9e, 0x9c, 0x8e, 0xb1, 0xf1, 0x64, 0x05, 0x86, 0x4b, 0xe7, 0x7c, 0x91, 0xb8,
0xd3, 0x32, 0x8d, 0xa7, 0x51, 0xd7, 0x85, 0xb8, 0xe4, 0xab, 0xc8, 0x3d, 0x00, 0xde, 0x17, 0x9a, 0xb0, 0x33, 0x2d, 0xd3, 0x78, 0x1a, 0x75, 0x5d, 0x88, 0x4b, 0xbe, 0x8a, 0xdc, 0x03, 0xe0, 0x7d,
0x5d, 0x40, 0xb3, 0xfb, 0x86, 0xb9, 0x23, 0xfa, 0xda, 0xdf, 0x62, 0x85, 0x49, 0x44, 0xd1, 0x14, 0xa1, 0xd9, 0x05, 0x34, 0xbb, 0x6f, 0x98, 0x3b, 0xa2, 0xaf, 0xfd, 0x2d, 0x56, 0x98, 0x44, 0x14,
0x6b, 0x5f, 0xda, 0xbf, 0x6c, 0x41, 0x43, 0xab, 0x23, 0xab, 0xb0, 0xb4, 0xfd, 0xf0, 0xe1, 0xe1, 0x4d, 0xb1, 0xf6, 0xa5, 0xfd, 0x0b, 0x16, 0x34, 0xb4, 0x3a, 0xb2, 0x0c, 0x0b, 0xdb, 0x0f, 0x1f,
0xae, 0xb3, 0xf5, 0xe8, 0xc1, 0x97, 0x77, 0x7b, 0xdb, 0xfb, 0x0f, 0x8f, 0x76, 0xdb, 0x97, 0x18, 0x1e, 0xee, 0x3a, 0x5b, 0x8f, 0x1e, 0x7c, 0x65, 0xb7, 0xb7, 0xbd, 0xff, 0xf0, 0x68, 0xb7, 0x7d,
0xbc, 0xff, 0x70, 0x7b, 0x6b, 0xbf, 0x77, 0xef, 0xa1, 0xb3, 0x2d, 0x61, 0x8b, 0xac, 0x01, 0x71, 0x85, 0xc1, 0xfb, 0x0f, 0xb7, 0xb7, 0xf6, 0x7b, 0xf7, 0x1e, 0x3a, 0xdb, 0x12, 0xb6, 0xc8, 0x0a,
0x76, 0xdf, 0x7f, 0xf8, 0x68, 0xd7, 0xc0, 0x4b, 0xa4, 0x0d, 0xcd, 0xbb, 0xce, 0xee, 0xd6, 0xf6, 0x10, 0x67, 0xf7, 0xfd, 0x87, 0x8f, 0x76, 0x0d, 0xbc, 0x44, 0xda, 0xd0, 0xbc, 0xeb, 0xec, 0x6e,
0x9e, 0x40, 0xca, 0x64, 0x05, 0xda, 0xf7, 0x1e, 0x1f, 0xec, 0x3c, 0x38, 0xb8, 0xdf, 0xdb, 0xde, 0x6d, 0xef, 0x09, 0xa4, 0x4c, 0x96, 0xa0, 0x7d, 0xef, 0xf1, 0xc1, 0xce, 0x83, 0x83, 0xfb, 0xbd,
0x3a, 0xd8, 0xde, 0xdd, 0xdf, 0xdd, 0x69, 0x57, 0xc8, 0x02, 0xd4, 0xb7, 0xee, 0x6e, 0x1d, 0xec, 0xed, 0xad, 0x83, 0xed, 0xdd, 0xfd, 0xdd, 0x9d, 0x76, 0x85, 0xcc, 0x41, 0x7d, 0xeb, 0xee, 0xd6,
0x3c, 0x3c, 0xd8, 0xdd, 0x69, 0x57, 0xed, 0xbf, 0xb7, 0x60, 0x15, 0x47, 0x3d, 0xc8, 0x0a, 0xc8, 0xc1, 0xce, 0xc3, 0x83, 0xdd, 0x9d, 0x76, 0xd5, 0xfe, 0x3b, 0x0b, 0x96, 0x71, 0xd4, 0x83, 0xac,
0x75, 0x68, 0xf4, 0xc3, 0x70, 0x4c, 0x99, 0xb6, 0x57, 0x0a, 0x5d, 0x87, 0x18, 0xf3, 0x73, 0xf5, 0x80, 0xac, 0x41, 0xa3, 0x1f, 0x86, 0x63, 0xca, 0xb4, 0xbd, 0x52, 0xe8, 0x3a, 0xc4, 0x98, 0x9f,
0x79, 0x12, 0x46, 0x7d, 0x2a, 0xe4, 0x03, 0x10, 0xba, 0xc7, 0x10, 0xc6, 0xfc, 0x62, 0x7b, 0x39, 0xab, 0xcf, 0x93, 0x30, 0xea, 0x53, 0x21, 0x1f, 0x80, 0xd0, 0x3d, 0x86, 0x30, 0xe6, 0x17, 0xdb,
0x05, 0x17, 0x8f, 0x06, 0xc7, 0x38, 0xc9, 0x1a, 0xcc, 0x1d, 0x47, 0xd4, 0xed, 0x9f, 0x0a, 0xc9, 0xcb, 0x29, 0xb8, 0x78, 0x34, 0x38, 0xc6, 0x49, 0x56, 0x60, 0xe6, 0x38, 0xa2, 0x6e, 0xff, 0x54,
0x10, 0x25, 0xf2, 0xc9, 0xf4, 0x80, 0xd1, 0x67, 0xab, 0xef, 0xd3, 0x01, 0x72, 0x4c, 0xcd, 0x59, 0x48, 0x86, 0x28, 0x91, 0x4f, 0xa6, 0x07, 0x8c, 0x3e, 0x5b, 0x7d, 0x9f, 0x0e, 0x90, 0x63, 0x6a,
0x14, 0xf8, 0xb6, 0x80, 0x99, 0xfc, 0xbb, 0xc7, 0x6e, 0x30, 0x08, 0x03, 0x3a, 0x10, 0xce, 0x5e, 0xce, 0xbc, 0xc0, 0xb7, 0x05, 0xcc, 0xe4, 0xdf, 0x3d, 0x76, 0x83, 0x41, 0x18, 0xd0, 0x81, 0x70,
0x0a, 0xd8, 0x87, 0xb0, 0x96, 0x9d, 0x9f, 0x90, 0xaf, 0xb7, 0x35, 0xf9, 0xe2, 0xbe, 0x57, 0x77, 0xf6, 0x52, 0xc0, 0x3e, 0x84, 0x95, 0xec, 0xfc, 0x84, 0x7c, 0xbd, 0xad, 0xc9, 0x17, 0xf7, 0xbd,
0xf6, 0x6e, 0x6a, 0xb2, 0xf6, 0x2f, 0x16, 0x54, 0x98, 0x29, 0x9e, 0x6d, 0xb6, 0x75, 0xef, 0xaa, 0xba, 0xd3, 0x77, 0x53, 0x93, 0xb5, 0x7f, 0xb6, 0xa0, 0xc2, 0x4c, 0xf1, 0x74, 0xb3, 0xad, 0x7b,
0x9c, 0x8b, 0x50, 0xe1, 0x99, 0x85, 0x2b, 0x67, 0x6e, 0xc0, 0x34, 0x24, 0xad, 0x8f, 0x68, 0xff, 0x57, 0xe5, 0x5c, 0x84, 0x0a, 0xcf, 0x2c, 0x5c, 0x39, 0x73, 0x03, 0xa6, 0x21, 0x69, 0x7d, 0x44,
0x0c, 0x67, 0xac, 0xea, 0x19, 0xc2, 0x04, 0x84, 0xb9, 0xbe, 0xf8, 0xb5, 0x10, 0x10, 0x59, 0x96, 0xfb, 0x67, 0x38, 0x63, 0x55, 0xcf, 0x10, 0x26, 0x20, 0xcc, 0xf5, 0xc5, 0xaf, 0x85, 0x80, 0xc8,
0x75, 0xf8, 0xe5, 0x7c, 0x5a, 0x87, 0xdf, 0x75, 0x60, 0xde, 0x0b, 0x8e, 0xc3, 0x49, 0x30, 0x40, 0xb2, 0xac, 0xc3, 0x2f, 0x67, 0xd3, 0x3a, 0xfc, 0xae, 0x03, 0xb3, 0x5e, 0x70, 0x1c, 0x4e, 0x82,
0x81, 0xa8, 0x39, 0xb2, 0x88, 0x31, 0x31, 0x14, 0x54, 0x6f, 0x24, 0xd9, 0x3f, 0x05, 0x6c, 0xc2, 0x01, 0x0a, 0x44, 0xcd, 0x91, 0x45, 0x8c, 0x89, 0xa1, 0xa0, 0x7a, 0x23, 0xc9, 0xfe, 0x29, 0x60,
0x8e, 0x46, 0x31, 0xba, 0x1e, 0x2a, 0x3c, 0xf3, 0x36, 0x2c, 0x69, 0x58, 0xea, 0xc6, 0x8e, 0x19, 0x13, 0x76, 0x34, 0x8a, 0xd1, 0xf5, 0x50, 0xe1, 0x99, 0xb7, 0x61, 0x41, 0xc3, 0x52, 0x37, 0x76,
0x90, 0x71, 0x63, 0xd1, 0x67, 0xe1, 0x35, 0x76, 0x1b, 0x5a, 0xf7, 0x69, 0xf2, 0x20, 0x38, 0x09, 0xcc, 0x80, 0x8c, 0x1b, 0x8b, 0x3e, 0x0b, 0xaf, 0xb1, 0xdb, 0xd0, 0xba, 0x4f, 0x93, 0x07, 0xc1,
0x65, 0x4b, 0x7f, 0x50, 0x81, 0x45, 0x05, 0x89, 0x86, 0xd6, 0x61, 0xd1, 0x1b, 0xd0, 0x20, 0xf1, 0x49, 0x28, 0x5b, 0xfa, 0xdd, 0x0a, 0xcc, 0x2b, 0x48, 0x34, 0xb4, 0x0e, 0xf3, 0xde, 0x80, 0x06,
0x92, 0x69, 0xcf, 0x38, 0x81, 0x65, 0x61, 0xe6, 0xeb, 0xb9, 0xbe, 0xe7, 0xca, 0x28, 0x20, 0x2f, 0x89, 0x97, 0x5c, 0xf4, 0x8c, 0x13, 0x58, 0x16, 0x66, 0xbe, 0x9e, 0xeb, 0x7b, 0xae, 0x8c, 0x02,
0x90, 0x3b, 0xb0, 0xc2, 0x0c, 0x91, 0xb4, 0x2d, 0x6a, 0x8b, 0xf9, 0xc1, 0xaf, 0xb0, 0x8e, 0x29, 0xf2, 0x02, 0xb9, 0x03, 0x4b, 0xcc, 0x10, 0x49, 0xdb, 0xa2, 0xb6, 0x98, 0x1f, 0xfc, 0x0a, 0xeb,
0x03, 0x86, 0x0b, 0x6d, 0xaf, 0x3e, 0xe1, 0x3e, 0x4f, 0x51, 0x15, 0x5b, 0x35, 0xde, 0x12, 0x9b, 0x98, 0x32, 0x60, 0xb8, 0xd0, 0xf6, 0xea, 0x13, 0xee, 0xf3, 0x14, 0x55, 0xb1, 0x55, 0xe3, 0x2d,
0x72, 0x95, 0x1b, 0x2b, 0x05, 0xe4, 0xc2, 0x6c, 0x73, 0x5c, 0x55, 0x65, 0xc3, 0x6c, 0x5a, 0xa8, 0xb1, 0x29, 0x57, 0xb9, 0xb1, 0x52, 0x40, 0x2e, 0xcc, 0x36, 0xc3, 0x55, 0x55, 0x36, 0xcc, 0xa6,
0xae, 0x96, 0x0b, 0xd5, 0x31, 0x55, 0x36, 0x0d, 0xfa, 0x74, 0xd0, 0x4b, 0xc2, 0x1e, 0xaa, 0x5c, 0x85, 0xea, 0x6a, 0xb9, 0x50, 0x1d, 0x53, 0x65, 0x17, 0x41, 0x9f, 0x0e, 0x7a, 0x49, 0xd8, 0x43,
0xdc, 0x9d, 0x9a, 0x93, 0x85, 0xc9, 0x55, 0x98, 0x4f, 0x68, 0x9c, 0x04, 0x34, 0x41, 0xad, 0x54, 0x95, 0x8b, 0xbb, 0x53, 0x73, 0xb2, 0x30, 0xb9, 0x06, 0xb3, 0x09, 0x8d, 0x93, 0x80, 0x26, 0xa8,
0xc3, 0x80, 0x80, 0x84, 0x98, 0x83, 0x3a, 0x89, 0xbc, 0xb8, 0xd3, 0xc4, 0x20, 0x1c, 0xfe, 0x4f, 0x95, 0x6a, 0x18, 0x10, 0x90, 0x10, 0x73, 0x50, 0x27, 0x91, 0x17, 0x77, 0x9a, 0x18, 0x84, 0xc3,
0x3e, 0x03, 0xab, 0xc7, 0x34, 0x4e, 0x7a, 0xa7, 0xd4, 0x1d, 0xd0, 0x08, 0x77, 0x9a, 0x47, 0xfb, 0xff, 0xc9, 0x67, 0x60, 0xf9, 0x98, 0xc6, 0x49, 0xef, 0x94, 0xba, 0x03, 0x1a, 0xe1, 0x4e, 0xf3,
0xb8, 0xdd, 0x2f, 0xae, 0x64, 0x3c, 0x74, 0x46, 0xa3, 0xd8, 0x0b, 0x03, 0xb4, 0xf8, 0x75, 0x47, 0x68, 0x1f, 0xb7, 0xfb, 0xc5, 0x95, 0x8c, 0x87, 0xce, 0x68, 0x14, 0x7b, 0x61, 0x80, 0x16, 0xbf,
0x16, 0x59, 0x7b, 0x6c, 0xf2, 0xca, 0x5e, 0xaa, 0x15, 0x5c, 0xc4, 0x89, 0x17, 0x57, 0x92, 0x1b, 0xee, 0xc8, 0x22, 0x6b, 0x8f, 0x4d, 0x5e, 0xd9, 0x4b, 0xb5, 0x82, 0xf3, 0x38, 0xf1, 0xe2, 0x4a,
0x30, 0x87, 0x13, 0x88, 0x3b, 0x6d, 0x23, 0xaa, 0xb1, 0xcd, 0x40, 0x47, 0xd4, 0x7d, 0xa1, 0x52, 0x72, 0x03, 0x66, 0x70, 0x02, 0x71, 0xa7, 0x6d, 0x44, 0x35, 0xb6, 0x19, 0xe8, 0x88, 0xba, 0x2f,
0x6b, 0xb4, 0x9b, 0xf6, 0xff, 0x81, 0x2a, 0xc2, 0x6c, 0xd3, 0xf9, 0x62, 0x70, 0xa6, 0xe0, 0x05, 0x56, 0x6a, 0x8d, 0x76, 0xd3, 0xfe, 0x1c, 0x54, 0x11, 0x66, 0x9b, 0xce, 0x17, 0x83, 0x33, 0x05,
0x36, 0xb4, 0x80, 0x26, 0xe7, 0x61, 0xf4, 0x54, 0x86, 0x84, 0x45, 0xd1, 0xfe, 0x26, 0xba, 0xf8, 0x2f, 0xb0, 0xa1, 0x05, 0x34, 0x39, 0x0f, 0xa3, 0xa7, 0x32, 0x24, 0x2c, 0x8a, 0xf6, 0xb7, 0xd0,
0x2a, 0x44, 0xfa, 0x18, 0xfd, 0x13, 0x76, 0x50, 0xe3, 0x4b, 0x1d, 0x9f, 0xba, 0xe2, 0xd4, 0x51, 0xc5, 0x57, 0x21, 0xd2, 0xc7, 0xe8, 0x9f, 0xb0, 0x83, 0x1a, 0x5f, 0xea, 0xf8, 0xd4, 0x15, 0xa7,
0x43, 0xe0, 0xe8, 0xd4, 0x65, 0x6a, 0xcb, 0xd8, 0x3d, 0x7e, 0x90, 0x6b, 0x20, 0xb6, 0xc7, 0x37, 0x8e, 0x1a, 0x02, 0x47, 0xa7, 0x2e, 0x53, 0x5b, 0xc6, 0xee, 0xf1, 0x83, 0x5c, 0x03, 0xb1, 0x3d,
0xef, 0x06, 0xb4, 0x64, 0xf0, 0x35, 0xee, 0xf9, 0xf4, 0x24, 0x91, 0x71, 0x85, 0x60, 0x32, 0xc2, 0xbe, 0x79, 0x37, 0xa0, 0x25, 0x83, 0xaf, 0x71, 0xcf, 0xa7, 0x27, 0x89, 0x8c, 0x2b, 0x04, 0x93,
0xd3, 0xde, 0x3e, 0x3d, 0x49, 0xec, 0x03, 0x58, 0x12, 0xaa, 0xe4, 0xe1, 0x98, 0xca, 0xae, 0x3f, 0x11, 0x9e, 0xf6, 0xf6, 0xe9, 0x49, 0x62, 0x1f, 0xc0, 0x82, 0x50, 0x25, 0x0f, 0xc7, 0x54, 0x76,
0x57, 0x64, 0x92, 0x1b, 0x77, 0x96, 0x4d, 0xdd, 0xc3, 0xc3, 0xcd, 0x26, 0xa5, 0xed, 0x00, 0xd1, 0xfd, 0xf9, 0x22, 0x93, 0xdc, 0xb8, 0xb3, 0x68, 0xea, 0x1e, 0x1e, 0x6e, 0x36, 0x29, 0x6d, 0x07,
0x55, 0x93, 0x68, 0x50, 0xd8, 0x45, 0x19, 0x39, 0x11, 0xd3, 0x31, 0x30, 0xb6, 0x3e, 0xf1, 0xa4, 0x88, 0xae, 0x9a, 0x44, 0x83, 0xc2, 0x2e, 0xca, 0xc8, 0x89, 0x98, 0x8e, 0x81, 0xb1, 0xf5, 0x89,
0xdf, 0x97, 0x21, 0x73, 0x76, 0x1c, 0xe6, 0x45, 0xfb, 0x0f, 0x2d, 0x58, 0xc6, 0xd6, 0xa4, 0x53, 0x27, 0xfd, 0xbe, 0x0c, 0x99, 0xb3, 0xe3, 0x30, 0x2f, 0xda, 0xbf, 0x67, 0xc1, 0x22, 0xb6, 0x26,
0x21, 0xd4, 0xff, 0x3b, 0x1f, 0x63, 0x98, 0xcd, 0xbe, 0x1e, 0x4d, 0x5a, 0x81, 0xaa, 0x6e, 0x10, 0x9d, 0x0a, 0xa1, 0xfe, 0xdf, 0xf9, 0x18, 0xc3, 0x6c, 0xf6, 0xf5, 0x68, 0xd2, 0x12, 0x54, 0x75,
0x78, 0xe1, 0xe3, 0x1f, 0xea, 0x2b, 0xd9, 0x43, 0xbd, 0xfd, 0x5b, 0x16, 0x2c, 0x71, 0x9d, 0x9c, 0x83, 0xc0, 0x0b, 0x1f, 0xff, 0x50, 0x5f, 0xc9, 0x1e, 0xea, 0xed, 0x5f, 0xb7, 0x60, 0x81, 0xeb,
0xb8, 0xc9, 0x24, 0x16, 0xd3, 0xff, 0xbf, 0xb0, 0xc0, 0x8d, 0xab, 0x90, 0x6a, 0x31, 0xd0, 0x15, 0xe4, 0xc4, 0x4d, 0x26, 0xb1, 0x98, 0xfe, 0xff, 0x82, 0x39, 0x6e, 0x5c, 0x85, 0x54, 0x8b, 0x81,
0xa5, 0x80, 0x10, 0xe5, 0xc4, 0x7b, 0x97, 0x1c, 0x93, 0x98, 0xbc, 0x87, 0x0e, 0x4e, 0xd0, 0x43, 0x2e, 0x29, 0x05, 0x84, 0x28, 0x27, 0xde, 0xbb, 0xe2, 0x98, 0xc4, 0xe4, 0x3d, 0x74, 0x70, 0x82,
0x54, 0x04, 0x06, 0xaf, 0x14, 0x98, 0x01, 0xf5, 0xbd, 0x46, 0x7e, 0xb7, 0x06, 0x73, 0xdc, 0xdf, 0x1e, 0xa2, 0x22, 0x30, 0x78, 0xb5, 0xc0, 0x0c, 0xa8, 0xef, 0x35, 0xf2, 0xbb, 0x35, 0x98, 0xe1,
0xb5, 0xef, 0xc3, 0x82, 0xd1, 0x91, 0x11, 0x50, 0x68, 0xf2, 0x80, 0x42, 0x2e, 0x14, 0x55, 0x2a, 0xfe, 0xae, 0x7d, 0x1f, 0xe6, 0x8c, 0x8e, 0x8c, 0x80, 0x42, 0x93, 0x07, 0x14, 0x72, 0xa1, 0xa8,
0x08, 0x45, 0xfd, 0x51, 0x19, 0x08, 0x63, 0x96, 0xcc, 0x6e, 0x30, 0x87, 0x3b, 0x1c, 0x18, 0xc7, 0x52, 0x41, 0x28, 0xea, 0xf7, 0xcb, 0x40, 0x18, 0xb3, 0x64, 0x76, 0x83, 0x39, 0xdc, 0xe1, 0xc0,
0xa7, 0xa6, 0xa3, 0x43, 0xe4, 0x16, 0x10, 0xad, 0x28, 0x23, 0x8a, 0xdc, 0xfa, 0x14, 0xd4, 0x30, 0x38, 0x3e, 0x35, 0x1d, 0x1d, 0x22, 0xb7, 0x80, 0x68, 0x45, 0x19, 0x51, 0xe4, 0xd6, 0xa7, 0xa0,
0x35, 0x29, 0x8c, 0xb7, 0x30, 0xb3, 0xe2, 0xa0, 0xc8, 0x97, 0xbd, 0xb0, 0x8e, 0x19, 0x98, 0xf1, 0x86, 0xa9, 0x49, 0x61, 0xbc, 0x85, 0x99, 0x15, 0x07, 0x45, 0xbe, 0xec, 0x85, 0x75, 0xcc, 0xc0,
0x24, 0x3e, 0xc5, 0xcb, 0x15, 0x71, 0xc0, 0x92, 0xe5, 0xec, 0xfe, 0xce, 0x5d, 0xb8, 0xbf, 0xf3, 0x8c, 0x27, 0xf1, 0x29, 0x5e, 0xae, 0x88, 0x03, 0x96, 0x2c, 0x67, 0xf7, 0x77, 0xe6, 0xd2, 0xfd,
0xb9, 0xa0, 0x8d, 0xe6, 0xe2, 0xd7, 0x4c, 0x17, 0xff, 0x06, 0x2c, 0x8c, 0x98, 0xcb, 0x99, 0xf8, 0x9d, 0xcd, 0x05, 0x6d, 0x34, 0x17, 0xbf, 0x66, 0xba, 0xf8, 0x37, 0x60, 0x6e, 0xc4, 0x5c, 0xce,
0xfd, 0xde, 0x88, 0xf5, 0x2e, 0xce, 0x53, 0x06, 0x48, 0x36, 0xa0, 0x2d, 0xdc, 0x8d, 0xf4, 0x1c, 0xc4, 0xef, 0xf7, 0x46, 0xac, 0x77, 0x71, 0x9e, 0x32, 0x40, 0xb2, 0x01, 0x6d, 0xe1, 0x6e, 0xa4,
0x01, 0xb8, 0xc6, 0x39, 0x9c, 0xe9, 0xef, 0x34, 0x8c, 0xd3, 0xc0, 0xc1, 0xa6, 0x00, 0x3b, 0x79, 0xe7, 0x08, 0xc0, 0x35, 0xce, 0xe1, 0x4c, 0x7f, 0xa7, 0x61, 0x9c, 0x06, 0x0e, 0x36, 0x05, 0xd8,
0xc5, 0x8c, 0x43, 0x7a, 0x93, 0x40, 0xdc, 0xaf, 0xd0, 0x01, 0x9e, 0xa4, 0x6a, 0x4e, 0xbe, 0xc2, 0xc9, 0x2b, 0x66, 0x1c, 0xd2, 0x9b, 0x04, 0xe2, 0x7e, 0x85, 0x0e, 0xf0, 0x24, 0x55, 0x73, 0xf2,
0xfe, 0x0d, 0x0b, 0xda, 0x6c, 0xcf, 0x0c, 0xb6, 0x7c, 0x17, 0x50, 0x2a, 0x5e, 0x92, 0x2b, 0x0d, 0x15, 0xf6, 0xaf, 0x5a, 0xd0, 0x66, 0x7b, 0x66, 0xb0, 0xe5, 0xbb, 0x80, 0x52, 0xf1, 0x92, 0x5c,
0x5a, 0xf2, 0x0e, 0xd4, 0xb1, 0x1c, 0x8e, 0x69, 0x20, 0x78, 0xb2, 0x63, 0xf2, 0x64, 0xaa, 0x4f, 0x69, 0xd0, 0x92, 0x77, 0xa0, 0x8e, 0xe5, 0x70, 0x4c, 0x03, 0xc1, 0x93, 0x1d, 0x93, 0x27, 0x53,
0xf6, 0x2e, 0x39, 0x29, 0xb1, 0xc6, 0x91, 0x7f, 0x6d, 0x41, 0x43, 0xf4, 0xf2, 0x23, 0x87, 0x09, 0x7d, 0xb2, 0x77, 0xc5, 0x49, 0x89, 0x35, 0x8e, 0xfc, 0x2b, 0x0b, 0x1a, 0xa2, 0x97, 0x1f, 0x39,
0xba, 0xda, 0x85, 0x18, 0xe7, 0xa4, 0xf4, 0xfe, 0x6b, 0x1d, 0x16, 0x47, 0x6e, 0x32, 0x89, 0x98, 0x4c, 0xd0, 0xd5, 0x2e, 0xc4, 0x38, 0x27, 0xa5, 0xf7, 0x5f, 0xeb, 0x30, 0x3f, 0x72, 0x93, 0x49,
0x3d, 0x36, 0x42, 0x04, 0x59, 0x98, 0x19, 0x57, 0x54, 0x9d, 0x71, 0x2f, 0xf1, 0xfc, 0x9e, 0xac, 0xc4, 0xec, 0xb1, 0x11, 0x22, 0xc8, 0xc2, 0xcc, 0xb8, 0xa2, 0xea, 0x8c, 0x7b, 0x89, 0xe7, 0xf7,
0x15, 0x57, 0x4f, 0x45, 0x55, 0x4c, 0x83, 0xc4, 0x89, 0x3b, 0xa4, 0xc2, 0x6e, 0xf2, 0x82, 0xdd, 0x64, 0xad, 0xb8, 0x7a, 0x2a, 0xaa, 0x62, 0x1a, 0x24, 0x4e, 0xdc, 0x21, 0x15, 0x76, 0x93, 0x17,
0x81, 0x35, 0x31, 0xa1, 0x8c, 0xab, 0x6a, 0xff, 0x59, 0x13, 0x2e, 0xe7, 0xaa, 0xd4, 0xfd, 0xb4, 0xec, 0x0e, 0xac, 0x88, 0x09, 0x65, 0x5c, 0x55, 0xfb, 0x4f, 0x9a, 0xb0, 0x9a, 0xab, 0x52, 0xf7,
0x38, 0xfb, 0xfa, 0xde, 0xe8, 0x38, 0x54, 0x7e, 0xbe, 0xa5, 0x1f, 0x8b, 0x8d, 0x2a, 0x32, 0x84, 0xd3, 0xe2, 0xec, 0xeb, 0x7b, 0xa3, 0xe3, 0x50, 0xf9, 0xf9, 0x96, 0x7e, 0x2c, 0x36, 0xaa, 0xc8,
0x55, 0xe9, 0x20, 0xb0, 0x35, 0x4d, 0x8d, 0x59, 0x09, 0xad, 0xd4, 0x5b, 0xe6, 0x16, 0x66, 0x3b, 0x10, 0x96, 0xa5, 0x83, 0xc0, 0xd6, 0x34, 0x35, 0x66, 0x25, 0xb4, 0x52, 0x6f, 0x99, 0x5b, 0x98,
0x94, 0xb8, 0x2e, 0xc4, 0xc5, 0xed, 0x91, 0x53, 0xe8, 0x28, 0x4f, 0x44, 0x28, 0x6b, 0xcd, 0x5b, 0xed, 0x50, 0xe2, 0xba, 0x10, 0x17, 0xb7, 0x47, 0x4e, 0xa1, 0xa3, 0x3c, 0x11, 0xa1, 0xac, 0x35,
0x61, 0x7d, 0xbd, 0x79, 0x41, 0x5f, 0x86, 0x67, 0xeb, 0xcc, 0x6c, 0x8d, 0x4c, 0xe1, 0x9a, 0xac, 0x6f, 0x85, 0xf5, 0xf5, 0xe6, 0x25, 0x7d, 0x19, 0x9e, 0xad, 0x33, 0xb5, 0x35, 0x72, 0x01, 0xd7,
0x43, 0x6d, 0x9c, 0xef, 0xaf, 0xf2, 0x52, 0x73, 0x43, 0x9f, 0xdd, 0xec, 0xf4, 0x82, 0x86, 0xc9, 0x65, 0x1d, 0x6a, 0xe3, 0x7c, 0x7f, 0x95, 0x97, 0x9a, 0x1b, 0xfa, 0xec, 0x66, 0xa7, 0x97, 0x34,
0x87, 0xb0, 0x76, 0xee, 0x7a, 0x89, 0x1c, 0x96, 0xe6, 0x1b, 0x54, 0xb1, 0xcb, 0x3b, 0x17, 0x74, 0x4c, 0x3e, 0x84, 0x95, 0x73, 0xd7, 0x4b, 0xe4, 0xb0, 0x34, 0xdf, 0xa0, 0x8a, 0x5d, 0xde, 0xb9,
0xf9, 0x84, 0x7f, 0x6c, 0x98, 0xa8, 0x19, 0x2d, 0x76, 0xff, 0xd2, 0x82, 0x96, 0xd9, 0x0e, 0x63, 0xa4, 0xcb, 0x27, 0xfc, 0x63, 0xc3, 0x44, 0x4d, 0x69, 0xb1, 0xfb, 0x17, 0x16, 0xb4, 0xcc, 0x76,
0x53, 0x21, 0xfb, 0x52, 0x07, 0x4a, 0x6f, 0x32, 0x03, 0xe7, 0x8f, 0xca, 0xa5, 0xa2, 0xa3, 0xb2, 0x18, 0x9b, 0x0a, 0xd9, 0x97, 0x3a, 0x50, 0x7a, 0x93, 0x19, 0x38, 0x7f, 0x54, 0x2e, 0x15, 0x1d,
0x7e, 0x40, 0x2d, 0x5f, 0x14, 0x63, 0xaa, 0xbc, 0x5c, 0x8c, 0xa9, 0x5a, 0x14, 0x63, 0xea, 0xfe, 0x95, 0xf5, 0x03, 0x6a, 0xf9, 0xb2, 0x18, 0x53, 0xe5, 0xe5, 0x62, 0x4c, 0xd5, 0xa2, 0x18, 0x53,
0x87, 0x05, 0x24, 0xcf, 0x4b, 0xe4, 0x3e, 0x3f, 0xab, 0x07, 0xd4, 0x17, 0x2a, 0xe5, 0x7f, 0xbf, 0xf7, 0xdf, 0x2d, 0x20, 0x79, 0x5e, 0x22, 0xf7, 0xf9, 0x59, 0x3d, 0xa0, 0xbe, 0x50, 0x29, 0xff,
0x1c, 0x3f, 0xca, 0xb5, 0x93, 0x5f, 0x33, 0xc1, 0xd0, 0xef, 0x8e, 0x75, 0x67, 0x67, 0xc1, 0x29, 0xf3, 0xe5, 0xf8, 0x51, 0xae, 0x9d, 0xfc, 0x9a, 0x09, 0x86, 0x7e, 0x77, 0xac, 0x3b, 0x3b, 0x73,
0xaa, 0xca, 0x44, 0xbd, 0x2a, 0x17, 0x47, 0xbd, 0xaa, 0x17, 0x47, 0xbd, 0xe6, 0xb2, 0x51, 0xaf, 0x4e, 0x51, 0x55, 0x26, 0xea, 0x55, 0xb9, 0x3c, 0xea, 0x55, 0xbd, 0x3c, 0xea, 0x35, 0x93, 0x8d,
0xee, 0x2f, 0x5a, 0xb0, 0x5c, 0xb0, 0xe9, 0x3f, 0xb9, 0x89, 0xb3, 0x6d, 0x32, 0x74, 0x41, 0x49, 0x7a, 0x75, 0x7f, 0xce, 0x82, 0xc5, 0x82, 0x4d, 0xff, 0xc9, 0x4d, 0x9c, 0x6d, 0x93, 0xa1, 0x0b,
0x6c, 0x93, 0x0e, 0x76, 0x7f, 0x16, 0x16, 0x0c, 0x46, 0xff, 0xc9, 0xf5, 0x9f, 0xf5, 0xd7, 0x38, 0x4a, 0x62, 0x9b, 0x74, 0xb0, 0xfb, 0x53, 0x30, 0x67, 0x30, 0xfa, 0x4f, 0xae, 0xff, 0xac, 0xbf,
0x9f, 0x19, 0x58, 0xf7, 0x5f, 0x4b, 0x40, 0xf2, 0xc2, 0xf6, 0x3f, 0x3a, 0x86, 0xfc, 0x3a, 0x95, 0xc6, 0xf9, 0xcc, 0xc0, 0xba, 0xff, 0x52, 0x02, 0x92, 0x17, 0xb6, 0xff, 0xd6, 0x31, 0xe4, 0xd7,
0x0b, 0xd6, 0xe9, 0xbf, 0xd5, 0x0e, 0xbc, 0x09, 0x4b, 0x22, 0x99, 0x45, 0x8b, 0xd0, 0x70, 0x8e, 0xa9, 0x5c, 0xb0, 0x4e, 0xff, 0xa5, 0x76, 0xe0, 0x4d, 0x58, 0x10, 0xc9, 0x2c, 0x5a, 0x84, 0x86,
0xc9, 0x57, 0x30, 0x8f, 0xd5, 0x0c, 0x39, 0xd6, 0x8c, 0x04, 0x01, 0xcd, 0x18, 0x66, 0x22, 0x8f, 0x73, 0x4c, 0xbe, 0x82, 0x79, 0xac, 0x66, 0xc8, 0xb1, 0x66, 0x24, 0x08, 0x68, 0xc6, 0x30, 0x13,
0x76, 0x17, 0x3a, 0x62, 0x85, 0x76, 0xcf, 0x68, 0x90, 0x1c, 0x4d, 0x8e, 0x79, 0x46, 0x88, 0x17, 0x79, 0xb4, 0xbb, 0xd0, 0x11, 0x2b, 0xb4, 0x7b, 0x46, 0x83, 0xe4, 0x68, 0x72, 0xcc, 0x33, 0x42,
0x06, 0xf6, 0xf7, 0xcb, 0xca, 0xe9, 0xc6, 0x4a, 0x61, 0xde, 0x3f, 0x03, 0x4d, 0x5d, 0x99, 0x8b, 0xbc, 0x30, 0xb0, 0x7f, 0x50, 0x56, 0x4e, 0x37, 0x56, 0x0a, 0xf3, 0xfe, 0x19, 0x68, 0xea, 0xca,
0xed, 0xc8, 0x04, 0xe8, 0x98, 0x61, 0xd7, 0xa9, 0xc8, 0x0e, 0xb4, 0x50, 0x65, 0x0d, 0xd4, 0x77, 0x5c, 0x6c, 0x47, 0x26, 0x40, 0xc7, 0x0c, 0xbb, 0x4e, 0x45, 0x76, 0xa0, 0x85, 0x2a, 0x6b, 0xa0,
0x25, 0xfc, 0xee, 0x05, 0x81, 0x87, 0xbd, 0x4b, 0x4e, 0xe6, 0x1b, 0xf2, 0x79, 0x68, 0x99, 0x47, 0xbe, 0x2b, 0xe1, 0x77, 0x2f, 0x08, 0x3c, 0xec, 0x5d, 0x71, 0x32, 0xdf, 0x90, 0x2f, 0x40, 0xcb,
0x29, 0xe1, 0x23, 0x14, 0xf9, 0xe6, 0xec, 0x73, 0x93, 0x98, 0x6c, 0x41, 0x3b, 0x7b, 0x16, 0x13, 0x3c, 0x4a, 0x09, 0x1f, 0xa1, 0xc8, 0x37, 0x67, 0x9f, 0x9b, 0xc4, 0x64, 0x0b, 0xda, 0xd9, 0xb3,
0xb7, 0xc5, 0x33, 0x1a, 0xc8, 0x91, 0x93, 0x77, 0xc4, 0xdd, 0x53, 0x15, 0x83, 0x60, 0x37, 0xcc, 0x98, 0xb8, 0x2d, 0x9e, 0xd2, 0x40, 0x8e, 0x9c, 0xbc, 0x23, 0xee, 0x9e, 0xaa, 0x18, 0x04, 0xbb,
0xcf, 0xb4, 0x65, 0xba, 0xc5, 0xff, 0x68, 0xb7, 0x51, 0x5f, 0x03, 0x48, 0x31, 0xd2, 0x86, 0xe6, 0x61, 0x7e, 0xa6, 0x2d, 0xd3, 0x2d, 0xfe, 0x47, 0xbb, 0x8d, 0xfa, 0x3a, 0x40, 0x8a, 0x91, 0x36,
0xc3, 0xc3, 0xdd, 0x83, 0xde, 0xf6, 0xde, 0xd6, 0xc1, 0xc1, 0xee, 0x7e, 0xfb, 0x12, 0x21, 0xd0, 0x34, 0x1f, 0x1e, 0xee, 0x1e, 0xf4, 0xb6, 0xf7, 0xb6, 0x0e, 0x0e, 0x76, 0xf7, 0xdb, 0x57, 0x08,
0xc2, 0xf8, 0xd5, 0x8e, 0xc2, 0x2c, 0x86, 0x6d, 0x6d, 0xf3, 0xd8, 0x98, 0xc0, 0x4a, 0x64, 0x05, 0x81, 0x16, 0xc6, 0xaf, 0x76, 0x14, 0x66, 0x31, 0x6c, 0x6b, 0x9b, 0xc7, 0xc6, 0x04, 0x56, 0x22,
0xda, 0x0f, 0x0e, 0x32, 0x68, 0xf9, 0x6e, 0x5d, 0xc9, 0x87, 0xbd, 0x06, 0x2b, 0x3c, 0xe1, 0xe9, 0x4b, 0xd0, 0x7e, 0x70, 0x90, 0x41, 0xcb, 0x77, 0xeb, 0x4a, 0x3e, 0xec, 0x15, 0x58, 0xe2, 0x09,
0x2e, 0x67, 0x0f, 0xe9, 0x2b, 0xfc, 0x8e, 0x05, 0xab, 0x99, 0x8a, 0x34, 0xf1, 0x80, 0xbb, 0x03, 0x4f, 0x77, 0x39, 0x7b, 0x48, 0x5f, 0xe1, 0x37, 0x2d, 0x58, 0xce, 0x54, 0xa4, 0x89, 0x07, 0xdc,
0xa6, 0x8f, 0x60, 0x82, 0x8c, 0x27, 0x95, 0xe7, 0x97, 0xd1, 0x20, 0xf9, 0x0a, 0xc6, 0xf3, 0x9a, 0x1d, 0x30, 0x7d, 0x04, 0x13, 0x64, 0x3c, 0xa9, 0x3c, 0xbf, 0x8c, 0x06, 0xc9, 0x57, 0x30, 0x9e,
0xa7, 0x98, 0x91, 0xa4, 0xa2, 0x2a, 0xfb, 0x32, 0x4f, 0xcb, 0x0a, 0xa8, 0x9f, 0x19, 0xf8, 0x09, 0xd7, 0x3c, 0xc5, 0x8c, 0x24, 0x15, 0x55, 0xd9, 0xab, 0x3c, 0x2d, 0x2b, 0xa0, 0x7e, 0x66, 0xe0,
0x4f, 0xa4, 0xd2, 0x2b, 0xd2, 0xbb, 0x3c, 0x73, 0xc8, 0xb2, 0xc8, 0x9c, 0x7c, 0xc3, 0xf5, 0x30, 0x27, 0x3c, 0x91, 0x4a, 0xaf, 0x48, 0xef, 0xf2, 0xcc, 0x21, 0xcb, 0x22, 0x73, 0xf2, 0x0d, 0xd7,
0xc7, 0x5b, 0x58, 0x67, 0xff, 0xc0, 0x02, 0xf2, 0xa5, 0x09, 0x8d, 0xa6, 0x98, 0x33, 0xa0, 0xc2, 0xc3, 0x1c, 0x6f, 0x61, 0x9d, 0xfd, 0xa7, 0x25, 0x20, 0x5f, 0x9e, 0xd0, 0xe8, 0x02, 0x73, 0x06,
0x81, 0x97, 0xb3, 0xc1, 0xae, 0xb9, 0xf1, 0xe4, 0xf8, 0x8b, 0x74, 0x2a, 0x13, 0x5a, 0x4a, 0x69, 0x54, 0x38, 0x70, 0x35, 0x1b, 0xec, 0x9a, 0x19, 0x4f, 0x8e, 0xbf, 0x44, 0x2f, 0x64, 0x42, 0x4b,
0x42, 0xcb, 0xab, 0x00, 0xec, 0x70, 0xac, 0x32, 0x16, 0xd0, 0xb9, 0x0e, 0x26, 0x23, 0xde, 0x60, 0x49, 0x4f, 0x68, 0x01, 0x76, 0x38, 0x56, 0x19, 0x0b, 0xd6, 0x7a, 0x15, 0x43, 0x12, 0xf5, 0x60,
0x61, 0xce, 0x49, 0xe5, 0xe2, 0x9c, 0x93, 0xea, 0x05, 0x39, 0x27, 0xf6, 0x7b, 0xb0, 0x6c, 0x8c, 0x32, 0xe2, 0x8d, 0x16, 0xe6, 0x9d, 0x54, 0x2e, 0xcf, 0x3b, 0xa9, 0x5e, 0x96, 0x77, 0xf2, 0x09,
0x5b, 0x6d, 0xab, 0xcc, 0x9d, 0xb0, 0xf2, 0xb9, 0x13, 0x32, 0x6f, 0xc2, 0xfe, 0x56, 0x09, 0xca, 0x98, 0xf3, 0x86, 0x41, 0xc8, 0xd4, 0x02, 0x33, 0xec, 0x71, 0x67, 0x66, 0xad, 0xcc, 0x0e, 0xc3,
0x7b, 0xe1, 0x58, 0x0f, 0x85, 0x5b, 0x66, 0x28, 0x5c, 0xf8, 0x07, 0x3d, 0x65, 0xfe, 0x85, 0xd9, 0x02, 0x3c, 0x60, 0x18, 0xf9, 0x5c, 0x4a, 0x44, 0x07, 0x43, 0xcc, 0x61, 0xd2, 0x15, 0xc5, 0xee,
0x30, 0x40, 0xb2, 0x01, 0x2d, 0x77, 0x94, 0xf4, 0x92, 0x90, 0xf9, 0x43, 0xe7, 0x6e, 0x34, 0xe0, 0x60, 0x48, 0xf7, 0xc3, 0xbe, 0x9b, 0x84, 0x91, 0xfa, 0x90, 0x61, 0x31, 0x3b, 0xf5, 0xc7, 0xe1,
0x7b, 0x8d, 0x21, 0x99, 0x4c, 0x0d, 0x59, 0x81, 0xb2, 0x32, 0xa4, 0x48, 0xc0, 0x8a, 0xcc, 0x19, 0x84, 0xb9, 0x39, 0x72, 0x29, 0x78, 0xd8, 0xa6, 0xc9, 0xd1, 0x43, 0x5c, 0x10, 0xfb, 0xab, 0xd0,
0xc7, 0x4b, 0xb6, 0xa9, 0x08, 0x2b, 0x89, 0x12, 0x63, 0x25, 0xf3, 0x7b, 0x7e, 0x12, 0xe2, 0xea, 0xd0, 0x9a, 0x20, 0xaf, 0xf2, 0x13, 0x26, 0x73, 0x21, 0xc4, 0x79, 0xb0, 0xc2, 0x3d, 0xf6, 0x80,
0xb0, 0xa8, 0x8a, 0xf9, 0x2a, 0x6c, 0xf9, 0x90, 0x4c, 0xc4, 0x03, 0x65, 0x59, 0x8f, 0x5d, 0xd6, 0xfa, 0x0f, 0x06, 0xe4, 0x53, 0xb0, 0x30, 0xf0, 0x22, 0x8a, 0xb9, 0x4a, 0xbd, 0x88, 0x9e, 0xd1,
0xcc, 0x2b, 0xc7, 0x7f, 0xb6, 0xa0, 0x8a, 0x6b, 0xc3, 0x54, 0x3b, 0xe7, 0x7d, 0x15, 0x0d, 0xc7, 0x28, 0x96, 0x27, 0xe7, 0xb6, 0xaa, 0x70, 0x38, 0x6e, 0xbf, 0x07, 0x8b, 0xc6, 0xd6, 0x28, 0xce,
0x35, 0x59, 0x70, 0xb2, 0x30, 0xb1, 0x8d, 0x94, 0xb0, 0x92, 0x9a, 0x90, 0x9e, 0x16, 0x76, 0x1d, 0x95, 0xe9, 0x21, 0x56, 0x3e, 0x3d, 0x44, 0xa6, 0x86, 0xd8, 0xdf, 0x2e, 0x41, 0x79, 0x2f, 0x1c,
0xea, 0xbc, 0xa4, 0xd2, 0x9f, 0x90, 0x24, 0x05, 0xc9, 0x35, 0xa8, 0x9c, 0x86, 0x63, 0xe9, 0x8b, 0xeb, 0xd1, 0x7e, 0xcb, 0x8c, 0xf6, 0x0b, 0x17, 0xa8, 0xa7, 0x3c, 0x1c, 0x61, 0x19, 0x0d, 0x90,
0x82, 0xbc, 0x2a, 0x0a, 0xc7, 0x0e, 0xe2, 0xe9, 0x78, 0x58, 0x7b, 0x7c, 0x5a, 0xdc, 0xc3, 0xc8, 0x6c, 0x40, 0xcb, 0x1d, 0x25, 0xbd, 0x24, 0x64, 0x2e, 0xdf, 0xb9, 0x1b, 0x0d, 0x38, 0x3b, 0xe3,
0xc2, 0xcc, 0xc7, 0x52, 0xcd, 0xea, 0xcb, 0x94, 0x41, 0xed, 0x0d, 0x58, 0x3c, 0x08, 0x07, 0x54, 0x16, 0x67, 0x6a, 0xc8, 0x12, 0x94, 0x95, 0xaf, 0x80, 0x04, 0xac, 0xc8, 0xce, 0x1b, 0x78, 0x8f,
0x0b, 0x49, 0xce, 0xe4, 0x73, 0xfb, 0xe7, 0x2c, 0xa8, 0x49, 0x62, 0xb2, 0x0e, 0x15, 0xe6, 0x38, 0x78, 0x21, 0x22, 0x67, 0xa2, 0xc4, 0xa4, 0xc5, 0xfc, 0x9e, 0x1f, 0xf6, 0xb8, 0xc6, 0x2f, 0xaa,
0x66, 0x4e, 0x75, 0xea, 0x8a, 0x98, 0xd1, 0x39, 0x48, 0xc1, 0x2c, 0x2d, 0x46, 0x8a, 0xd2, 0x43, 0x62, 0xee, 0x18, 0xe3, 0x0e, 0x24, 0x13, 0x21, 0x4f, 0x59, 0xd6, 0xc3, 0xb3, 0x35, 0xf3, 0x56,
0x84, 0x8c, 0x13, 0xa5, 0x3e, 0xb2, 0x1a, 0x6e, 0xc6, 0xb5, 0xcc, 0xa0, 0xf6, 0xf7, 0x2c, 0x58, 0xf5, 0x9f, 0x2c, 0xa8, 0xe2, 0xda, 0x30, 0xeb, 0xc5, 0xc5, 0x5b, 0x05, 0xfc, 0x71, 0x4d, 0xe6,
0x30, 0xfa, 0x20, 0xd7, 0xa1, 0xe1, 0xbb, 0x71, 0x22, 0xae, 0xdd, 0xc4, 0xf6, 0xe8, 0x90, 0xbe, 0x9c, 0x2c, 0x4c, 0x6c, 0x23, 0xeb, 0xad, 0xa4, 0x26, 0xa4, 0x67, 0xbe, 0xad, 0x41, 0x9d, 0x97,
0xd1, 0x25, 0x33, 0x48, 0xad, 0xc2, 0xa7, 0x65, 0x3d, 0x7c, 0x7a, 0x1b, 0xea, 0x69, 0xe2, 0x5e, 0x54, 0x86, 0x17, 0xe7, 0x7b, 0x05, 0x92, 0xeb, 0x50, 0x39, 0x0d, 0xc7, 0xd2, 0xdd, 0x06, 0x79,
0xc5, 0xb0, 0xa0, 0xac, 0x47, 0x79, 0xf9, 0x9d, 0x12, 0x61, 0x44, 0x2e, 0xf4, 0xc3, 0x48, 0xdc, 0x1b, 0x16, 0x8e, 0x1d, 0xc4, 0xd3, 0xf1, 0xb0, 0xf6, 0xf8, 0xb4, 0xb8, 0x13, 0x95, 0x85, 0x99,
0xe8, 0xf0, 0x82, 0xfd, 0x1e, 0x34, 0x34, 0x7a, 0x3d, 0x40, 0x67, 0x19, 0x01, 0x3a, 0x95, 0x19, 0x1b, 0xa9, 0x9a, 0xd5, 0x97, 0x29, 0x83, 0xda, 0x1b, 0x30, 0xcf, 0xb8, 0x5e, 0x8b, 0xba, 0x4e,
0x52, 0x4a, 0x33, 0x43, 0xec, 0x7f, 0xb3, 0x60, 0x81, 0xf1, 0xa0, 0x17, 0x0c, 0x0f, 0x43, 0xdf, 0x15, 0x65, 0xfb, 0xa7, 0x2d, 0xa8, 0x49, 0x62, 0xb2, 0x0e, 0x15, 0x26, 0x42, 0x99, 0x83, 0xab,
0xeb, 0x4f, 0x71, 0xef, 0x25, 0xbb, 0x09, 0x9d, 0x21, 0x79, 0xd1, 0x84, 0x19, 0xd7, 0xcb, 0xb0, 0xba, 0x05, 0x67, 0x74, 0x0e, 0x52, 0x30, 0x67, 0x02, 0x83, 0x61, 0xe9, 0x39, 0x49, 0x86, 0xc2,
0x80, 0x10, 0x51, 0x55, 0x66, 0x32, 0xcc, 0x24, 0xe0, 0xd8, 0x8d, 0x85, 0x58, 0x08, 0x97, 0xc6, 0xd2, 0x63, 0x80, 0x1a, 0x6e, 0xc6, 0x7b, 0xce, 0xa0, 0xf6, 0xf7, 0x2d, 0x98, 0x33, 0xfa, 0x20,
0x00, 0x99, 0xa4, 0x31, 0x20, 0x72, 0x13, 0xda, 0x1b, 0x79, 0xbe, 0xef, 0x71, 0x5a, 0xee, 0xf0, 0x6b, 0xd0, 0xf0, 0xdd, 0x38, 0x11, 0x37, 0x8b, 0x62, 0x7b, 0x74, 0x48, 0xdf, 0xe8, 0x92, 0x19,
0x16, 0x55, 0xb1, 0x3e, 0x07, 0x5e, 0xec, 0x1e, 0xa7, 0xb7, 0x14, 0xaa, 0x8c, 0xb1, 0x0b, 0xf7, 0x87, 0x57, 0x11, 0xe2, 0xb2, 0x1e, 0x21, 0xbe, 0x0d, 0xf5, 0x34, 0x37, 0xb1, 0x62, 0xc8, 0x3e,
0x99, 0x16, 0xbb, 0x98, 0x43, 0xbd, 0x62, 0x82, 0xf6, 0x9f, 0x94, 0xa0, 0x21, 0xed, 0xe7, 0x60, 0xeb, 0x51, 0xde, 0xef, 0xa7, 0x44, 0x18, 0x74, 0x0c, 0xfd, 0x30, 0x12, 0x97, 0x56, 0xbc, 0x60,
0x48, 0xc5, 0xc5, 0x1b, 0x1e, 0x3c, 0x94, 0x2a, 0xd2, 0x10, 0x59, 0x6f, 0x1c, 0x55, 0x34, 0x24, 0xbf, 0x07, 0x0d, 0x8d, 0x5e, 0x8f, 0x41, 0x5a, 0x46, 0x0c, 0x52, 0x25, 0xbf, 0x94, 0xd2, 0xe4,
0xcb, 0x18, 0xe5, 0x3c, 0x63, 0x5c, 0x85, 0x3a, 0x63, 0xd0, 0xb7, 0xf0, 0x4c, 0x24, 0x72, 0x61, 0x17, 0xfb, 0x5f, 0x2d, 0x98, 0x63, 0x3c, 0xe8, 0x05, 0xc3, 0xc3, 0xd0, 0xf7, 0xfa, 0x17, 0xb8,
0x15, 0x20, 0x6b, 0xef, 0x60, 0x6d, 0x35, 0xad, 0x45, 0xe0, 0x85, 0xd7, 0x74, 0xef, 0x40, 0x53, 0xf7, 0x92, 0xdd, 0x84, 0x4a, 0x94, 0xbc, 0x68, 0xc2, 0x8c, 0xeb, 0x65, 0xe4, 0x43, 0x88, 0xa8,
0x34, 0x83, 0x3b, 0x87, 0x9a, 0x27, 0x15, 0x11, 0x63, 0x57, 0x1d, 0x83, 0x52, 0x7e, 0x79, 0x47, 0x2a, 0x33, 0x19, 0x66, 0x12, 0x70, 0xec, 0xc6, 0x42, 0x2c, 0x84, 0xd7, 0x66, 0x80, 0x4c, 0xd2,
0x7e, 0x59, 0xbb, 0xe8, 0x4b, 0x49, 0x69, 0xdf, 0x57, 0xb7, 0x9f, 0xf7, 0x23, 0x77, 0x7c, 0x2a, 0x18, 0x10, 0xb9, 0x09, 0xed, 0x8d, 0x3c, 0xdf, 0xf7, 0x38, 0x2d, 0xf7, 0xe9, 0x8b, 0xaa, 0x58,
0x65, 0xf9, 0x36, 0x2c, 0x7b, 0x41, 0xdf, 0x9f, 0x0c, 0x68, 0x6f, 0x12, 0xb8, 0x41, 0x10, 0x4e, 0x9f, 0x03, 0x2f, 0x76, 0x8f, 0xd3, 0x8b, 0x18, 0x55, 0xc6, 0xf0, 0x8c, 0xfb, 0x4c, 0x0b, 0xcf,
0x82, 0x3e, 0x95, 0xa9, 0x21, 0x45, 0x55, 0xf6, 0x40, 0x65, 0xc6, 0x61, 0x43, 0x64, 0x03, 0xaa, 0xcc, 0xa0, 0x5e, 0x31, 0x41, 0xfb, 0x8f, 0x4a, 0xd0, 0x90, 0x2e, 0xc2, 0x60, 0x48, 0xc5, 0xdd,
0xac, 0x23, 0x69, 0x3b, 0x8a, 0x05, 0x9d, 0x93, 0x90, 0x75, 0xa8, 0xd2, 0xc1, 0x90, 0xca, 0x38, 0xa2, 0xa9, 0x18, 0x35, 0x44, 0xd6, 0x1b, 0xa7, 0x31, 0x0d, 0xc9, 0x32, 0x46, 0x39, 0xcf, 0x18,
0x01, 0xc9, 0x78, 0x45, 0x83, 0x21, 0x75, 0x38, 0x01, 0x53, 0x3b, 0x98, 0xfd, 0x68, 0xaa, 0x1d, 0xd7, 0xa0, 0xce, 0x18, 0xf4, 0x2d, 0x3c, 0xf6, 0x89, 0x74, 0x5f, 0x05, 0xc8, 0xda, 0x3b, 0x58,
0xd3, 0xee, 0xcc, 0xf5, 0x79, 0x7e, 0xe4, 0x0a, 0x90, 0x03, 0x2e, 0x29, 0xfa, 0xc5, 0xc9, 0x2f, 0x5b, 0x4d, 0x6b, 0x11, 0x78, 0xe1, 0x4d, 0xe4, 0x3b, 0xd0, 0x14, 0xcd, 0xe0, 0xce, 0xa1, 0xe6,
0x94, 0xa1, 0xa1, 0xc1, 0x4c, 0x83, 0x0c, 0xd9, 0x80, 0x7b, 0x03, 0xcf, 0x1d, 0xd1, 0x84, 0x46, 0x49, 0x45, 0xc4, 0xd8, 0x55, 0xc7, 0xa0, 0x94, 0x5f, 0xde, 0x91, 0x5f, 0xd6, 0x2e, 0xfb, 0x52,
0x42, 0x3a, 0x32, 0x28, 0xa3, 0x73, 0xcf, 0x86, 0xbd, 0x70, 0x92, 0xf4, 0x06, 0x74, 0x18, 0x51, 0x52, 0xda, 0xf7, 0xd5, 0x05, 0xef, 0xfd, 0xc8, 0x1d, 0x9f, 0x4a, 0x59, 0xbe, 0x0d, 0x8b, 0x5e,
0xee, 0x0a, 0x30, 0xd3, 0x64, 0xa0, 0x8c, 0x8e, 0xf1, 0xa7, 0x46, 0xc7, 0x39, 0x28, 0x83, 0xca, 0xd0, 0xf7, 0x27, 0x03, 0xda, 0x9b, 0x04, 0x6e, 0x10, 0x84, 0x93, 0xa0, 0x4f, 0x65, 0xf6, 0x4b,
0x6b, 0x10, 0xbe, 0x46, 0x95, 0xf4, 0x1a, 0x84, 0xaf, 0x48, 0x56, 0xf7, 0x55, 0x0b, 0x74, 0xdf, 0x51, 0x95, 0x3d, 0x50, 0xc9, 0x7f, 0xd8, 0x10, 0xd9, 0x80, 0x2a, 0x37, 0x95, 0xdc, 0x76, 0x14,
0xdb, 0xb0, 0xc6, 0xb5, 0x9c, 0xd0, 0x07, 0xbd, 0x0c, 0x63, 0xcd, 0xa8, 0x25, 0x1b, 0xd0, 0x66, 0x0b, 0x3a, 0x27, 0x21, 0xeb, 0x50, 0xe5, 0x16, 0xb3, 0x64, 0x48, 0x8d, 0xb6, 0xab, 0x0e, 0x27,
0x63, 0x96, 0x22, 0x11, 0x7b, 0xdf, 0xe4, 0x21, 0x45, 0xcb, 0xc9, 0xe1, 0x8c, 0x16, 0x63, 0x7b, 0x60, 0x6a, 0x07, 0x13, 0x3c, 0x4d, 0xb5, 0x63, 0xda, 0x9d, 0x99, 0x3e, 0x4f, 0x01, 0x5d, 0x02,
0x3a, 0x2d, 0xbf, 0x16, 0xce, 0xe1, 0x48, 0xeb, 0x3e, 0x33, 0x69, 0xeb, 0x82, 0x36, 0x83, 0xdb, 0x72, 0xc0, 0x25, 0x45, 0xbf, 0x1b, 0xfa, 0xd9, 0x32, 0x34, 0x34, 0x98, 0x69, 0x90, 0x21, 0x1b,
0x0b, 0xd0, 0x38, 0x4a, 0xc2, 0xb1, 0xdc, 0x94, 0x16, 0x34, 0x79, 0x51, 0xa4, 0xe8, 0xbc, 0x02, 0x70, 0x6f, 0xe0, 0xb9, 0x23, 0x9a, 0xd0, 0x48, 0x48, 0x47, 0x06, 0x65, 0x74, 0xee, 0xd9, 0xb0,
0x57, 0x90, 0x8b, 0x1e, 0x85, 0xe3, 0xd0, 0x0f, 0x87, 0x53, 0xe3, 0x5c, 0xf1, 0x57, 0x16, 0x2c, 0x17, 0x4e, 0x92, 0xde, 0x80, 0x0e, 0x23, 0xca, 0xad, 0x29, 0x33, 0x4d, 0x06, 0xca, 0xe8, 0x18,
0x1b, 0xb5, 0xe9, 0xc1, 0x02, 0x43, 0x12, 0x32, 0xb7, 0x82, 0x33, 0xde, 0x92, 0xa6, 0x82, 0x39, 0x7f, 0x6a, 0x74, 0x9c, 0x83, 0x32, 0xa8, 0xbc, 0xe9, 0xe1, 0x6b, 0x54, 0x49, 0x6f, 0x7a, 0xf8,
0x21, 0x8f, 0xfe, 0x3e, 0x16, 0xe9, 0x16, 0x5b, 0xb0, 0x28, 0x47, 0x26, 0x3f, 0xe4, 0x5c, 0xd8, 0x8a, 0x64, 0x75, 0x5f, 0xb5, 0x40, 0xf7, 0xbd, 0x0d, 0x2b, 0x5c, 0xcb, 0x09, 0x7d, 0xd0, 0xcb,
0xc9, 0x73, 0xa1, 0xf8, 0xbe, 0x25, 0x3e, 0x90, 0x4d, 0x7c, 0x5e, 0x5c, 0xaf, 0xf3, 0x73, 0x86, 0x30, 0xd6, 0x94, 0x5a, 0xb2, 0x01, 0x6d, 0x36, 0x66, 0x29, 0x12, 0xb1, 0xf7, 0x2d, 0x1e, 0x35,
0x8c, 0x40, 0xa9, 0x93, 0x89, 0x7e, 0x0e, 0x95, 0x23, 0xe8, 0x2b, 0x30, 0xb6, 0x7f, 0xc5, 0x02, 0xb5, 0x9c, 0x1c, 0xce, 0x68, 0x31, 0x7c, 0xa9, 0xd3, 0xf2, 0x9b, 0xef, 0x1c, 0x8e, 0xb4, 0xee,
0x48, 0x47, 0x87, 0x97, 0xb2, 0xca, 0x8c, 0xf0, 0xb7, 0x20, 0x9a, 0xc9, 0x78, 0x1d, 0x9a, 0xea, 0x33, 0x93, 0xb6, 0x2e, 0x68, 0x33, 0xb8, 0x3d, 0x07, 0x8d, 0xa3, 0x24, 0x1c, 0xcb, 0x4d, 0x69,
0x32, 0x2f, 0xb5, 0x4c, 0x0d, 0x89, 0x31, 0xb7, 0xf2, 0x26, 0x2c, 0x0e, 0xfd, 0xf0, 0x18, 0xcd, 0x41, 0x93, 0x17, 0x45, 0x16, 0xd2, 0x2b, 0x70, 0x15, 0xb9, 0xe8, 0x51, 0x38, 0x0e, 0xfd, 0x70,
0x3a, 0xe6, 0x7c, 0xc5, 0x22, 0x51, 0xa9, 0xc5, 0xe1, 0x7b, 0x02, 0x4d, 0xcd, 0x58, 0x45, 0x33, 0x78, 0x61, 0x1c, 0x9d, 0xfe, 0xd2, 0x82, 0x45, 0xa3, 0x36, 0x3d, 0x3b, 0x61, 0xd4, 0x45, 0xa6,
0x63, 0xf6, 0xaf, 0x96, 0xd4, 0xdd, 0x4b, 0x3a, 0xe7, 0x99, 0x52, 0x46, 0xee, 0xe4, 0xd4, 0xe9, 0x8f, 0x70, 0xc6, 0x5b, 0xd0, 0x54, 0x30, 0x27, 0xe4, 0x01, 0xee, 0xc7, 0x22, 0xa3, 0x64, 0x0b,
0x8c, 0xab, 0x0e, 0x8c, 0xb5, 0x1e, 0x5e, 0x18, 0x0a, 0x7a, 0x0f, 0x5a, 0x11, 0xd7, 0x57, 0x52, 0xe6, 0xe5, 0xc8, 0xe4, 0x87, 0x9c, 0x0b, 0x3b, 0x79, 0x2e, 0x14, 0xdf, 0xb7, 0xc4, 0x07, 0xb2,
0x99, 0x55, 0x5e, 0xa0, 0xcc, 0x16, 0x22, 0xc3, 0xd6, 0x7d, 0x12, 0xda, 0xee, 0xe0, 0x8c, 0x46, 0x89, 0x2f, 0x88, 0x0c, 0x02, 0x7e, 0x94, 0x92, 0x41, 0x36, 0x75, 0xf8, 0xd2, 0x8f, 0xda, 0x72,
0x89, 0x87, 0x87, 0x71, 0x74, 0x34, 0xb8, 0x0a, 0x5e, 0xd4, 0x70, 0xb4, 0xff, 0x37, 0x61, 0x51, 0x04, 0x7d, 0x05, 0xc6, 0xf6, 0x2f, 0x5a, 0x00, 0xe9, 0xe8, 0xf0, 0xde, 0x59, 0x99, 0x11, 0xfe,
0x24, 0x87, 0x29, 0x4a, 0x91, 0xe8, 0x9d, 0xc2, 0x8c, 0xd0, 0xfe, 0x3d, 0x79, 0xcd, 0x63, 0xee, 0xdc, 0x45, 0x33, 0x19, 0xaf, 0x43, 0x53, 0xdd, 0x57, 0xa6, 0x96, 0xa9, 0x21, 0x31, 0xe6, 0x39,
0xe1, 0xec, 0x15, 0xd1, 0x67, 0x57, 0xca, 0xcc, 0xee, 0x13, 0xe2, 0xca, 0x65, 0x20, 0x4f, 0xfc, 0xdf, 0x84, 0xf9, 0xa1, 0x1f, 0x1e, 0xa3, 0x59, 0xc7, 0xb4, 0xb6, 0x58, 0xe4, 0x62, 0xb5, 0x38,
0x65, 0x2d, 0x15, 0x63, 0x20, 0xae, 0xc8, 0xcc, 0x25, 0xad, 0xbc, 0xcc, 0x92, 0xda, 0x3f, 0xb4, 0x7c, 0x4f, 0xa0, 0xa9, 0x19, 0xab, 0x68, 0x66, 0xcc, 0xfe, 0xa5, 0x92, 0xba, 0x5e, 0x4a, 0xe7,
0x60, 0x7e, 0x2f, 0x1c, 0xef, 0x89, 0xa4, 0x14, 0x14, 0x04, 0x95, 0x95, 0x29, 0x8b, 0x2f, 0x48, 0x3c, 0x55, 0xca, 0xc8, 0x9d, 0x9c, 0x3a, 0x9d, 0x72, 0x9b, 0x83, 0xce, 0xe9, 0xe1, 0xa5, 0xd1,
0x57, 0x29, 0xb4, 0xef, 0x0b, 0x59, 0xfb, 0xfe, 0x53, 0xf0, 0x0a, 0xc6, 0x9b, 0xa2, 0x70, 0x1c, 0xae, 0xf7, 0xa0, 0x15, 0x71, 0x7d, 0x25, 0x95, 0x59, 0xe5, 0x05, 0xca, 0x6c, 0x2e, 0x32, 0x6c,
0x46, 0x4c, 0x18, 0x5d, 0x9f, 0x1b, 0xf3, 0x30, 0x48, 0x4e, 0xa5, 0x1a, 0x7b, 0x11, 0x09, 0x1e, 0xdd, 0x27, 0xa1, 0xed, 0x0e, 0xce, 0x68, 0x94, 0x78, 0x18, 0x6f, 0x40, 0x47, 0x83, 0xab, 0xe0,
0x02, 0xd9, 0xe1, 0x85, 0xbb, 0xe6, 0xc2, 0x1f, 0xe1, 0xda, 0x2d, 0x5f, 0x61, 0x7f, 0x0e, 0xea, 0x79, 0x0d, 0x47, 0xfb, 0x7f, 0x13, 0xe6, 0x45, 0xfe, 0x9b, 0xa2, 0x14, 0xb9, 0xec, 0x29, 0xcc,
0xe8, 0x50, 0xe3, 0xb4, 0xde, 0x84, 0xfa, 0x69, 0x38, 0xee, 0x9d, 0x7a, 0x41, 0x22, 0x85, 0xbb, 0x08, 0xed, 0xdf, 0x96, 0x37, 0x59, 0xe6, 0x1e, 0x4e, 0x5f, 0x11, 0x7d, 0x76, 0xa5, 0xcc, 0xec,
0x95, 0x7a, 0xba, 0x7b, 0xb8, 0x20, 0x8a, 0xc0, 0xfe, 0xd6, 0x1c, 0xcc, 0x3f, 0x08, 0xce, 0x42, 0x3e, 0x21, 0x6e, 0x95, 0x06, 0x32, 0xa8, 0x51, 0xd6, 0xb2, 0x4d, 0x06, 0xe2, 0x16, 0xd0, 0x5c,
0xaf, 0x8f, 0x57, 0x4a, 0x23, 0x3a, 0x0a, 0x65, 0x8e, 0x2a, 0xfb, 0x9f, 0x5c, 0x85, 0x79, 0x4c, 0xd2, 0xca, 0xcb, 0x2c, 0xa9, 0xfd, 0x43, 0x0b, 0x66, 0xf7, 0xc2, 0xf1, 0x9e, 0xc8, 0xbb, 0x41,
0xca, 0x1a, 0x73, 0xa6, 0x6d, 0xf2, 0xab, 0x5f, 0x01, 0x31, 0x27, 0x21, 0x4a, 0xd3, 0xe3, 0xb9, 0x41, 0x50, 0x89, 0xa7, 0xb2, 0xf8, 0x82, 0x8c, 0x9c, 0x42, 0xfb, 0x3e, 0x97, 0xb5, 0xef, 0xff,
0xf8, 0x68, 0x08, 0x3b, 0x6a, 0x44, 0x7a, 0x7a, 0xbb, 0x28, 0xa5, 0x39, 0xc0, 0x55, 0x2d, 0x07, 0x17, 0x5e, 0xc1, 0x90, 0x5a, 0x14, 0x8e, 0xc3, 0x88, 0x09, 0xa3, 0xeb, 0x73, 0x63, 0x1e, 0x06,
0x98, 0xf5, 0x25, 0x92, 0x68, 0x78, 0x96, 0x05, 0xef, 0x4b, 0x40, 0x78, 0x3c, 0x8a, 0x28, 0x8f, 0xc9, 0xa9, 0x54, 0x63, 0x2f, 0x22, 0xc1, 0x73, 0x2e, 0x3b, 0x9b, 0x71, 0xd7, 0x5c, 0xf8, 0x23,
0x17, 0xa2, 0xcb, 0x31, 0x2f, 0x8e, 0x47, 0x3a, 0xc8, 0xdc, 0x12, 0xfe, 0x01, 0xa7, 0xe1, 0x4a, 0x5c, 0xbb, 0xe5, 0x2b, 0xec, 0xcf, 0x43, 0x1d, 0x1d, 0x6a, 0x9c, 0xd6, 0x9b, 0x50, 0x3f, 0x0d,
0x58, 0x87, 0x98, 0xa3, 0x97, 0x7d, 0xba, 0x50, 0xe7, 0xbc, 0x9f, 0x81, 0x99, 0xa6, 0x1e, 0x50, 0xc7, 0xbd, 0x53, 0x2f, 0x48, 0xa4, 0x70, 0xb7, 0x52, 0x4f, 0x77, 0x0f, 0x17, 0x44, 0x11, 0xd8,
0xa5, 0x50, 0xf9, 0x3c, 0x80, 0x3f, 0x01, 0xc8, 0xe2, 0xda, 0xa1, 0x8a, 0xe7, 0xcf, 0xc9, 0x43, 0xdf, 0x9e, 0x81, 0xd9, 0x07, 0xc1, 0x59, 0xe8, 0xf5, 0xf1, 0xd6, 0x6c, 0x44, 0x47, 0xa1, 0x4c,
0x15, 0x63, 0x18, 0xd7, 0xf7, 0x8f, 0xdd, 0xfe, 0x53, 0x7c, 0x99, 0x82, 0x97, 0x3c, 0x75, 0xc7, 0xc3, 0x65, 0xff, 0x93, 0x6b, 0x30, 0x8b, 0x79, 0x67, 0x63, 0xce, 0xb4, 0x4d, 0x7e, 0xbb, 0x2d,
0x04, 0x31, 0x15, 0x26, 0xdd, 0x55, 0xbc, 0x24, 0xaf, 0x38, 0x3a, 0x44, 0xee, 0x40, 0x03, 0x0f, 0x20, 0xe6, 0x24, 0x44, 0xe9, 0x0b, 0x00, 0x2e, 0x3e, 0x1a, 0xc2, 0x8e, 0x1a, 0x91, 0x9e, 0xc1,
0x92, 0x62, 0x5f, 0x5b, 0xb8, 0xaf, 0x6d, 0xfd, 0xa4, 0x89, 0x3b, 0xab, 0x13, 0xe9, 0xd7, 0x5d, 0x2f, 0x4a, 0x69, 0x9a, 0x73, 0x55, 0x4b, 0x73, 0x66, 0x7d, 0x89, 0x3c, 0x21, 0x9e, 0x48, 0xc2,
0x8b, 0xb9, 0x8c, 0x36, 0x77, 0x30, 0x10, 0xb7, 0x84, 0x6d, 0xec, 0x2d, 0x05, 0x98, 0x55, 0x15, 0xfb, 0x12, 0x10, 0x1e, 0x8f, 0x22, 0xca, 0x43, 0xa2, 0xe8, 0x72, 0xcc, 0x8a, 0xe3, 0x91, 0x0e,
0x0b, 0xc6, 0x09, 0x96, 0x90, 0xc0, 0xc0, 0xc8, 0x35, 0xa8, 0xb1, 0x43, 0xce, 0xd8, 0xf5, 0x06, 0x32, 0xb7, 0x84, 0x7f, 0xc0, 0x69, 0xb8, 0x12, 0xd6, 0x21, 0xe6, 0xe8, 0x65, 0x5f, 0x67, 0xd4,
0x98, 0x12, 0xc7, 0xcf, 0x5a, 0x0a, 0x63, 0x6d, 0xc8, 0xff, 0xf1, 0x36, 0x6f, 0x19, 0x57, 0xc5, 0x39, 0xef, 0x67, 0x60, 0xa6, 0xa9, 0x07, 0x54, 0x29, 0x54, 0x3e, 0x0f, 0xe0, 0xaf, 0x1c, 0xb2,
0xc0, 0xd8, 0xda, 0xa8, 0x32, 0x0a, 0xd3, 0x0a, 0xdf, 0x51, 0x03, 0x24, 0x6f, 0xe1, 0x5d, 0x4d, 0xb8, 0x76, 0xa8, 0xe2, 0x29, 0x82, 0xf2, 0x50, 0xc5, 0x18, 0xc6, 0xf5, 0xfd, 0x63, 0xb7, 0xff,
0x42, 0x3b, 0xab, 0x18, 0x0b, 0x7a, 0x45, 0xcc, 0x59, 0x30, 0xad, 0xfc, 0x7b, 0xc4, 0x48, 0x1c, 0x14, 0x1f, 0xdf, 0xe0, 0x3d, 0x56, 0xdd, 0x31, 0x41, 0xcc, 0xf6, 0x49, 0x77, 0x15, 0xf3, 0x00,
0x4e, 0x69, 0x7f, 0x1a, 0x9a, 0x3a, 0x4c, 0x6a, 0x50, 0x79, 0x78, 0xb8, 0x7b, 0xd0, 0xbe, 0x44, 0x2a, 0x8e, 0x0e, 0x91, 0x3b, 0xd0, 0xc0, 0x83, 0xa4, 0xd8, 0xd7, 0x16, 0xee, 0x6b, 0x5b, 0x3f,
0x1a, 0x30, 0x7f, 0xb4, 0xfb, 0xe8, 0xd1, 0xfe, 0xee, 0x4e, 0xdb, 0x22, 0x4d, 0xa8, 0xa9, 0xbc, 0x69, 0xe2, 0xce, 0xea, 0x44, 0xfa, 0x8d, 0xde, 0x7c, 0x2e, 0x69, 0xcf, 0x1d, 0x0c, 0xc4, 0x45,
0xa5, 0x92, 0x9d, 0x00, 0xd9, 0x1a, 0x0c, 0xc4, 0x77, 0xea, 0x70, 0x9f, 0x72, 0xb0, 0x65, 0x70, 0x68, 0x9b, 0x1f, 0x8a, 0x15, 0xc0, 0xac, 0xaa, 0x58, 0x30, 0x4e, 0xb0, 0x80, 0x04, 0x06, 0x46,
0x70, 0x01, 0x17, 0x95, 0x8a, 0xb9, 0xe8, 0x85, 0x6b, 0x6d, 0xef, 0x42, 0xe3, 0x50, 0x7b, 0xb7, 0xae, 0x43, 0x8d, 0x1d, 0x72, 0xc6, 0xae, 0x37, 0xc0, 0xac, 0x3f, 0x7e, 0xd6, 0x52, 0x18, 0x6b,
0x81, 0x02, 0x25, 0x5f, 0x6c, 0x08, 0x41, 0xd4, 0x10, 0x6d, 0x38, 0x25, 0x7d, 0x38, 0xf6, 0xef, 0x43, 0xfe, 0x8f, 0x17, 0x96, 0x8b, 0xb8, 0x2a, 0x06, 0xc6, 0xd6, 0x46, 0x95, 0x51, 0x98, 0x96,
0x5b, 0x3c, 0x97, 0x5c, 0x0d, 0x9f, 0xf7, 0x6d, 0x43, 0x53, 0x85, 0x60, 0xd2, 0x24, 0x44, 0x03, 0xf8, 0x8e, 0x1a, 0x20, 0x79, 0x0b, 0xaf, 0xa3, 0x12, 0xda, 0x59, 0xc6, 0x70, 0xd7, 0x2b, 0x62,
0x63, 0x34, 0x38, 0x94, 0x5e, 0x78, 0x72, 0x12, 0x53, 0x99, 0x32, 0x64, 0x60, 0x4c, 0x12, 0x98, 0xce, 0x82, 0x69, 0xe5, 0xdf, 0x23, 0x46, 0xe2, 0x70, 0x4a, 0xfb, 0xd3, 0xd0, 0xd4, 0x61, 0x52,
0x4f, 0xc5, 0xfc, 0x13, 0x8f, 0xf7, 0x10, 0x8b, 0xd4, 0xa1, 0x1c, 0xce, 0xf4, 0x7a, 0x44, 0xcf, 0x83, 0xca, 0xc3, 0xc3, 0xdd, 0x83, 0xf6, 0x15, 0xd2, 0x80, 0xd9, 0xa3, 0xdd, 0x47, 0x8f, 0xf6,
0x68, 0x14, 0xab, 0x64, 0x29, 0x55, 0x56, 0xb9, 0x92, 0xd9, 0x55, 0xde, 0x80, 0x9a, 0x6a, 0xd7, 0x77, 0x77, 0xda, 0x16, 0x69, 0x42, 0x4d, 0xa5, 0x66, 0x95, 0xec, 0x04, 0xc8, 0xd6, 0x60, 0x20,
0x54, 0x59, 0x92, 0x52, 0xd5, 0x33, 0xd5, 0x88, 0xa7, 0x0c, 0x63, 0xd0, 0x5c, 0x4d, 0xe7, 0x2b, 0xbe, 0x53, 0x87, 0xfb, 0x94, 0x83, 0x2d, 0x83, 0x83, 0x0b, 0xb8, 0xa8, 0x54, 0xcc, 0x45, 0x2f,
0xc8, 0x2d, 0x20, 0x27, 0x5e, 0x94, 0x25, 0x2f, 0x23, 0x79, 0x41, 0x8d, 0xfd, 0x04, 0x96, 0x25, 0x5c, 0x6b, 0x7b, 0x17, 0x1a, 0x87, 0xda, 0xd3, 0x14, 0x14, 0x28, 0xf9, 0x28, 0x45, 0x08, 0xa2,
0xeb, 0x68, 0xce, 0x94, 0xb9, 0x89, 0xd6, 0x45, 0x02, 0x53, 0xca, 0x0b, 0x8c, 0xfd, 0x9f, 0x16, 0x86, 0x68, 0xc3, 0x29, 0xe9, 0xc3, 0xb1, 0x7f, 0xc7, 0xe2, 0xe9, 0xf2, 0x6a, 0xf8, 0xbc, 0x6f,
0xcc, 0x8b, 0x9d, 0xce, 0xbd, 0xfd, 0xe1, 0xfb, 0x6c, 0x60, 0xa4, 0x63, 0x3c, 0x93, 0x40, 0xe9, 0x1b, 0x9a, 0x2a, 0xca, 0x94, 0xe6, 0x59, 0x1a, 0x18, 0xa3, 0xc1, 0xa1, 0xf4, 0xc2, 0x93, 0x93,
0x12, 0x6a, 0x32, 0xa7, 0x08, 0xcb, 0x45, 0x8a, 0x90, 0x40, 0x65, 0xec, 0x26, 0xa7, 0x78, 0xc2, 0x98, 0xca, 0xac, 0x28, 0x03, 0x63, 0x92, 0xc0, 0x7c, 0x2a, 0xe6, 0x9f, 0x78, 0xbc, 0x87, 0x58,
0xae, 0x3b, 0xf8, 0x3f, 0x69, 0xf3, 0x78, 0x10, 0x57, 0xba, 0x18, 0x0b, 0x2a, 0x7a, 0xe5, 0xc4, 0x64, 0x47, 0xe5, 0x70, 0xa6, 0xd7, 0x45, 0x20, 0x45, 0xe6, 0x83, 0xa9, 0xb2, 0x4a, 0x07, 0xcd,
0xed, 0x7b, 0xfe, 0x95, 0xd3, 0x55, 0xa8, 0xe3, 0x00, 0x7a, 0x69, 0xb8, 0x27, 0x05, 0x18, 0xe7, 0xae, 0xf2, 0x06, 0xd4, 0x54, 0xbb, 0xa6, 0xca, 0x92, 0x94, 0xaa, 0x9e, 0xa9, 0x46, 0x3c, 0x65,
0xf2, 0x02, 0x4a, 0xb2, 0xc8, 0x58, 0x4e, 0x11, 0x7b, 0x95, 0xef, 0xbc, 0x58, 0x02, 0x75, 0xb3, 0x18, 0x83, 0xe6, 0x6a, 0x3a, 0x5f, 0x41, 0x6e, 0x01, 0x39, 0xf1, 0xa2, 0x2c, 0x79, 0x19, 0xc9,
0x2a, 0x72, 0x53, 0x53, 0x38, 0xe5, 0x08, 0x31, 0x80, 0x2c, 0x47, 0x08, 0x52, 0x47, 0xd5, 0xdb, 0x0b, 0x6a, 0xec, 0x27, 0xb0, 0x28, 0x59, 0x47, 0x73, 0xa6, 0xcc, 0x4d, 0xb4, 0x2e, 0x13, 0x98,
0x5d, 0xe8, 0xec, 0x50, 0x9f, 0x26, 0x74, 0xcb, 0xf7, 0xb3, 0xed, 0xbf, 0x02, 0x57, 0x0a, 0xea, 0x52, 0x5e, 0x60, 0xec, 0xff, 0xb0, 0x60, 0x56, 0xec, 0x74, 0xee, 0x79, 0x13, 0xdf, 0x67, 0x03,
0x84, 0xff, 0xfc, 0x25, 0x58, 0xdd, 0xe2, 0x79, 0x7c, 0x3f, 0xa9, 0xdc, 0x14, 0xbb, 0x03, 0x6b, 0x23, 0x1d, 0xe3, 0x25, 0x08, 0x4a, 0x97, 0x50, 0x93, 0x39, 0x45, 0x58, 0x2e, 0x52, 0x84, 0x04,
0xd9, 0x26, 0x45, 0x67, 0xf7, 0x60, 0x69, 0x87, 0x1e, 0x4f, 0x86, 0xfb, 0xf4, 0x2c, 0xed, 0x88, 0x2a, 0x63, 0x37, 0x39, 0xc5, 0x13, 0x76, 0xdd, 0xc1, 0xff, 0x49, 0x9b, 0xc7, 0x83, 0xb8, 0xd2,
0x40, 0x25, 0x3e, 0x0d, 0xcf, 0x85, 0x60, 0xe2, 0xff, 0xe4, 0x55, 0x00, 0x9f, 0xd1, 0xf4, 0xe2, 0xc5, 0x58, 0x50, 0xd1, 0x43, 0x2e, 0x6e, 0xdf, 0xf3, 0x0f, 0xb9, 0xae, 0x41, 0x1d, 0x07, 0xd0,
0x31, 0xed, 0xcb, 0x97, 0x09, 0x88, 0x1c, 0x8d, 0x69, 0xdf, 0x7e, 0x1b, 0x88, 0xde, 0x8e, 0x58, 0x4b, 0xc3, 0x3d, 0x29, 0xc0, 0x38, 0x97, 0x17, 0x50, 0x92, 0x45, 0x52, 0x76, 0x8a, 0xd8, 0xcb,
0x2f, 0x66, 0xf7, 0x26, 0xc7, 0xbd, 0x78, 0x1a, 0x27, 0x74, 0x24, 0x9f, 0x5c, 0xe8, 0x90, 0x7d, 0x7c, 0xe7, 0xc5, 0x12, 0xa8, 0xcb, 0x63, 0x91, 0x7e, 0x9b, 0xc2, 0x29, 0x47, 0x88, 0x01, 0x64,
0x13, 0x9a, 0x87, 0xee, 0xd4, 0xa1, 0xdf, 0x10, 0x4f, 0xbe, 0x2e, 0xc3, 0xfc, 0xd8, 0x9d, 0x32, 0x39, 0x42, 0x90, 0x3a, 0xaa, 0xde, 0xee, 0x42, 0x67, 0x87, 0xfa, 0x34, 0xa1, 0x5b, 0xbe, 0x9f,
0x35, 0xa5, 0xe2, 0x50, 0x58, 0x6d, 0xff, 0x7b, 0x09, 0xe6, 0x38, 0x25, 0x6b, 0x75, 0x40, 0xe3, 0x6d, 0xff, 0x15, 0xb8, 0x5a, 0x50, 0x27, 0xfc, 0xe7, 0x2f, 0xc3, 0xf2, 0x16, 0x4f, 0x55, 0xfc,
0xc4, 0x0b, 0x90, 0xb1, 0x64, 0xab, 0x1a, 0x94, 0x63, 0xe5, 0x52, 0x01, 0x2b, 0x8b, 0x53, 0x9a, 0x49, 0xa5, 0xdf, 0xd8, 0x1d, 0x58, 0xc9, 0x36, 0x29, 0x3a, 0xbb, 0x07, 0x0b, 0x3b, 0xf4, 0x78,
0xcc, 0xf2, 0x16, 0xfc, 0x6a, 0x60, 0x8c, 0xb9, 0xd2, 0x24, 0x31, 0x1e, 0x08, 0x49, 0x81, 0x4c, 0x32, 0xdc, 0xa7, 0x67, 0x69, 0x47, 0x04, 0x2a, 0xf1, 0x69, 0x78, 0x2e, 0x04, 0x13, 0xff, 0x27,
0xc8, 0x32, 0xb5, 0xae, 0x7c, 0x7c, 0x52, 0x4a, 0x05, 0xe7, 0xea, 0x50, 0xa1, 0x0d, 0x9f, 0xe7, 0xaf, 0x02, 0xf8, 0x8c, 0xa6, 0x17, 0x8f, 0x69, 0x5f, 0x3e, 0xbe, 0x40, 0xe4, 0x68, 0x4c, 0xfb,
0x0c, 0x9e, 0xb3, 0xe1, 0x39, 0x5b, 0x5d, 0x7b, 0x09, 0x5b, 0xcd, 0x8f, 0x6e, 0x2f, 0xb2, 0xd5, 0xf6, 0xdb, 0x40, 0xf4, 0x76, 0xc4, 0x7a, 0x31, 0xbb, 0x37, 0x39, 0xee, 0xc5, 0x17, 0x71, 0x42,
0xf0, 0x12, 0xb6, 0xda, 0x26, 0xd0, 0xbe, 0x47, 0xa9, 0x43, 0x99, 0x37, 0x28, 0x79, 0xf7, 0xdb, 0x47, 0xf2, 0x55, 0x89, 0x0e, 0xd9, 0x37, 0xa1, 0x79, 0xe8, 0x5e, 0x38, 0xf4, 0x9b, 0xe2, 0x55,
0x16, 0xb4, 0x05, 0x17, 0xa9, 0x3a, 0xf2, 0xba, 0xe1, 0xf5, 0x16, 0x66, 0x5b, 0xdf, 0x80, 0x05, 0xdb, 0x2a, 0xcc, 0x8e, 0xdd, 0x0b, 0xa6, 0xa6, 0x54, 0x1c, 0x0a, 0xab, 0xed, 0x7f, 0x2b, 0xc1,
0xf4, 0x45, 0x55, 0x6c, 0x56, 0x04, 0x92, 0x0d, 0x90, 0xcd, 0x43, 0x5e, 0x8a, 0x8e, 0x3c, 0x5f, 0x0c, 0xa7, 0x64, 0xad, 0x0e, 0x68, 0x9c, 0x78, 0x01, 0x32, 0x96, 0x6c, 0x55, 0x83, 0x72, 0xac,
0x6c, 0x8a, 0x0e, 0xc9, 0xf0, 0x6e, 0xe4, 0x8a, 0x64, 0x29, 0xcb, 0x51, 0x65, 0xfb, 0x4f, 0x2d, 0x5c, 0x2a, 0x60, 0x65, 0x71, 0x4a, 0x93, 0x89, 0xec, 0x82, 0x5f, 0x0d, 0x8c, 0x31, 0x57, 0x9a,
0x58, 0xd2, 0x06, 0x2c, 0xb8, 0xf0, 0x3d, 0x90, 0xd2, 0xc0, 0x03, 0xb5, 0x5c, 0x72, 0x2f, 0x9b, 0x07, 0xc7, 0x03, 0x21, 0x29, 0x90, 0x09, 0x59, 0xa6, 0xd6, 0x95, 0x8f, 0x4f, 0x4a, 0xa9, 0xe0,
0x62, 0x93, 0x7e, 0x66, 0x10, 0xe3, 0x66, 0xba, 0x53, 0x1c, 0x60, 0x3c, 0x19, 0x09, 0x25, 0xaa, 0x5c, 0x1d, 0x2a, 0xb4, 0xe1, 0xb3, 0x9c, 0xc1, 0x73, 0x36, 0x3c, 0x67, 0xab, 0x6b, 0x2f, 0x61,
0x43, 0x8c, 0x91, 0xce, 0x29, 0x7d, 0xaa, 0x48, 0xb8, 0x1a, 0x37, 0x30, 0x8c, 0x86, 0x31, 0x1f, 0xab, 0xf9, 0xd1, 0xed, 0x45, 0xb6, 0x1a, 0x5e, 0xc2, 0x56, 0xdb, 0x04, 0xda, 0xf7, 0x28, 0x75,
0x5a, 0x11, 0x55, 0x44, 0x34, 0x4c, 0x07, 0xed, 0xbf, 0xb3, 0x60, 0x99, 0x1f, 0x86, 0xc4, 0x51, 0x28, 0xf3, 0x06, 0x25, 0xef, 0x7e, 0xc7, 0x82, 0xb6, 0xe0, 0x22, 0x55, 0x47, 0x5e, 0x37, 0xbc,
0x53, 0x3d, 0x94, 0x99, 0xe3, 0xa7, 0x3f, 0x2e, 0x91, 0x7b, 0x97, 0x1c, 0x51, 0x26, 0x9f, 0x7d, 0xde, 0xc2, 0x84, 0xf2, 0x1b, 0x30, 0x87, 0xbe, 0xa8, 0x8a, 0xcd, 0x8a, 0x40, 0xb2, 0x01, 0xb2,
0xc9, 0x03, 0x9c, 0xca, 0xe0, 0x9a, 0xb1, 0x17, 0xe5, 0xa2, 0xbd, 0x78, 0xc1, 0x4a, 0x17, 0x05, 0x79, 0xc8, 0x7b, 0xdf, 0x91, 0xe7, 0x8b, 0x4d, 0xd1, 0x21, 0x19, 0xde, 0x8d, 0x5c, 0x91, 0x0f,
0x26, 0xab, 0x85, 0x81, 0xc9, 0xbb, 0xf3, 0x50, 0x8d, 0xfb, 0xe1, 0x98, 0xda, 0x6b, 0xb0, 0x62, 0x66, 0x39, 0xaa, 0x6c, 0xff, 0xb1, 0x05, 0x0b, 0xda, 0x80, 0x05, 0x17, 0xbe, 0x07, 0x52, 0x1a,
0x4e, 0x4e, 0xa8, 0xa0, 0xef, 0x5a, 0xd0, 0xb9, 0xc7, 0x03, 0xf8, 0x5e, 0x30, 0xdc, 0xf3, 0xe2, 0x78, 0xa0, 0x96, 0x4b, 0xee, 0xaa, 0x29, 0x36, 0xe9, 0x67, 0x06, 0x31, 0x6e, 0xa6, 0x7b, 0x81,
0x24, 0x8c, 0xd4, 0x7b, 0xc2, 0x6b, 0x00, 0x71, 0xe2, 0x46, 0x09, 0xcf, 0xd3, 0x15, 0x01, 0xc1, 0x03, 0x8c, 0x27, 0x23, 0xa1, 0x44, 0x75, 0x88, 0x31, 0xd2, 0x39, 0xa5, 0x4f, 0x15, 0x09, 0x57,
0x14, 0x61, 0x63, 0xa4, 0xc1, 0x80, 0xd7, 0xf2, 0xbd, 0x51, 0xe5, 0x9c, 0x0f, 0x21, 0x8e, 0x6b, 0xe3, 0x06, 0x86, 0xd1, 0x30, 0xe6, 0x43, 0x2b, 0xa2, 0x8a, 0x88, 0x86, 0xe9, 0xa0, 0xfd, 0xb7,
0x86, 0x25, 0x7e, 0x83, 0x67, 0x34, 0x32, 0x5f, 0x81, 0x9e, 0xa1, 0x5e, 0xe7, 0xe7, 0xa0, 0x0c, 0x16, 0x2c, 0xf2, 0xc3, 0x90, 0x38, 0x6a, 0xaa, 0xb7, 0x40, 0x33, 0xfc, 0xf4, 0xc7, 0x25, 0x72,
0x6a, 0xff, 0x8d, 0x05, 0x8b, 0xe9, 0x20, 0xf1, 0xae, 0xcf, 0xd4, 0x0e, 0xc2, 0xfc, 0xa6, 0xda, 0xef, 0x8a, 0x23, 0xca, 0xe4, 0xb3, 0x2f, 0x79, 0x80, 0x53, 0x49, 0x6a, 0x53, 0xf6, 0xa2, 0x5c,
0x41, 0x86, 0x2a, 0x3d, 0x66, 0x8f, 0xc5, 0xd8, 0x34, 0x04, 0x25, 0x56, 0x94, 0xc2, 0x89, 0x74, 0xb4, 0x17, 0x2f, 0x58, 0xe9, 0xa2, 0xc0, 0x64, 0xb5, 0x30, 0x30, 0x79, 0x77, 0x16, 0xaa, 0x71,
0x70, 0x74, 0x88, 0xe7, 0x27, 0x31, 0x4f, 0x40, 0x78, 0x35, 0xa2, 0x84, 0x69, 0xd6, 0xa3, 0x04, 0x3f, 0x1c, 0x53, 0x7b, 0x05, 0x96, 0xcc, 0xc9, 0x09, 0x15, 0xf4, 0x3d, 0x0b, 0x3a, 0xf7, 0x78,
0xbf, 0xe2, 0x41, 0x55, 0x59, 0x94, 0xa6, 0x74, 0x1e, 0x51, 0x34, 0xa5, 0xfa, 0x65, 0x48, 0x8d, 0x00, 0xdf, 0x0b, 0x86, 0x7b, 0x5e, 0x9c, 0x84, 0x91, 0x7a, 0x32, 0x79, 0x1d, 0x20, 0x4e, 0xdc,
0xaf, 0x8f, 0x2c, 0xdb, 0xbf, 0x66, 0xc1, 0x95, 0x82, 0x85, 0x17, 0x52, 0xb3, 0x03, 0x4b, 0x27, 0x28, 0xe1, 0xa9, 0xc8, 0x22, 0x20, 0x98, 0x22, 0x6c, 0x8c, 0x34, 0x18, 0xf0, 0x5a, 0xbe, 0x37,
0xaa, 0x52, 0x2e, 0x0e, 0x17, 0x9d, 0x35, 0x79, 0x1b, 0x65, 0x2e, 0x88, 0x93, 0xff, 0x40, 0xf9, 0xaa, 0x9c, 0xf3, 0x21, 0xc4, 0x71, 0xcd, 0xb0, 0xc4, 0x6f, 0xf0, 0xa4, 0x4d, 0xe6, 0x2b, 0xd0,
0x45, 0x7c, 0xb9, 0x8d, 0x0c, 0xc0, 0x7c, 0xc5, 0xc6, 0x73, 0x68, 0x68, 0x2f, 0xf9, 0xc8, 0x65, 0x33, 0xd4, 0xeb, 0xfc, 0x1c, 0x94, 0x41, 0xed, 0xbf, 0xb6, 0x60, 0x3e, 0x1d, 0x24, 0x5e, 0x67,
0x58, 0x7e, 0xf2, 0xe0, 0xd1, 0xc1, 0xee, 0xd1, 0x51, 0xef, 0xf0, 0xf1, 0xdd, 0x2f, 0xee, 0x7e, 0x9a, 0xda, 0x41, 0x98, 0xdf, 0x54, 0x3b, 0xc8, 0x50, 0xa5, 0xc7, 0xec, 0xb1, 0x18, 0x9b, 0x86,
0xa5, 0xb7, 0xb7, 0x75, 0xb4, 0xd7, 0xbe, 0x44, 0xd6, 0x80, 0x1c, 0xec, 0x1e, 0x3d, 0xda, 0xdd, 0xa0, 0xc4, 0x8a, 0x52, 0x38, 0x91, 0x0e, 0x8e, 0x0e, 0xf1, 0x14, 0x2c, 0xe6, 0x09, 0x08, 0xaf,
0x31, 0x70, 0x8b, 0x5c, 0x83, 0xee, 0xe3, 0x83, 0xc7, 0x47, 0xbb, 0x3b, 0xbd, 0xa2, 0xef, 0x4a, 0x46, 0x94, 0x30, 0x93, 0x7c, 0x94, 0xe0, 0x57, 0x3c, 0xa8, 0x2a, 0x8b, 0xd2, 0x94, 0xce, 0x22,
0xe4, 0x55, 0xb8, 0x22, 0xea, 0x0b, 0x3e, 0x2f, 0xdf, 0xf9, 0xf5, 0x32, 0xb4, 0xf8, 0x25, 0x29, 0x8a, 0xa6, 0x54, 0xbf, 0x0c, 0xa9, 0xf1, 0xf5, 0x91, 0x65, 0xfb, 0x97, 0x2d, 0xb8, 0x5a, 0xb0,
0xff, 0xe9, 0x08, 0x1a, 0x91, 0xf7, 0x61, 0x5e, 0xfc, 0xf4, 0x07, 0x59, 0x15, 0xb3, 0x36, 0x7f, 0xf0, 0x42, 0x6a, 0x76, 0x60, 0xe1, 0x44, 0x55, 0xca, 0xc5, 0xe1, 0xa2, 0xb3, 0x22, 0x2f, 0xdb,
0x6c, 0xa4, 0xbb, 0x96, 0x85, 0x05, 0x5b, 0x2f, 0xff, 0xfc, 0x0f, 0xff, 0xe9, 0x37, 0x4b, 0x0b, 0xcc, 0x05, 0x71, 0xf2, 0x1f, 0x28, 0xbf, 0x88, 0x2f, 0xb7, 0x91, 0xe4, 0x98, 0xaf, 0xd8, 0x78,
0xa4, 0xb1, 0x79, 0xf6, 0xd6, 0xe6, 0x90, 0x06, 0x31, 0x6b, 0xe3, 0x6b, 0x00, 0xe9, 0x8f, 0x62, 0x0e, 0x0d, 0xed, 0xb1, 0x22, 0x59, 0x85, 0xc5, 0x27, 0x0f, 0x1e, 0x1d, 0xec, 0x1e, 0x1d, 0xf5,
0x90, 0x8e, 0x72, 0x27, 0x33, 0xbf, 0xf6, 0xd1, 0xbd, 0x52, 0x50, 0x23, 0xda, 0xbd, 0x82, 0xed, 0x0e, 0x1f, 0xdf, 0xfd, 0xd2, 0xee, 0x57, 0x7b, 0x7b, 0x5b, 0x47, 0x7b, 0xed, 0x2b, 0x64, 0x05,
0x2e, 0xdb, 0x2d, 0xd6, 0xae, 0x17, 0x78, 0x09, 0xff, 0x85, 0x8c, 0x77, 0xad, 0x0d, 0x32, 0x80, 0xc8, 0xc1, 0xee, 0xd1, 0xa3, 0xdd, 0x1d, 0x03, 0xb7, 0xc8, 0x75, 0xe8, 0x3e, 0x3e, 0x78, 0x7c,
0xa6, 0xfe, 0x9b, 0x17, 0x44, 0x46, 0xb1, 0x0a, 0x7e, 0x71, 0xa3, 0xfb, 0x4a, 0x61, 0x9d, 0x0c, 0xb4, 0xbb, 0xd3, 0x2b, 0xfa, 0xae, 0x44, 0x5e, 0x85, 0xab, 0xa2, 0xbe, 0xe0, 0xf3, 0xf2, 0x9d,
0xe1, 0x61, 0x1f, 0xab, 0x76, 0x9b, 0xf5, 0x31, 0x41, 0x8a, 0xb4, 0x17, 0x1f, 0x5a, 0xe6, 0x4f, 0x5f, 0x29, 0x43, 0x8b, 0xdf, 0x03, 0xf3, 0x5f, 0xc7, 0xa0, 0x11, 0x79, 0x1f, 0x66, 0xc5, 0xaf,
0x5b, 0x90, 0xab, 0x9a, 0xc6, 0xc9, 0xfd, 0xb0, 0x46, 0xf7, 0xd5, 0x19, 0xb5, 0xa2, 0xaf, 0x57, 0x9b, 0x90, 0x65, 0x31, 0x6b, 0xf3, 0xf7, 0x54, 0xba, 0x2b, 0x59, 0x58, 0xb0, 0xf5, 0xe2, 0xcf,
0xb1, 0xaf, 0xcb, 0x36, 0x61, 0x7d, 0xf5, 0x91, 0x46, 0xfe, 0xb0, 0xc6, 0xbb, 0xd6, 0xc6, 0x9d, 0xfc, 0xf0, 0x1f, 0x7f, 0xad, 0x34, 0x47, 0x1a, 0x9b, 0x67, 0x6f, 0x6d, 0x0e, 0x69, 0x10, 0xb3,
0xbf, 0xb8, 0x0e, 0x75, 0x15, 0x77, 0x26, 0x1f, 0xc2, 0x82, 0x71, 0x8b, 0x4d, 0xe4, 0x34, 0x8a, 0x36, 0xbe, 0x0e, 0x90, 0xfe, 0xee, 0x07, 0xe9, 0x28, 0x77, 0x32, 0xf3, 0x83, 0x26, 0xdd, 0xab,
0x2e, 0xbd, 0xbb, 0x57, 0x8b, 0x2b, 0x45, 0xc7, 0xd7, 0xb0, 0xe3, 0x0e, 0x59, 0x63, 0x1d, 0x8b, 0x05, 0x35, 0xa2, 0xdd, 0xab, 0xd8, 0xee, 0xa2, 0xdd, 0x62, 0xed, 0x7a, 0x81, 0x97, 0xf0, 0x1f,
0x6b, 0xe0, 0x4d, 0xcc, 0xc7, 0xe0, 0xc9, 0xd5, 0x4f, 0xf9, 0x3c, 0xd3, 0x9b, 0x67, 0x63, 0x9e, 0x01, 0x79, 0xd7, 0xda, 0x20, 0x03, 0x68, 0xea, 0x3f, 0xeb, 0x41, 0x64, 0x14, 0xab, 0xe0, 0x47,
0xb9, 0x9b, 0x6a, 0x63, 0x9e, 0xf9, 0xeb, 0x6a, 0xfb, 0x2a, 0x76, 0xb7, 0x46, 0x56, 0xf4, 0xee, 0x45, 0xba, 0xaf, 0x14, 0xd6, 0xc9, 0x10, 0x1e, 0xf6, 0xb1, 0x6c, 0xb7, 0x59, 0x1f, 0x13, 0xa4,
0x54, 0x3c, 0x98, 0xe2, 0x8b, 0x00, 0xfd, 0x57, 0x21, 0xc8, 0xab, 0x8a, 0xb1, 0x8a, 0x7e, 0x2d, 0x48, 0x7b, 0xf1, 0xa1, 0x65, 0xfe, 0x7a, 0x07, 0xb9, 0xa6, 0x69, 0x9c, 0xdc, 0x6f, 0x87, 0x74,
0x42, 0xb1, 0x48, 0xfe, 0x27, 0x23, 0xec, 0x0e, 0x76, 0x45, 0x08, 0x6e, 0x9f, 0xfe, 0xa3, 0x10, 0x5f, 0x9d, 0x52, 0x2b, 0xfa, 0x7a, 0x15, 0xfb, 0x5a, 0xb5, 0x09, 0xeb, 0xab, 0x8f, 0x34, 0xf2,
0xe4, 0xab, 0x50, 0x57, 0xaf, 0x80, 0xc9, 0x65, 0xed, 0x55, 0xb6, 0xfe, 0x6a, 0xb9, 0xdb, 0xc9, 0xb7, 0x43, 0xde, 0xb5, 0x36, 0xee, 0xfc, 0xf9, 0x1a, 0xd4, 0x55, 0xdc, 0x99, 0x7c, 0x08, 0x73,
0x57, 0x14, 0x31, 0x86, 0xde, 0x32, 0x63, 0x8c, 0x27, 0xd0, 0xd0, 0x5e, 0xfa, 0x92, 0x2b, 0xea, 0xc6, 0x45, 0x3d, 0x91, 0xd3, 0x28, 0xba, 0xd7, 0xef, 0x5e, 0x2b, 0xae, 0x14, 0x1d, 0x5f, 0xc7,
0xd6, 0x20, 0xfb, 0x9a, 0xb8, 0xdb, 0x2d, 0xaa, 0x12, 0x5d, 0x2c, 0x61, 0x17, 0x0d, 0x52, 0x47, 0x8e, 0x3b, 0x64, 0x85, 0x75, 0x2c, 0x6e, 0xba, 0x37, 0x31, 0xe5, 0x84, 0xe7, 0x8f, 0x3f, 0xe5,
0xde, 0x4b, 0x9e, 0x85, 0x31, 0xd9, 0x87, 0x55, 0x71, 0xee, 0x39, 0xa6, 0x1f, 0x67, 0x89, 0x0a, 0xf3, 0x4c, 0x2f, 0xd7, 0x8d, 0x79, 0xe6, 0x2e, 0xe3, 0x8d, 0x79, 0xe6, 0x6f, 0xe4, 0xed, 0x6b,
0x7e, 0x24, 0xe3, 0xb6, 0x45, 0xde, 0x83, 0x9a, 0x7c, 0xd0, 0x4d, 0xd6, 0x8a, 0x1f, 0xa6, 0x77, 0xd8, 0xdd, 0x0a, 0x59, 0xd2, 0xbb, 0x53, 0xf1, 0x60, 0x8a, 0x8f, 0x1e, 0xf4, 0x1f, 0xbe, 0x20,
0x2f, 0xe7, 0x70, 0xa1, 0x15, 0xbf, 0x02, 0x90, 0x3e, 0x2b, 0x56, 0x02, 0x9c, 0x7b, 0xa6, 0xac, 0xaf, 0x2a, 0xc6, 0x2a, 0xfa, 0x41, 0x0c, 0xc5, 0x22, 0xf9, 0x5f, 0xc5, 0xb0, 0x3b, 0xd8, 0x15,
0x76, 0x27, 0xff, 0x06, 0xd9, 0x5e, 0xc3, 0x09, 0xb6, 0x09, 0x0a, 0x70, 0x40, 0xcf, 0xe5, 0x1b, 0x21, 0xb8, 0x7d, 0xfa, 0xef, 0x5e, 0x90, 0xaf, 0x41, 0x5d, 0x3d, 0x74, 0x26, 0xab, 0xda, 0xc3,
0x99, 0xaf, 0x43, 0x43, 0x7b, 0x59, 0xac, 0x96, 0x2f, 0xff, 0x2a, 0x59, 0x2d, 0x5f, 0xc1, 0x43, 0x73, 0xfd, 0x61, 0x76, 0xb7, 0x93, 0xaf, 0x28, 0x62, 0x0c, 0xbd, 0x65, 0xc6, 0x18, 0x4f, 0xa0,
0x64, 0xbb, 0x8b, 0xad, 0xaf, 0xd8, 0x8b, 0xac, 0xf5, 0xd8, 0x1b, 0x06, 0x23, 0x4e, 0xc0, 0x36, 0xa1, 0x3d, 0x66, 0x26, 0x57, 0xd5, 0xad, 0x41, 0xf6, 0xc1, 0x74, 0xb7, 0x5b, 0x54, 0x25, 0xba,
0xe8, 0x14, 0x16, 0x8c, 0xe7, 0xc3, 0x4a, 0x7a, 0x8a, 0x1e, 0x27, 0x2b, 0xe9, 0x29, 0x7c, 0x71, 0x58, 0xc0, 0x2e, 0x1a, 0xa4, 0x8e, 0xbc, 0x97, 0x3c, 0x0b, 0x63, 0xb2, 0x0f, 0xcb, 0xe2, 0xdc,
0x2c, 0xd9, 0xd9, 0x5e, 0x62, 0xfd, 0x9c, 0x21, 0x89, 0xd6, 0xd3, 0x07, 0xd0, 0xd0, 0x9e, 0x02, 0x73, 0x4c, 0x3f, 0xce, 0x12, 0x15, 0xfc, 0x0e, 0xc8, 0x6d, 0x8b, 0xbc, 0x07, 0x35, 0xf9, 0x66,
0xab, 0xb9, 0xe4, 0x5f, 0x1d, 0xab, 0xb9, 0x14, 0xbd, 0x1c, 0x5e, 0xc1, 0x3e, 0x5a, 0x36, 0xb2, 0x9d, 0xac, 0x14, 0xbf, 0xbd, 0xef, 0xae, 0xe6, 0x70, 0xa1, 0x15, 0xbf, 0x0a, 0x90, 0xbe, 0x9c,
0x02, 0x3e, 0x31, 0x61, 0x6d, 0x7f, 0x08, 0x2d, 0xf3, 0x71, 0xb0, 0x92, 0xcb, 0xc2, 0x67, 0xc6, 0x56, 0x02, 0x9c, 0x7b, 0x89, 0xad, 0x76, 0x27, 0xff, 0xcc, 0xda, 0x5e, 0xc1, 0x09, 0xb6, 0x09,
0x4a, 0x2e, 0x67, 0xbc, 0x28, 0x16, 0x2c, 0xbd, 0xb1, 0xac, 0x3a, 0xd9, 0xfc, 0x48, 0xdc, 0x15, 0x0a, 0x70, 0x40, 0xcf, 0xe5, 0x33, 0xa0, 0x6f, 0x40, 0x43, 0x7b, 0x3c, 0xad, 0x96, 0x2f, 0xff,
0x3f, 0x27, 0x5f, 0x62, 0xca, 0x47, 0xbc, 0xf9, 0x21, 0x97, 0x35, 0xae, 0xd5, 0x5f, 0x06, 0x29, 0xf0, 0x5a, 0x2d, 0x5f, 0xc1, 0x5b, 0x6b, 0xbb, 0x8b, 0xad, 0x2f, 0xd9, 0xf3, 0xac, 0xf5, 0xd8,
0x79, 0xc9, 0x3d, 0x0f, 0x32, 0x99, 0x99, 0x3f, 0x92, 0x41, 0x8b, 0x82, 0x6f, 0x7f, 0x34, 0x8b, 0x1b, 0x06, 0x23, 0x4e, 0xc0, 0x36, 0xe8, 0x14, 0xe6, 0x8c, 0x17, 0xd2, 0x4a, 0x7a, 0x8a, 0xde,
0xa2, 0x3f, 0x0f, 0xd2, 0x2c, 0x8a, 0xf1, 0x44, 0x28, 0x6b, 0x51, 0x12, 0x8f, 0xb5, 0x11, 0xc0, 0x5f, 0x2b, 0xe9, 0x29, 0x7c, 0x54, 0x2d, 0xd9, 0xd9, 0x5e, 0x60, 0xfd, 0x9c, 0x21, 0x89, 0xd6,
0x62, 0x26, 0x0b, 0x4e, 0x49, 0x45, 0x71, 0xda, 0x70, 0xf7, 0xda, 0x8b, 0x93, 0xe7, 0x4c, 0x45, 0xd3, 0x07, 0xd0, 0xd0, 0x5e, 0x3b, 0xab, 0xb9, 0xe4, 0x1f, 0x56, 0xab, 0xb9, 0x14, 0x3d, 0x8e,
0x25, 0x15, 0xd4, 0xa6, 0x4c, 0xd2, 0xfe, 0x19, 0x68, 0xea, 0xcf, 0x36, 0x89, 0x2e, 0xca, 0xd9, 0x5e, 0xc2, 0x3e, 0x5a, 0x36, 0xb2, 0x02, 0xbe, 0xa2, 0x61, 0x6d, 0x7f, 0x08, 0x2d, 0xf3, 0xfd,
0x9e, 0x5e, 0x29, 0xac, 0x33, 0x37, 0x97, 0x34, 0xf5, 0x6e, 0xc8, 0x97, 0x61, 0x4d, 0x89, 0xba, 0xb3, 0x92, 0xcb, 0xc2, 0x97, 0xd4, 0x4a, 0x2e, 0xa7, 0x3c, 0x9a, 0x16, 0x2c, 0xbd, 0xb1, 0xa8,
0x9e, 0x58, 0x15, 0x93, 0xd7, 0x0a, 0xd2, 0xad, 0xf4, 0x68, 0x48, 0xf7, 0xca, 0xcc, 0x7c, 0xac, 0x3a, 0xd9, 0xfc, 0x48, 0xdc, 0x15, 0x3f, 0x27, 0x5f, 0x66, 0xca, 0x47, 0x3c, 0x6b, 0x22, 0xab,
0xdb, 0x16, 0x63, 0x1a, 0xf3, 0x3d, 0x5c, 0xaa, 0xcc, 0x8b, 0x9e, 0x01, 0xa6, 0xca, 0xbc, 0xf0, 0x1a, 0xd7, 0xea, 0x8f, 0x9f, 0x94, 0xbc, 0xe4, 0x5e, 0x40, 0x99, 0xcc, 0xcc, 0xdf, 0x01, 0xa1,
0x11, 0x9d, 0x64, 0x1a, 0xb2, 0x6c, 0xac, 0x11, 0xbf, 0x08, 0x20, 0x1f, 0xc0, 0xa2, 0x96, 0xba, 0x45, 0xc1, 0xe7, 0x4d, 0x9a, 0x45, 0xd1, 0x5f, 0x40, 0x69, 0x16, 0xc5, 0x78, 0x05, 0x95, 0xb5,
0x7a, 0x34, 0x0d, 0xfa, 0x4a, 0x00, 0xf2, 0x6f, 0x1c, 0xba, 0x45, 0xee, 0xba, 0x7d, 0x19, 0xdb, 0x28, 0x89, 0xc7, 0xda, 0x08, 0x60, 0x3e, 0x93, 0xe8, 0xa7, 0xa4, 0xa2, 0x38, 0x33, 0xba, 0x7b,
0x5f, 0xb2, 0x8d, 0xc5, 0x61, 0xcc, 0xbf, 0x0d, 0x0d, 0x3d, 0x2d, 0xf6, 0x05, 0xed, 0x5e, 0xd6, 0xfd, 0xc5, 0xf9, 0x81, 0xa6, 0xa2, 0x92, 0x0a, 0x6a, 0x53, 0xe6, 0xa1, 0xff, 0x7f, 0x68, 0xea,
0xaa, 0xf4, 0x14, 0xfd, 0xdb, 0x16, 0xf9, 0x6d, 0x0b, 0x9a, 0x46, 0x92, 0xa9, 0x71, 0xdd, 0x95, 0x2f, 0x53, 0x89, 0x2e, 0xca, 0xd9, 0x9e, 0x5e, 0x29, 0xac, 0x33, 0x37, 0x97, 0x34, 0xf5, 0x6e,
0x69, 0xa7, 0xa3, 0xd7, 0xe9, 0x0d, 0xd9, 0x0e, 0x0e, 0x72, 0x7f, 0xe3, 0x0b, 0xc6, 0x22, 0x7c, 0xc8, 0x57, 0x60, 0x45, 0x89, 0xba, 0x9e, 0x3b, 0x16, 0x93, 0xd7, 0x0a, 0x32, 0xca, 0xf4, 0x68,
0x64, 0x1c, 0xfb, 0x6e, 0x65, 0x7f, 0x15, 0xe5, 0x79, 0x96, 0x40, 0x7f, 0x07, 0xf2, 0xfc, 0xb6, 0x48, 0xf7, 0xea, 0xd4, 0x94, 0xb3, 0xdb, 0x16, 0x63, 0x1a, 0xf3, 0xc9, 0x5f, 0xaa, 0xcc, 0x8b,
0x45, 0xbe, 0x67, 0x41, 0xcb, 0x0c, 0x56, 0xa8, 0xad, 0x2a, 0x0c, 0x8b, 0xa8, 0xad, 0x9a, 0x11, 0x5e, 0x3a, 0xa6, 0xca, 0xbc, 0xf0, 0x9d, 0xa0, 0x64, 0x1a, 0xb2, 0x68, 0xac, 0x11, 0xbf, 0x08,
0xe1, 0xf8, 0x00, 0x47, 0xf9, 0x68, 0xc3, 0x31, 0x46, 0x29, 0x5e, 0x4a, 0xfe, 0x78, 0xa3, 0x25, 0x20, 0x1f, 0xc0, 0xbc, 0x96, 0x9d, 0x7b, 0x74, 0x11, 0xf4, 0x95, 0x00, 0xe4, 0x9f, 0x71, 0x74,
0xef, 0xf2, 0x5f, 0x46, 0x92, 0x11, 0x34, 0xa2, 0x59, 0x8d, 0xec, 0xf6, 0xea, 0x3f, 0xf6, 0xb3, 0x8b, 0xdc, 0x75, 0x7b, 0x15, 0xdb, 0x5f, 0xb0, 0x8d, 0xc5, 0x61, 0xcc, 0xbf, 0x0d, 0x0d, 0x3d,
0x6e, 0xdd, 0xb6, 0xc8, 0xd7, 0xf9, 0x8f, 0xa7, 0x88, 0x6f, 0x91, 0x4b, 0x5e, 0xf6, 0x7b, 0xfb, 0xf3, 0xf7, 0x05, 0xed, 0xae, 0x6a, 0x55, 0xfa, 0x2b, 0x84, 0xdb, 0x16, 0xf9, 0x0d, 0x0b, 0x9a,
0x06, 0xce, 0xe9, 0x9a, 0x7d, 0xc5, 0x98, 0x53, 0xd6, 0x1e, 0x6f, 0xf1, 0xd1, 0x89, 0xdf, 0xe9, 0x46, 0x1e, 0xad, 0x71, 0xdd, 0x95, 0x69, 0xa7, 0xa3, 0xd7, 0xe9, 0x0d, 0xd9, 0x0e, 0x0e, 0x72,
0x49, 0x0d, 0x4a, 0xee, 0xb7, 0x7b, 0x66, 0x0f, 0x72, 0xc4, 0x07, 0x29, 0xc8, 0x0d, 0x56, 0x7e, 0x7f, 0xe3, 0x8b, 0xc6, 0x22, 0x7c, 0x64, 0x1c, 0xfb, 0x6e, 0x65, 0x7f, 0xf8, 0xe5, 0x79, 0x96,
0xc9, 0x66, 0xec, 0x0d, 0x1c, 0xeb, 0x0d, 0xfb, 0xb5, 0x99, 0x63, 0xdd, 0xc4, 0x90, 0x03, 0x1b, 0x40, 0x7f, 0xea, 0xf2, 0xfc, 0xb6, 0x45, 0xbe, 0x6f, 0x41, 0xcb, 0x0c, 0x56, 0xa8, 0xad, 0x2a,
0xf1, 0x21, 0x40, 0x1a, 0xed, 0x26, 0x99, 0x68, 0xab, 0x12, 0xf0, 0x7c, 0x40, 0xdc, 0x94, 0x17, 0x0c, 0x8b, 0xa8, 0xad, 0x9a, 0x12, 0xe1, 0xf8, 0x00, 0x47, 0xf9, 0x68, 0xc3, 0x31, 0x46, 0x29,
0x19, 0x94, 0x65, 0x2d, 0x7e, 0x95, 0xab, 0xab, 0x07, 0x32, 0x4e, 0xab, 0x3b, 0x25, 0x66, 0x58, 0x1e, 0x83, 0xfe, 0x78, 0xa3, 0x25, 0xef, 0xf2, 0x1f, 0x7f, 0x92, 0x11, 0x34, 0xa2, 0x59, 0x8d,
0xda, 0x70, 0x4a, 0xb2, 0xed, 0x1b, 0xca, 0x4a, 0x05, 0x7d, 0x1f, 0xc3, 0xc2, 0x7e, 0x18, 0x3e, 0xec, 0xf6, 0xea, 0xbf, 0x67, 0xb4, 0x6e, 0xdd, 0xb6, 0xc8, 0x37, 0xf8, 0xef, 0xc3, 0x88, 0x6f,
0x9d, 0x8c, 0xd5, 0x5d, 0x95, 0x19, 0x0d, 0xdc, 0x73, 0xe3, 0xd3, 0x6e, 0x66, 0x16, 0xf6, 0x75, 0x91, 0x4b, 0x5e, 0xf6, 0x7b, 0xfb, 0x06, 0xce, 0xe9, 0xba, 0x7d, 0xd5, 0x98, 0x53, 0xd6, 0x1e,
0x6c, 0xaa, 0x4b, 0x3a, 0x5a, 0x53, 0x9b, 0x1f, 0xa5, 0xd1, 0xf4, 0xe7, 0xc4, 0x85, 0x25, 0xa5, 0x6f, 0xf1, 0xd1, 0x89, 0x9f, 0x22, 0x4a, 0x0d, 0x4a, 0xee, 0xe7, 0x89, 0xa6, 0x0f, 0x72, 0xc4,
0x03, 0xd5, 0xc0, 0xbb, 0x66, 0x33, 0x86, 0xe6, 0xcb, 0x76, 0x61, 0x78, 0xb6, 0x72, 0xb4, 0x9b, 0x07, 0x29, 0xc8, 0x0d, 0x56, 0x7e, 0xc9, 0x66, 0xec, 0x0d, 0x1c, 0xeb, 0x0d, 0xfb, 0xb5, 0xa9,
0xb1, 0x6c, 0xf3, 0xb6, 0x45, 0x0e, 0xa1, 0xb9, 0x43, 0xfb, 0xe1, 0x80, 0x8a, 0x90, 0xda, 0x72, 0x63, 0xdd, 0xc4, 0x90, 0x03, 0x1b, 0xf1, 0x21, 0x40, 0x1a, 0xed, 0x26, 0x99, 0x68, 0xab, 0x12,
0x3a, 0x70, 0x15, 0x8b, 0xeb, 0x2e, 0x18, 0xa0, 0x69, 0x17, 0xc6, 0xee, 0x34, 0xa2, 0xdf, 0xd8, 0xf0, 0x7c, 0x40, 0xdc, 0x94, 0x17, 0x19, 0x94, 0x65, 0x2d, 0x7e, 0x8d, 0xab, 0xab, 0x07, 0x32,
0xfc, 0x48, 0x04, 0xeb, 0x9e, 0x4b, 0xbb, 0x20, 0xa3, 0x99, 0x86, 0x5d, 0xc8, 0x84, 0x3f, 0x0d, 0x4e, 0xab, 0x3b, 0x25, 0x66, 0x58, 0xda, 0x70, 0x4a, 0xb2, 0xed, 0x1b, 0xca, 0x4a, 0x05, 0x7d,
0xbb, 0x90, 0x0b, 0x7f, 0x1a, 0x4b, 0x2d, 0xa3, 0xa9, 0xc4, 0x87, 0xa5, 0x5c, 0xc4, 0x54, 0x99, 0x1f, 0xc3, 0xdc, 0x7e, 0x18, 0x3e, 0x9d, 0x8c, 0xd5, 0x5d, 0x95, 0x19, 0x0d, 0xdc, 0x73, 0xe3,
0x84, 0x59, 0x71, 0xd6, 0xee, 0xf5, 0xd9, 0x04, 0x66, 0x6f, 0x1b, 0x66, 0x6f, 0x47, 0xb0, 0xb0, 0xd3, 0x6e, 0x66, 0x16, 0xf6, 0x1a, 0x36, 0xd5, 0x25, 0x1d, 0xad, 0xa9, 0xcd, 0x8f, 0xd2, 0x68,
0x43, 0xf9, 0x62, 0xf1, 0x84, 0x98, 0x4c, 0xa6, 0xb2, 0x9e, 0x6e, 0x93, 0x55, 0xe0, 0x58, 0x67, 0xfa, 0x73, 0xe2, 0xc2, 0x82, 0xd2, 0x81, 0x6a, 0xe0, 0x5d, 0xb3, 0x19, 0x43, 0xf3, 0x65, 0xbb,
0x1a, 0x7e, 0xcc, 0x46, 0x21, 0x5f, 0x85, 0xc6, 0x7d, 0x9a, 0xc8, 0x0c, 0x18, 0xe5, 0x7a, 0x66, 0x30, 0x3c, 0x5b, 0x39, 0xda, 0xcd, 0x58, 0xb6, 0x79, 0xdb, 0x22, 0x87, 0xd0, 0xdc, 0xa1, 0xfd,
0x52, 0x62, 0xba, 0x05, 0x09, 0x34, 0x26, 0xcf, 0x60, 0x6b, 0x9b, 0x74, 0x30, 0xa4, 0x5c, 0x39, 0x70, 0x40, 0x45, 0x48, 0x6d, 0x31, 0x1d, 0xb8, 0x8a, 0xc5, 0x75, 0xe7, 0x0c, 0xd0, 0xb4, 0x0b,
0xf5, 0xbc, 0xc1, 0x73, 0xf2, 0xd3, 0xd8, 0xb8, 0x4a, 0xd4, 0x5b, 0xd3, 0x12, 0x27, 0xf4, 0xc6, 0x63, 0xf7, 0x22, 0xa2, 0xdf, 0xdc, 0xfc, 0x48, 0x04, 0xeb, 0x9e, 0x4b, 0xbb, 0x20, 0xa3, 0x99,
0x17, 0x33, 0x78, 0x51, 0xcb, 0x41, 0x38, 0xa0, 0x9a, 0x0b, 0x14, 0x40, 0x43, 0xcb, 0x2f, 0x55, 0x86, 0x5d, 0xc8, 0x84, 0x3f, 0x0d, 0xbb, 0x90, 0x0b, 0x7f, 0x1a, 0x4b, 0x2d, 0xa3, 0xa9, 0xc4,
0x02, 0x94, 0xcf, 0x95, 0x55, 0x02, 0x54, 0x90, 0x8e, 0x6a, 0xaf, 0x63, 0x3f, 0x36, 0xb9, 0x9e, 0x87, 0x85, 0x5c, 0xc4, 0x54, 0x99, 0x84, 0x69, 0x71, 0xd6, 0xee, 0xda, 0x74, 0x02, 0xb3, 0xb7,
0xf6, 0xc3, 0x53, 0x50, 0xd3, 0x9e, 0x36, 0x3f, 0x72, 0x47, 0xc9, 0x73, 0xf2, 0x04, 0x9f, 0x4b, 0x0d, 0xb3, 0xb7, 0x23, 0x98, 0xdb, 0xa1, 0x7c, 0xb1, 0x78, 0x42, 0x4c, 0x26, 0x19, 0x5b, 0x4f,
0xeb, 0x59, 0x3e, 0xa9, 0x2f, 0x9d, 0x4d, 0x08, 0x52, 0x8b, 0xa5, 0x55, 0x99, 0xfe, 0x35, 0xef, 0xb7, 0xc9, 0x2a, 0x70, 0xac, 0x33, 0x0d, 0x3f, 0x66, 0xa3, 0x90, 0xaf, 0x41, 0xe3, 0x3e, 0x4d,
0x0a, 0x3d, 0xa5, 0xcf, 0x02, 0x1c, 0x25, 0xe1, 0x78, 0xc7, 0xa5, 0xa3, 0x30, 0x48, 0x75, 0x6d, 0x64, 0x06, 0x8c, 0x72, 0x3d, 0x33, 0x29, 0x31, 0xdd, 0x82, 0x04, 0x1a, 0x93, 0x67, 0xb0, 0xb5,
0x9a, 0xc9, 0x92, 0xea, 0x2f, 0x2d, 0x9d, 0x85, 0x3c, 0xd1, 0x0e, 0x1f, 0x46, 0x92, 0x94, 0x64, 0x4d, 0x3a, 0x18, 0x52, 0xae, 0x9c, 0x7a, 0xde, 0xe0, 0x39, 0xf9, 0x7f, 0xd8, 0xb8, 0x4a, 0xd4,
0xae, 0x99, 0xc9, 0x2e, 0x6a, 0x41, 0x0a, 0x12, 0x5e, 0x6e, 0x5b, 0x64, 0x0b, 0x20, 0x0d, 0x99, 0x5b, 0xd1, 0x12, 0x27, 0xf4, 0xc6, 0xe7, 0x33, 0x78, 0x51, 0xcb, 0x41, 0x38, 0xa0, 0x9a, 0x0b,
0xab, 0xa3, 0x44, 0x2e, 0x1a, 0xaf, 0xd4, 0x5e, 0x41, 0x7c, 0xfd, 0x10, 0xea, 0x69, 0x0c, 0xf6, 0x14, 0x40, 0x43, 0xcb, 0x2f, 0x55, 0x02, 0x94, 0x4f, 0x07, 0x56, 0x02, 0x54, 0x90, 0x8e, 0x6a,
0x72, 0x9a, 0x23, 0x6c, 0x44, 0x6c, 0x95, 0x05, 0xcf, 0x45, 0x46, 0xed, 0x36, 0x2e, 0x15, 0x90, 0xaf, 0x63, 0x3f, 0x36, 0x59, 0x4b, 0xfb, 0xe1, 0x29, 0xa8, 0x69, 0x4f, 0x9b, 0x1f, 0xb9, 0xa3,
0x1a, 0x5b, 0x2a, 0x0c, 0x77, 0x7a, 0xb0, 0xcc, 0x07, 0xa8, 0xdc, 0x11, 0xcc, 0xcd, 0x90, 0x33, 0xe4, 0x39, 0x79, 0x82, 0x2f, 0xc2, 0xf5, 0x2c, 0x9f, 0xd4, 0x97, 0xce, 0x26, 0x04, 0xa9, 0xc5,
0x29, 0x88, 0x4e, 0x2a, 0x69, 0x2e, 0x0c, 0xee, 0x19, 0xd1, 0x0a, 0xc6, 0xad, 0x3c, 0x2f, 0x84, 0xd2, 0xaa, 0x4c, 0xff, 0x9a, 0x77, 0x85, 0x9e, 0xd2, 0x67, 0x01, 0x8e, 0x92, 0x70, 0xbc, 0xe3,
0xa9, 0xe6, 0x11, 0x2c, 0xe5, 0xa2, 0x4f, 0x4a, 0xa4, 0x67, 0x05, 0x04, 0x95, 0x48, 0xcf, 0x0c, 0xd2, 0x51, 0x18, 0xa4, 0xba, 0x36, 0xcd, 0x64, 0x49, 0xf5, 0x97, 0x96, 0xce, 0x42, 0x9e, 0x68,
0x5c, 0xd9, 0xab, 0xd8, 0xe5, 0xa2, 0x0d, 0x78, 0x02, 0x3a, 0xf7, 0x92, 0xfe, 0xe9, 0xbb, 0xd6, 0x87, 0x0f, 0x23, 0x49, 0x4a, 0x32, 0xd7, 0xd4, 0x64, 0x17, 0xb5, 0x20, 0x05, 0x09, 0x2f, 0xb7,
0xc6, 0xdd, 0x9b, 0x1f, 0xfc, 0xaf, 0xa1, 0x97, 0x9c, 0x4e, 0x8e, 0x6f, 0xf5, 0xc3, 0xd1, 0xa6, 0x2d, 0xb2, 0x05, 0x90, 0x86, 0xcc, 0xd5, 0x51, 0x22, 0x17, 0x8d, 0x57, 0x6a, 0xaf, 0x20, 0xbe,
0x2f, 0x43, 0x0a, 0x22, 0xc3, 0x6a, 0xd3, 0x0f, 0x06, 0x9b, 0xd8, 0xf2, 0xf1, 0x1c, 0xfe, 0xac, 0x7e, 0x08, 0xf5, 0x34, 0x06, 0xbb, 0x9a, 0xa6, 0x40, 0x1b, 0x11, 0x5b, 0x65, 0xc1, 0x73, 0x91,
0xec, 0xa7, 0xff, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x16, 0x57, 0x9e, 0x5b, 0x88, 0x56, 0x00, 0x00, 0x51, 0xbb, 0x8d, 0x4b, 0x05, 0xa4, 0xc6, 0x96, 0x0a, 0xc3, 0x9d, 0x1e, 0x2c, 0xf2, 0x01, 0x2a,
0x77, 0x04, 0x73, 0x33, 0xe4, 0x4c, 0x0a, 0xa2, 0x93, 0x4a, 0x9a, 0x0b, 0x83, 0x7b, 0x46, 0xb4,
0x82, 0x71, 0x2b, 0xcf, 0x0b, 0x61, 0xaa, 0x79, 0x04, 0x0b, 0xb9, 0xe8, 0x93, 0x12, 0xe9, 0x69,
0x01, 0x41, 0x25, 0xd2, 0x53, 0x03, 0x57, 0xf6, 0x32, 0x76, 0x39, 0x6f, 0x03, 0x9e, 0x80, 0xce,
0xbd, 0xa4, 0x7f, 0xfa, 0xae, 0xb5, 0x71, 0xf7, 0xe6, 0x07, 0xff, 0x63, 0xe8, 0x25, 0xa7, 0x93,
0xe3, 0x5b, 0xfd, 0x70, 0xb4, 0xe9, 0xcb, 0x90, 0x82, 0xc8, 0xb0, 0xda, 0xf4, 0x83, 0xc1, 0x26,
0xb6, 0x7c, 0x3c, 0x83, 0xbf, 0x9c, 0xfb, 0xe9, 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x58, 0x14,
0xcd, 0xde, 0x6b, 0x57, 0x00, 0x00,
} }

@ -1467,8 +1467,11 @@ message QueryRoutesRequest {
/// The amount to send expressed in satoshis /// The amount to send expressed in satoshis
int64 amt = 2; int64 amt = 2;
/// The max number of routes to return. /**
int32 num_routes = 3; Deprecated. The max number of routes to return. In the future, QueryRoutes
will only return a single route.
*/
int32 num_routes = 3 [deprecated = true];
/// An optional CLTV delta from the current height that should be used for the timelock of the final hop /// An optional CLTV delta from the current height that should be used for the timelock of the final hop
int32 final_cltv_delta = 4; int32 final_cltv_delta = 4;
@ -1480,7 +1483,37 @@ message QueryRoutesRequest {
send the payment. send the payment.
*/ */
FeeLimit fee_limit = 5; FeeLimit fee_limit = 5;
/**
A list of nodes to ignore during path finding.
*/
repeated bytes ignored_nodes = 6;
/**
A list of edges to ignore during path finding.
*/
repeated EdgeLocator ignored_edges = 7;
/**
The source node where the request route should originated from. If empty,
self is assumed.
*/
string source_pub_key = 8;
} }
message EdgeLocator {
/// The short channel id of this edge.
uint64 channel_id = 1;
/**
The direction of this edge. If direction_reverse is false, the direction
of this edge is from the channel endpoint with the lexicographically smaller
pub key to the endpoint with the larger pub key. If direction_reverse is
is true, the edge goes the other way.
*/
bool direction_reverse = 2;
}
message QueryRoutesResponse { message QueryRoutesResponse {
repeated Route routes = 1 [json_name = "routes"]; repeated Route routes = 1 [json_name = "routes"];
} }

@ -564,7 +564,7 @@
}, },
{ {
"name": "num_routes", "name": "num_routes",
"description": "/ The max number of routes to return.", "description": "*\nDeprecated. The max number of routes to return. In the future, QueryRoutes\nwill only return a single route.",
"in": "query", "in": "query",
"required": false, "required": false,
"type": "integer", "type": "integer",
@ -593,6 +593,24 @@
"required": false, "required": false,
"type": "string", "type": "string",
"format": "int64" "format": "int64"
},
{
"name": "ignored_nodes",
"description": "*\nA list of nodes to ignore during path finding.",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "string",
"format": "byte"
}
},
{
"name": "source_pub_key",
"description": "*\nThe source node where the request route should originated from. If empty,\nself is assumed.",
"in": "query",
"required": false,
"type": "string"
} }
], ],
"tags": [ "tags": [

@ -46,7 +46,7 @@ type missionControl struct {
// it was added to the prune view. Edges are added to this map if a // it was added to the prune view. Edges are added to this map if a
// caller reports to missionControl a failure localized to that edge // caller reports to missionControl a failure localized to that edge
// when sending a payment. // when sending a payment.
failedEdges map[edgeLocator]time.Time failedEdges map[EdgeLocator]time.Time
// failedVertexes maps a node's public key that should be pruned, to // failedVertexes maps a node's public key that should be pruned, to
// the time that it was added to the prune view. Vertexes are added to // the time that it was added to the prune view. Vertexes are added to
@ -75,7 +75,7 @@ func newMissionControl(g *channeldb.ChannelGraph, selfNode *channeldb.LightningN
qb func(*channeldb.ChannelEdgeInfo) lnwire.MilliSatoshi) *missionControl { qb func(*channeldb.ChannelEdgeInfo) lnwire.MilliSatoshi) *missionControl {
return &missionControl{ return &missionControl{
failedEdges: make(map[edgeLocator]time.Time), failedEdges: make(map[EdgeLocator]time.Time),
failedVertexes: make(map[Vertex]time.Time), failedVertexes: make(map[Vertex]time.Time),
selfNode: selfNode, selfNode: selfNode,
queryBandwidth: qb, queryBandwidth: qb,
@ -89,7 +89,7 @@ func newMissionControl(g *channeldb.ChannelGraph, selfNode *channeldb.LightningN
// state of the wider network from the PoV of mission control compiled via HTLC // state of the wider network from the PoV of mission control compiled via HTLC
// routing attempts in the past. // routing attempts in the past.
type graphPruneView struct { type graphPruneView struct {
edges map[edgeLocator]struct{} edges map[EdgeLocator]struct{}
vertexes map[Vertex]struct{} vertexes map[Vertex]struct{}
} }
@ -124,7 +124,7 @@ func (m *missionControl) GraphPruneView() graphPruneView {
// We'll also do the same for edges, but use the edgeDecay this time // We'll also do the same for edges, but use the edgeDecay this time
// rather than the decay for vertexes. // rather than the decay for vertexes.
edges := make(map[edgeLocator]struct{}) edges := make(map[EdgeLocator]struct{})
for edge, pruneTime := range m.failedEdges { for edge, pruneTime := range m.failedEdges {
if now.Sub(pruneTime) >= edgeDecay { if now.Sub(pruneTime) >= edgeDecay {
log.Tracef("Pruning decayed failure report for edge %v "+ log.Tracef("Pruning decayed failure report for edge %v "+
@ -153,7 +153,7 @@ func (m *missionControl) GraphPruneView() graphPruneView {
// in order to populate additional edges to explore when finding a path to the // in order to populate additional edges to explore when finding a path to the
// payment's destination. // payment's destination.
func (m *missionControl) NewPaymentSession(routeHints [][]HopHint, func (m *missionControl) NewPaymentSession(routeHints [][]HopHint,
target *btcec.PublicKey) (*paymentSession, error) { target Vertex) (*paymentSession, error) {
viewSnapshot := m.GraphPruneView() viewSnapshot := m.GraphPruneView()
@ -175,7 +175,13 @@ func (m *missionControl) NewPaymentSession(routeHints [][]HopHint,
if i != len(routeHint)-1 { if i != len(routeHint)-1 {
endNode.AddPubKey(routeHint[i+1].NodeID) endNode.AddPubKey(routeHint[i+1].NodeID)
} else { } else {
endNode.AddPubKey(target) targetPubKey, err := btcec.ParsePubKey(
target[:], btcec.S256(),
)
if err != nil {
return nil, err
}
endNode.AddPubKey(targetPubKey)
} }
// Finally, create the channel edge from the hop hint // Finally, create the channel edge from the hop hint
@ -217,7 +223,7 @@ func (m *missionControl) NewPaymentSession(routeHints [][]HopHint,
pruneViewSnapshot: viewSnapshot, pruneViewSnapshot: viewSnapshot,
additionalEdges: edges, additionalEdges: edges,
bandwidthHints: bandwidthHints, bandwidthHints: bandwidthHints,
errFailedPolicyChans: make(map[edgeLocator]struct{}), errFailedPolicyChans: make(map[EdgeLocator]struct{}),
mc: m, mc: m,
}, nil }, nil
} }
@ -231,7 +237,7 @@ func (m *missionControl) NewPaymentSessionFromRoutes(routes []*Route) *paymentSe
pruneViewSnapshot: m.GraphPruneView(), pruneViewSnapshot: m.GraphPruneView(),
haveRoutes: true, haveRoutes: true,
preBuiltRoutes: routes, preBuiltRoutes: routes,
errFailedPolicyChans: make(map[edgeLocator]struct{}), errFailedPolicyChans: make(map[EdgeLocator]struct{}),
mc: m, mc: m,
} }
} }
@ -275,7 +281,7 @@ func generateBandwidthHints(sourceNode *channeldb.LightningNode,
// if no payment attempts have been made. // if no payment attempts have been made.
func (m *missionControl) ResetHistory() { func (m *missionControl) ResetHistory() {
m.Lock() m.Lock()
m.failedEdges = make(map[edgeLocator]time.Time) m.failedEdges = make(map[EdgeLocator]time.Time)
m.failedVertexes = make(map[Vertex]time.Time) m.failedVertexes = make(map[Vertex]time.Time)
m.Unlock() m.Unlock()
} }

@ -1,7 +1,6 @@
package routing package routing
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"math" "math"
@ -210,7 +209,7 @@ func (r *Route) ToHopPayloads() []sphinx.HopData {
// //
// NOTE: The passed slice of ChannelHops MUST be sorted in forward order: from // NOTE: The passed slice of ChannelHops MUST be sorted in forward order: from
// the source to the target node of the path finding attempt. // the source to the target node of the path finding attempt.
func newRoute(amtToSend, feeLimit lnwire.MilliSatoshi, sourceVertex Vertex, func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex,
pathEdges []*channeldb.ChannelEdgePolicy, currentHeight uint32, pathEdges []*channeldb.ChannelEdgePolicy, currentHeight uint32,
finalCLTVDelta uint16) (*Route, error) { finalCLTVDelta uint16) (*Route, error) {
@ -310,13 +309,6 @@ func newRoute(amtToSend, feeLimit lnwire.MilliSatoshi, sourceVertex Vertex,
return nil, err return nil, err
} }
// Invalidate this route if its total fees exceed our fee limit.
if newRoute.TotalFees > feeLimit {
err := fmt.Sprintf("total route fees exceeded fee "+
"limit of %v", feeLimit)
return nil, newErrf(ErrFeeLimitExceeded, err)
}
return newRoute, nil return newRoute, nil
} }
@ -405,24 +397,24 @@ type graphParams struct {
bandwidthHints map[uint64]lnwire.MilliSatoshi bandwidthHints map[uint64]lnwire.MilliSatoshi
} }
// restrictParams wraps the set of restrictions passed to findPath that the // RestrictParams wraps the set of restrictions passed to findPath that the
// found path must adhere to. // found path must adhere to.
type restrictParams struct { type RestrictParams struct {
// ignoredNodes is an optional set of nodes that should be ignored if // IgnoredNodes is an optional set of nodes that should be ignored if
// encountered during path finding. // encountered during path finding.
ignoredNodes map[Vertex]struct{} IgnoredNodes map[Vertex]struct{}
// ignoredEdges is an optional set of edges that should be ignored if // IgnoredEdges is an optional set of edges that should be ignored if
// encountered during path finding. // encountered during path finding.
ignoredEdges map[edgeLocator]struct{} IgnoredEdges map[EdgeLocator]struct{}
// feeLimit is a maximum fee amount allowed to be used on the path from // FeeLimit is a maximum fee amount allowed to be used on the path from
// the source to the target. // the source to the target.
feeLimit lnwire.MilliSatoshi FeeLimit lnwire.MilliSatoshi
// outgoingChannelID is the channel that needs to be taken to the first // OutgoingChannelID is the channel that needs to be taken to the first
// hop. If nil, any channel may be used. // hop. If nil, any channel may be used.
outgoingChannelID *uint64 OutgoingChannelID *uint64
} }
// findPath attempts to find a path from the source node within the // findPath attempts to find a path from the source node within the
@ -436,8 +428,7 @@ type restrictParams struct {
// destination node back to source. This is to properly accumulate fees // destination node back to source. This is to properly accumulate fees
// that need to be paid along the path and accurately check the amount // that need to be paid along the path and accurately check the amount
// to forward at every node against the available bandwidth. // to forward at every node against the available bandwidth.
func findPath(g *graphParams, r *restrictParams, func findPath(g *graphParams, r *RestrictParams, source, target Vertex,
sourceNode *channeldb.LightningNode, target *btcec.PublicKey,
amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy, error) { amt lnwire.MilliSatoshi) ([]*channeldb.ChannelEdgePolicy, error) {
var err error var err error
@ -498,17 +489,14 @@ func findPath(g *graphParams, r *restrictParams,
} }
} }
sourceVertex := Vertex(sourceNode.PubKeyBytes)
// We can't always assume that the end destination is publicly // We can't always assume that the end destination is publicly
// advertised to the network and included in the graph.ForEachNode call // advertised to the network and included in the graph.ForEachNode call
// above, so we'll manually include the target node. The target node // above, so we'll manually include the target node. The target node
// charges no fee. Distance is set to 0, because this is the starting // charges no fee. Distance is set to 0, because this is the starting
// point of the graph traversal. We are searching backwards to get the // point of the graph traversal. We are searching backwards to get the
// fees first time right and correctly match channel bandwidth. // fees first time right and correctly match channel bandwidth.
targetVertex := NewVertex(target) targetNode := &channeldb.LightningNode{PubKeyBytes: target}
targetNode := &channeldb.LightningNode{PubKeyBytes: targetVertex} distance[target] = nodeWithDist{
distance[targetVertex] = nodeWithDist{
dist: 0, dist: 0,
node: targetNode, node: targetNode,
amountToReceive: amt, amountToReceive: amt,
@ -520,6 +508,15 @@ func findPath(g *graphParams, r *restrictParams,
// mapped to within `next`. // mapped to within `next`.
next := make(map[Vertex]*channeldb.ChannelEdgePolicy) next := make(map[Vertex]*channeldb.ChannelEdgePolicy)
ignoredEdges := r.IgnoredEdges
if ignoredEdges == nil {
ignoredEdges = make(map[EdgeLocator]struct{})
}
ignoredNodes := r.IgnoredNodes
if ignoredNodes == nil {
ignoredNodes = make(map[Vertex]struct{})
}
// processEdge is a helper closure that will be used to make sure edges // processEdge is a helper closure that will be used to make sure edges
// satisfy our specific requirements. // satisfy our specific requirements.
processEdge := func(fromNode *channeldb.LightningNode, processEdge := func(fromNode *channeldb.LightningNode,
@ -532,7 +529,7 @@ func findPath(g *graphParams, r *restrictParams,
// skip it. // skip it.
// TODO(halseth): also ignore disable flags for non-local // TODO(halseth): also ignore disable flags for non-local
// channels if bandwidth hint is set? // channels if bandwidth hint is set?
isSourceChan := fromVertex == sourceVertex isSourceChan := fromVertex == source
edgeFlags := edge.ChannelFlags edgeFlags := edge.ChannelFlags
isDisabled := edgeFlags&lnwire.ChanUpdateDisabled != 0 isDisabled := edgeFlags&lnwire.ChanUpdateDisabled != 0
@ -543,20 +540,20 @@ func findPath(g *graphParams, r *restrictParams,
// If we have an outgoing channel restriction and this is not // If we have an outgoing channel restriction and this is not
// the specified channel, skip it. // the specified channel, skip it.
if isSourceChan && r.outgoingChannelID != nil && if isSourceChan && r.OutgoingChannelID != nil &&
*r.outgoingChannelID != edge.ChannelID { *r.OutgoingChannelID != edge.ChannelID {
return return
} }
// If this vertex or edge has been black listed, then we'll // If this vertex or edge has been black listed, then we'll
// skip exploring this edge. // skip exploring this edge.
if _, ok := r.ignoredNodes[fromVertex]; ok { if _, ok := ignoredNodes[fromVertex]; ok {
return return
} }
locator := newEdgeLocator(edge) locator := newEdgeLocator(edge)
if _, ok := r.ignoredEdges[*locator]; ok { if _, ok := ignoredEdges[*locator]; ok {
return return
} }
@ -595,7 +592,7 @@ func findPath(g *graphParams, r *restrictParams,
// node, no additional timelock is required. // node, no additional timelock is required.
var fee lnwire.MilliSatoshi var fee lnwire.MilliSatoshi
var timeLockDelta uint16 var timeLockDelta uint16
if fromVertex != sourceVertex { if fromVertex != source {
fee = computeFee(amountToSend, edge) fee = computeFee(amountToSend, edge)
timeLockDelta = edge.TimeLockDelta timeLockDelta = edge.TimeLockDelta
} }
@ -610,7 +607,7 @@ func findPath(g *graphParams, r *restrictParams,
// Check if accumulated fees would exceed fee limit when this // Check if accumulated fees would exceed fee limit when this
// node would be added to the path. // node would be added to the path.
totalFee := amountToReceive - amt totalFee := amountToReceive - amt
if totalFee > r.feeLimit { if totalFee > r.FeeLimit {
return return
} }
@ -664,7 +661,7 @@ func findPath(g *graphParams, r *restrictParams,
// To start, our target node will the sole item within our distance // To start, our target node will the sole item within our distance
// heap. // heap.
heap.Push(&nodeHeap, distance[targetVertex]) heap.Push(&nodeHeap, distance[target])
for nodeHeap.Len() != 0 { for nodeHeap.Len() != 0 {
// Fetch the node within the smallest distance from our source // Fetch the node within the smallest distance from our source
@ -675,7 +672,7 @@ func findPath(g *graphParams, r *restrictParams,
// If we've reached our source (or we don't have any incoming // If we've reached our source (or we don't have any incoming
// edges), then we're done here and can exit the graph // edges), then we're done here and can exit the graph
// traversal early. // traversal early.
if bytes.Equal(bestNode.PubKeyBytes[:], sourceVertex[:]) { if bestNode.PubKeyBytes == source {
break break
} }
@ -742,7 +739,7 @@ func findPath(g *graphParams, r *restrictParams,
// If the source node isn't found in the next hop map, then a path // If the source node isn't found in the next hop map, then a path
// doesn't exist, so we terminate in an error. // doesn't exist, so we terminate in an error.
if _, ok := next[sourceVertex]; !ok { if _, ok := next[source]; !ok {
return nil, newErrf(ErrNoPathFound, "unable to find a path to "+ return nil, newErrf(ErrNoPathFound, "unable to find a path to "+
"destination") "destination")
} }
@ -750,8 +747,8 @@ func findPath(g *graphParams, r *restrictParams,
// Use the nextHop map to unravel the forward path from source to // Use the nextHop map to unravel the forward path from source to
// target. // target.
pathEdges := make([]*channeldb.ChannelEdgePolicy, 0, len(next)) pathEdges := make([]*channeldb.ChannelEdgePolicy, 0, len(next))
currentNode := sourceVertex currentNode := source
for currentNode != targetVertex { // TODO(roasbeef): assumes no cycles for currentNode != target { // TODO(roasbeef): assumes no cycles
// Determine the next hop forward using the next map. // Determine the next hop forward using the next map.
nextNode := next[currentNode] nextNode := next[currentNode]
@ -787,12 +784,10 @@ func findPath(g *graphParams, r *restrictParams,
// algorithm, rather than attempting to use an unmodified path finding // algorithm, rather than attempting to use an unmodified path finding
// algorithm in a block box manner. // algorithm in a block box manner.
func findPaths(tx *bbolt.Tx, graph *channeldb.ChannelGraph, func findPaths(tx *bbolt.Tx, graph *channeldb.ChannelGraph,
source *channeldb.LightningNode, target *btcec.PublicKey, source, target Vertex, amt lnwire.MilliSatoshi,
amt lnwire.MilliSatoshi, feeLimit lnwire.MilliSatoshi, numPaths uint32, restrictions *RestrictParams, numPaths uint32,
bandwidthHints map[uint64]lnwire.MilliSatoshi) ([][]*channeldb.ChannelEdgePolicy, error) { bandwidthHints map[uint64]lnwire.MilliSatoshi) (
[][]*channeldb.ChannelEdgePolicy, error) {
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
// TODO(roasbeef): modifying ordering within heap to eliminate final // TODO(roasbeef): modifying ordering within heap to eliminate final
// sorting step? // sorting step?
@ -810,12 +805,7 @@ func findPaths(tx *bbolt.Tx, graph *channeldb.ChannelGraph,
graph: graph, graph: graph,
bandwidthHints: bandwidthHints, bandwidthHints: bandwidthHints,
}, },
&restrictParams{ restrictions, source, target, amt,
ignoredNodes: ignoredVertexes,
ignoredEdges: ignoredEdges,
feeLimit: feeLimit,
},
source, target, amt,
) )
if err != nil { if err != nil {
log.Errorf("Unable to find path: %v", err) log.Errorf("Unable to find path: %v", err)
@ -827,7 +817,7 @@ func findPaths(tx *bbolt.Tx, graph *channeldb.ChannelGraph,
// function properly. // function properly.
firstPath := make([]*channeldb.ChannelEdgePolicy, 0, len(startingPath)+1) firstPath := make([]*channeldb.ChannelEdgePolicy, 0, len(startingPath)+1)
firstPath = append(firstPath, &channeldb.ChannelEdgePolicy{ firstPath = append(firstPath, &channeldb.ChannelEdgePolicy{
Node: source, Node: &channeldb.LightningNode{PubKeyBytes: source},
}) })
firstPath = append(firstPath, startingPath...) firstPath = append(firstPath, startingPath...)
@ -846,8 +836,15 @@ func findPaths(tx *bbolt.Tx, graph *channeldb.ChannelGraph,
// we'll exclude from the next path finding attempt. // we'll exclude from the next path finding attempt.
// These are required to ensure the paths are unique // These are required to ensure the paths are unique
// and loopless. // and loopless.
ignoredEdges = make(map[edgeLocator]struct{}) ignoredEdges := make(map[EdgeLocator]struct{})
ignoredVertexes = make(map[Vertex]struct{}) ignoredVertexes := make(map[Vertex]struct{})
for e := range restrictions.IgnoredEdges {
ignoredEdges[e] = struct{}{}
}
for n := range restrictions.IgnoredNodes {
ignoredVertexes[n] = struct{}{}
}
// Our spur node is the i-th node in the prior shortest // Our spur node is the i-th node in the prior shortest
// path, and our root path will be all nodes in the // path, and our root path will be all nodes in the
@ -888,17 +885,27 @@ func findPaths(tx *bbolt.Tx, graph *channeldb.ChannelGraph,
// the Vertexes (other than the spur path) within the // the Vertexes (other than the spur path) within the
// root path removed, we'll attempt to find another // root path removed, we'll attempt to find another
// shortest path from the spur node to the destination. // shortest path from the spur node to the destination.
//
// TODO: Fee limit passed to spur path finding isn't
// correct, because it doesn't take into account the
// fees already paid on the root path.
//
// TODO: Outgoing channel restriction isn't obeyed for
// spur paths.
spurRestrictions := &RestrictParams{
IgnoredEdges: ignoredEdges,
IgnoredNodes: ignoredVertexes,
FeeLimit: restrictions.FeeLimit,
}
spurPath, err := findPath( spurPath, err := findPath(
&graphParams{ &graphParams{
tx: tx, tx: tx,
graph: graph, graph: graph,
bandwidthHints: bandwidthHints, bandwidthHints: bandwidthHints,
}, },
&restrictParams{ spurRestrictions, spurNode.PubKeyBytes,
ignoredNodes: ignoredVertexes, target, amt,
ignoredEdges: ignoredEdges,
feeLimit: feeLimit,
}, spurNode, target, amt,
) )
// If we weren't able to find a path, we'll continue to // If we weren't able to find a path, we'll continue to

@ -47,6 +47,12 @@ const (
noFeeLimit = lnwire.MilliSatoshi(math.MaxUint32) noFeeLimit = lnwire.MilliSatoshi(math.MaxUint32)
) )
var (
noRestrictions = &RestrictParams{
FeeLimit: noFeeLimit,
}
)
var ( var (
testSig = &btcec.Signature{ testSig = &btcec.Signature{
R: new(big.Int), R: new(big.Int),
@ -156,7 +162,7 @@ func parseTestGraph(path string) (*testGraphInstance, error) {
return nil, err return nil, err
} }
aliasMap := make(map[string]*btcec.PublicKey) aliasMap := make(map[string]Vertex)
var source *channeldb.LightningNode var source *channeldb.LightningNode
// First we insert all the nodes within the graph as vertexes. // First we insert all the nodes within the graph as vertexes.
@ -183,14 +189,9 @@ func parseTestGraph(path string) (*testGraphInstance, error) {
"must be unique!") "must be unique!")
} }
pub, err := btcec.ParsePubKey(pubBytes, btcec.S256())
if err != nil {
return nil, err
}
// If the alias is unique, then add the node to the // If the alias is unique, then add the node to the
// alias map for easy lookup. // alias map for easy lookup.
aliasMap[node.Alias] = pub aliasMap[node.Alias] = dbNode.PubKeyBytes
// If the node is tagged as the source, then we create a // If the node is tagged as the source, then we create a
// pointer to is so we can mark the source in the graph // pointer to is so we can mark the source in the graph
@ -359,7 +360,7 @@ type testGraphInstance struct {
// aliasMap is a map from a node's alias to its public key. This type is // aliasMap is a map from a node's alias to its public key. This type is
// provided in order to allow easily look up from the human memorable alias // provided in order to allow easily look up from the human memorable alias
// to an exact node's public key. // to an exact node's public key.
aliasMap map[string]*btcec.PublicKey aliasMap map[string]Vertex
// privKeyMap maps a node alias to its private key. This is used to be // privKeyMap maps a node alias to its private key. This is used to be
// able to mock a remote node's signing behaviour. // able to mock a remote node's signing behaviour.
@ -388,7 +389,7 @@ func createTestGraphFromChannels(testChannels []*testChannel) (*testGraphInstanc
return nil, err return nil, err
} }
aliasMap := make(map[string]*btcec.PublicKey) aliasMap := make(map[string]Vertex)
privKeyMap := make(map[string]*btcec.PrivateKey) privKeyMap := make(map[string]*btcec.PrivateKey)
nodeIndex := byte(0) nodeIndex := byte(0)
@ -423,7 +424,7 @@ func createTestGraphFromChannels(testChannels []*testChannel) (*testGraphInstanc
return nil, err return nil, err
} }
aliasMap[alias] = pubKey aliasMap[alias] = dbNode.PubKeyBytes
nodeIndex++ nodeIndex++
return dbNode, nil return dbNode, nil
@ -476,16 +477,13 @@ func createTestGraphFromChannels(testChannels []*testChannel) (*testGraphInstanc
AuthProof: &testAuthProof, AuthProof: &testAuthProof,
ChannelPoint: *fundingPoint, ChannelPoint: *fundingPoint,
Capacity: testChannel.Capacity, Capacity: testChannel.Capacity,
NodeKey1Bytes: aliasMap[testChannel.Node1.Alias],
BitcoinKey1Bytes: aliasMap[testChannel.Node1.Alias],
NodeKey2Bytes: aliasMap[testChannel.Node2.Alias],
BitcoinKey2Bytes: aliasMap[testChannel.Node2.Alias],
} }
node1Bytes := aliasMap[testChannel.Node1.Alias].SerializeCompressed()
node2Bytes := aliasMap[testChannel.Node2.Alias].SerializeCompressed()
copy(edgeInfo.NodeKey1Bytes[:], node1Bytes)
copy(edgeInfo.NodeKey2Bytes[:], node2Bytes)
copy(edgeInfo.BitcoinKey1Bytes[:], node1Bytes)
copy(edgeInfo.BitcoinKey2Bytes[:], node2Bytes)
err = graph.AddChannelEdge(&edgeInfo) err = graph.AddChannelEdge(&edgeInfo)
if err != nil && err != channeldb.ErrEdgeAlreadyExist { if err != nil && err != channeldb.ErrEdgeAlreadyExist {
return nil, err return nil, err
@ -598,9 +596,6 @@ func TestFindLowestFeePath(t *testing.T) {
} }
sourceVertex := Vertex(sourceNode.PubKeyBytes) sourceVertex := Vertex(sourceNode.PubKeyBytes)
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
const ( const (
startingHeight = 100 startingHeight = 100
finalHopCLTV = 1 finalHopCLTV = 1
@ -612,38 +607,35 @@ func TestFindLowestFeePath(t *testing.T) {
&graphParams{ &graphParams{
graph: testGraphInstance.graph, graph: testGraphInstance.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, paymentAmt, sourceNode.PubKeyBytes, target, paymentAmt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find path: %v", err) t.Fatalf("unable to find path: %v", err)
} }
route, err := newRoute( route, err := newRoute(
paymentAmt, infinity, sourceVertex, path, startingHeight, paymentAmt, sourceVertex, path, startingHeight,
finalHopCLTV) finalHopCLTV)
if err != nil { if err != nil {
t.Fatalf("unable to create path: %v", err) t.Fatalf("unable to create path: %v", err)
} }
// Assert that the lowest fee route is returned. // Assert that the lowest fee route is returned.
if !bytes.Equal(route.Hops[1].PubKeyBytes[:], if route.Hops[1].PubKeyBytes != testGraphInstance.aliasMap["b"] {
testGraphInstance.aliasMap["b"].SerializeCompressed()) {
t.Fatalf("expected route to pass through b, "+ t.Fatalf("expected route to pass through b, "+
"but got a route through %v", "but got a route through %v",
getAliasFromPubKey(route.Hops[1].PubKeyBytes[:], getAliasFromPubKey(route.Hops[1].PubKeyBytes,
testGraphInstance.aliasMap)) testGraphInstance.aliasMap))
} }
} }
func getAliasFromPubKey(pubKey []byte, func getAliasFromPubKey(pubKey Vertex,
aliases map[string]*btcec.PublicKey) string { aliases map[string]Vertex) string {
for alias, key := range aliases { for alias, key := range aliases {
if bytes.Equal(key.SerializeCompressed(), pubKey) { if key == pubKey {
return alias return alias
} }
} }
@ -744,9 +736,6 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
} }
sourceVertex := Vertex(sourceNode.PubKeyBytes) sourceVertex := Vertex(sourceNode.PubKeyBytes)
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
const ( const (
startingHeight = 100 startingHeight = 100
finalHopCLTV = 1 finalHopCLTV = 1
@ -758,12 +747,10 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
&graphParams{ &graphParams{
graph: graphInstance.graph, graph: graphInstance.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: test.feeLimit,
ignoredEdges: ignoredEdges,
feeLimit: test.feeLimit,
}, },
sourceNode, target, paymentAmt, sourceNode.PubKeyBytes, target, paymentAmt,
) )
if test.expectFailureNoPath { if test.expectFailureNoPath {
if err == nil { if err == nil {
@ -776,7 +763,7 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
} }
route, err := newRoute( route, err := newRoute(
paymentAmt, test.feeLimit, sourceVertex, path, startingHeight, paymentAmt, sourceVertex, path, startingHeight,
finalHopCLTV, finalHopCLTV,
) )
if err != nil { if err != nil {
@ -790,12 +777,11 @@ func testBasicGraphPathFindingCase(t *testing.T, graphInstance *testGraphInstanc
// Check hop nodes // Check hop nodes
for i := 0; i < len(expectedHops); i++ { for i := 0; i < len(expectedHops); i++ {
if !bytes.Equal(route.Hops[i].PubKeyBytes[:], if route.Hops[i].PubKeyBytes != aliases[expectedHops[i].alias] {
aliases[expectedHops[i].alias].SerializeCompressed()) {
t.Fatalf("%v-th hop should be %v, is instead: %v", t.Fatalf("%v-th hop should be %v, is instead: %v",
i, expectedHops[i], i, expectedHops[i],
getAliasFromPubKey(route.Hops[i].PubKeyBytes[:], getAliasFromPubKey(route.Hops[i].PubKeyBytes,
aliases)) aliases))
} }
} }
@ -904,6 +890,8 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) {
doge := &channeldb.LightningNode{} doge := &channeldb.LightningNode{}
doge.AddPubKey(dogePubKey) doge.AddPubKey(dogePubKey)
doge.Alias = "doge" doge.Alias = "doge"
copy(doge.PubKeyBytes[:], dogePubKeyBytes)
graph.aliasMap["doge"] = doge.PubKeyBytes
// Create the channel edge going from songoku to doge and include it in // Create the channel edge going from songoku to doge and include it in
// our map of additional edges. // our map of additional edges.
@ -916,7 +904,7 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) {
} }
additionalEdges := map[Vertex][]*channeldb.ChannelEdgePolicy{ additionalEdges := map[Vertex][]*channeldb.ChannelEdgePolicy{
NewVertex(graph.aliasMap["songoku"]): {songokuToDoge}, graph.aliasMap["songoku"]: {songokuToDoge},
} }
// We should now be able to find a path from roasbeef to doge. // We should now be able to find a path from roasbeef to doge.
@ -925,10 +913,10 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) {
graph: graph.graph, graph: graph.graph,
additionalEdges: additionalEdges, additionalEdges: additionalEdges,
}, },
&restrictParams{ &RestrictParams{
feeLimit: noFeeLimit, FeeLimit: noFeeLimit,
}, },
sourceNode, dogePubKey, paymentAmt, sourceNode.PubKeyBytes, doge.PubKeyBytes, paymentAmt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find private path to doge: %v", err) t.Fatalf("unable to find private path to doge: %v", err)
@ -936,7 +924,7 @@ func TestPathFindingWithAdditionalEdges(t *testing.T) {
// The path should represent the following hops: // The path should represent the following hops:
// roasbeef -> songoku -> doge // roasbeef -> songoku -> doge
assertExpectedPath(t, path, "songoku", "doge") assertExpectedPath(t, graph.aliasMap, path, "songoku", "doge")
} }
func TestKShortestPathFinding(t *testing.T) { func TestKShortestPathFinding(t *testing.T) {
@ -963,9 +951,12 @@ func TestKShortestPathFinding(t *testing.T) {
paymentAmt := lnwire.NewMSatFromSatoshis(100) paymentAmt := lnwire.NewMSatFromSatoshis(100)
target := graph.aliasMap["luoji"] target := graph.aliasMap["luoji"]
restrictions := &RestrictParams{
FeeLimit: noFeeLimit,
}
paths, err := findPaths( paths, err := findPaths(
nil, graph.graph, sourceNode, target, paymentAmt, noFeeLimit, 100, nil, graph.graph, sourceNode.PubKeyBytes, target, paymentAmt,
nil, restrictions, 100, nil,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find paths between roasbeef and "+ t.Fatalf("unable to find paths between roasbeef and "+
@ -985,10 +976,12 @@ func TestKShortestPathFinding(t *testing.T) {
} }
// The first route should be a direct route to luo ji. // The first route should be a direct route to luo ji.
assertExpectedPath(t, paths[0], "roasbeef", "luoji") assertExpectedPath(t, graph.aliasMap, paths[0], "roasbeef", "luoji")
// The second route should be a route to luo ji via satoshi. // The second route should be a route to luo ji via satoshi.
assertExpectedPath(t, paths[1], "roasbeef", "satoshi", "luoji") assertExpectedPath(
t, graph.aliasMap, paths[1], "roasbeef", "satoshi", "luoji",
)
} }
// TestNewRoute tests whether the construction of hop payloads by newRoute // TestNewRoute tests whether the construction of hop payloads by newRoute
@ -1056,8 +1049,6 @@ func TestNewRoute(t *testing.T) {
// expectedErrorCode indicates the expected error code when // expectedErrorCode indicates the expected error code when
// expectError is true. // expectError is true.
expectedErrorCode errorCode expectedErrorCode errorCode
feeLimit lnwire.MilliSatoshi
}{ }{
{ {
// For a single hop payment, no fees are expected to be paid. // For a single hop payment, no fees are expected to be paid.
@ -1070,7 +1061,6 @@ func TestNewRoute(t *testing.T) {
expectedTimeLocks: []uint32{1}, expectedTimeLocks: []uint32{1},
expectedTotalAmount: 100000, expectedTotalAmount: 100000,
expectedTotalTimeLock: 1, expectedTotalTimeLock: 1,
feeLimit: noFeeLimit,
}, { }, {
// For a two hop payment, only the fee for the first hop // For a two hop payment, only the fee for the first hop
// needs to be paid. The destination hop does not require // needs to be paid. The destination hop does not require
@ -1085,7 +1075,6 @@ func TestNewRoute(t *testing.T) {
expectedTimeLocks: []uint32{1, 1}, expectedTimeLocks: []uint32{1, 1},
expectedTotalAmount: 100130, expectedTotalAmount: 100130,
expectedTotalTimeLock: 6, expectedTotalTimeLock: 6,
feeLimit: noFeeLimit,
}, { }, {
// A three hop payment where the first and second hop // A three hop payment where the first and second hop
// will both charge 1 msat. The fee for the first hop // will both charge 1 msat. The fee for the first hop
@ -1103,7 +1092,6 @@ func TestNewRoute(t *testing.T) {
expectedTotalAmount: 100002, expectedTotalAmount: 100002,
expectedTimeLocks: []uint32{4, 1, 1}, expectedTimeLocks: []uint32{4, 1, 1},
expectedTotalTimeLock: 9, expectedTotalTimeLock: 9,
feeLimit: noFeeLimit,
}, { }, {
// A three hop payment where the fee of the first hop // A three hop payment where the fee of the first hop
// is slightly higher (11) than the fee at the second hop, // is slightly higher (11) than the fee at the second hop,
@ -1119,7 +1107,6 @@ func TestNewRoute(t *testing.T) {
expectedTotalAmount: 102010, expectedTotalAmount: 102010,
expectedTimeLocks: []uint32{4, 1, 1}, expectedTimeLocks: []uint32{4, 1, 1},
expectedTotalTimeLock: 9, expectedTotalTimeLock: 9,
feeLimit: noFeeLimit,
}, { }, {
// A three hop payment where the fee policies of the first and // A three hop payment where the fee policies of the first and
// second hop are just high enough to show the fee carry over // second hop are just high enough to show the fee carry over
@ -1141,53 +1128,6 @@ func TestNewRoute(t *testing.T) {
expectedTotalAmount: 101101, expectedTotalAmount: 101101,
expectedTimeLocks: []uint32{4, 1, 1}, expectedTimeLocks: []uint32{4, 1, 1},
expectedTotalTimeLock: 9, expectedTotalTimeLock: 9,
feeLimit: noFeeLimit,
},
// Check fee limit behaviour
{
name: "two hop success with fee limit (greater)",
paymentAmount: 100000,
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 144),
createHop(0, 1000, 1000000, 144),
},
expectedTotalAmount: 100100,
expectedFees: []lnwire.MilliSatoshi{100, 0},
expectedTimeLocks: []uint32{1, 1},
expectedTotalTimeLock: 145,
feeLimit: 150,
}, {
name: "two hop success with fee limit (equal)",
paymentAmount: 100000,
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 144),
createHop(0, 1000, 1000000, 144),
},
expectedTotalAmount: 100100,
expectedFees: []lnwire.MilliSatoshi{100, 0},
expectedTimeLocks: []uint32{1, 1},
expectedTotalTimeLock: 145,
feeLimit: 100,
}, {
name: "two hop failure with fee limit (smaller)",
paymentAmount: 100000,
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 144),
createHop(0, 1000, 1000000, 144),
},
feeLimit: 50,
expectError: true,
expectedErrorCode: ErrFeeLimitExceeded,
}, {
name: "two hop failure with fee limit (zero)",
paymentAmount: 100000,
hops: []*channeldb.ChannelEdgePolicy{
createHop(0, 1000, 1000000, 144),
createHop(0, 1000, 1000000, 144),
},
feeLimit: 0,
expectError: true,
expectedErrorCode: ErrFeeLimitExceeded,
}} }}
for _, testCase := range testCases { for _, testCase := range testCases {
@ -1238,7 +1178,6 @@ func TestNewRoute(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) { t.Run(testCase.name, func(t *testing.T) {
route, err := newRoute(testCase.paymentAmount, route, err := newRoute(testCase.paymentAmount,
testCase.feeLimit,
sourceVertex, testCase.hops, startingHeight, sourceVertex, testCase.hops, startingHeight,
finalHopCLTV) finalHopCLTV)
@ -1278,9 +1217,6 @@ func TestNewRoutePathTooLong(t *testing.T) {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
paymentAmt := lnwire.NewMSatFromSatoshis(100) paymentAmt := lnwire.NewMSatFromSatoshis(100)
// We start by confirming that routing a payment 20 hops away is // We start by confirming that routing a payment 20 hops away is
@ -1290,12 +1226,10 @@ func TestNewRoutePathTooLong(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, paymentAmt, sourceNode.PubKeyBytes, target, paymentAmt,
) )
if err != nil { if err != nil {
t.Fatalf("path should have been found") t.Fatalf("path should have been found")
@ -1308,12 +1242,10 @@ func TestNewRoutePathTooLong(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, paymentAmt, sourceNode.PubKeyBytes, target, paymentAmt,
) )
if err == nil { if err == nil {
t.Fatalf("should not have been able to find path, supposed to be "+ t.Fatalf("should not have been able to find path, supposed to be "+
@ -1337,9 +1269,6 @@ func TestPathNotAvailable(t *testing.T) {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
// With the test graph loaded, we'll test that queries for target that // With the test graph loaded, we'll test that queries for target that
// are either unreachable within the graph, or unknown result in an // are either unreachable within the graph, or unknown result in an
// error. // error.
@ -1348,21 +1277,17 @@ func TestPathNotAvailable(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to parse bytes: %v", err) t.Fatalf("unable to parse bytes: %v", err)
} }
unknownNode, err := btcec.ParsePubKey(unknownNodeBytes, btcec.S256()) var unknownNode Vertex
if err != nil { copy(unknownNode[:], unknownNodeBytes)
t.Fatalf("unable to parse pubkey: %v", err)
}
_, err = findPath( _, err = findPath(
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, unknownNode, 100, sourceNode.PubKeyBytes, unknownNode, 100,
) )
if !IsError(err, ErrNoPathFound) { if !IsError(err, ErrNoPathFound) {
t.Fatalf("path shouldn't have been found: %v", err) t.Fatalf("path shouldn't have been found: %v", err)
@ -1382,8 +1307,6 @@ func TestPathInsufficientCapacity(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
// Next, test that attempting to find a path in which the current // Next, test that attempting to find a path in which the current
// channel graph cannot support due to insufficient capacity triggers // channel graph cannot support due to insufficient capacity triggers
@ -1400,12 +1323,10 @@ func TestPathInsufficientCapacity(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if !IsError(err, ErrNoPathFound) { if !IsError(err, ErrNoPathFound) {
t.Fatalf("graph shouldn't be able to support payment: %v", err) t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -1427,8 +1348,6 @@ func TestRouteFailMinHTLC(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
// We'll not attempt to route an HTLC of 10 SAT from roasbeef to Son // We'll not attempt to route an HTLC of 10 SAT from roasbeef to Son
// Goku. However, the min HTLC of Son Goku is 1k SAT, as a result, this // Goku. However, the min HTLC of Son Goku is 1k SAT, as a result, this
@ -1439,12 +1358,10 @@ func TestRouteFailMinHTLC(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if !IsError(err, ErrNoPathFound) { if !IsError(err, ErrNoPathFound) {
t.Fatalf("graph shouldn't be able to support payment: %v", err) t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -1492,8 +1409,6 @@ func TestRouteFailMaxHTLC(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
// First, attempt to send a payment greater than the max HTLC we are // First, attempt to send a payment greater than the max HTLC we are
// about to set, which should succeed. // about to set, which should succeed.
@ -1503,12 +1418,10 @@ func TestRouteFailMaxHTLC(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if err != nil { if err != nil {
t.Fatalf("graph should've been able to support payment: %v", err) t.Fatalf("graph should've been able to support payment: %v", err)
@ -1529,12 +1442,10 @@ func TestRouteFailMaxHTLC(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if !IsError(err, ErrNoPathFound) { if !IsError(err, ErrNoPathFound) {
t.Fatalf("graph shouldn't be able to support payment: %v", err) t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -1559,8 +1470,6 @@ func TestRouteFailDisabledEdge(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
// First, we'll try to route from roasbeef -> sophon. This should // First, we'll try to route from roasbeef -> sophon. This should
// succeed without issue, and return a single path via phamnuwen // succeed without issue, and return a single path via phamnuwen
@ -1570,12 +1479,10 @@ func TestRouteFailDisabledEdge(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find path: %v", err) t.Fatalf("unable to find path: %v", err)
@ -1602,12 +1509,10 @@ func TestRouteFailDisabledEdge(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find path: %v", err) t.Fatalf("unable to find path: %v", err)
@ -1631,12 +1536,10 @@ func TestRouteFailDisabledEdge(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if !IsError(err, ErrNoPathFound) { if !IsError(err, ErrNoPathFound) {
t.Fatalf("graph shouldn't be able to support payment: %v", err) t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -1659,8 +1562,6 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
// First, we'll try to route from roasbeef -> sophon. This should // First, we'll try to route from roasbeef -> sophon. This should
// succeed without issue, and return a path via songoku, as that's the // succeed without issue, and return a path via songoku, as that's the
@ -1671,17 +1572,15 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
&graphParams{ &graphParams{
graph: graph.graph, graph: graph.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find path: %v", err) t.Fatalf("unable to find path: %v", err)
} }
assertExpectedPath(t, path, "songoku", "sophon") assertExpectedPath(t, graph.aliasMap, path, "songoku", "sophon")
// Now we'll set the bandwidth of the edge roasbeef->songoku and // Now we'll set the bandwidth of the edge roasbeef->songoku and
// roasbeef->phamnuwen to 0. // roasbeef->phamnuwen to 0.
@ -1699,12 +1598,10 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
graph: graph.graph, graph: graph.graph,
bandwidthHints: bandwidths, bandwidthHints: bandwidths,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if !IsError(err, ErrNoPathFound) { if !IsError(err, ErrNoPathFound) {
t.Fatalf("graph shouldn't be able to support payment: %v", err) t.Fatalf("graph shouldn't be able to support payment: %v", err)
@ -1721,17 +1618,15 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
graph: graph.graph, graph: graph.graph,
bandwidthHints: bandwidths, bandwidthHints: bandwidths,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find path: %v", err) t.Fatalf("unable to find path: %v", err)
} }
assertExpectedPath(t, path, "phamnuwen", "sophon") assertExpectedPath(t, graph.aliasMap, path, "phamnuwen", "sophon")
// Finally, set the roasbeef->songoku bandwidth, but also set its // Finally, set the roasbeef->songoku bandwidth, but also set its
// disable flag. // disable flag.
@ -1756,17 +1651,15 @@ func TestPathSourceEdgesBandwidth(t *testing.T) {
graph: graph.graph, graph: graph.graph,
bandwidthHints: bandwidths, bandwidthHints: bandwidths,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges,
feeLimit: noFeeLimit,
}, },
sourceNode, target, payAmt, sourceNode.PubKeyBytes, target, payAmt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find path: %v", err) t.Fatalf("unable to find path: %v", err)
} }
assertExpectedPath(t, path, "songoku", "sophon") assertExpectedPath(t, graph.aliasMap, path, "songoku", "sophon")
} }
func TestPathInsufficientCapacityWithFee(t *testing.T) { func TestPathInsufficientCapacityWithFee(t *testing.T) {
@ -1803,7 +1696,11 @@ func TestPathFindSpecExample(t *testing.T) {
// Carol, so we set "B" as the source node so path finding starts from // Carol, so we set "B" as the source node so path finding starts from
// Bob. // Bob.
bob := ctx.aliases["B"] bob := ctx.aliases["B"]
bobNode, err := ctx.graph.FetchLightningNode(bob) bobKey, err := btcec.ParsePubKey(bob[:], btcec.S256())
if err != nil {
t.Fatal(err)
}
bobNode, err := ctx.graph.FetchLightningNode(bobKey)
if err != nil { if err != nil {
t.Fatalf("unable to find bob: %v", err) t.Fatalf("unable to find bob: %v", err)
} }
@ -1814,7 +1711,9 @@ func TestPathFindSpecExample(t *testing.T) {
// Query for a route of 4,999,999 mSAT to carol. // Query for a route of 4,999,999 mSAT to carol.
carol := ctx.aliases["C"] carol := ctx.aliases["C"]
const amt lnwire.MilliSatoshi = 4999999 const amt lnwire.MilliSatoshi = 4999999
routes, err := ctx.router.FindRoutes(carol, amt, noFeeLimit, 100) routes, err := ctx.router.FindRoutes(
bobNode.PubKeyBytes, carol, amt, noRestrictions, 100,
)
if err != nil { if err != nil {
t.Fatalf("unable to find route: %v", err) t.Fatalf("unable to find route: %v", err)
} }
@ -1857,7 +1756,11 @@ func TestPathFindSpecExample(t *testing.T) {
// Next, we'll set A as the source node so we can assert that we create // Next, we'll set A as the source node so we can assert that we create
// the proper route for any queries starting with Alice. // the proper route for any queries starting with Alice.
alice := ctx.aliases["A"] alice := ctx.aliases["A"]
aliceNode, err := ctx.graph.FetchLightningNode(alice) aliceKey, err := btcec.ParsePubKey(alice[:], btcec.S256())
if err != nil {
t.Fatal(err)
}
aliceNode, err := ctx.graph.FetchLightningNode(aliceKey)
if err != nil { if err != nil {
t.Fatalf("unable to find alice: %v", err) t.Fatalf("unable to find alice: %v", err)
} }
@ -1869,13 +1772,15 @@ func TestPathFindSpecExample(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to retrieve source node: %v", err) t.Fatalf("unable to retrieve source node: %v", err)
} }
if !bytes.Equal(source.PubKeyBytes[:], alice.SerializeCompressed()) { if source.PubKeyBytes != alice {
t.Fatalf("source node not set") t.Fatalf("source node not set")
} }
// We'll now request a route from A -> B -> C. // We'll now request a route from A -> B -> C.
ctx.router.routeCache = make(map[routeTuple][]*Route) ctx.router.routeCache = make(map[routeTuple][]*Route)
routes, err = ctx.router.FindRoutes(carol, amt, noFeeLimit, 100) routes, err = ctx.router.FindRoutes(
source.PubKeyBytes, carol, amt, noRestrictions, 100,
)
if err != nil { if err != nil {
t.Fatalf("unable to find routes: %v", err) t.Fatalf("unable to find routes: %v", err)
} }
@ -2002,15 +1907,15 @@ func TestPathFindSpecExample(t *testing.T) {
} }
} }
func assertExpectedPath(t *testing.T, path []*channeldb.ChannelEdgePolicy, func assertExpectedPath(t *testing.T, aliasMap map[string]Vertex,
nodeAliases ...string) { path []*channeldb.ChannelEdgePolicy, nodeAliases ...string) {
if len(path) != len(nodeAliases) { if len(path) != len(nodeAliases) {
t.Fatal("number of hops and number of aliases do not match") t.Fatal("number of hops and number of aliases do not match")
} }
for i, hop := range path { for i, hop := range path {
if hop.Node.Alias != nodeAliases[i] { if hop.Node.PubKeyBytes != aliasMap[nodeAliases[i]] {
t.Fatalf("expected %v to be pos #%v in hop, instead "+ t.Fatalf("expected %v to be pos #%v in hop, instead "+
"%v was", nodeAliases[i], i, hop.Node.Alias) "%v was", nodeAliases[i], i, hop.Node.Alias)
} }
@ -2076,9 +1981,6 @@ func TestRestrictOutgoingChannel(t *testing.T) {
} }
sourceVertex := Vertex(sourceNode.PubKeyBytes) sourceVertex := Vertex(sourceNode.PubKeyBytes)
ignoredEdges := make(map[edgeLocator]struct{})
ignoredVertexes := make(map[Vertex]struct{})
const ( const (
startingHeight = 100 startingHeight = 100
finalHopCLTV = 1 finalHopCLTV = 1
@ -2094,19 +1996,17 @@ func TestRestrictOutgoingChannel(t *testing.T) {
&graphParams{ &graphParams{
graph: testGraphInstance.graph, graph: testGraphInstance.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoredVertexes, FeeLimit: noFeeLimit,
ignoredEdges: ignoredEdges, OutgoingChannelID: &outgoingChannelID,
feeLimit: noFeeLimit,
outgoingChannelID: &outgoingChannelID,
}, },
sourceNode, target, paymentAmt, sourceVertex, target, paymentAmt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find path: %v", err) t.Fatalf("unable to find path: %v", err)
} }
route, err := newRoute( route, err := newRoute(
paymentAmt, infinity, sourceVertex, path, startingHeight, paymentAmt, sourceVertex, path, startingHeight,
finalHopCLTV, finalHopCLTV,
) )
if err != nil { if err != nil {

@ -27,7 +27,7 @@ type paymentSession struct {
// source of policy related routing failures during this payment attempt. // source of policy related routing failures during this payment attempt.
// We'll use this map to prune out channels when the first error may not // We'll use this map to prune out channels when the first error may not
// require pruning, but any subsequent ones do. // require pruning, but any subsequent ones do.
errFailedPolicyChans map[edgeLocator]struct{} errFailedPolicyChans map[EdgeLocator]struct{}
mc *missionControl mc *missionControl
@ -61,7 +61,7 @@ func (p *paymentSession) ReportVertexFailure(v Vertex) {
// retrying an edge after its pruning has expired. // retrying an edge after its pruning has expired.
// //
// TODO(roasbeef): also add value attempted to send and capacity of channel // TODO(roasbeef): also add value attempted to send and capacity of channel
func (p *paymentSession) ReportEdgeFailure(e *edgeLocator) { func (p *paymentSession) ReportEdgeFailure(e *EdgeLocator) {
log.Debugf("Reporting edge %v failure to Mission Control", e) log.Debugf("Reporting edge %v failure to Mission Control", e)
// First, we'll add the failed edge to our local prune view snapshot. // First, we'll add the failed edge to our local prune view snapshot.
@ -82,7 +82,7 @@ func (p *paymentSession) ReportEdgeFailure(e *edgeLocator) {
// pruned. This is to prevent nodes from keeping us busy by continuously sending // pruned. This is to prevent nodes from keeping us busy by continuously sending
// new channel updates. // new channel updates.
func (p *paymentSession) ReportEdgePolicyFailure( func (p *paymentSession) ReportEdgePolicyFailure(
errSource Vertex, failedEdge *edgeLocator) { errSource Vertex, failedEdge *EdgeLocator) {
// Check to see if we've already reported a policy related failure for // Check to see if we've already reported a policy related failure for
// this channel. If so, then we'll prune out the vertex. // this channel. If so, then we'll prune out the vertex.
@ -147,13 +147,14 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
additionalEdges: p.additionalEdges, additionalEdges: p.additionalEdges,
bandwidthHints: p.bandwidthHints, bandwidthHints: p.bandwidthHints,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: pruneView.vertexes, IgnoredNodes: pruneView.vertexes,
ignoredEdges: pruneView.edges, IgnoredEdges: pruneView.edges,
feeLimit: payment.FeeLimit, FeeLimit: payment.FeeLimit,
outgoingChannelID: payment.OutgoingChannelID, OutgoingChannelID: payment.OutgoingChannelID,
}, },
p.mc.selfNode, payment.Target, payment.Amount, p.mc.selfNode.PubKeyBytes, payment.Target,
payment.Amount,
) )
if err != nil { if err != nil {
return nil, err return nil, err
@ -163,8 +164,7 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment,
// a route by applying the time-lock and fee requirements. // a route by applying the time-lock and fee requirements.
sourceVertex := Vertex(p.mc.selfNode.PubKeyBytes) sourceVertex := Vertex(p.mc.selfNode.PubKeyBytes)
route, err := newRoute( route, err := newRoute(
payment.Amount, payment.FeeLimit, sourceVertex, path, height, payment.Amount, sourceVertex, path, height, finalCltvDelta,
finalCltvDelta,
) )
if err != nil { if err != nil {
// TODO(roasbeef): return which edge/vertex didn't work // TODO(roasbeef): return which edge/vertex didn't work

@ -215,18 +215,20 @@ func newRouteTuple(amt lnwire.MilliSatoshi, dest []byte) routeTuple {
return r return r
} }
// edgeLocator is a struct used to identify a specific edge. The direction // EdgeLocator is a struct used to identify a specific edge.
// fields takes the value of 0 or 1 and is identical in definition to the type EdgeLocator struct {
// channel direction flag. A value of 0 means the direction from the lower node // ChannelID is the channel of this edge.
// pubkey to the higher. ChannelID uint64
type edgeLocator struct {
channelID uint64 // Direction takes the value of 0 or 1 and is identical in definition to
direction uint8 // the channel direction flag. A value of 0 means the direction from the
// lower node pubkey to the higher.
Direction uint8
} }
// newEdgeLocatorByPubkeys returns an edgeLocator based on its end point // newEdgeLocatorByPubkeys returns an edgeLocator based on its end point
// pubkeys. // pubkeys.
func newEdgeLocatorByPubkeys(channelID uint64, fromNode, toNode *Vertex) *edgeLocator { func newEdgeLocatorByPubkeys(channelID uint64, fromNode, toNode *Vertex) *EdgeLocator {
// Determine direction based on lexicographical ordering of both // Determine direction based on lexicographical ordering of both
// pubkeys. // pubkeys.
var direction uint8 var direction uint8
@ -234,24 +236,24 @@ func newEdgeLocatorByPubkeys(channelID uint64, fromNode, toNode *Vertex) *edgeLo
direction = 1 direction = 1
} }
return &edgeLocator{ return &EdgeLocator{
channelID: channelID, ChannelID: channelID,
direction: direction, Direction: direction,
} }
} }
// newEdgeLocator extracts an edgeLocator based for a full edge policy // newEdgeLocator extracts an edgeLocator based for a full edge policy
// structure. // structure.
func newEdgeLocator(edge *channeldb.ChannelEdgePolicy) *edgeLocator { func newEdgeLocator(edge *channeldb.ChannelEdgePolicy) *EdgeLocator {
return &edgeLocator{ return &EdgeLocator{
channelID: edge.ChannelID, ChannelID: edge.ChannelID,
direction: uint8(edge.ChannelFlags & lnwire.ChanUpdateDirection), Direction: uint8(edge.ChannelFlags & lnwire.ChanUpdateDirection),
} }
} }
// String returns a human readable version of the edgeLocator values. // String returns a human readable version of the edgeLocator values.
func (e *edgeLocator) String() string { func (e *EdgeLocator) String() string {
return fmt.Sprintf("%v:%v", e.channelID, e.direction) return fmt.Sprintf("%v:%v", e.ChannelID, e.Direction)
} }
// ChannelRouter is the layer 3 router within the Lightning stack. Below the // ChannelRouter is the layer 3 router within the Lightning stack. Below the
@ -1266,7 +1268,7 @@ type routingMsg struct {
// initial set of paths as it's possible we drop a route if it can't handle the // initial set of paths as it's possible we drop a route if it can't handle the
// total payment flow after fees are calculated. // total payment flow after fees are calculated.
func pathsToFeeSortedRoutes(source Vertex, paths [][]*channeldb.ChannelEdgePolicy, func pathsToFeeSortedRoutes(source Vertex, paths [][]*channeldb.ChannelEdgePolicy,
finalCLTVDelta uint16, amt, feeLimit lnwire.MilliSatoshi, finalCLTVDelta uint16, amt lnwire.MilliSatoshi,
currentHeight uint32) ([]*Route, error) { currentHeight uint32) ([]*Route, error) {
validRoutes := make([]*Route, 0, len(paths)) validRoutes := make([]*Route, 0, len(paths))
@ -1275,8 +1277,7 @@ func pathsToFeeSortedRoutes(source Vertex, paths [][]*channeldb.ChannelEdgePolic
// hop in the path as it contains a "self-hop" that is inserted // hop in the path as it contains a "self-hop" that is inserted
// by our KSP algorithm. // by our KSP algorithm.
route, err := newRoute( route, err := newRoute(
amt, feeLimit, source, path[1:], currentHeight, amt, source, path[1:], currentHeight, finalCLTVDelta,
finalCLTVDelta,
) )
if err != nil { if err != nil {
// TODO(roasbeef): report straw breaking edge? // TODO(roasbeef): report straw breaking edge?
@ -1324,8 +1325,8 @@ func pathsToFeeSortedRoutes(source Vertex, paths [][]*channeldb.ChannelEdgePolic
// the required fee and time lock values running backwards along the route. The // the required fee and time lock values running backwards along the route. The
// route that will be ranked the highest is the one with the lowest cumulative // route that will be ranked the highest is the one with the lowest cumulative
// fee along the route. // fee along the route.
func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey, func (r *ChannelRouter) FindRoutes(source, target Vertex,
amt, feeLimit lnwire.MilliSatoshi, numPaths uint32, amt lnwire.MilliSatoshi, restrictions *RestrictParams, numPaths uint32,
finalExpiry ...uint16) ([]*Route, error) { finalExpiry ...uint16) ([]*Route, error) {
var finalCLTVDelta uint16 var finalCLTVDelta uint16
@ -1335,13 +1336,16 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
finalCLTVDelta = finalExpiry[0] finalCLTVDelta = finalExpiry[0]
} }
dest := target.SerializeCompressed() log.Debugf("Searching for path to %x, sending %v", target, amt)
log.Debugf("Searching for path to %x, sending %v", dest, amt)
// Before attempting to perform a series of graph traversals to find // Before attempting to perform a series of graph traversals to find the
// the k-shortest paths to the destination, we'll first consult our // k-shortest paths to the destination, we'll first consult our path
// path cache // cache
rt := newRouteTuple(amt, dest) //
// TODO: Route cache should store all request parameters instead of just
// amt and target. Currently false positives are returned if just the
// restrictions (fee limit, ignore lists) or finalExpiry are different.
rt := newRouteTuple(amt, target[:])
r.routeCacheMtx.RLock() r.routeCacheMtx.RLock()
routes, ok := r.routeCache[rt] routes, ok := r.routeCache[rt]
r.routeCacheMtx.RUnlock() r.routeCacheMtx.RUnlock()
@ -1360,11 +1364,10 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
// We can short circuit the routing by opportunistically checking to // We can short circuit the routing by opportunistically checking to
// see if the target vertex event exists in the current graph. // see if the target vertex event exists in the current graph.
targetVertex := NewVertex(target) if _, exists, err := r.cfg.Graph.HasLightningNode(target); err != nil {
if _, exists, err := r.cfg.Graph.HasLightningNode(targetVertex); err != nil {
return nil, err return nil, err
} else if !exists { } else if !exists {
log.Debugf("Target %x is not in known graph", dest) log.Debugf("Target %x is not in known graph", target)
return nil, newErrf(ErrTargetNotInNetwork, "target not found") return nil, newErrf(ErrTargetNotInNetwork, "target not found")
} }
@ -1395,8 +1398,8 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
// we'll execute our KSP algorithm to find the k-shortest paths from // we'll execute our KSP algorithm to find the k-shortest paths from
// our source to the destination. // our source to the destination.
shortestPaths, err := findPaths( shortestPaths, err := findPaths(
tx, r.cfg.Graph, r.selfNode, target, amt, feeLimit, numPaths, tx, r.cfg.Graph, source, target, amt, restrictions,
bandwidthHints, numPaths, bandwidthHints,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
@ -1412,7 +1415,7 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
// factored in. // factored in.
sourceVertex := Vertex(r.selfNode.PubKeyBytes) sourceVertex := Vertex(r.selfNode.PubKeyBytes)
validRoutes, err := pathsToFeeSortedRoutes( validRoutes, err := pathsToFeeSortedRoutes(
sourceVertex, shortestPaths, finalCLTVDelta, amt, feeLimit, sourceVertex, shortestPaths, finalCLTVDelta, amt,
uint32(currentHeight), uint32(currentHeight),
) )
if err != nil { if err != nil {
@ -1420,7 +1423,7 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey,
} }
go log.Tracef("Obtained %v paths sending %v to %x: %v", len(validRoutes), go log.Tracef("Obtained %v paths sending %v to %x: %v", len(validRoutes),
amt, dest, newLogClosure(func() string { amt, target, newLogClosure(func() string {
return spew.Sdump(validRoutes) return spew.Sdump(validRoutes)
}), }),
) )
@ -1512,7 +1515,7 @@ func generateSphinxPacket(route *Route, paymentHash []byte) ([]byte,
// final destination. // final destination.
type LightningPayment struct { type LightningPayment struct {
// Target is the node in which the payment should be routed towards. // Target is the node in which the payment should be routed towards.
Target *btcec.PublicKey Target Vertex
// Amount is the value of the payment to send through the network in // Amount is the value of the payment to send through the network in
// milli-satoshis. // milli-satoshis.
@ -1607,12 +1610,6 @@ func (r *ChannelRouter) sendPayment(payment *LightningPayment,
log.Tracef("Dispatching route for lightning payment: %v", log.Tracef("Dispatching route for lightning payment: %v",
newLogClosure(func() string { newLogClosure(func() string {
// Remove the public key curve parameters when logging
// the route to prevent spamming the logs.
if payment.Target != nil {
payment.Target.Curve = nil
}
for _, routeHint := range payment.RouteHints { for _, routeHint := range payment.RouteHints {
for _, hopHint := range routeHint { for _, hopHint := range routeHint {
hopHint.NodeID.Curve = nil hopHint.NodeID.Curve = nil
@ -1973,13 +1970,13 @@ func (r *ChannelRouter) processSendError(paySession *paymentSession,
// we'll prune the channel in both directions and // we'll prune the channel in both directions and
// continue with the rest of the routes. // continue with the rest of the routes.
case *lnwire.FailPermanentChannelFailure: case *lnwire.FailPermanentChannelFailure:
paySession.ReportEdgeFailure(&edgeLocator{ paySession.ReportEdgeFailure(&EdgeLocator{
channelID: failedEdge.channelID, ChannelID: failedEdge.ChannelID,
direction: 0, Direction: 0,
}) })
paySession.ReportEdgeFailure(&edgeLocator{ paySession.ReportEdgeFailure(&EdgeLocator{
channelID: failedEdge.channelID, ChannelID: failedEdge.ChannelID,
direction: 1, Direction: 1,
}) })
return false return false
@ -1992,7 +1989,7 @@ func (r *ChannelRouter) processSendError(paySession *paymentSession,
// pubkey of the node that sent the error. It will assume that the error is // pubkey of the node that sent the error. It will assume that the error is
// associated with the outgoing channel of the error node. // associated with the outgoing channel of the error node.
func getFailedEdge(route *Route, errSource Vertex) ( func getFailedEdge(route *Route, errSource Vertex) (
*edgeLocator, error) { *EdgeLocator, error) {
hopCount := len(route.Hops) hopCount := len(route.Hops)
fromNode := route.SourcePubKey fromNode := route.SourcePubKey

@ -30,7 +30,7 @@ type testCtx struct {
graph *channeldb.ChannelGraph graph *channeldb.ChannelGraph
aliases map[string]*btcec.PublicKey aliases map[string]Vertex
chain *mockChain chain *mockChain
@ -184,7 +184,8 @@ func TestFindRoutesFeeSorting(t *testing.T) {
paymentAmt := lnwire.NewMSatFromSatoshis(100) paymentAmt := lnwire.NewMSatFromSatoshis(100)
target := ctx.aliases["luoji"] target := ctx.aliases["luoji"]
routes, err := ctx.router.FindRoutes( routes, err := ctx.router.FindRoutes(
target, paymentAmt, noFeeLimit, defaultNumRoutes, ctx.router.selfNode.PubKeyBytes,
target, paymentAmt, noRestrictions, defaultNumRoutes,
DefaultFinalCLTVDelta, DefaultFinalCLTVDelta,
) )
if err != nil { if err != nil {
@ -240,10 +241,13 @@ func TestFindRoutesWithFeeLimit(t *testing.T) {
// see the first route. // see the first route.
target := ctx.aliases["sophon"] target := ctx.aliases["sophon"]
paymentAmt := lnwire.NewMSatFromSatoshis(100) paymentAmt := lnwire.NewMSatFromSatoshis(100)
feeLimit := lnwire.NewMSatFromSatoshis(10) restrictions := &RestrictParams{
FeeLimit: lnwire.NewMSatFromSatoshis(10),
}
routes, err := ctx.router.FindRoutes( routes, err := ctx.router.FindRoutes(
target, paymentAmt, feeLimit, defaultNumRoutes, ctx.router.selfNode.PubKeyBytes,
target, paymentAmt, restrictions, defaultNumRoutes,
DefaultFinalCLTVDelta, DefaultFinalCLTVDelta,
) )
if err != nil { if err != nil {
@ -254,7 +258,7 @@ func TestFindRoutesWithFeeLimit(t *testing.T) {
t.Fatalf("expected 1 route, got %d", len(routes)) t.Fatalf("expected 1 route, got %d", len(routes))
} }
if routes[0].TotalFees > feeLimit { if routes[0].TotalFees > restrictions.FeeLimit {
t.Fatalf("route exceeded fee limit: %v", spew.Sdump(routes[0])) t.Fatalf("route exceeded fee limit: %v", spew.Sdump(routes[0]))
} }
@ -263,11 +267,10 @@ func TestFindRoutesWithFeeLimit(t *testing.T) {
t.Fatalf("expected 2 hops, got %d", len(hops)) t.Fatalf("expected 2 hops, got %d", len(hops))
} }
if !bytes.Equal(hops[0].PubKeyBytes[:], if hops[0].PubKeyBytes != ctx.aliases["songoku"] {
ctx.aliases["songoku"].SerializeCompressed()) {
t.Fatalf("expected first hop through songoku, got %s", t.Fatalf("expected first hop through songoku, got %s",
getAliasFromPubKey(hops[0].PubKeyBytes[:], getAliasFromPubKey(hops[0].PubKeyBytes,
ctx.aliases)) ctx.aliases))
} }
} }
@ -345,12 +348,11 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) {
} }
// The route should have satoshi as the first hop. // The route should have satoshi as the first hop.
if !bytes.Equal(route.Hops[0].PubKeyBytes[:], if route.Hops[0].PubKeyBytes != ctx.aliases["satoshi"] {
ctx.aliases["satoshi"].SerializeCompressed()) {
t.Fatalf("route should go through satoshi as first hop, "+ t.Fatalf("route should go through satoshi as first hop, "+
"instead passes through: %v", "instead passes through: %v",
getAliasFromPubKey(route.Hops[0].PubKeyBytes[:], getAliasFromPubKey(route.Hops[0].PubKeyBytes,
ctx.aliases)) ctx.aliases))
} }
} }
@ -408,11 +410,9 @@ func TestChannelUpdateValidation(t *testing.T) {
// Setup a route from source a to destination c. The route will be used // Setup a route from source a to destination c. The route will be used
// in a call to SendToRoute. SendToRoute also applies channel updates, // in a call to SendToRoute. SendToRoute also applies channel updates,
// but it saves us from including RequestRoute in the test scope too. // but it saves us from including RequestRoute in the test scope too.
var hop1 [33]byte hop1 := ctx.aliases["b"]
copy(hop1[:], ctx.aliases["b"].SerializeCompressed())
var hop2 [33]byte hop2 := ctx.aliases["c"]
copy(hop2[:], ctx.aliases["c"].SerializeCompressed())
hops := []*Hop{ hops := []*Hop{
{ {
@ -427,7 +427,7 @@ func TestChannelUpdateValidation(t *testing.T) {
route, err := NewRouteFromHops( route, err := NewRouteFromHops(
lnwire.MilliSatoshi(10000), 100, lnwire.MilliSatoshi(10000), 100,
NewVertex(ctx.aliases["a"]), hops, ctx.aliases["a"], hops,
) )
if err != nil { if err != nil {
t.Fatalf("unable to create route: %v", err) t.Fatalf("unable to create route: %v", err)
@ -449,8 +449,16 @@ func TestChannelUpdateValidation(t *testing.T) {
ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID, ctx.router.cfg.SendToSwitch = func(firstHop lnwire.ShortChannelID,
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
v := ctx.aliases["b"]
source, err := btcec.ParsePubKey(
v[:], btcec.S256(),
)
if err != nil {
t.Fatal(err)
}
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: ctx.aliases["b"], ErrorSource: source,
FailureMessage: &lnwire.FailFeeInsufficient{ FailureMessage: &lnwire.FailFeeInsufficient{
Update: errChanUpdate, Update: errChanUpdate,
}, },
@ -574,8 +582,15 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) {
roasbeefSongoku := lnwire.NewShortChanIDFromInt(chanID) roasbeefSongoku := lnwire.NewShortChanIDFromInt(chanID)
if firstHop == roasbeefSongoku { if firstHop == roasbeefSongoku {
sourceKey, err := btcec.ParsePubKey(
sourceNode[:], btcec.S256(),
)
if err != nil {
t.Fatal(err)
}
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode, ErrorSource: sourceKey,
// Within our error, we'll add a channel update // Within our error, we'll add a channel update
// which is meant to reflect he new fee // which is meant to reflect he new fee
@ -609,12 +624,11 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) {
} }
// The route should have pham nuwen as the first hop. // The route should have pham nuwen as the first hop.
if !bytes.Equal(route.Hops[0].PubKeyBytes[:], if route.Hops[0].PubKeyBytes != ctx.aliases["phamnuwen"] {
ctx.aliases["phamnuwen"].SerializeCompressed()) {
t.Fatalf("route should go through satoshi as first hop, "+ t.Fatalf("route should go through satoshi as first hop, "+
"instead passes through: %v", "instead passes through: %v",
getAliasFromPubKey(route.Hops[0].PubKeyBytes[:], getAliasFromPubKey(route.Hops[0].PubKeyBytes,
ctx.aliases)) ctx.aliases))
} }
} }
@ -682,8 +696,15 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
if firstHop == roasbeefSongoku { if firstHop == roasbeefSongoku {
sourceKey, err := btcec.ParsePubKey(
sourceNode[:], btcec.S256(),
)
if err != nil {
t.Fatal(err)
}
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode, ErrorSource: sourceKey,
FailureMessage: &lnwire.FailExpiryTooSoon{ FailureMessage: &lnwire.FailExpiryTooSoon{
Update: errChanUpdate, Update: errChanUpdate,
}, },
@ -710,12 +731,11 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
} }
// The route should have satoshi as the first hop. // The route should have satoshi as the first hop.
if !bytes.Equal(route.Hops[0].PubKeyBytes[:], if route.Hops[0].PubKeyBytes != ctx.aliases["phamnuwen"] {
ctx.aliases["phamnuwen"].SerializeCompressed()) {
t.Fatalf("route should go through phamnuwen as first hop, "+ t.Fatalf("route should go through phamnuwen as first hop, "+
"instead passes through: %v", "instead passes through: %v",
getAliasFromPubKey(route.Hops[0].PubKeyBytes[:], getAliasFromPubKey(route.Hops[0].PubKeyBytes,
ctx.aliases)) ctx.aliases))
} }
} }
@ -737,8 +757,15 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) {
_ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) { _ *lnwire.UpdateAddHTLC, _ *sphinx.Circuit) ([32]byte, error) {
if firstHop == roasbeefSongoku { if firstHop == roasbeefSongoku {
sourceKey, err := btcec.ParsePubKey(
sourceNode[:], btcec.S256(),
)
if err != nil {
t.Fatal(err)
}
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: sourceNode, ErrorSource: sourceKey,
FailureMessage: &lnwire.FailIncorrectCltvExpiry{ FailureMessage: &lnwire.FailIncorrectCltvExpiry{
Update: errChanUpdate, Update: errChanUpdate,
}, },
@ -821,8 +848,16 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
// prune out the rest of the routes. // prune out the rest of the routes.
roasbeefSatoshi := lnwire.NewShortChanIDFromInt(2340213491) roasbeefSatoshi := lnwire.NewShortChanIDFromInt(2340213491)
if firstHop == roasbeefSatoshi { if firstHop == roasbeefSatoshi {
vertex := ctx.aliases["satoshi"]
key, err := btcec.ParsePubKey(
vertex[:], btcec.S256(),
)
if err != nil {
t.Fatal(err)
}
return [32]byte{}, &htlcswitch.ForwardingError{ return [32]byte{}, &htlcswitch.ForwardingError{
ErrorSource: ctx.aliases["satoshi"], ErrorSource: key,
FailureMessage: &lnwire.FailUnknownNextPeer{}, FailureMessage: &lnwire.FailUnknownNextPeer{},
} }
} }
@ -880,12 +915,11 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
t.Fatalf("incorrect preimage used: expected %x got %x", t.Fatalf("incorrect preimage used: expected %x got %x",
preImage[:], paymentPreImage[:]) preImage[:], paymentPreImage[:])
} }
if !bytes.Equal(route.Hops[0].PubKeyBytes[:], if route.Hops[0].PubKeyBytes != ctx.aliases["satoshi"] {
ctx.aliases["satoshi"].SerializeCompressed()) {
t.Fatalf("route should go through satoshi as first hop, "+ t.Fatalf("route should go through satoshi as first hop, "+
"instead passes through: %v", "instead passes through: %v",
getAliasFromPubKey(route.Hops[0].PubKeyBytes[:], getAliasFromPubKey(route.Hops[0].PubKeyBytes,
ctx.aliases)) ctx.aliases))
} }
@ -928,12 +962,11 @@ func TestSendPaymentErrorPathPruning(t *testing.T) {
} }
// The route should have satoshi as the first hop. // The route should have satoshi as the first hop.
if !bytes.Equal(route.Hops[0].PubKeyBytes[:], if route.Hops[0].PubKeyBytes != ctx.aliases["satoshi"] {
ctx.aliases["satoshi"].SerializeCompressed()) {
t.Fatalf("route should go through satoshi as first hop, "+ t.Fatalf("route should go through satoshi as first hop, "+
"instead passes through: %v", "instead passes through: %v",
getAliasFromPubKey(route.Hops[0].PubKeyBytes[:], getAliasFromPubKey(route.Hops[0].PubKeyBytes,
ctx.aliases)) ctx.aliases))
} }
} }
@ -1231,8 +1264,9 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// We will connect node 1 to "sophon" // We will connect node 1 to "sophon"
connectNode := ctx.aliases["sophon"] connectNode := ctx.aliases["sophon"]
if connectNode == nil { connectNodeKey, err := btcec.ParsePubKey(connectNode[:], btcec.S256())
t.Fatalf("could not find node to connect to") if err != nil {
t.Fatal(err)
} }
var ( var (
@ -1240,12 +1274,12 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
pubKey2 *btcec.PublicKey pubKey2 *btcec.PublicKey
) )
node1Bytes := priv1.PubKey().SerializeCompressed() node1Bytes := priv1.PubKey().SerializeCompressed()
node2Bytes := connectNode.SerializeCompressed() node2Bytes := connectNode
if bytes.Compare(node1Bytes, node2Bytes) == -1 { if bytes.Compare(node1Bytes[:], node2Bytes[:]) == -1 {
pubKey1 = priv1.PubKey() pubKey1 = priv1.PubKey()
pubKey2 = connectNode pubKey2 = connectNodeKey
} else { } else {
pubKey1 = connectNode pubKey1 = connectNodeKey
pubKey2 = priv1.PubKey() pubKey2 = priv1.PubKey()
} }
@ -1265,9 +1299,9 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
AuthProof: nil, AuthProof: nil,
} }
copy(edge.NodeKey1Bytes[:], node1Bytes) copy(edge.NodeKey1Bytes[:], node1Bytes)
copy(edge.NodeKey2Bytes[:], node2Bytes) edge.NodeKey2Bytes = node2Bytes
copy(edge.BitcoinKey1Bytes[:], node1Bytes) copy(edge.BitcoinKey1Bytes[:], node1Bytes)
copy(edge.BitcoinKey2Bytes[:], node2Bytes) edge.BitcoinKey2Bytes = node2Bytes
if err := ctx.router.AddEdge(edge); err != nil { if err := ctx.router.AddEdge(edge); err != nil {
t.Fatalf("unable to add edge to the channel graph: %v.", err) t.Fatalf("unable to add edge to the channel graph: %v.", err)
@ -1306,8 +1340,11 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// We should now be able to find two routes to node 2. // We should now be able to find two routes to node 2.
paymentAmt := lnwire.NewMSatFromSatoshis(100) paymentAmt := lnwire.NewMSatFromSatoshis(100)
targetNode := priv2.PubKey() targetNode := priv2.PubKey()
var targetPubKeyBytes Vertex
copy(targetPubKeyBytes[:], targetNode.SerializeCompressed())
routes, err := ctx.router.FindRoutes( routes, err := ctx.router.FindRoutes(
targetNode, paymentAmt, noFeeLimit, defaultNumRoutes, ctx.router.selfNode.PubKeyBytes,
targetPubKeyBytes, paymentAmt, noRestrictions, defaultNumRoutes,
DefaultFinalCLTVDelta, DefaultFinalCLTVDelta,
) )
if err != nil { if err != nil {
@ -1352,7 +1389,8 @@ func TestAddEdgeUnknownVertexes(t *testing.T) {
// Should still be able to find the routes, and the info should be // Should still be able to find the routes, and the info should be
// updated. // updated.
routes, err = ctx.router.FindRoutes( routes, err = ctx.router.FindRoutes(
targetNode, paymentAmt, noFeeLimit, defaultNumRoutes, ctx.router.selfNode.PubKeyBytes,
targetPubKeyBytes, paymentAmt, noRestrictions, defaultNumRoutes,
DefaultFinalCLTVDelta, DefaultFinalCLTVDelta,
) )
if err != nil { if err != nil {
@ -1949,15 +1987,9 @@ func TestFindPathFeeWeighting(t *testing.T) {
t.Fatalf("unable to fetch source node: %v", err) t.Fatalf("unable to fetch source node: %v", err)
} }
ignoreVertex := make(map[Vertex]struct{})
ignoreEdge := make(map[edgeLocator]struct{})
amt := lnwire.MilliSatoshi(100) amt := lnwire.MilliSatoshi(100)
target := ctx.aliases["luoji"] target := ctx.aliases["luoji"]
if target == nil {
t.Fatalf("unable to find target node")
}
// We'll now attempt a path finding attempt using this set up. Due to // We'll now attempt a path finding attempt using this set up. Due to
// the edge weighting, we should select the direct path over the 2 hop // the edge weighting, we should select the direct path over the 2 hop
@ -1966,12 +1998,10 @@ func TestFindPathFeeWeighting(t *testing.T) {
&graphParams{ &graphParams{
graph: ctx.graph, graph: ctx.graph,
}, },
&restrictParams{ &RestrictParams{
ignoredNodes: ignoreVertex, FeeLimit: noFeeLimit,
ignoredEdges: ignoreEdge,
feeLimit: noFeeLimit,
}, },
sourceNode, target, amt, sourceNode.PubKeyBytes, target, amt,
) )
if err != nil { if err != nil {
t.Fatalf("unable to find path: %v", err) t.Fatalf("unable to find path: %v", err)

@ -17,6 +17,8 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/btcsuite/btcd/blockchain" "github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
@ -388,6 +390,10 @@ type rpcServer struct {
// connect to the main gRPC server to proxy all incoming requests. // connect to the main gRPC server to proxy all incoming requests.
tlsCfg *tls.Config tlsCfg *tls.Config
// RouterBackend contains the backend implementation of the router
// rpc sub server.
RouterBackend *routerrpc.RouterBackend
quit chan struct{} quit chan struct{}
} }
@ -471,6 +477,28 @@ func newRPCServer(s *server, macService *macaroons.Service,
) )
} }
// Set up router rpc backend.
channelGraph := s.chanDB.ChannelGraph()
selfNode, err := channelGraph.SourceNode()
if err != nil {
return nil, err
}
graph := s.chanDB.ChannelGraph()
RouterBackend := &routerrpc.RouterBackend{
MaxPaymentMSat: maxPaymentMSat,
SelfNode: selfNode.PubKeyBytes,
FetchChannelCapacity: func(chanID uint64) (btcutil.Amount,
error) {
info, _, _, err := graph.FetchChannelEdgesByID(chanID)
if err != nil {
return 0, err
}
return info.Capacity, nil
},
FindRoutes: s.chanRouter.FindRoutes,
}
// Finally, with all the pre-set up complete, we can create the main // Finally, with all the pre-set up complete, we can create the main
// gRPC server, and register the main lnrpc server along side. // gRPC server, and register the main lnrpc server along side.
grpcServer := grpc.NewServer(serverOpts...) grpcServer := grpc.NewServer(serverOpts...)
@ -480,6 +508,7 @@ func newRPCServer(s *server, macService *macaroons.Service,
tlsCfg: tlsCfg, tlsCfg: tlsCfg,
grpcServer: grpcServer, grpcServer: grpcServer,
server: s, server: s,
RouterBackend: RouterBackend,
quit: make(chan struct{}, 1), quit: make(chan struct{}, 1),
} }
lnrpc.RegisterLightningServer(grpcServer, rootRPCServer) lnrpc.RegisterLightningServer(grpcServer, rootRPCServer)
@ -2764,7 +2793,7 @@ func unmarshallSendToRouteRequest(req *lnrpc.SendToRouteRequest,
type rpcPaymentIntent struct { type rpcPaymentIntent struct {
msat lnwire.MilliSatoshi msat lnwire.MilliSatoshi
feeLimit lnwire.MilliSatoshi feeLimit lnwire.MilliSatoshi
dest *btcec.PublicKey dest routing.Vertex
rHash [32]byte rHash [32]byte
cltvDelta uint16 cltvDelta uint16
routeHints [][]routing.HopHint routeHints [][]routing.HopHint
@ -2778,7 +2807,6 @@ type rpcPaymentIntent struct {
// three ways a client can specify their payment details: a payment request, // three ways a client can specify their payment details: a payment request,
// via manual details, or via a complete route. // via manual details, or via a complete route.
func extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPaymentIntent, error) { func extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPaymentIntent, error) {
var err error
payIntent := rpcPaymentIntent{} payIntent := rpcPaymentIntent{}
// If a route was specified, then we can use that directly. // If a route was specified, then we can use that directly.
@ -2849,7 +2877,8 @@ func extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPaymentIntent, error
) )
copy(payIntent.rHash[:], payReq.PaymentHash[:]) copy(payIntent.rHash[:], payReq.PaymentHash[:])
payIntent.dest = payReq.Destination destKey := payReq.Destination.SerializeCompressed()
copy(payIntent.dest[:], destKey)
payIntent.cltvDelta = uint16(payReq.MinFinalCLTVExpiry()) payIntent.cltvDelta = uint16(payReq.MinFinalCLTVExpiry())
payIntent.routeHints = payReq.RouteHints payIntent.routeHints = payReq.RouteHints
@ -2859,24 +2888,20 @@ func extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPaymentIntent, error
// At this point, a destination MUST be specified, so we'll convert it // At this point, a destination MUST be specified, so we'll convert it
// into the proper representation now. The destination will either be // into the proper representation now. The destination will either be
// encoded as raw bytes, or via a hex string. // encoded as raw bytes, or via a hex string.
var pubBytes []byte
if len(rpcPayReq.Dest) != 0 { if len(rpcPayReq.Dest) != 0 {
payIntent.dest, err = btcec.ParsePubKey( pubBytes = rpcPayReq.Dest
rpcPayReq.Dest, btcec.S256(),
)
if err != nil {
return payIntent, err
}
} else { } else {
pubBytes, err := hex.DecodeString(rpcPayReq.DestString) var err error
if err != nil { pubBytes, err = hex.DecodeString(rpcPayReq.DestString)
return payIntent, err
}
payIntent.dest, err = btcec.ParsePubKey(pubBytes, btcec.S256())
if err != nil { if err != nil {
return payIntent, err return payIntent, err
} }
} }
if len(pubBytes) != 33 {
return payIntent, errors.New("invalid key length")
}
copy(payIntent.dest[:], pubBytes)
// Otherwise, If the payment request field was not specified // Otherwise, If the payment request field was not specified
// (and a custom route wasn't specified), construct the payment // (and a custom route wasn't specified), construct the payment
@ -3157,7 +3182,7 @@ func (r *rpcServer) sendPayment(stream *paymentStream) error {
return return
} }
marshalledRouted := r.marshallRoute(resp.Route) marshalledRouted := r.RouterBackend.MarshallRoute(resp.Route)
err := stream.send(&lnrpc.SendResponse{ err := stream.send(&lnrpc.SendResponse{
PaymentHash: payIntent.rHash[:], PaymentHash: payIntent.rHash[:],
PaymentPreimage: resp.Preimage[:], PaymentPreimage: resp.Preimage[:],
@ -3242,7 +3267,7 @@ func (r *rpcServer) sendPaymentSync(ctx context.Context,
return &lnrpc.SendResponse{ return &lnrpc.SendResponse{
PaymentHash: payIntent.rHash[:], PaymentHash: payIntent.rHash[:],
PaymentPreimage: resp.Preimage[:], PaymentPreimage: resp.Preimage[:],
PaymentRoute: r.marshallRoute(resp.Route), PaymentRoute: r.RouterBackend.MarshallRoute(resp.Route),
}, nil }, nil
} }
@ -4001,121 +4026,7 @@ func (r *rpcServer) GetNodeInfo(ctx context.Context,
func (r *rpcServer) QueryRoutes(ctx context.Context, func (r *rpcServer) QueryRoutes(ctx context.Context,
in *lnrpc.QueryRoutesRequest) (*lnrpc.QueryRoutesResponse, error) { in *lnrpc.QueryRoutesRequest) (*lnrpc.QueryRoutesResponse, error) {
// First parse the hex-encoded public key into a full public key object return r.RouterBackend.QueryRoutes(ctx, in)
// we can properly manipulate.
pubKeyBytes, err := hex.DecodeString(in.PubKey)
if err != nil {
return nil, err
}
pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256())
if err != nil {
return nil, err
}
// Currently, within the bootstrap phase of the network, we limit the
// largest payment size allotted to (2^32) - 1 mSAT or 4.29 million
// satoshis.
amt := btcutil.Amount(in.Amt)
amtMSat := lnwire.NewMSatFromSatoshis(amt)
if amtMSat > maxPaymentMSat {
return nil, fmt.Errorf("payment of %v is too large, max payment "+
"allowed is %v", amt, maxPaymentMSat.ToSatoshis())
}
feeLimit := calculateFeeLimit(in.FeeLimit, amtMSat)
// numRoutes will default to 10 if not specified explicitly.
numRoutesIn := uint32(in.NumRoutes)
if numRoutesIn == 0 {
numRoutesIn = 10
}
// Query the channel router for a possible path to the destination that
// can carry `in.Amt` satoshis _including_ the total fee required on
// the route.
var (
routes []*routing.Route
findErr error
)
if in.FinalCltvDelta == 0 {
routes, findErr = r.server.chanRouter.FindRoutes(
pubKey, amtMSat, feeLimit, numRoutesIn,
)
} else {
routes, findErr = r.server.chanRouter.FindRoutes(
pubKey, amtMSat, feeLimit, numRoutesIn,
uint16(in.FinalCltvDelta),
)
}
if findErr != nil {
return nil, findErr
}
// As the number of returned routes can be less than the number of
// requested routes, we'll clamp down the length of the response to the
// minimum of the two.
numRoutes := uint32(len(routes))
if numRoutesIn < numRoutes {
numRoutes = numRoutesIn
}
// For each valid route, we'll convert the result into the format
// required by the RPC system.
routeResp := &lnrpc.QueryRoutesResponse{
Routes: make([]*lnrpc.Route, 0, in.NumRoutes),
}
for i := uint32(0); i < numRoutes; i++ {
routeResp.Routes = append(
routeResp.Routes, r.marshallRoute(routes[i]),
)
}
return routeResp, nil
}
func (r *rpcServer) marshallRoute(route *routing.Route) *lnrpc.Route {
resp := &lnrpc.Route{
TotalTimeLock: route.TotalTimeLock,
TotalFees: int64(route.TotalFees.ToSatoshis()),
TotalFeesMsat: int64(route.TotalFees),
TotalAmt: int64(route.TotalAmount.ToSatoshis()),
TotalAmtMsat: int64(route.TotalAmount),
Hops: make([]*lnrpc.Hop, len(route.Hops)),
}
graph := r.server.chanDB.ChannelGraph()
incomingAmt := route.TotalAmount
for i, hop := range route.Hops {
fee := route.HopFee(i)
// Channel capacity is not a defining property of a route. For
// backwards RPC compatibility, we retrieve it here from the
// graph.
var chanCapacity btcutil.Amount
info, _, _, err := graph.FetchChannelEdgesByID(hop.ChannelID)
if err == nil {
chanCapacity = info.Capacity
} else {
// If capacity cannot be retrieved, this may be a
// not-yet-received or private channel. Then report
// amount that is sent through the channel as capacity.
chanCapacity = incomingAmt.ToSatoshis()
}
resp.Hops[i] = &lnrpc.Hop{
ChanId: hop.ChannelID,
ChanCapacity: int64(chanCapacity),
AmtToForward: int64(hop.AmtToForward.ToSatoshis()),
AmtToForwardMsat: int64(hop.AmtToForward),
Fee: int64(fee.ToSatoshis()),
FeeMsat: int64(fee),
Expiry: uint32(hop.OutgoingTimeLock),
PubKey: hex.EncodeToString(
hop.PubKeyBytes[:]),
}
incomingAmt = hop.AmtToForward
}
return resp
} }
// unmarshallHopByChannelLookup unmarshalls an rpc hop for which the pub key is // unmarshallHopByChannelLookup unmarshalls an rpc hop for which the pub key is