Merge pull request #5017 from Roasbeef/default-max-parts

routing: if MaxShardAmt is set, then use that as a ceiling for our splits, use default of 16 for MaxParts
This commit is contained in:
Conner Fromknecht 2021-02-16 09:43:34 -08:00 committed by GitHub
commit db5af6fc14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 328 additions and 184 deletions

@ -14,12 +14,14 @@ import (
"strings" "strings"
"time" "time"
"github.com/btcsuite/btcutil"
"github.com/jedib0t/go-pretty/table" "github.com/jedib0t/go-pretty/table"
"github.com/jedib0t/go-pretty/text" "github.com/jedib0t/go-pretty/text"
"github.com/lightninglabs/protobuf-hex-display/jsonpb" "github.com/lightninglabs/protobuf-hex-display/jsonpb"
"github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc" "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/record" "github.com/lightningnetwork/lnd/record"
"github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/routing/route"
"github.com/urfave/cli" "github.com/urfave/cli"
@ -62,7 +64,7 @@ var (
Name: "max_parts", Name: "max_parts",
Usage: "the maximum number of partial payments that may be " + Usage: "the maximum number of partial payments that may be " +
"used", "used",
Value: 1, Value: routerrpc.DefaultMaxParts,
} }
jsonFlag = cli.BoolFlag{ jsonFlag = cli.BoolFlag{
@ -71,6 +73,20 @@ var (
"messages. Set by default on Windows because table " + "messages. Set by default on Windows because table " +
"formatting is unsupported.", "formatting is unsupported.",
} }
maxShardSizeSatFlag = cli.UintFlag{
Name: "max_shard_size_sat",
Usage: "the largest payment split that should be attempted if " +
"payment splitting is required to attempt a payment, " +
"specified in satoshis",
}
maxShardSizeMsatFlag = cli.UintFlag{
Name: "max_shard_size_msat",
Usage: "the largest payment split that should be attempted if " +
"payment splitting is required to attempt a payment, " +
"specified in milli-satoshis",
}
) )
// paymentFlags returns common flags for sendpayment and payinvoice. // paymentFlags returns common flags for sendpayment and payinvoice.
@ -115,6 +131,7 @@ func paymentFlags() []cli.Flag {
Usage: "allow sending a circular payment to self", Usage: "allow sending a circular payment to self",
}, },
dataFlag, inflightUpdatesFlag, maxPartsFlag, jsonFlag, dataFlag, inflightUpdatesFlag, maxPartsFlag, jsonFlag,
maxShardSizeSatFlag, maxShardSizeMsatFlag,
} }
} }
@ -354,6 +371,23 @@ func sendPaymentRequest(ctx *cli.Context,
req.MaxParts = uint32(ctx.Uint(maxPartsFlag.Name)) req.MaxParts = uint32(ctx.Uint(maxPartsFlag.Name))
switch {
// If the max shard size is specified, then it should either be in sat
// or msat, but not both.
case ctx.Uint64(maxShardSizeMsatFlag.Name) != 0 &&
ctx.Uint64(maxShardSizeSatFlag.Name) != 0:
return fmt.Errorf("only --max_split_size_msat or " +
"--max_split_size_sat should be set, but not both")
case ctx.Uint64(maxShardSizeMsatFlag.Name) != 0:
req.MaxShardSizeMsat = ctx.Uint64(maxShardSizeMsatFlag.Name)
case ctx.Uint64(maxShardSizeSatFlag.Name) != 0:
req.MaxShardSizeMsat = uint64(lnwire.NewMSatFromSatoshis(
btcutil.Amount(ctx.Uint64(maxShardSizeSatFlag.Name)),
))
}
// Parse custom data records. // Parse custom data records.
data := ctx.String(dataFlag.Name) data := ctx.String(dataFlag.Name)
if data != "" { if data != "" {

@ -323,6 +323,12 @@ type SendPaymentRequest struct {
//If set, only the final payment update is streamed back. Intermediate updates //If set, only the final payment update is streamed back. Intermediate updates
//that show which htlcs are still in flight are suppressed. //that show which htlcs are still in flight are suppressed.
NoInflightUpdates bool `protobuf:"varint,18,opt,name=no_inflight_updates,json=noInflightUpdates,proto3" json:"no_inflight_updates,omitempty"` NoInflightUpdates bool `protobuf:"varint,18,opt,name=no_inflight_updates,json=noInflightUpdates,proto3" json:"no_inflight_updates,omitempty"`
//
//The largest payment split that should be attempted when making a payment if
//splitting is necessary. Setting this value will effectively cause lnd to
//split more aggressively, vs only when it thinks it needs to. Note that this
//value is in milli-satoshis.
MaxShardSizeMsat uint64 `protobuf:"varint,21,opt,name=max_shard_size_msat,json=maxShardSizeMsat,proto3" json:"max_shard_size_msat,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:"-"`
@ -494,6 +500,13 @@ func (m *SendPaymentRequest) GetNoInflightUpdates() bool {
return false return false
} }
func (m *SendPaymentRequest) GetMaxShardSizeMsat() uint64 {
if m != nil {
return m.MaxShardSizeMsat
}
return 0
}
type TrackPaymentRequest struct { type TrackPaymentRequest struct {
// The hash of the payment to look up. // The hash of the payment to look up.
PaymentHash []byte `protobuf:"bytes,1,opt,name=payment_hash,json=paymentHash,proto3" json:"payment_hash,omitempty"` PaymentHash []byte `protobuf:"bytes,1,opt,name=payment_hash,json=paymentHash,proto3" json:"payment_hash,omitempty"`
@ -2290,184 +2303,186 @@ func init() {
func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) } func init() { proto.RegisterFile("routerrpc/router.proto", fileDescriptor_7a0613f69d37b0a5) }
var fileDescriptor_7a0613f69d37b0a5 = []byte{ var fileDescriptor_7a0613f69d37b0a5 = []byte{
// 2823 bytes of a gzipped FileDescriptorProto // 2854 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0xcb, 0x7a, 0xdb, 0xc6, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x59, 0x4b, 0x77, 0xdb, 0xc6,
0x15, 0x0e, 0x78, 0x13, 0x79, 0x78, 0x83, 0x46, 0xb2, 0xc5, 0x52, 0xbe, 0x30, 0x4c, 0x62, 0xb3, 0x15, 0x0e, 0x48, 0x8a, 0x22, 0x2f, 0x5f, 0xd0, 0x50, 0xb6, 0x58, 0xca, 0x0f, 0x86, 0x79, 0x98,
0x6e, 0x22, 0x3b, 0x6a, 0xbf, 0x24, 0x6d, 0x2e, 0x0d, 0x45, 0x42, 0x16, 0x6c, 0x8a, 0x54, 0x86, 0x75, 0x13, 0xd9, 0x51, 0x7b, 0x92, 0xb4, 0x79, 0x34, 0x14, 0x09, 0x59, 0xb0, 0x29, 0x52, 0x19,
0x94, 0x13, 0x27, 0x8b, 0x29, 0x44, 0x0e, 0x45, 0x54, 0xb8, 0xb0, 0xc0, 0xd0, 0xb6, 0x76, 0xed, 0x52, 0x4e, 0x9c, 0x2c, 0xa6, 0x10, 0x39, 0x14, 0x51, 0xe1, 0xc1, 0x02, 0x43, 0xdb, 0xca, 0xaa,
0xae, 0x5f, 0x1f, 0xa0, 0xcf, 0xd0, 0x55, 0x9f, 0xa0, 0xdf, 0xd7, 0xae, 0xfb, 0x12, 0xdd, 0xf6, 0xdd, 0xf5, 0xf4, 0x97, 0x74, 0xd5, 0x5f, 0xd0, 0x73, 0xda, 0x4d, 0x37, 0xfd, 0x13, 0xdd, 0xf6,
0x09, 0xba, 0xee, 0x37, 0x83, 0x01, 0x08, 0x48, 0x94, 0xe4, 0x5e, 0x36, 0x36, 0xf1, 0x9f, 0x7f, 0x17, 0x74, 0xdd, 0x33, 0x83, 0x01, 0x08, 0x48, 0x94, 0xe4, 0x3e, 0x36, 0x36, 0xf1, 0xdd, 0x6f,
0xce, 0x9c, 0x99, 0x39, 0xb7, 0x19, 0xc1, 0x6d, 0xcf, 0x5d, 0x30, 0xea, 0x79, 0xf3, 0xf1, 0xe3, 0xee, 0xdc, 0xb9, 0x73, 0xef, 0x9d, 0x3b, 0x23, 0xb8, 0xed, 0xb9, 0x0b, 0x46, 0x3d, 0x6f, 0x3e,
0xe0, 0xd7, 0xce, 0xdc, 0x73, 0x99, 0x8b, 0x0a, 0x11, 0x5e, 0x2f, 0x78, 0xf3, 0x71, 0x80, 0x36, 0x7e, 0x14, 0xfc, 0xda, 0x99, 0x7b, 0x2e, 0x73, 0x51, 0x3e, 0xc2, 0xeb, 0x79, 0x6f, 0x3e, 0x0e,
0xff, 0xb8, 0x06, 0x68, 0x48, 0x9d, 0xc9, 0x91, 0x71, 0x6e, 0x53, 0x87, 0x61, 0xfa, 0x9b, 0x05, 0xd0, 0xe6, 0xdf, 0xd6, 0x01, 0x0d, 0xa9, 0x33, 0x39, 0x32, 0xce, 0x6d, 0xea, 0x30, 0x4c, 0x7f,
0xf5, 0x19, 0x42, 0x90, 0x99, 0x50, 0x9f, 0xd5, 0x94, 0x86, 0xd2, 0x2a, 0x61, 0xf1, 0x1b, 0xa9, 0xb3, 0xa0, 0x3e, 0x43, 0x08, 0x32, 0x13, 0xea, 0xb3, 0x9a, 0xd2, 0x50, 0x5a, 0x45, 0x2c, 0x7e,
0x90, 0x36, 0x6c, 0x56, 0x4b, 0x35, 0x94, 0x56, 0x1a, 0xf3, 0x9f, 0xe8, 0x47, 0x90, 0x37, 0x6c, 0x23, 0x15, 0xd2, 0x86, 0xcd, 0x6a, 0xa9, 0x86, 0xd2, 0x4a, 0x63, 0xfe, 0x13, 0xfd, 0x08, 0x72,
0x46, 0x6c, 0xdf, 0x60, 0xb5, 0x92, 0x80, 0xd7, 0x0c, 0x9b, 0x1d, 0xfa, 0x06, 0x43, 0xef, 0x42, 0x86, 0xcd, 0x88, 0xed, 0x1b, 0xac, 0x56, 0x14, 0xf0, 0xba, 0x61, 0xb3, 0x43, 0xdf, 0x60, 0xe8,
0x69, 0x1e, 0xa8, 0x24, 0x33, 0xc3, 0x9f, 0xd5, 0xd2, 0x42, 0x51, 0x51, 0x62, 0x07, 0x86, 0x3f, 0x6d, 0x28, 0xce, 0x03, 0x95, 0x64, 0x66, 0xf8, 0xb3, 0x5a, 0x5a, 0x28, 0x2a, 0x48, 0xec, 0xc0,
0x43, 0x2d, 0x50, 0xa7, 0xa6, 0x63, 0x58, 0x64, 0x6c, 0xb1, 0x57, 0x64, 0x42, 0x2d, 0x66, 0xd4, 0xf0, 0x67, 0xa8, 0x05, 0xea, 0xd4, 0x74, 0x0c, 0x8b, 0x8c, 0x2d, 0xf6, 0x92, 0x4c, 0xa8, 0xc5,
0x32, 0x0d, 0xa5, 0x95, 0xc5, 0x15, 0x81, 0x77, 0x2c, 0xf6, 0xaa, 0xcb, 0xd1, 0xb8, 0x32, 0x63, 0x8c, 0x5a, 0xa6, 0xa1, 0xb4, 0xd6, 0x70, 0x59, 0xe0, 0x1d, 0x8b, 0xbd, 0xec, 0x72, 0x34, 0xae,
0x32, 0xf1, 0x6a, 0x9b, 0x09, 0x65, 0xed, 0xc9, 0xc4, 0x43, 0x0f, 0xa1, 0x1a, 0x52, 0xbc, 0x60, 0xcc, 0x98, 0x4c, 0xbc, 0xda, 0x66, 0x42, 0x59, 0x7b, 0x32, 0xf1, 0xd0, 0x03, 0xa8, 0x84, 0x14,
0x0d, 0xb5, 0x6c, 0x43, 0x69, 0x15, 0x70, 0x65, 0x9e, 0x5c, 0xd9, 0x43, 0xa8, 0x32, 0xd3, 0xa6, 0x2f, 0x58, 0x43, 0x6d, 0xad, 0xa1, 0xb4, 0xf2, 0xb8, 0x3c, 0x4f, 0xae, 0xec, 0x01, 0x54, 0x98,
0xee, 0x82, 0x11, 0x9f, 0x8e, 0x5d, 0x67, 0xe2, 0xd7, 0x72, 0xc1, 0xa4, 0x12, 0x1e, 0x06, 0x28, 0x69, 0x53, 0x77, 0xc1, 0x88, 0x4f, 0xc7, 0xae, 0x33, 0xf1, 0x6b, 0xd9, 0x60, 0x52, 0x09, 0x0f,
0x6a, 0x42, 0x79, 0x4a, 0x29, 0xb1, 0x4c, 0xdb, 0x64, 0x84, 0xaf, 0x70, 0x4d, 0xac, 0xb0, 0x38, 0x03, 0x14, 0x35, 0xa1, 0x34, 0xa5, 0x94, 0x58, 0xa6, 0x6d, 0x32, 0xc2, 0x57, 0xb8, 0x2e, 0x56,
0xa5, 0xb4, 0xc7, 0xb1, 0xa1, 0xc1, 0xd0, 0xfb, 0x50, 0x59, 0x72, 0xc4, 0x36, 0x94, 0x05, 0xa9, 0x58, 0x98, 0x52, 0xda, 0xe3, 0xd8, 0xd0, 0x60, 0xe8, 0x5d, 0x28, 0x2f, 0x39, 0xc2, 0x0d, 0x25,
0x14, 0x92, 0xc4, 0x5e, 0xec, 0x80, 0xea, 0x2e, 0xd8, 0xa9, 0x6b, 0x3a, 0xa7, 0x64, 0x3c, 0x33, 0x41, 0x2a, 0x86, 0x24, 0xe1, 0x8b, 0x1d, 0x50, 0xdd, 0x05, 0x3b, 0x75, 0x4d, 0xe7, 0x94, 0x8c,
0x1c, 0x62, 0x4e, 0x6a, 0xf9, 0x86, 0xd2, 0xca, 0xec, 0x65, 0x6a, 0xca, 0x13, 0x05, 0x57, 0x42, 0x67, 0x86, 0x43, 0xcc, 0x49, 0x2d, 0xd7, 0x50, 0x5a, 0x99, 0xbd, 0x4c, 0x4d, 0x79, 0xac, 0xe0,
0x69, 0x67, 0x66, 0x38, 0xfa, 0x04, 0x3d, 0x82, 0xf5, 0x8b, 0x7c, 0xbf, 0xb6, 0xd1, 0x48, 0xb7, 0x72, 0x28, 0xed, 0xcc, 0x0c, 0x47, 0x9f, 0xa0, 0x87, 0xb0, 0x71, 0x91, 0xef, 0xd7, 0xaa, 0x8d,
0x32, 0xb8, 0x9a, 0xa4, 0xfa, 0xe8, 0x01, 0x54, 0x2d, 0xc3, 0x67, 0x64, 0xe6, 0xce, 0xc9, 0x7c, 0x74, 0x2b, 0x83, 0x2b, 0x49, 0xaa, 0x8f, 0xde, 0x87, 0x8a, 0x65, 0xf8, 0x8c, 0xcc, 0xdc, 0x39,
0x71, 0x72, 0x46, 0xcf, 0x6b, 0x15, 0xb1, 0x3b, 0x65, 0x0e, 0x1f, 0xb8, 0xf3, 0x23, 0x01, 0xa2, 0x99, 0x2f, 0x4e, 0xce, 0xe8, 0x79, 0xad, 0x2c, 0xbc, 0x53, 0xe2, 0xf0, 0x81, 0x3b, 0x3f, 0x12,
0xbb, 0x00, 0x62, 0x9b, 0x85, 0xa9, 0xb5, 0x82, 0x58, 0x71, 0x81, 0x23, 0xc2, 0x4c, 0xf4, 0x31, 0x20, 0xba, 0x0b, 0x20, 0xdc, 0x2c, 0x4c, 0xad, 0xe5, 0xc5, 0x8a, 0xf3, 0x1c, 0x11, 0x66, 0xa2,
0x14, 0x85, 0x7b, 0x90, 0x99, 0xe9, 0x30, 0xbf, 0x06, 0x8d, 0x74, 0xab, 0xb8, 0xab, 0xee, 0x58, 0x8f, 0xa0, 0x20, 0xc2, 0x83, 0xcc, 0x4c, 0x87, 0xf9, 0x35, 0x68, 0xa4, 0x5b, 0x85, 0x5d, 0x75,
0x0e, 0xf7, 0x14, 0xcc, 0x25, 0x07, 0xa6, 0xc3, 0x30, 0x78, 0xe1, 0x4f, 0x1f, 0x4d, 0x60, 0x83, 0xc7, 0x72, 0x78, 0xa4, 0x60, 0x2e, 0x39, 0x30, 0x1d, 0x86, 0xc1, 0x0b, 0x7f, 0xfa, 0x68, 0x02,
0xbb, 0x05, 0x19, 0x2f, 0x7c, 0xe6, 0xda, 0xc4, 0xa3, 0x63, 0xd7, 0x9b, 0xf8, 0xb5, 0xa2, 0x18, 0x55, 0x1e, 0x16, 0x64, 0xbc, 0xf0, 0x99, 0x6b, 0x13, 0x8f, 0x8e, 0x5d, 0x6f, 0xe2, 0xd7, 0x0a,
0xfa, 0xb3, 0x9d, 0xc8, 0xdb, 0x76, 0x2e, 0xbb, 0xd7, 0x4e, 0x97, 0xfa, 0xac, 0x23, 0xc6, 0xe1, 0x62, 0xe8, 0xcf, 0x76, 0xa2, 0x68, 0xdb, 0xb9, 0x1c, 0x5e, 0x3b, 0x5d, 0xea, 0xb3, 0x8e, 0x18,
0x60, 0x98, 0xe6, 0x30, 0xef, 0x1c, 0xaf, 0x4f, 0x2e, 0xe2, 0xe8, 0x43, 0x40, 0x86, 0x65, 0xb9, 0x87, 0x83, 0x61, 0x9a, 0xc3, 0xbc, 0x73, 0xbc, 0x31, 0xb9, 0x88, 0xa3, 0x0f, 0x00, 0x19, 0x96,
0xaf, 0x89, 0x4f, 0xad, 0x29, 0x91, 0x67, 0x59, 0xab, 0x36, 0x94, 0x56, 0x1e, 0xab, 0x42, 0x32, 0xe5, 0xbe, 0x22, 0x3e, 0xb5, 0xa6, 0x44, 0xee, 0x65, 0xad, 0xd2, 0x50, 0x5a, 0x39, 0xac, 0x0a,
0xa4, 0xd6, 0x54, 0xaa, 0x47, 0x9f, 0x40, 0x59, 0xd8, 0x34, 0xa5, 0x06, 0x5b, 0x78, 0xd4, 0xaf, 0xc9, 0x90, 0x5a, 0x53, 0xa9, 0x1e, 0x7d, 0x0c, 0x25, 0x61, 0xd3, 0x94, 0x1a, 0x6c, 0xe1, 0x51,
0xa9, 0x8d, 0x74, 0xab, 0xb2, 0xbb, 0x2e, 0x17, 0xb2, 0x1f, 0xc0, 0x7b, 0x26, 0xc3, 0x25, 0xce, 0xbf, 0xa6, 0x36, 0xd2, 0xad, 0xf2, 0xee, 0x86, 0x5c, 0xc8, 0x7e, 0x00, 0xef, 0x99, 0x0c, 0x17,
0x93, 0xdf, 0x3e, 0xda, 0x86, 0x82, 0x6d, 0xbc, 0x21, 0x73, 0xc3, 0x63, 0x7e, 0x6d, 0xbd, 0xa1, 0x39, 0x4f, 0x7e, 0xfb, 0x68, 0x1b, 0xf2, 0xb6, 0xf1, 0x9a, 0xcc, 0x0d, 0x8f, 0xf9, 0xb5, 0x8d,
0xb4, 0xca, 0x38, 0x6f, 0x1b, 0x6f, 0x8e, 0xf8, 0x37, 0xda, 0x81, 0x0d, 0xc7, 0x25, 0xa6, 0x33, 0x86, 0xd2, 0x2a, 0xe1, 0x9c, 0x6d, 0xbc, 0x3e, 0xe2, 0xdf, 0x68, 0x07, 0xaa, 0x8e, 0x4b, 0x4c,
0xb5, 0xcc, 0xd3, 0x19, 0x23, 0x8b, 0xf9, 0xc4, 0x60, 0xd4, 0xaf, 0x21, 0x61, 0xc3, 0xba, 0xe3, 0x67, 0x6a, 0x99, 0xa7, 0x33, 0x46, 0x16, 0xf3, 0x89, 0xc1, 0xa8, 0x5f, 0x43, 0xc2, 0x86, 0x0d,
0xea, 0x52, 0x72, 0x1c, 0x08, 0xea, 0x5d, 0xb8, 0xbd, 0x7a, 0x7d, 0x3c, 0x82, 0xf8, 0x01, 0xf1, 0xc7, 0xd5, 0xa5, 0xe4, 0x38, 0x10, 0xa0, 0x0f, 0xa1, 0xca, 0x95, 0xf9, 0x33, 0xc3, 0x9b, 0x10,
0xa0, 0xca, 0x60, 0xfe, 0x13, 0x6d, 0x42, 0xf6, 0x95, 0x61, 0x2d, 0xa8, 0x88, 0xaa, 0x12, 0x0e, 0xdf, 0xfc, 0x81, 0x06, 0x91, 0x71, 0x8b, 0xef, 0x38, 0x56, 0x6d, 0xe3, 0xf5, 0x90, 0x4b, 0x86,
0x3e, 0x7e, 0x91, 0xfa, 0x4c, 0x69, 0xce, 0x60, 0x63, 0xe4, 0x19, 0xe3, 0xb3, 0x0b, 0x81, 0x79, 0xe6, 0x0f, 0x94, 0x47, 0x47, 0xbd, 0x0b, 0xb7, 0x57, 0xbb, 0x83, 0x27, 0x1c, 0xdf, 0x4f, 0x45,
0x31, 0xae, 0x94, 0xcb, 0x71, 0x75, 0x85, 0xbd, 0xa9, 0x2b, 0xec, 0x6d, 0x7e, 0x05, 0x55, 0x71, 0x0c, 0xe4, 0x3f, 0xd1, 0x26, 0xac, 0xbd, 0x34, 0xac, 0x05, 0x15, 0x49, 0x58, 0xc4, 0xc1, 0xc7,
0xc2, 0xfb, 0x94, 0x5e, 0x17, 0xfe, 0x5b, 0xc0, 0x83, 0x5b, 0x44, 0x42, 0x90, 0x02, 0x72, 0x86, 0x2f, 0x52, 0x9f, 0x2a, 0xcd, 0x19, 0x54, 0x47, 0x9e, 0x31, 0x3e, 0xbb, 0x90, 0xc7, 0x17, 0xd3,
0xcd, 0x83, 0xa0, 0x39, 0x01, 0x75, 0x39, 0xde, 0x9f, 0xbb, 0x8e, 0x4f, 0x79, 0x6c, 0x73, 0x07, 0x50, 0xb9, 0x9c, 0x86, 0x57, 0x2c, 0x2f, 0x75, 0xc5, 0xf2, 0x9a, 0x5f, 0x42, 0x45, 0x04, 0xc4,
0xe0, 0x1e, 0xcc, 0x03, 0x44, 0x84, 0x86, 0x22, 0x46, 0x55, 0x24, 0xbe, 0x4f, 0xa9, 0x08, 0x8e, 0x3e, 0xa5, 0xd7, 0x55, 0x8b, 0x2d, 0xe0, 0xb5, 0x40, 0x24, 0x4e, 0x50, 0x31, 0xb2, 0x86, 0xcd,
0x07, 0x41, 0x3c, 0x12, 0xcb, 0x1d, 0x9f, 0xf1, 0x24, 0x60, 0x9c, 0x4b, 0xf5, 0x65, 0x0e, 0xf7, 0x73, 0xa6, 0x39, 0x01, 0x75, 0x39, 0xde, 0x9f, 0xbb, 0x8e, 0x4f, 0x79, 0x29, 0xe0, 0xf1, 0xc2,
0xdc, 0xf1, 0x59, 0x97, 0x83, 0xcd, 0x1f, 0x82, 0x3c, 0x35, 0x72, 0xc5, 0x5c, 0xff, 0xc1, 0x76, 0x03, 0x9e, 0xe7, 0x93, 0xf0, 0x97, 0x22, 0x46, 0x95, 0x25, 0xbe, 0x4f, 0x85, 0xb7, 0x78, 0xbc,
0x34, 0x21, 0x2b, 0x7c, 0x51, 0xa8, 0x2d, 0xee, 0x96, 0xe2, 0x4e, 0x8d, 0x03, 0x51, 0xf3, 0x07, 0xf3, 0x3c, 0x25, 0x96, 0x3b, 0x3e, 0xe3, 0x35, 0xc3, 0x38, 0x97, 0xea, 0x4b, 0x1c, 0xee, 0xb9,
0xd8, 0x48, 0x28, 0x97, 0xab, 0xa8, 0x43, 0x7e, 0xee, 0x51, 0xd3, 0x36, 0x4e, 0xa9, 0xd4, 0x1c, 0xe3, 0xb3, 0x2e, 0x07, 0x9b, 0xdf, 0x07, 0x65, 0x6d, 0xe4, 0x8a, 0xb9, 0xfe, 0x03, 0x77, 0x34,
0x7d, 0xa3, 0x16, 0xac, 0x4d, 0x0d, 0xd3, 0x5a, 0x78, 0xa1, 0xe2, 0x4a, 0xe8, 0x64, 0x01, 0x8a, 0x61, 0x4d, 0x84, 0xae, 0x50, 0x5b, 0xd8, 0x2d, 0xc6, 0x73, 0x00, 0x07, 0xa2, 0xe6, 0xf7, 0x50,
0x43, 0x71, 0xf3, 0x0e, 0xd4, 0x31, 0xf5, 0x29, 0x3b, 0x34, 0x7d, 0xdf, 0x74, 0x9d, 0x8e, 0xeb, 0x4d, 0x28, 0x97, 0xab, 0xa8, 0x43, 0x6e, 0xee, 0x51, 0xd3, 0x36, 0x4e, 0xa9, 0xd4, 0x1c, 0x7d,
0x30, 0xcf, 0xb5, 0xe4, 0x0a, 0x9a, 0x77, 0x61, 0x7b, 0xa5, 0x34, 0x30, 0x81, 0x0f, 0xfe, 0x66, 0xa3, 0x16, 0xac, 0x4f, 0x0d, 0xd3, 0x5a, 0x78, 0xa1, 0xe2, 0x72, 0x18, 0x93, 0x01, 0x8a, 0x43,
0x41, 0xbd, 0xf3, 0xd5, 0x83, 0xbf, 0x81, 0xed, 0x95, 0x52, 0x69, 0xff, 0x87, 0x90, 0x9d, 0x1b, 0x71, 0xf3, 0x0e, 0xd4, 0x31, 0xf5, 0x29, 0x3b, 0x34, 0x7d, 0xdf, 0x74, 0x9d, 0x8e, 0xeb, 0x30,
0xa6, 0xc7, 0xcf, 0x9e, 0x07, 0xe5, 0xed, 0x58, 0x50, 0x1e, 0x19, 0xa6, 0x77, 0x60, 0xfa, 0xcc, 0xcf, 0xb5, 0xe4, 0x0a, 0x9a, 0x77, 0x61, 0x7b, 0xa5, 0x34, 0x30, 0x81, 0x0f, 0xfe, 0x7a, 0x41,
0xf5, 0xce, 0x71, 0x40, 0x7a, 0x96, 0xc9, 0x2b, 0x6a, 0xaa, 0xf9, 0x07, 0x05, 0x8a, 0x31, 0x21, 0xbd, 0xf3, 0xd5, 0x83, 0xbf, 0x86, 0xed, 0x95, 0x52, 0x69, 0xff, 0x07, 0xb0, 0x36, 0x37, 0x4c,
0x0f, 0x0d, 0xc7, 0x9d, 0x50, 0x32, 0xf5, 0x5c, 0x3b, 0xdc, 0x04, 0x0e, 0xec, 0x7b, 0xae, 0xcd, 0x8f, 0xef, 0x3d, 0xcf, 0xe1, 0xdb, 0xb1, 0x1c, 0x3e, 0x32, 0x4c, 0xef, 0xc0, 0xf4, 0x99, 0xeb,
0x7d, 0x42, 0x08, 0x99, 0x2b, 0x1d, 0x38, 0xc7, 0x3f, 0x47, 0x2e, 0xfa, 0x08, 0xd6, 0x66, 0x81, 0x9d, 0xe3, 0x80, 0xf4, 0x34, 0x93, 0x53, 0xd4, 0x54, 0xf3, 0x0f, 0x0a, 0x14, 0x62, 0x42, 0x9e,
0x02, 0x91, 0x36, 0x8b, 0xbb, 0x1b, 0x17, 0xe6, 0xee, 0x1a, 0xcc, 0xc0, 0x21, 0xe7, 0x59, 0x26, 0x49, 0x8e, 0x3b, 0xa1, 0x64, 0xea, 0xb9, 0x76, 0xe8, 0x04, 0x0e, 0xec, 0x7b, 0xae, 0xcd, 0x63,
0x9f, 0x56, 0x33, 0xcf, 0x32, 0xf9, 0x8c, 0x9a, 0x7d, 0x96, 0xc9, 0x67, 0xd5, 0xdc, 0xb3, 0x4c, 0x42, 0x08, 0x99, 0x2b, 0x03, 0x38, 0xcb, 0x3f, 0x47, 0x2e, 0xfa, 0x10, 0xd6, 0x67, 0x81, 0x02,
0x3e, 0xa7, 0xae, 0x35, 0xff, 0xa9, 0x40, 0x3e, 0x64, 0x73, 0x4b, 0xf8, 0x96, 0x12, 0xee, 0x17, 0x51, 0x65, 0x0b, 0xbb, 0xd5, 0x0b, 0x73, 0x77, 0x0d, 0x66, 0xe0, 0x90, 0xf3, 0x34, 0x93, 0x4b,
0xd2, 0x99, 0xf2, 0x1c, 0x18, 0x99, 0x36, 0x45, 0x0d, 0x28, 0x09, 0x61, 0xd2, 0x45, 0x81, 0x63, 0xab, 0x99, 0xa7, 0x99, 0x5c, 0x46, 0x5d, 0x7b, 0x9a, 0xc9, 0xad, 0xa9, 0xd9, 0xa7, 0x99, 0x5c,
0x6d, 0xe1, 0xa6, 0x22, 0x9f, 0x87, 0x0c, 0xe1, 0x8f, 0x19, 0x99, 0xcf, 0x03, 0x4a, 0x58, 0xb5, 0x56, 0x5d, 0x6f, 0xfe, 0x53, 0x81, 0x5c, 0xc8, 0xe6, 0x96, 0x70, 0x97, 0x12, 0x1e, 0x17, 0x32,
0xfc, 0xc5, 0x78, 0x4c, 0x7d, 0x3f, 0x98, 0x25, 0x1b, 0x50, 0x24, 0x26, 0x26, 0x7a, 0x00, 0xd5, 0x98, 0x72, 0x1c, 0x18, 0x99, 0x36, 0x45, 0x0d, 0x28, 0x0a, 0x61, 0x32, 0x44, 0x81, 0x63, 0x6d,
0x90, 0x12, 0xce, 0x95, 0x0b, 0xfc, 0x55, 0xc2, 0x72, 0xba, 0x16, 0xa8, 0x71, 0x9e, 0xbd, 0xac, 0x11, 0xa6, 0xa2, 0xfc, 0x87, 0x0c, 0x11, 0x8f, 0x19, 0x59, 0xfe, 0x03, 0x4a, 0x78, 0xc8, 0xf9,
0x20, 0x95, 0x25, 0x91, 0x4f, 0x1a, 0x2c, 0xbe, 0xd9, 0x80, 0x7b, 0x4f, 0x2f, 0x7a, 0x41, 0xc7, 0x8b, 0xf1, 0x98, 0xfa, 0x7e, 0x30, 0xcb, 0x5a, 0x40, 0x91, 0x98, 0x98, 0xe8, 0x7d, 0xa8, 0x84,
0x75, 0xa6, 0xe6, 0x69, 0x78, 0xd8, 0xdf, 0xc3, 0xfd, 0x2b, 0x19, 0xf2, 0xc0, 0x3f, 0x85, 0xdc, 0x94, 0x70, 0xae, 0x6c, 0x10, 0xaf, 0x12, 0x96, 0xd3, 0xb5, 0x40, 0x8d, 0xf3, 0xec, 0xe5, 0x81,
0x58, 0x20, 0x62, 0x7f, 0x8a, 0xbb, 0xf7, 0x63, 0xbb, 0xbe, 0x72, 0xa0, 0xa4, 0x37, 0x5f, 0xc2, 0x53, 0x5e, 0x12, 0xf9, 0xa4, 0xc1, 0xe2, 0x9b, 0x0d, 0xb8, 0xf7, 0xe4, 0x62, 0x14, 0x74, 0x5c,
0xbd, 0xe1, 0xb5, 0xb3, 0xff, 0xf7, 0xaa, 0xdf, 0x85, 0xfb, 0xc3, 0xeb, 0xcd, 0x6e, 0xfe, 0x36, 0x67, 0x6a, 0x9e, 0x86, 0x9b, 0xfd, 0x1d, 0xdc, 0xbf, 0x92, 0x21, 0x37, 0xfc, 0x13, 0xc8, 0x8e,
0x05, 0x9b, 0xab, 0x08, 0xbc, 0x12, 0xce, 0x0c, 0x6b, 0x4a, 0x2c, 0x73, 0x4a, 0xa3, 0x72, 0x1d, 0x05, 0x22, 0xfc, 0x53, 0xd8, 0xbd, 0x1f, 0xf3, 0xfa, 0xca, 0x81, 0x92, 0xde, 0x7c, 0x01, 0xf7,
0xa4, 0xcf, 0x2a, 0x17, 0xf4, 0xcc, 0x29, 0x0d, 0xeb, 0xf5, 0x43, 0xa8, 0x8a, 0x22, 0xe8, 0xb9, 0x86, 0xd7, 0xce, 0xfe, 0xdf, 0xab, 0x7e, 0x1b, 0xee, 0x0f, 0xaf, 0x37, 0xbb, 0xf9, 0xdb, 0x14,
0x27, 0xc6, 0x89, 0x69, 0x99, 0x2c, 0x48, 0x24, 0x29, 0x5c, 0x99, 0xb9, 0xf3, 0xa3, 0x25, 0x8a, 0x6c, 0xae, 0x22, 0xf0, 0x83, 0x73, 0x66, 0x58, 0x53, 0x62, 0x99, 0x53, 0x1a, 0x9d, 0xee, 0x41,
0x6e, 0x43, 0xee, 0x35, 0xe5, 0x09, 0x50, 0x34, 0x25, 0x29, 0x2c, 0xbf, 0xd0, 0x27, 0xb0, 0x65, 0xf9, 0xac, 0x70, 0x41, 0xcf, 0x9c, 0xd2, 0xf0, 0x78, 0x7f, 0x00, 0x15, 0x71, 0x66, 0x7a, 0xee,
0x1b, 0x6f, 0x4c, 0x7b, 0x61, 0x93, 0x65, 0x2b, 0xe1, 0x2f, 0x2c, 0xe6, 0x0b, 0x57, 0x29, 0xe3, 0x89, 0x71, 0x62, 0x5a, 0x26, 0x0b, 0x0a, 0x49, 0x0a, 0x97, 0x67, 0xee, 0xfc, 0x68, 0x89, 0xa2,
0x5b, 0x52, 0x1c, 0xa5, 0x64, 0x21, 0x44, 0x1d, 0xb8, 0x67, 0x9b, 0x8e, 0x18, 0x27, 0x43, 0x9e, 0xdb, 0x90, 0x7d, 0x45, 0x79, 0x01, 0x14, 0x3d, 0x4c, 0x0a, 0xcb, 0x2f, 0xf4, 0x31, 0x6c, 0xd9,
0x78, 0xd4, 0x32, 0xde, 0x10, 0xd3, 0x61, 0xd4, 0x7b, 0x65, 0x58, 0xc2, 0x8d, 0x32, 0x78, 0x5b, 0xc6, 0x6b, 0xd3, 0x5e, 0xd8, 0x64, 0xd9, 0x79, 0xf8, 0x0b, 0x8b, 0xf9, 0x22, 0x54, 0x4a, 0xf8,
0xb2, 0xc2, 0x04, 0xc1, 0x39, 0xba, 0xa4, 0x34, 0x7f, 0x0d, 0x5b, 0x22, 0x92, 0x63, 0x86, 0x86, 0x96, 0x14, 0x47, 0x25, 0x59, 0x08, 0x51, 0x07, 0xee, 0xd9, 0xa6, 0x23, 0xc6, 0xc9, 0x94, 0x27,
0x3b, 0xcf, 0xfd, 0xde, 0x73, 0x6d, 0xc2, 0x43, 0x2b, 0x8c, 0x40, 0x0e, 0xf4, 0xdd, 0x09, 0xe5, 0x1e, 0xb5, 0x8c, 0xd7, 0xc4, 0x74, 0x18, 0xf5, 0x5e, 0x1a, 0x96, 0x08, 0xa3, 0x0c, 0xde, 0x96,
0x11, 0xc8, 0xdc, 0x40, 0x24, 0x23, 0x90, 0xb9, 0x42, 0x10, 0xef, 0xcd, 0xd2, 0x89, 0xde, 0xac, 0xac, 0xb0, 0x40, 0x70, 0x8e, 0x2e, 0x29, 0xcd, 0x5f, 0xc3, 0x96, 0xc8, 0xe4, 0x98, 0xa1, 0xa1,
0x79, 0x06, 0xb5, 0xcb, 0x73, 0x49, 0x0f, 0x6a, 0x40, 0x31, 0xbe, 0x83, 0x7c, 0x3a, 0x05, 0xc7, 0xe7, 0x79, 0xdc, 0x7b, 0xae, 0x4d, 0x78, 0x6a, 0x85, 0x19, 0xc8, 0x81, 0xbe, 0x3b, 0xa1, 0x3c,
0xa1, 0x78, 0x68, 0xa7, 0x6e, 0x0e, 0xed, 0xe6, 0xdf, 0x15, 0x58, 0xdf, 0x5b, 0x98, 0xd6, 0x24, 0x03, 0x99, 0x1b, 0x88, 0x64, 0x06, 0x32, 0x57, 0x08, 0xe2, 0xad, 0x5c, 0x3a, 0xd1, 0xca, 0x35,
0x91, 0xb7, 0xe3, 0xd6, 0x29, 0xc9, 0xce, 0x71, 0x55, 0x5b, 0x98, 0x5a, 0xd9, 0x16, 0x7e, 0xb8, 0xcf, 0xa0, 0x76, 0x79, 0x2e, 0x19, 0x41, 0x0d, 0x28, 0xc4, 0x3d, 0xc8, 0xa7, 0x53, 0x70, 0x1c,
0xa2, 0xaf, 0x4a, 0x8b, 0xbe, 0x2a, 0xb5, 0xa2, 0xab, 0xba, 0x0f, 0xc5, 0x65, 0x93, 0xc4, 0x8f, 0x8a, 0xa7, 0x76, 0xea, 0xe6, 0xd4, 0x6e, 0xfe, 0x5d, 0x81, 0x8d, 0xbd, 0x85, 0x69, 0x4d, 0x12,
0x34, 0xdd, 0x2a, 0x61, 0x98, 0x85, 0x1d, 0x92, 0x7f, 0xa9, 0xcb, 0xcc, 0x5e, 0xea, 0x32, 0x9b, 0x75, 0x3b, 0x6e, 0x9d, 0x92, 0x6c, 0x34, 0x57, 0x75, 0x91, 0xa9, 0x95, 0x5d, 0xe4, 0x07, 0x2b,
0x9f, 0x01, 0x8a, 0xaf, 0x45, 0xee, 0x59, 0x54, 0x61, 0x94, 0xab, 0x2b, 0xcc, 0x1d, 0xa8, 0x0f, 0xda, 0xb0, 0xb4, 0x68, 0xc3, 0x52, 0x2b, 0x9a, 0xb0, 0xfb, 0x50, 0x58, 0xf6, 0x54, 0x7c, 0x4b,
0x17, 0x27, 0xfe, 0xd8, 0x33, 0x4f, 0xe8, 0x01, 0xb3, 0xc6, 0xda, 0x2b, 0xea, 0x30, 0x3f, 0x0c, 0xd3, 0xad, 0x22, 0x86, 0x59, 0xd8, 0x50, 0xf9, 0x97, 0x9a, 0xd2, 0xb5, 0x4b, 0x4d, 0x69, 0xf3,
0xed, 0x7f, 0x65, 0xa0, 0x10, 0xa1, 0xbc, 0x80, 0x9b, 0xce, 0xd8, 0xb5, 0xc3, 0x75, 0x39, 0xd4, 0x53, 0x40, 0xf1, 0xb5, 0x48, 0x9f, 0x45, 0x27, 0x8c, 0x72, 0xf5, 0x09, 0x73, 0x07, 0xea, 0xc3,
0xe2, 0x4b, 0x0b, 0xfc, 0x7e, 0x3d, 0x14, 0x75, 0x02, 0x89, 0x3e, 0xe1, 0xfc, 0xc4, 0x3e, 0x48, 0xc5, 0x89, 0x3f, 0xf6, 0xcc, 0x13, 0x7a, 0xc0, 0xac, 0xb1, 0xf6, 0x92, 0x3a, 0xcc, 0x0f, 0x53,
0x7e, 0x2a, 0xe0, 0xc7, 0xb7, 0x21, 0xe0, 0xb7, 0x40, 0x8d, 0xf4, 0xcf, 0x98, 0x35, 0x8e, 0xf6, 0xfb, 0x5f, 0x19, 0xc8, 0x47, 0x28, 0x3f, 0xc0, 0x4d, 0x67, 0xec, 0xda, 0xe1, 0xba, 0x1c, 0x6a,
0x0d, 0x57, 0x42, 0x9c, 0x1b, 0x13, 0x30, 0x23, 0xcd, 0x21, 0x33, 0x13, 0x30, 0x43, 0x5c, 0x32, 0xf1, 0xa5, 0x05, 0x71, 0xbf, 0x11, 0x8a, 0x3a, 0x81, 0x44, 0x9f, 0x70, 0x7e, 0xc2, 0x0f, 0x92,
0xdf, 0x85, 0x12, 0xcf, 0x98, 0x3e, 0x33, 0xec, 0x39, 0x71, 0x7c, 0xe9, 0xf2, 0xc5, 0x08, 0xeb, 0x9f, 0x0a, 0xf8, 0x71, 0x37, 0x04, 0xfc, 0x16, 0xa8, 0x91, 0xfe, 0x19, 0xb3, 0xc6, 0x91, 0xdf,
0xfb, 0xe8, 0x4b, 0x00, 0xca, 0xd7, 0x47, 0xd8, 0xf9, 0x9c, 0x8a, 0xa4, 0x59, 0xd9, 0xbd, 0x17, 0x70, 0x39, 0xc4, 0xb9, 0x31, 0x01, 0x33, 0xd2, 0x1c, 0x32, 0x33, 0x01, 0x33, 0xc4, 0x25, 0xf3,
0xf3, 0x9d, 0x68, 0x03, 0x76, 0xc4, 0xbf, 0xa3, 0xf3, 0x39, 0xc5, 0x05, 0x1a, 0xfe, 0x44, 0x5f, 0x6d, 0x28, 0xf2, 0x8a, 0xe9, 0x33, 0xc3, 0x9e, 0x13, 0xc7, 0x97, 0x21, 0x5f, 0x88, 0xb0, 0xbe,
0x41, 0x79, 0xea, 0x7a, 0xaf, 0x0d, 0x6f, 0x42, 0x04, 0x28, 0x0b, 0xcb, 0x56, 0x4c, 0xc3, 0x7e, 0x8f, 0xbe, 0x00, 0xa0, 0x7c, 0x7d, 0x84, 0x9d, 0xcf, 0xa9, 0x28, 0x9a, 0xe5, 0xdd, 0x7b, 0xb1,
0x20, 0x17, 0xc3, 0x0f, 0xde, 0xc1, 0xa5, 0x69, 0xec, 0x1b, 0x3d, 0x07, 0x14, 0x8e, 0x17, 0x75, 0xd8, 0x89, 0x1c, 0xb0, 0x23, 0xfe, 0x1d, 0x9d, 0xcf, 0x29, 0xce, 0xd3, 0xf0, 0x27, 0xfa, 0x12,
0x20, 0x50, 0x92, 0x17, 0x4a, 0xb6, 0x2f, 0x2b, 0xe1, 0x51, 0x1a, 0x2a, 0x52, 0xa7, 0x17, 0x30, 0x4a, 0x53, 0xd7, 0x7b, 0xc5, 0x7b, 0x30, 0x01, 0xca, 0x83, 0x65, 0x2b, 0xa6, 0x61, 0x3f, 0x90,
0xf4, 0x39, 0x94, 0x7c, 0xca, 0x98, 0x45, 0xa5, 0x9a, 0x82, 0x50, 0x73, 0x3b, 0xd1, 0xf5, 0x72, 0x8b, 0xe1, 0x07, 0x6f, 0xe1, 0xe2, 0x34, 0xf6, 0x8d, 0x9e, 0x01, 0x0a, 0xc7, 0x8b, 0x73, 0x20,
0x71, 0xa8, 0xa1, 0xe8, 0x2f, 0x3f, 0xd1, 0x1e, 0x54, 0x2d, 0xd3, 0x39, 0x8b, 0x9b, 0x01, 0x62, 0x50, 0x92, 0x13, 0x4a, 0xb6, 0x2f, 0x2b, 0xe1, 0x59, 0x1a, 0x2a, 0x52, 0xa7, 0x17, 0x30, 0xf4,
0x7c, 0x2d, 0x36, 0xbe, 0x67, 0x3a, 0x67, 0x71, 0x1b, 0xca, 0x56, 0x1c, 0x68, 0x7e, 0x01, 0x85, 0x19, 0x14, 0x7d, 0xca, 0x98, 0x45, 0xa5, 0x9a, 0xbc, 0x50, 0x73, 0x3b, 0xd1, 0x24, 0x73, 0x71,
0x68, 0x97, 0x50, 0x11, 0xd6, 0x8e, 0xfb, 0xcf, 0xfb, 0x83, 0x6f, 0xfb, 0xea, 0x3b, 0x28, 0x0f, 0xa8, 0xa1, 0xe0, 0x2f, 0x3f, 0xd1, 0x1e, 0x54, 0x2c, 0xd3, 0x39, 0x8b, 0x9b, 0x01, 0x62, 0x7c,
0x99, 0xa1, 0xd6, 0xef, 0xaa, 0x0a, 0x87, 0xb1, 0xd6, 0xd1, 0xf4, 0x17, 0x9a, 0x9a, 0xe2, 0x1f, 0x2d, 0x36, 0xbe, 0x67, 0x3a, 0x67, 0x71, 0x1b, 0x4a, 0x56, 0x1c, 0x68, 0x7e, 0x0e, 0xf9, 0xc8,
0xfb, 0x03, 0xfc, 0x6d, 0x1b, 0x77, 0xd5, 0xf4, 0xde, 0x1a, 0x64, 0xc5, 0xbc, 0xcd, 0xbf, 0x28, 0x4b, 0xa8, 0x00, 0xeb, 0xc7, 0xfd, 0x67, 0xfd, 0xc1, 0x37, 0x7d, 0xf5, 0x2d, 0x94, 0x83, 0xcc,
0x90, 0x17, 0x27, 0xe8, 0x4c, 0x5d, 0xf4, 0x13, 0x88, 0x9c, 0x4b, 0x94, 0x3f, 0xde, 0x92, 0x09, 0x50, 0xeb, 0x77, 0x55, 0x85, 0xc3, 0x58, 0xeb, 0x68, 0xfa, 0x73, 0x4d, 0x4d, 0xf1, 0x8f, 0xfd,
0xaf, 0x2b, 0xe3, 0xc8, 0x61, 0x46, 0x12, 0xe7, 0xe4, 0xc8, 0x35, 0x22, 0x72, 0x2a, 0x20, 0x87, 0x01, 0xfe, 0xa6, 0x8d, 0xbb, 0x6a, 0x7a, 0x6f, 0x1d, 0xd6, 0xc4, 0xbc, 0xcd, 0x3f, 0x2b, 0x90,
0x82, 0x88, 0xfc, 0x28, 0xa6, 0x39, 0x91, 0x95, 0x32, 0xb8, 0x1a, 0x0a, 0xc2, 0x1a, 0x1c, 0xbf, 0x13, 0x3b, 0xe8, 0x4c, 0x5d, 0xf4, 0x13, 0x88, 0x82, 0x4b, 0x1c, 0x7f, 0xbc, 0x25, 0x13, 0x51,
0xfd, 0x24, 0x6a, 0x75, 0xec, 0xf6, 0x23, 0xb9, 0xcd, 0x4f, 0xa1, 0x14, 0x3f, 0x73, 0xf4, 0x10, 0x57, 0xc2, 0x51, 0xc0, 0x8c, 0x24, 0xce, 0xc9, 0x51, 0x68, 0x44, 0xe4, 0x54, 0x40, 0x0e, 0x05,
0x32, 0xa6, 0x33, 0x75, 0x65, 0x20, 0x6e, 0x5c, 0x70, 0x2e, 0xbe, 0x48, 0x2c, 0x08, 0x4d, 0x04, 0x11, 0xf9, 0x61, 0x4c, 0x73, 0xa2, 0x2a, 0x65, 0x70, 0x25, 0x14, 0x84, 0x67, 0x70, 0xfc, 0xb2,
0xea, 0xc5, 0x73, 0x6e, 0x96, 0xa1, 0x18, 0x3b, 0xb4, 0xe6, 0x3f, 0x14, 0x28, 0x27, 0x0e, 0xe1, 0x94, 0x38, 0xab, 0x63, 0x97, 0x25, 0xc9, 0x6d, 0x7e, 0x02, 0xc5, 0xf8, 0x9e, 0xa3, 0x07, 0x90,
0xad, 0xb5, 0xa3, 0x2f, 0xa1, 0xf4, 0xda, 0xf4, 0x28, 0x89, 0x37, 0x88, 0x95, 0xdd, 0x7a, 0xb2, 0x31, 0x9d, 0xa9, 0x2b, 0x13, 0xb1, 0x7a, 0x21, 0xb8, 0xf8, 0x22, 0xb1, 0x20, 0x34, 0x11, 0xa8,
0x41, 0x0c, 0xff, 0xef, 0xb8, 0x13, 0x8a, 0x8b, 0x9c, 0x2f, 0x01, 0xf4, 0x4b, 0xa8, 0x84, 0x85, 0x17, 0xf7, 0xb9, 0x59, 0x82, 0x42, 0x6c, 0xd3, 0x9a, 0xff, 0x50, 0xa0, 0x94, 0xd8, 0x84, 0x37,
0x64, 0x42, 0x99, 0x61, 0x5a, 0x62, 0xab, 0x2a, 0x09, 0xf7, 0x90, 0xdc, 0xae, 0x90, 0xe3, 0xf2, 0xd6, 0x8e, 0xbe, 0x80, 0xe2, 0x2b, 0xd3, 0xa3, 0x24, 0xde, 0x20, 0x96, 0x77, 0xeb, 0xc9, 0x06,
0x34, 0xfe, 0x89, 0x3e, 0x58, 0x2a, 0xf0, 0x99, 0x67, 0x3a, 0xa7, 0x62, 0xff, 0x0a, 0x11, 0x6d, 0x31, 0xfc, 0xbf, 0xe3, 0x4e, 0x28, 0x2e, 0x70, 0xbe, 0x04, 0xd0, 0x2f, 0xa1, 0x1c, 0x1e, 0x24,
0x28, 0x40, 0xde, 0xea, 0x95, 0x65, 0x2d, 0x1b, 0x32, 0x83, 0x2d, 0x7c, 0xf4, 0x11, 0x64, 0x7d, 0x13, 0xca, 0x0c, 0xd3, 0x12, 0xae, 0x2a, 0x27, 0xc2, 0x43, 0x72, 0xbb, 0x42, 0x8e, 0x4b, 0xd3,
0x66, 0xc8, 0x4c, 0x56, 0x49, 0xc4, 0x56, 0x8c, 0x48, 0x71, 0xc0, 0x4a, 0xf4, 0xc7, 0xa9, 0x4b, 0xf8, 0x27, 0x7a, 0x6f, 0xa9, 0xc0, 0x67, 0x9e, 0xe9, 0x9c, 0x0a, 0xff, 0xe5, 0x23, 0xda, 0x50,
0xfd, 0x71, 0x96, 0x67, 0x8c, 0x20, 0xd1, 0x16, 0x77, 0x91, 0x5c, 0xfc, 0xc1, 0xa8, 0xd7, 0x69, 0x80, 0xbc, 0xd5, 0x2b, 0xc9, 0xb3, 0x6c, 0xc8, 0x0c, 0xb6, 0xe0, 0x37, 0x9d, 0x35, 0x9f, 0x19,
0x33, 0x46, 0xed, 0x39, 0xc3, 0x01, 0x41, 0xf6, 0x3f, 0x5f, 0x01, 0x74, 0x4c, 0x6f, 0xbc, 0x30, 0xb2, 0x92, 0x95, 0x13, 0xb9, 0x15, 0x23, 0x52, 0x1c, 0xb0, 0x12, 0xfd, 0x71, 0xea, 0x52, 0x7f,
0xd9, 0x73, 0x7a, 0xce, 0xcb, 0x5a, 0x98, 0xd1, 0x83, 0xb4, 0x97, 0x1b, 0x07, 0x59, 0x7c, 0x0b, 0xbc, 0xc6, 0x2b, 0x46, 0x50, 0x68, 0x0b, 0xbb, 0x48, 0x2e, 0xfe, 0x60, 0xd4, 0xeb, 0xb4, 0x19,
0xd6, 0xc2, 0x44, 0x14, 0xe4, 0xb7, 0xdc, 0x4c, 0x24, 0xa0, 0xe6, 0x5f, 0x33, 0xb0, 0x2d, 0x8f, 0xa3, 0xf6, 0x9c, 0xe1, 0x80, 0x20, 0xfb, 0x9f, 0x2f, 0x01, 0x3a, 0xa6, 0x37, 0x5e, 0x98, 0xec,
0x34, 0x38, 0x0d, 0x46, 0xbd, 0x31, 0x9d, 0x47, 0x17, 0xa7, 0xa7, 0xb0, 0xb9, 0x4c, 0xaa, 0xc1, 0x19, 0x3d, 0xe7, 0xc7, 0x5a, 0x58, 0xd1, 0x83, 0xb2, 0x97, 0x1d, 0x07, 0x55, 0x7c, 0x0b, 0xd6,
0x44, 0x24, 0xbc, 0x8c, 0x15, 0x77, 0x6f, 0xc5, 0x56, 0xba, 0x34, 0x03, 0xa3, 0x28, 0xd9, 0x2e, 0xc3, 0x42, 0x14, 0xd4, 0xb7, 0xec, 0x4c, 0x14, 0xa0, 0xe6, 0x5f, 0x32, 0xb0, 0x2d, 0xb7, 0x34,
0x4d, 0x7b, 0x12, 0x53, 0x64, 0xd8, 0xee, 0xc2, 0x91, 0x2e, 0x1a, 0x64, 0x3c, 0xb4, 0x74, 0x67, 0xd8, 0x0d, 0x46, 0xbd, 0x31, 0x9d, 0x47, 0x17, 0xa7, 0x27, 0xb0, 0xb9, 0x2c, 0xaa, 0xc1, 0x44,
0x2e, 0x12, 0x1e, 0xfd, 0x10, 0x22, 0x27, 0x27, 0xf4, 0xcd, 0xdc, 0xf4, 0xce, 0x45, 0xf6, 0x2b, 0x24, 0xbc, 0x8c, 0x15, 0x76, 0x6f, 0xc5, 0x56, 0xba, 0x34, 0x03, 0xa3, 0xa8, 0xd8, 0x2e, 0x4d,
0x2f, 0xd3, 0xad, 0x26, 0xd0, 0x4b, 0xb7, 0x99, 0xd4, 0xe5, 0xdb, 0xcc, 0xe7, 0x50, 0x8f, 0xa2, 0x7b, 0x1c, 0x53, 0x64, 0xd8, 0xee, 0xc2, 0x91, 0x21, 0x1a, 0x54, 0x3c, 0xb4, 0x0c, 0x67, 0x2e,
0x43, 0x3e, 0x74, 0xd0, 0x49, 0x54, 0xfd, 0xd6, 0x84, 0x0d, 0x5b, 0x21, 0x03, 0x87, 0x04, 0x59, 0x12, 0x11, 0xfd, 0x00, 0xa2, 0x20, 0x27, 0xf4, 0xf5, 0xdc, 0xf4, 0xce, 0x45, 0xf5, 0x2b, 0x2d,
0x02, 0x9f, 0xc0, 0x66, 0x2c, 0xb4, 0x96, 0xa6, 0x07, 0x91, 0x88, 0x96, 0xd1, 0x15, 0x37, 0x3d, 0xcb, 0xad, 0x26, 0xd0, 0x4b, 0xb7, 0x99, 0xd4, 0xe5, 0xdb, 0xcc, 0x67, 0x50, 0x8f, 0xb2, 0x43,
0x1a, 0x21, 0x4d, 0x0f, 0x7a, 0xa1, 0x28, 0xff, 0x4b, 0xd3, 0x7f, 0x05, 0x95, 0x0b, 0x0f, 0x01, 0xbe, 0x8b, 0xd0, 0x49, 0x74, 0xfa, 0xad, 0x0b, 0x1b, 0xb6, 0x42, 0x06, 0x0e, 0x09, 0xf2, 0x08,
0x79, 0x71, 0xee, 0x3f, 0xbf, 0x9c, 0x59, 0x57, 0x1d, 0xcf, 0xce, 0x8a, 0xd7, 0x80, 0xf2, 0x38, 0x7c, 0x0c, 0x9b, 0xb1, 0xd4, 0x5a, 0x9a, 0x1e, 0x64, 0x22, 0x5a, 0x66, 0x57, 0xdc, 0xf4, 0x68,
0xf1, 0x12, 0x70, 0x17, 0xc0, 0x75, 0x4c, 0xd7, 0x21, 0x27, 0x96, 0x7b, 0x22, 0x12, 0x6e, 0x09, 0x84, 0x34, 0x3d, 0xe8, 0x85, 0xa2, 0xfa, 0x2f, 0x4d, 0xff, 0x15, 0x94, 0x2f, 0xbc, 0x1b, 0xe4,
0x17, 0x04, 0xb2, 0x67, 0xb9, 0x27, 0xf5, 0xaf, 0x01, 0xfd, 0x8f, 0x37, 0xee, 0xbf, 0x29, 0x70, 0xc4, 0xbe, 0xff, 0xfc, 0x72, 0x65, 0x5d, 0xb5, 0x3d, 0x3b, 0x2b, 0x1e, 0x0f, 0x4a, 0xe3, 0xc4,
0x67, 0xb5, 0x89, 0xb2, 0xce, 0xff, 0xdf, 0x5c, 0xe8, 0x73, 0xc8, 0x19, 0x63, 0x66, 0xba, 0x8e, 0xc3, 0xc1, 0x5d, 0x00, 0xd7, 0x31, 0x5d, 0x87, 0x9c, 0x58, 0xee, 0x89, 0x28, 0xb8, 0x45, 0x9c,
0xcc, 0x0c, 0xef, 0xc5, 0x86, 0x62, 0xea, 0xbb, 0xd6, 0x2b, 0x7a, 0xe0, 0x5a, 0x13, 0x69, 0x4c, 0x17, 0xc8, 0x9e, 0xe5, 0x9e, 0xd4, 0xbf, 0x02, 0xf4, 0x3f, 0xde, 0xb8, 0xff, 0xaa, 0xc0, 0x9d,
0x5b, 0x50, 0xb1, 0x1c, 0x92, 0x08, 0xba, 0x74, 0x32, 0xe8, 0x1e, 0xfd, 0x2e, 0x03, 0xe5, 0x44, 0xd5, 0x26, 0xca, 0x73, 0xfe, 0xff, 0x16, 0x42, 0x9f, 0x41, 0xd6, 0x18, 0x33, 0xd3, 0x75, 0x64,
0x66, 0x48, 0x96, 0x86, 0x32, 0x14, 0xfa, 0x03, 0xd2, 0xd5, 0x46, 0x6d, 0xbd, 0xa7, 0x2a, 0x48, 0x65, 0x78, 0x27, 0x36, 0x14, 0x53, 0xdf, 0xb5, 0x5e, 0xd2, 0x03, 0xd7, 0x9a, 0x48, 0x63, 0xda,
0x85, 0xd2, 0xa0, 0xaf, 0x0f, 0xfa, 0xa4, 0xab, 0x75, 0x06, 0x5d, 0x5e, 0x24, 0x6e, 0xc1, 0x7a, 0x82, 0x8a, 0xe5, 0x90, 0x44, 0xd2, 0xa5, 0x93, 0x49, 0xf7, 0xf0, 0x77, 0x19, 0x28, 0x25, 0x2a,
0x4f, 0xef, 0x3f, 0x27, 0xfd, 0xc1, 0x88, 0x68, 0x3d, 0xfd, 0xa9, 0xbe, 0xd7, 0xd3, 0xd4, 0x34, 0x43, 0xf2, 0x68, 0x28, 0x41, 0xbe, 0x3f, 0x20, 0x5d, 0x6d, 0xd4, 0xd6, 0x7b, 0xaa, 0x82, 0x54,
0xda, 0x04, 0x75, 0xd0, 0x27, 0x9d, 0x83, 0xb6, 0xde, 0x27, 0x23, 0xfd, 0x50, 0x1b, 0x1c, 0x8f, 0x28, 0x0e, 0xfa, 0xfa, 0xa0, 0x4f, 0xba, 0x5a, 0x67, 0xd0, 0xe5, 0x87, 0xc4, 0x2d, 0xd8, 0xe8,
0xd4, 0x0c, 0x47, 0x79, 0x34, 0x13, 0xed, 0xbb, 0x8e, 0xa6, 0x75, 0x87, 0xe4, 0xb0, 0xfd, 0x9d, 0xe9, 0xfd, 0x67, 0xa4, 0x3f, 0x18, 0x11, 0xad, 0xa7, 0x3f, 0xd1, 0xf7, 0x7a, 0x9a, 0x9a, 0x46,
0x9a, 0x45, 0x35, 0xd8, 0xd4, 0xfb, 0xc3, 0xe3, 0xfd, 0x7d, 0xbd, 0xa3, 0x6b, 0xfd, 0x11, 0xd9, 0x9b, 0xa0, 0x0e, 0xfa, 0xa4, 0x73, 0xd0, 0xd6, 0xfb, 0x64, 0xa4, 0x1f, 0x6a, 0x83, 0xe3, 0x91,
0x6b, 0xf7, 0xda, 0xfd, 0x8e, 0xa6, 0xe6, 0xd0, 0x6d, 0x40, 0x7a, 0xbf, 0x33, 0x38, 0x3c, 0xea, 0x9a, 0xe1, 0x28, 0xcf, 0x66, 0xa2, 0x7d, 0xdb, 0xd1, 0xb4, 0xee, 0x90, 0x1c, 0xb6, 0xbf, 0x55,
0x69, 0x23, 0x8d, 0x84, 0xc5, 0x68, 0x0d, 0x6d, 0x40, 0x55, 0xe8, 0x69, 0x77, 0xbb, 0x64, 0xbf, 0xd7, 0x50, 0x0d, 0x36, 0xf5, 0xfe, 0xf0, 0x78, 0x7f, 0x5f, 0xef, 0xe8, 0x5a, 0x7f, 0x44, 0xf6,
0xad, 0xf7, 0xb4, 0xae, 0x9a, 0xe7, 0x96, 0x48, 0xc6, 0x90, 0x74, 0xf5, 0x61, 0x7b, 0x8f, 0xc3, 0xda, 0xbd, 0x76, 0xbf, 0xa3, 0xa9, 0x59, 0x74, 0x1b, 0x90, 0xde, 0xef, 0x0c, 0x0e, 0x8f, 0x7a,
0x05, 0x3e, 0xa7, 0xde, 0x7f, 0x31, 0xd0, 0x3b, 0x1a, 0xe9, 0x70, 0xb5, 0x1c, 0x05, 0x4e, 0x0e, 0xda, 0x48, 0x23, 0xe1, 0x61, 0xb4, 0x8e, 0xaa, 0x50, 0x11, 0x7a, 0xda, 0xdd, 0x2e, 0xd9, 0x6f,
0xd1, 0xe3, 0x7e, 0x57, 0xc3, 0x47, 0x6d, 0xbd, 0xab, 0x16, 0xd1, 0x36, 0x6c, 0x85, 0xb0, 0xf6, 0xeb, 0x3d, 0xad, 0xab, 0xe6, 0xb8, 0x25, 0x92, 0x31, 0x24, 0x5d, 0x7d, 0xd8, 0xde, 0xe3, 0x70,
0xdd, 0x91, 0x8e, 0x5f, 0x92, 0xd1, 0x60, 0x40, 0x86, 0x83, 0x41, 0x5f, 0x2d, 0xc5, 0x35, 0xf1, 0x9e, 0xcf, 0xa9, 0xf7, 0x9f, 0x0f, 0xf4, 0x8e, 0x46, 0x3a, 0x5c, 0x2d, 0x47, 0x81, 0x93, 0x43,
0xd5, 0x0e, 0x8e, 0xb4, 0xbe, 0x5a, 0x46, 0x5b, 0xb0, 0x71, 0x78, 0x74, 0x44, 0x42, 0x49, 0xb8, 0xf4, 0xb8, 0xdf, 0xd5, 0xf0, 0x51, 0x5b, 0xef, 0xaa, 0x05, 0xb4, 0x0d, 0x5b, 0x21, 0xac, 0x7d,
0xd8, 0x0a, 0xa7, 0xb7, 0xbb, 0x5d, 0xac, 0x0d, 0x87, 0xe4, 0x50, 0x1f, 0x1e, 0xb6, 0x47, 0x9d, 0x7b, 0xa4, 0xe3, 0x17, 0x64, 0x34, 0x18, 0x90, 0xe1, 0x60, 0xd0, 0x57, 0x8b, 0x71, 0x4d, 0x7c,
0x03, 0xb5, 0xca, 0x97, 0x34, 0xd4, 0x46, 0x64, 0x34, 0x18, 0xb5, 0x7b, 0x4b, 0x5c, 0xe5, 0x06, 0xb5, 0x83, 0x23, 0xad, 0xaf, 0x96, 0xd0, 0x16, 0x54, 0x0f, 0x8f, 0x8e, 0x48, 0x28, 0x09, 0x17,
0x2d, 0x71, 0x3e, 0x69, 0x6f, 0xf0, 0xad, 0xba, 0xce, 0x37, 0x9c, 0xc3, 0x83, 0x17, 0xd2, 0x44, 0x5b, 0xe6, 0xf4, 0x76, 0xb7, 0x8b, 0xb5, 0xe1, 0x90, 0x1c, 0xea, 0xc3, 0xc3, 0xf6, 0xa8, 0x73,
0xc4, 0xd7, 0x2e, 0x8f, 0x27, 0x9c, 0x53, 0xdd, 0xe0, 0xa0, 0xde, 0x7f, 0xd1, 0xee, 0xe9, 0x5d, 0xa0, 0x56, 0xf8, 0x92, 0x86, 0xda, 0x88, 0x8c, 0x06, 0xa3, 0x76, 0x6f, 0x89, 0xab, 0xdc, 0xa0,
0xf2, 0x5c, 0x7b, 0x29, 0x8a, 0xf9, 0x26, 0x07, 0x03, 0xcb, 0xc8, 0x11, 0x1e, 0x3c, 0xe5, 0x86, 0x25, 0xce, 0x27, 0xed, 0x0d, 0xbe, 0x51, 0x37, 0xb8, 0xc3, 0x39, 0x3c, 0x78, 0x2e, 0x4d, 0x44,
0xa8, 0xb7, 0x10, 0x82, 0x4a, 0x47, 0xc7, 0x9d, 0xe3, 0x5e, 0x1b, 0x13, 0x3c, 0x38, 0x1e, 0x69, 0x7c, 0xed, 0x72, 0x7b, 0xc2, 0x39, 0xd5, 0x2a, 0x07, 0xf5, 0xfe, 0xf3, 0x76, 0x4f, 0xef, 0x92,
0xea, 0xed, 0x47, 0x7f, 0x56, 0xa0, 0x14, 0x4f, 0xd6, 0xfc, 0xd4, 0xf5, 0x3e, 0xd9, 0xef, 0xe9, 0x67, 0xda, 0x0b, 0x71, 0x98, 0x6f, 0x72, 0x30, 0xb0, 0x8c, 0x1c, 0xe1, 0xc1, 0x13, 0x6e, 0x88,
0x4f, 0x0f, 0x46, 0x81, 0x13, 0x0c, 0x8f, 0x3b, 0xfc, 0xc8, 0x34, 0xde, 0x24, 0x20, 0xa8, 0x04, 0x7a, 0x0b, 0x21, 0x28, 0x77, 0x74, 0xdc, 0x39, 0xee, 0xb5, 0x31, 0xc1, 0x83, 0xe3, 0x91, 0xa6,
0x9b, 0x1e, 0x2d, 0x36, 0xc5, 0xe7, 0x92, 0x58, 0x7f, 0x20, 0xf5, 0xa6, 0xb9, 0xf1, 0x12, 0xd4, 0xde, 0x7e, 0xf8, 0x27, 0x05, 0x8a, 0xf1, 0x62, 0xcd, 0x77, 0x5d, 0xef, 0x93, 0xfd, 0x9e, 0xfe,
0x30, 0x1e, 0x60, 0x35, 0x83, 0xde, 0x87, 0x86, 0x44, 0xf8, 0xb9, 0x62, 0xac, 0x75, 0x46, 0xe4, 0xe4, 0x60, 0x14, 0x04, 0xc1, 0xf0, 0xb8, 0xc3, 0xb7, 0x4c, 0xe3, 0x4d, 0x02, 0x82, 0x72, 0xe0,
0xa8, 0xfd, 0xf2, 0x90, 0x1f, 0x7b, 0xe0, 0x64, 0x43, 0x35, 0x8b, 0xee, 0xc3, 0x76, 0xc4, 0x5a, 0xf4, 0x68, 0xb1, 0x29, 0x3e, 0x97, 0xc4, 0xfa, 0x03, 0xa9, 0x37, 0xcd, 0x8d, 0x97, 0xa0, 0x86,
0xe5, 0x17, 0x8f, 0xbe, 0x80, 0xda, 0x55, 0x4e, 0x8f, 0x00, 0x72, 0x43, 0x6d, 0x34, 0xea, 0x69, 0xf1, 0x00, 0xab, 0x19, 0xf4, 0x2e, 0x34, 0x24, 0xc2, 0xf7, 0x15, 0x63, 0xad, 0x33, 0x22, 0x47,
0x41, 0x63, 0xb3, 0x1f, 0x38, 0x2e, 0x40, 0x0e, 0x6b, 0xc3, 0xe3, 0x43, 0x4d, 0x4d, 0xed, 0xfe, 0xed, 0x17, 0x87, 0x7c, 0xdb, 0x83, 0x20, 0x1b, 0xaa, 0x6b, 0xe8, 0x3e, 0x6c, 0x47, 0xac, 0x55,
0x89, 0x7f, 0x88, 0xe8, 0x41, 0x5f, 0x43, 0x39, 0xf6, 0xd6, 0xf8, 0x62, 0x17, 0xdd, 0xbd, 0xf6, 0x71, 0xf1, 0xf0, 0x73, 0xa8, 0x5d, 0x15, 0xf4, 0x08, 0x20, 0x3b, 0xd4, 0x46, 0xa3, 0x9e, 0x16,
0x15, 0xb2, 0x1e, 0xbe, 0xd8, 0x48, 0xf8, 0x89, 0x82, 0xf6, 0xa0, 0x12, 0x7f, 0x74, 0x7b, 0xb1, 0x34, 0x36, 0xfb, 0x41, 0xe0, 0x02, 0x64, 0xb1, 0x36, 0x3c, 0x3e, 0xd4, 0xd4, 0xd4, 0xee, 0x1f,
0x8b, 0xe2, 0x0d, 0xea, 0x8a, 0xf7, 0xb8, 0x15, 0x3a, 0x9e, 0x83, 0xaa, 0xf9, 0xcc, 0xb4, 0x79, 0xf9, 0x87, 0xc8, 0x1e, 0xf4, 0x15, 0x94, 0x62, 0x4f, 0x93, 0xcf, 0x77, 0xd1, 0xdd, 0x6b, 0x1f,
0x9d, 0x94, 0xcf, 0x62, 0xa8, 0x1e, 0x0f, 0xf0, 0xe4, 0x5b, 0x5b, 0x7d, 0x7b, 0xa5, 0x4c, 0xa6, 0x2d, 0xeb, 0xe1, 0x8b, 0x8d, 0x84, 0x1f, 0x2b, 0x68, 0x0f, 0xca, 0xf1, 0x47, 0xb7, 0xe7, 0xbb,
0x9c, 0x6f, 0x78, 0x4f, 0x12, 0x3d, 0x4c, 0x5d, 0x5a, 0x50, 0xf2, 0x35, 0xac, 0x7e, 0xef, 0x2a, 0x28, 0xde, 0xa0, 0xae, 0x78, 0x8f, 0x5b, 0xa1, 0xe3, 0x19, 0xa8, 0x9a, 0xcf, 0x4c, 0x9b, 0x9f,
0xb1, 0xbc, 0x67, 0xa7, 0x7f, 0x9f, 0xe2, 0x6b, 0x2c, 0xc7, 0x64, 0x2b, 0x76, 0xe9, 0x82, 0xd2, 0x93, 0xf2, 0x59, 0x0c, 0xd5, 0xe3, 0x09, 0x9e, 0x7c, 0x6b, 0xab, 0x6f, 0xaf, 0x94, 0xc9, 0x92,
0x15, 0x95, 0x1b, 0x4d, 0x60, 0x63, 0xc5, 0xa3, 0x15, 0xfa, 0x20, 0x99, 0xc7, 0xae, 0x78, 0xf2, 0xf3, 0x35, 0xef, 0x49, 0xa2, 0x87, 0xa9, 0x4b, 0x0b, 0x4a, 0xbe, 0x86, 0xd5, 0xef, 0x5d, 0x25,
0xaa, 0x3f, 0xb8, 0x89, 0x26, 0x17, 0x3f, 0x81, 0x8d, 0x15, 0xaf, 0x5b, 0x89, 0x59, 0xae, 0x7e, 0x96, 0xf7, 0xec, 0xf4, 0xef, 0x53, 0x7c, 0x8d, 0xa5, 0x98, 0x6c, 0x85, 0x97, 0x2e, 0x28, 0x5d,
0x1b, 0x4b, 0xcc, 0x72, 0xdd, 0x23, 0xd9, 0x1c, 0xb6, 0xae, 0x78, 0x56, 0x41, 0x3f, 0x8e, 0xa9, 0x71, 0x72, 0xa3, 0x09, 0x54, 0x57, 0x3c, 0x5a, 0xa1, 0xf7, 0x92, 0x75, 0xec, 0x8a, 0x27, 0xaf,
0xb8, 0xfe, 0x71, 0xa6, 0xfe, 0xe8, 0x6d, 0xa8, 0xcb, 0x19, 0x87, 0x6f, 0x31, 0xe3, 0xf0, 0xed, 0xfa, 0xfb, 0x37, 0xd1, 0xe4, 0xe2, 0x27, 0x50, 0x5d, 0xf1, 0xba, 0x95, 0x98, 0xe5, 0xea, 0xb7,
0x67, 0xbc, 0xe1, 0x81, 0x05, 0xfd, 0x00, 0xea, 0xc5, 0x1b, 0x3f, 0x6a, 0x5e, 0xdc, 0x9f, 0xcb, 0xb1, 0xc4, 0x2c, 0xd7, 0x3d, 0x92, 0xcd, 0x61, 0xeb, 0x8a, 0x67, 0x15, 0xf4, 0xe3, 0x98, 0x8a,
0x4f, 0x0f, 0xf5, 0xf7, 0xae, 0xe5, 0x48, 0xe5, 0x3a, 0xc0, 0xf2, 0x52, 0x8c, 0xee, 0xc4, 0x86, 0xeb, 0x1f, 0x67, 0xea, 0x0f, 0xdf, 0x84, 0xba, 0x9c, 0x71, 0xf8, 0x06, 0x33, 0x0e, 0xdf, 0x7c,
0x5c, 0xba, 0xf7, 0xd7, 0xef, 0x5e, 0x21, 0x95, 0xaa, 0x46, 0xb0, 0xb1, 0xe2, 0x96, 0x9c, 0x38, 0xc6, 0x1b, 0x1e, 0x58, 0xd0, 0xf7, 0xa0, 0x5e, 0xbc, 0xf1, 0xa3, 0xe6, 0x45, 0xff, 0x5c, 0x7e,
0xf1, 0xab, 0x6f, 0xd1, 0xf5, 0xcd, 0x55, 0x97, 0xc9, 0x27, 0x0a, 0x3a, 0x0c, 0x82, 0x28, 0xfc, 0x7a, 0xa8, 0xbf, 0x73, 0x2d, 0x47, 0x2a, 0xd7, 0x01, 0x96, 0x97, 0x62, 0x74, 0x27, 0x36, 0xe4,
0x23, 0xc1, 0x0d, 0x59, 0xa1, 0xb6, 0xba, 0xe9, 0x5d, 0xf8, 0x22, 0x7c, 0x9e, 0x28, 0x68, 0x00, 0xd2, 0xbd, 0xbf, 0x7e, 0xf7, 0x0a, 0xa9, 0x54, 0x35, 0x82, 0xea, 0x8a, 0x5b, 0x72, 0x62, 0xc7,
0xa5, 0x78, 0x26, 0xb8, 0x31, 0x45, 0xdc, 0xa8, 0x70, 0x0a, 0xd5, 0x44, 0xc3, 0xe1, 0x7a, 0xe8, 0xaf, 0xbe, 0x45, 0xd7, 0x37, 0x57, 0x5d, 0x26, 0x1f, 0x2b, 0xe8, 0x30, 0x48, 0xa2, 0xf0, 0x6f,
0xe1, 0x8d, 0x6d, 0x53, 0xb0, 0x63, 0x09, 0x2f, 0xbf, 0xa6, 0xbf, 0x6a, 0x29, 0x4f, 0x94, 0xbd, 0x0a, 0x37, 0x54, 0x85, 0xda, 0xea, 0xa6, 0x77, 0xe1, 0x8b, 0xf4, 0x79, 0xac, 0xa0, 0x01, 0x14,
0x8f, 0xbf, 0x7f, 0x7c, 0x6a, 0xb2, 0xd9, 0xe2, 0x64, 0x67, 0xec, 0xda, 0x8f, 0xc5, 0xdf, 0x00, 0xe3, 0x95, 0xe0, 0xc6, 0x12, 0x71, 0xa3, 0xc2, 0x29, 0x54, 0x12, 0x0d, 0x87, 0xeb, 0xa1, 0x07,
0x1c, 0xd3, 0x39, 0x75, 0x28, 0x7b, 0xed, 0x7a, 0x67, 0x8f, 0x2d, 0x67, 0xf2, 0x58, 0x84, 0xfa, 0x37, 0xb6, 0x4d, 0x81, 0xc7, 0x12, 0x51, 0x7e, 0x4d, 0x7f, 0xd5, 0x52, 0x1e, 0x2b, 0x7b, 0x1f,
0xe3, 0x48, 0xe5, 0x49, 0x4e, 0xfc, 0x95, 0xf0, 0xa7, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xff, 0x7d, 0xf7, 0xe8, 0xd4, 0x64, 0xb3, 0xc5, 0xc9, 0xce, 0xd8, 0xb5, 0x1f, 0x89, 0xbf, 0x01, 0x38,
0x7e, 0x76, 0x2e, 0x55, 0x1c, 0x00, 0x00, 0xa6, 0x73, 0xea, 0x50, 0xf6, 0xca, 0xf5, 0xce, 0x1e, 0x59, 0xce, 0xe4, 0x91, 0x48, 0xf5, 0x47,
0x91, 0xca, 0x93, 0xac, 0xf8, 0xa3, 0xe2, 0x4f, 0xff, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xa0, 0xe5,
0x92, 0xf0, 0x84, 0x1c, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

@ -253,6 +253,14 @@ message SendPaymentRequest {
that show which htlcs are still in flight are suppressed. that show which htlcs are still in flight are suppressed.
*/ */
bool no_inflight_updates = 18; bool no_inflight_updates = 18;
/*
The largest payment split that should be attempted when making a payment if
splitting is necessary. Setting this value will effectively cause lnd to
split more aggressively, vs only when it thinks it needs to. Note that this
value is in milli-satoshis.
*/
uint64 max_shard_size_msat = 21;
} }
message TrackPaymentRequest { message TrackPaymentRequest {

@ -1405,6 +1405,11 @@
"type": "boolean", "type": "boolean",
"format": "boolean", "format": "boolean",
"description": "If set, only the final payment update is streamed back. Intermediate updates\nthat show which htlcs are still in flight are suppressed." "description": "If set, only the final payment update is streamed back. Intermediate updates\nthat show which htlcs are still in flight are suppressed."
},
"max_shard_size_msat": {
"type": "string",
"format": "uint64",
"description": "The largest payment split that should be attempted when making a payment if\nsplitting is necessary. Setting this value will effectively cause lnd to\nsplit more aggressively, vs only when it thinks it needs to. Note that this\nvalue is in milli-satoshis."
} }
} }
}, },

@ -24,6 +24,15 @@ import (
"github.com/lightningnetwork/lnd/zpay32" "github.com/lightningnetwork/lnd/zpay32"
) )
const (
// DefaultMaxParts is the default number of splits we'll possibly use
// for MPP when the user is attempting to send a payment.
//
// TODO(roasbeef): make this value dynamic based on expected number of
// attempts for given amount
DefaultMaxParts = 16
)
// RouterBackend contains the backend implementation of the router rpc sub // RouterBackend contains the backend implementation of the router rpc sub
// server calls. // server calls.
type RouterBackend struct { type RouterBackend struct {
@ -554,14 +563,23 @@ func (r *RouterBackend) extractIntentFromSendRequest(
} }
payIntent.CltvLimit = cltvLimit payIntent.CltvLimit = cltvLimit
// Take max htlcs from the request. Map zero to one for backwards // Attempt to parse the max parts value set by the user, if this value
// compatibility. // isn't set, then we'll use the current default value for this
// setting.
maxParts := rpcPayReq.MaxParts maxParts := rpcPayReq.MaxParts
if maxParts == 0 { if maxParts == 0 {
maxParts = 1 maxParts = DefaultMaxParts
} }
payIntent.MaxParts = maxParts payIntent.MaxParts = maxParts
// If this payment had a max shard amount specified, then we'll apply
// that now, which'll force us to always make payment splits smaller
// than this.
if rpcPayReq.MaxShardSizeMsat > 0 {
shardAmtMsat := lnwire.MilliSatoshi(rpcPayReq.MaxShardSizeMsat)
payIntent.MaxShardAmt = &shardAmtMsat
}
// Take fee limit from request. // Take fee limit from request.
payIntent.FeeLimit, err = lnrpc.UnmarshallAmt( payIntent.FeeLimit, err = lnrpc.UnmarshallAmt(
rpcPayReq.FeeLimitSat, rpcPayReq.FeeLimitMsat, rpcPayReq.FeeLimitSat, rpcPayReq.FeeLimitMsat,

@ -204,6 +204,7 @@ out:
FinalCltvDelta: int32(carolPayReq.CltvExpiry), FinalCltvDelta: int32(carolPayReq.CltvExpiry),
TimeoutSeconds: 60, TimeoutSeconds: 60,
FeeLimitMsat: noFeeLimitMsat, FeeLimitMsat: noFeeLimitMsat,
MaxParts: 1,
} }
sendAndAssertFailure( sendAndAssertFailure(
t, net.Alice, t, net.Alice,
@ -240,6 +241,7 @@ out:
FinalCltvDelta: int32(carolPayReq.CltvExpiry), FinalCltvDelta: int32(carolPayReq.CltvExpiry),
TimeoutSeconds: 60, TimeoutSeconds: 60,
FeeLimitMsat: noFeeLimitMsat, FeeLimitMsat: noFeeLimitMsat,
MaxParts: 1,
} }
sendAndAssertFailure( sendAndAssertFailure(
t, net.Alice, t, net.Alice,
@ -300,6 +302,7 @@ out:
PaymentRequest: carolInvoice2.PaymentRequest, PaymentRequest: carolInvoice2.PaymentRequest,
TimeoutSeconds: 60, TimeoutSeconds: 60,
FeeLimitMsat: noFeeLimitMsat, FeeLimitMsat: noFeeLimitMsat,
MaxParts: 1,
}, },
) )
@ -332,6 +335,7 @@ out:
PaymentRequest: carolInvoice3.PaymentRequest, PaymentRequest: carolInvoice3.PaymentRequest,
TimeoutSeconds: 60, TimeoutSeconds: 60,
FeeLimitMsat: noFeeLimitMsat, FeeLimitMsat: noFeeLimitMsat,
MaxParts: 1,
} }
sendAndAssertFailure( sendAndAssertFailure(
t, net.Alice, t, net.Alice,
@ -381,6 +385,7 @@ out:
PaymentRequest: carolInvoice.PaymentRequest, PaymentRequest: carolInvoice.PaymentRequest,
TimeoutSeconds: 60, TimeoutSeconds: 60,
FeeLimitMsat: noFeeLimitMsat, FeeLimitMsat: noFeeLimitMsat,
MaxParts: 1,
}, },
lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE, lnrpc.PaymentFailureReason_FAILURE_REASON_NO_ROUTE,
) )

@ -28,6 +28,7 @@ type integratedRoutingContext struct {
target *mockNode target *mockNode
amt lnwire.MilliSatoshi amt lnwire.MilliSatoshi
maxShardAmt *lnwire.MilliSatoshi
finalExpiry int32 finalExpiry int32
mcCfg MissionControlConfig mcCfg MissionControlConfig
@ -151,6 +152,10 @@ func (c *integratedRoutingContext) testPayment(maxParts uint32,
MaxParts: maxParts, MaxParts: maxParts,
} }
if c.maxShardAmt != nil {
payment.MaxShardAmt = c.maxShardAmt
}
session, err := newPaymentSession( session, err := newPaymentSession(
&payment, getBandwidthHints, &payment, getBandwidthHints,
func() (routingGraph, func(), error) { func() (routingGraph, func(), error) {

@ -89,6 +89,7 @@ type mppSendTestCase struct {
graph func(g *mockGraph) graph func(g *mockGraph)
expectedFailure bool expectedFailure bool
maxParts uint32 maxParts uint32
maxShardSize btcutil.Amount
} }
const ( const (
@ -208,6 +209,33 @@ var mppTestCases = []mppSendTestCase{
expectedFailure: true, expectedFailure: true,
maxParts: 10, maxParts: 10,
}, },
// Test that if maxShardSize is set, then all attempts are below the
// max shard size, yet still sum up to the total payment amount. A
// payment of 30k satoshis with a max shard size of 10k satoshis should
// produce 3 payments of 10k sats each.
{
name: "max shard size clamping",
graph: onePathGraph,
amt: 30_000,
expectedAttempts: 3,
expectedSuccesses: []expectedHtlcSuccess{
{
amt: 10_000,
chans: []uint64{chanSourceIm1, chanIm1Target},
},
{
amt: 10_000,
chans: []uint64{chanSourceIm1, chanIm1Target},
},
{
amt: 10_000,
chans: []uint64{chanSourceIm1, chanIm1Target},
},
},
maxParts: 1000,
maxShardSize: 10_000,
},
} }
// TestMppSend tests that a payment can be completed using multiple shards. // TestMppSend tests that a payment can be completed using multiple shards.
@ -229,6 +257,11 @@ func testMppSend(t *testing.T, testCase *mppSendTestCase) {
ctx.amt = lnwire.NewMSatFromSatoshis(testCase.amt) ctx.amt = lnwire.NewMSatFromSatoshis(testCase.amt)
if testCase.maxShardSize != 0 {
shardAmt := lnwire.NewMSatFromSatoshis(testCase.maxShardSize)
ctx.maxShardAmt = &shardAmt
}
attempts, err := ctx.testPayment(testCase.maxParts) attempts, err := ctx.testPayment(testCase.maxParts)
switch { switch {
case err == nil && testCase.expectedFailure: case err == nil && testCase.expectedFailure:

@ -230,6 +230,18 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
finalHtlcExpiry := int32(height) + int32(finalCltvDelta) finalHtlcExpiry := int32(height) + int32(finalCltvDelta)
// Before we enter the loop below, we'll make sure to respect the max
// payment shard size (if it's set), which is effectively our
// client-side MTU that we'll attempt to respect at all times.
maxShardActive := p.payment.MaxShardAmt != nil
if maxShardActive && maxAmt > *p.payment.MaxShardAmt {
p.log.Debug("Clamping payment attempt from %v to %v due to "+
"max shard size of %v", maxAmt,
*p.payment.MaxShardAmt, maxAmt)
maxAmt = *p.payment.MaxShardAmt
}
for { for {
// We'll also obtain a set of bandwidthHints from the lower // We'll also obtain a set of bandwidthHints from the lower
// layer for each of our outbound channels. This will allow the // layer for each of our outbound channels. This will allow the
@ -279,7 +291,8 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
} }
if !p.payment.DestFeatures.HasFeature(lnwire.MPPOptional) { if !p.payment.DestFeatures.HasFeature(lnwire.MPPOptional) {
p.log.Debug("not splitting because destination doesn't declare MPP") p.log.Debug("not splitting because " +
"destination doesn't declare MPP")
return nil, errNoPathFound return nil, errNoPathFound
} }

@ -1684,6 +1684,14 @@ type LightningPayment struct {
// MaxParts is the maximum number of partial payments that may be used // MaxParts is the maximum number of partial payments that may be used
// to complete the full amount. // to complete the full amount.
MaxParts uint32 MaxParts uint32
// MaxShardAmt is the largest shard that we'll attempt to split using.
// If this field is set, and we need to split, rather than attempting
// half of the original payment amount, we'll use this value if half
// the payment amount is greater than it.
//
// NOTE: This field is _optional_.
MaxShardAmt *lnwire.MilliSatoshi
} }
// SendPayment attempts to send a payment as described within the passed // SendPayment attempts to send a payment as described within the passed