From 6746609ec604e1f74aab2b23936a186948d9244b Mon Sep 17 00:00:00 2001 From: Sebastian Delgado Date: Wed, 31 Jan 2018 17:36:10 -0500 Subject: [PATCH 1/8] Add constant and percentage-based fee limits to payments - Extend SendRequest and QueryRoutesRequest protos - newRoute function takes fee limit and cuts off routes that exceed it - queryRoutes, payInvoice and sendPayment commands take the feeLimit inputs and pass them down to newRoute - When no feeLimit is included, don't enforce any feeLimits at all (by setting feeLimit to maxValue) --- cmd/lncli/commands.go | 81 ++++- lnrpc/rpc.pb.go | 762 ++++++++++++++++++++------------------- lnrpc/rpc.proto | 7 + lnrpc/rpc.swagger.json | 13 + routing/errors.go | 4 + routing/pathfind.go | 13 +- routing/pathfind_test.go | 12 +- routing/router.go | 12 +- routing/router_test.go | 34 +- rpcserver.go | 1 + 10 files changed, 537 insertions(+), 402 deletions(-) diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 99f7a12a..a00ec192 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -103,6 +103,37 @@ func actionDecorator(f func(*cli.Context) error) func(*cli.Context) error { } } +// calculateFeeLimit takes ctx and the amount for the payment in satoshis. +// It checks the fee_limit and fee_limit_percent flags and determines the +// the feeLimit based on those values. If both flags are set, calculateFeeLimit +// sets feeLimit to the Minumum value between them. If neither flag is set, +// feeLimit is set to the maximum int64 value as to avoid enforcing a limit. +func calculateFeeLimit(ctx *cli.Context, amount int64) int64 { + var ( + feeLimit int64 + feeLimitPercent int64 + ) + + const MaxInt64Value int64 = 1<<63 - 1 // 9223372036854775807 + feeLimit = MaxInt64Value + + if ctx.IsSet("fee_limit_percent") { + feeRatio := float64(ctx.Int64("fee_limit_percent")) / 100 + feeLimitPercent = int64(float64(amount) * feeRatio) + feeLimit = feeLimitPercent + } + + if ctx.IsSet("fee_limit") { + feeLimit = ctx.Int64("fee_limit") + } + + // If both fee_limit and fee_limit_percent are set, pick the minimum + if ctx.IsSet("fee_limit") && ctx.IsSet("fee_limit_percent") { + feeLimit = int64(math.Min(float64(feeLimit), float64(feeLimitPercent))) + } + return feeLimit +} + var newAddressCommand = cli.Command{ Name: "newaddress", Category: "Wallet", @@ -1633,6 +1664,14 @@ var sendPaymentCommand = cli.Command{ Name: "final_cltv_delta", Usage: "the number of blocks the last hop has to reveal the preimage", }, + cli.Int64Flag{ + Name: "fee_limit", + Usage: "maximum total fees for the payment in satoshis", + }, + cli.Int64Flag{ + Name: "fee_limit_percent", + Usage: "maximum total fees as a percentage of amt", + }, }, Action: sendPayment, } @@ -1657,6 +1696,7 @@ func sendPayment(ctx *cli.Context) error { destNode []byte err error amount int64 + feeLimit int64 ) switch { @@ -1687,9 +1727,12 @@ func sendPayment(ctx *cli.Context) error { } } + feeLimit = calculateFeeLimit(ctx, amount) + req = &lnrpc.SendRequest{ - Dest: destNode, - Amt: amount, + Dest: destNode, + Amt: amount, + FeeLimit: feeLimit, } if ctx.Bool("debug_send") && (ctx.IsSet("payment_hash") || args.Present()) { @@ -1779,6 +1822,14 @@ var payInvoiceCommand = cli.Command{ Usage: "(optional) number of satoshis to fulfill the " + "invoice", }, + cli.Int64Flag{ + Name: "fee_limit", + Usage: "maximum total fees for the payment in satoshis", + }, + cli.Int64Flag{ + Name: "fee_limit_percent", + Usage: "maximum total fees as a percentage of amt", + }, }, Action: actionDecorator(payInvoice), } @@ -1787,6 +1838,8 @@ func payInvoice(ctx *cli.Context) error { args := ctx.Args() var payReq string + var feeLimit int64 + var amt int64 switch { case ctx.IsSet("pay_req"): @@ -1797,9 +1850,14 @@ func payInvoice(ctx *cli.Context) error { return fmt.Errorf("pay_req argument missing") } + amt = ctx.Int64("amt") + + feeLimit = calculateFeeLimit(ctx, amt) + req := &lnrpc.SendRequest{ PaymentRequest: payReq, - Amt: ctx.Int64("amt"), + Amt: amt, + FeeLimit: feeLimit, } return sendPaymentRequest(ctx, req) @@ -2499,6 +2557,14 @@ var queryRoutesCommand = cli.Command{ Name: "amt", Usage: "the amount to send expressed in satoshis", }, + cli.Int64Flag{ + Name: "fee_limit", + Usage: "maximum total fees for the payment in satoshis", + }, + cli.Int64Flag{ + Name: "fee_limit_percent", + Usage: "maximum total fees as a percentage of amt", + }, cli.Int64Flag{ Name: "num_max_routes", Usage: "the max number of routes to be returned (default: 10)", @@ -2519,9 +2585,10 @@ func queryRoutes(ctx *cli.Context) error { defer cleanUp() var ( - dest string - amt int64 - err error + dest string + amt int64 + err error + feeLimit int64 ) args := ctx.Args() @@ -2548,6 +2615,8 @@ func queryRoutes(ctx *cli.Context) error { return fmt.Errorf("amt argument missing") } + feeLimit = calculateFeeLimit(ctx, amt) + req := &lnrpc.QueryRoutesRequest{ PubKey: dest, Amt: amt, diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index 5cff9352..b48d21bc 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -488,6 +488,8 @@ type SendRequest struct { PaymentRequest string `protobuf:"bytes,6,opt,name=payment_request,json=paymentRequest" json:"payment_request,omitempty"` // / The CLTV delta from the current height that should be used to set the timelock for the final hop. FinalCltvDelta int32 `protobuf:"varint,7,opt,name=final_cltv_delta,json=finalCltvDelta" json:"final_cltv_delta,omitempty"` + // / The maximum total fees for the payment in satoshis. + FeeLimit int64 `protobuf:"varint,8,opt,name=fee_limit" json:"fee_limit,omitempty"` } func (m *SendRequest) Reset() { *m = SendRequest{} } @@ -544,6 +546,13 @@ func (m *SendRequest) GetFinalCltvDelta() int32 { return 0 } +func (m *SendRequest) GetFeeLimit() int64 { + if m != nil { + return m.FeeLimit + } + return 0 +} + type SendResponse struct { PaymentError string `protobuf:"bytes,1,opt,name=payment_error" json:"payment_error,omitempty"` PaymentPreimage []byte `protobuf:"bytes,2,opt,name=payment_preimage,proto3" json:"payment_preimage,omitempty"` @@ -625,9 +634,7 @@ func (m *ChannelPoint) String() string { return proto.CompactTextStri func (*ChannelPoint) ProtoMessage() {} func (*ChannelPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } -type isChannelPoint_FundingTxid interface { - isChannelPoint_FundingTxid() -} +type isChannelPoint_FundingTxid interface{ isChannelPoint_FundingTxid() } type ChannelPoint_FundingTxidBytes struct { FundingTxidBytes []byte `protobuf:"bytes,1,opt,name=funding_txid_bytes,proto3,oneof"` @@ -1714,9 +1721,7 @@ func (m *CloseStatusUpdate) String() string { return proto.CompactTex func (*CloseStatusUpdate) ProtoMessage() {} func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} } -type isCloseStatusUpdate_Update interface { - isCloseStatusUpdate_Update() -} +type isCloseStatusUpdate_Update interface{ isCloseStatusUpdate_Update() } type CloseStatusUpdate_ClosePending struct { ClosePending *PendingUpdate `protobuf:"bytes,1,opt,name=close_pending,oneof"` @@ -1979,9 +1984,7 @@ func (m *OpenStatusUpdate) String() string { return proto.CompactText func (*OpenStatusUpdate) ProtoMessage() {} func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{47} } -type isOpenStatusUpdate_Update interface { - isOpenStatusUpdate_Update() -} +type isOpenStatusUpdate_Update interface{ isOpenStatusUpdate_Update() } type OpenStatusUpdate_ChanPending struct { ChanPending *PendingUpdate `protobuf:"bytes,1,opt,name=chan_pending,oneof"` @@ -2588,6 +2591,8 @@ type QueryRoutesRequest struct { NumRoutes int32 `protobuf:"varint,3,opt,name=num_routes,json=numRoutes" json:"num_routes,omitempty"` // / 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" json:"final_cltv_delta,omitempty"` + // / The maximum total fees for the route in satoshis. + FeeLimit int64 `protobuf:"varint,5,opt,name=fee_limit,json=feeLimit" json:"fee_limit,omitempty"` } func (m *QueryRoutesRequest) Reset() { *m = QueryRoutesRequest{} } @@ -2623,6 +2628,13 @@ func (m *QueryRoutesRequest) GetFinalCltvDelta() int32 { return 0 } +func (m *QueryRoutesRequest) GetFeeLimit() int64 { + if m != nil { + return m.FeeLimit + } + return 0 +} + type QueryRoutesResponse struct { Routes []*Route `protobuf:"bytes,1,rep,name=routes" json:"routes,omitempty"` } @@ -4076,9 +4088,7 @@ func (m *PolicyUpdateRequest) String() string { return proto.CompactT func (*PolicyUpdateRequest) ProtoMessage() {} func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{97} } -type isPolicyUpdateRequest_Scope interface { - isPolicyUpdateRequest_Scope() -} +type isPolicyUpdateRequest_Scope interface{ isPolicyUpdateRequest_Scope() } type PolicyUpdateRequest_Global struct { Global bool `protobuf:"varint,1,opt,name=global,oneof"` @@ -6620,367 +6630,369 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 5786 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3c, 0x4b, 0x90, 0x1c, 0xc9, - 0x55, 0xaa, 0x9e, 0x9e, 0x4f, 0xbf, 0xee, 0xe9, 0x99, 0xc9, 0x19, 0xcd, 0xb4, 0x7a, 0xb5, 0x5a, - 0x6d, 0x59, 0x61, 0xc9, 0xc3, 0xa2, 0xd1, 0x8e, 0xed, 0x65, 0x2d, 0x81, 0x8d, 0xfe, 0xb3, 0xb6, - 0x56, 0x1e, 0xd7, 0x48, 0x16, 0xd8, 0x10, 0xed, 0x9a, 0xee, 0x9c, 0x9e, 0xb2, 0xba, 0xab, 0xca, - 0x55, 0xd5, 0x33, 0x6a, 0x2f, 0x8a, 0xe0, 0x17, 0x04, 0x07, 0x1c, 0x04, 0x81, 0x2f, 0x26, 0x82, - 0x20, 0xc2, 0x5c, 0xe0, 0xc0, 0x91, 0x93, 0xe1, 0xc6, 0x89, 0x08, 0x82, 0xc3, 0x9e, 0x1c, 0x1c, - 0x81, 0x03, 0x38, 0xb8, 0x10, 0xc1, 0x85, 0x03, 0x41, 0xbc, 0x97, 0x9f, 0xca, 0xac, 0xaa, 0x96, - 0xc6, 0x1f, 0xb8, 0x75, 0xbe, 0x7c, 0x95, 0xf9, 0x32, 0xf3, 0xbd, 0x97, 0xef, 0x97, 0x0d, 0x8d, - 0x24, 0xee, 0x5f, 0x8f, 0x93, 0x28, 0x8b, 0xd8, 0xfc, 0x28, 0x4c, 0xe2, 0x7e, 0xf7, 0xe2, 0x30, - 0x8a, 0x86, 0x23, 0xbe, 0xe3, 0xc7, 0xc1, 0x8e, 0x1f, 0x86, 0x51, 0xe6, 0x67, 0x41, 0x14, 0xa6, - 0x02, 0xc9, 0xfd, 0x06, 0xb4, 0x1f, 0xf2, 0xf0, 0x80, 0xf3, 0x81, 0xc7, 0xbf, 0x35, 0xe1, 0x69, - 0xc6, 0x7e, 0x0e, 0xd6, 0x7c, 0xfe, 0x6d, 0xce, 0x07, 0xbd, 0xd8, 0x4f, 0xd3, 0xf8, 0x38, 0xf1, - 0x53, 0xde, 0x71, 0x2e, 0x3b, 0xd7, 0x5a, 0xde, 0xaa, 0xe8, 0xd8, 0xd7, 0x70, 0xf6, 0x36, 0xb4, - 0x52, 0x44, 0xe5, 0x61, 0x96, 0x44, 0xf1, 0xb4, 0x53, 0x23, 0xbc, 0x26, 0xc2, 0xee, 0x0b, 0x90, - 0x3b, 0x82, 0x15, 0x3d, 0x43, 0x1a, 0x47, 0x61, 0xca, 0xd9, 0x0d, 0xd8, 0xe8, 0x07, 0xf1, 0x31, - 0x4f, 0x7a, 0xf4, 0xf1, 0x38, 0xe4, 0xe3, 0x28, 0x0c, 0xfa, 0x1d, 0xe7, 0xf2, 0xdc, 0xb5, 0x86, - 0xc7, 0x44, 0x1f, 0x7e, 0xf1, 0xa1, 0xec, 0x61, 0x57, 0x61, 0x85, 0x87, 0x02, 0xce, 0x07, 0xf4, - 0x95, 0x9c, 0xaa, 0x9d, 0x83, 0xf1, 0x03, 0xf7, 0xef, 0x1c, 0x58, 0xfb, 0x20, 0x0c, 0xb2, 0x67, - 0xfe, 0x68, 0xc4, 0x33, 0xb5, 0xa6, 0xab, 0xb0, 0x72, 0x4a, 0x00, 0x5a, 0xd3, 0x69, 0x94, 0x0c, - 0xe4, 0x8a, 0xda, 0x02, 0xbc, 0x2f, 0xa1, 0x33, 0x29, 0xab, 0xcd, 0xa4, 0xac, 0x72, 0xbb, 0xe6, - 0x66, 0x6c, 0xd7, 0x55, 0x58, 0x49, 0x78, 0x3f, 0x3a, 0xe1, 0xc9, 0xb4, 0x77, 0x1a, 0x84, 0x83, - 0xe8, 0xb4, 0x53, 0xbf, 0xec, 0x5c, 0x9b, 0xf7, 0xda, 0x0a, 0xfc, 0x8c, 0xa0, 0xee, 0x06, 0x30, - 0x73, 0x15, 0x62, 0xdf, 0xdc, 0x21, 0xac, 0x3f, 0x0d, 0x47, 0x51, 0xff, 0xf9, 0x4f, 0xb8, 0xba, - 0x8a, 0xe9, 0x6b, 0x95, 0xd3, 0x6f, 0xc2, 0x86, 0x3d, 0x91, 0x24, 0x80, 0xc3, 0xf9, 0xbb, 0xc7, - 0x7e, 0x38, 0xe4, 0x6a, 0x48, 0x45, 0xc2, 0xa7, 0x60, 0xb5, 0x3f, 0x49, 0x12, 0x1e, 0x96, 0x68, - 0x58, 0x91, 0x70, 0x4d, 0xc4, 0xdb, 0xd0, 0x0a, 0xf9, 0x69, 0x8e, 0x26, 0x59, 0x26, 0xe4, 0xa7, - 0x0a, 0xc5, 0xed, 0xc0, 0x66, 0x71, 0x1a, 0x49, 0xc0, 0xf7, 0x6a, 0xd0, 0x7c, 0x92, 0xf8, 0x61, - 0xea, 0xf7, 0x91, 0x8b, 0x59, 0x07, 0x16, 0xb3, 0x17, 0xbd, 0x63, 0x3f, 0x3d, 0xa6, 0xe9, 0x1a, - 0x9e, 0x6a, 0xb2, 0x4d, 0x58, 0xf0, 0xc7, 0xd1, 0x24, 0xcc, 0x68, 0x82, 0x39, 0x4f, 0xb6, 0xd8, - 0x3b, 0xb0, 0x16, 0x4e, 0xc6, 0xbd, 0x7e, 0x14, 0x1e, 0x05, 0xc9, 0x58, 0xc8, 0x02, 0x9d, 0xd7, - 0xbc, 0x57, 0xee, 0x60, 0x97, 0x00, 0x0e, 0x71, 0x1f, 0xc4, 0x14, 0x75, 0x9a, 0xc2, 0x80, 0x30, - 0x17, 0x5a, 0xb2, 0xc5, 0x83, 0xe1, 0x71, 0xd6, 0x99, 0xa7, 0x81, 0x2c, 0x18, 0x8e, 0x91, 0x05, - 0x63, 0xde, 0x4b, 0x33, 0x7f, 0x1c, 0x77, 0x16, 0x88, 0x1a, 0x03, 0x42, 0xfd, 0x51, 0xe6, 0x8f, - 0x7a, 0x47, 0x9c, 0xa7, 0x9d, 0x45, 0xd9, 0xaf, 0x21, 0xec, 0x93, 0xd0, 0x1e, 0xf0, 0x34, 0xeb, - 0xf9, 0x83, 0x41, 0xc2, 0xd3, 0x94, 0xa7, 0x9d, 0x25, 0xe2, 0xc6, 0x02, 0x14, 0x77, 0xed, 0x21, - 0xcf, 0x8c, 0xdd, 0x49, 0xe5, 0xe9, 0xb8, 0x8f, 0x80, 0x19, 0xe0, 0x7b, 0x3c, 0xf3, 0x83, 0x51, - 0xca, 0xde, 0x83, 0x56, 0x66, 0x20, 0x93, 0xf4, 0x35, 0x77, 0xd9, 0x75, 0x52, 0x1b, 0xd7, 0x8d, - 0x0f, 0x3c, 0x0b, 0xcf, 0xfd, 0x6f, 0x07, 0x9a, 0x07, 0x3c, 0xd4, 0x67, 0xcf, 0xa0, 0x8e, 0x94, - 0xc8, 0xf3, 0xa6, 0xdf, 0xec, 0x2d, 0x68, 0x12, 0x75, 0x69, 0x96, 0x04, 0xe1, 0x90, 0x8e, 0xa0, - 0xe1, 0x01, 0x82, 0x0e, 0x08, 0xc2, 0x56, 0x61, 0xce, 0x1f, 0x67, 0xb4, 0xf1, 0x73, 0x1e, 0xfe, - 0x44, 0xbe, 0x88, 0xfd, 0xe9, 0x18, 0x59, 0x48, 0x6f, 0x76, 0xcb, 0x6b, 0x4a, 0xd8, 0x1e, 0xee, - 0xf6, 0x75, 0x58, 0x37, 0x51, 0xd4, 0xe8, 0xf3, 0x34, 0xfa, 0x9a, 0x81, 0x29, 0x27, 0xb9, 0x0a, - 0x2b, 0x0a, 0x3f, 0x11, 0xc4, 0xd2, 0xf6, 0x37, 0xbc, 0xb6, 0x04, 0xab, 0x25, 0x5c, 0x83, 0xd5, - 0xa3, 0x20, 0xf4, 0x47, 0xbd, 0xfe, 0x28, 0x3b, 0xe9, 0x0d, 0xf8, 0x28, 0xf3, 0xe9, 0x20, 0xe6, - 0xbd, 0x36, 0xc1, 0xef, 0x8e, 0xb2, 0x93, 0x7b, 0x08, 0x75, 0xbf, 0xeb, 0x40, 0x4b, 0x2c, 0x5e, - 0xea, 0xb2, 0x2b, 0xb0, 0xac, 0xe6, 0xe0, 0x49, 0x12, 0x25, 0x92, 0x0f, 0x6d, 0x20, 0xdb, 0x86, - 0x55, 0x05, 0x88, 0x13, 0x1e, 0x8c, 0xfd, 0x21, 0x97, 0x8c, 0x5f, 0x82, 0xb3, 0xdd, 0x7c, 0xc4, - 0x24, 0x9a, 0x64, 0x42, 0x9b, 0x34, 0x77, 0x5b, 0xf2, 0x60, 0x3c, 0x84, 0x79, 0x36, 0x8a, 0xfb, - 0x1d, 0x07, 0x18, 0x92, 0xf5, 0x24, 0x12, 0xdd, 0x72, 0x5d, 0xc5, 0x3d, 0x75, 0xce, 0xbc, 0xa7, - 0xb5, 0x59, 0x7b, 0x7a, 0x05, 0x16, 0x68, 0x4a, 0x14, 0x9a, 0xb9, 0x12, 0x59, 0xb2, 0xcf, 0xfd, - 0xbe, 0x03, 0x2d, 0x14, 0xe1, 0x90, 0x8f, 0xf6, 0xa3, 0x20, 0xcc, 0xd8, 0x0d, 0x60, 0x47, 0x93, - 0x70, 0x10, 0x84, 0xc3, 0x5e, 0xf6, 0x22, 0x18, 0xf4, 0x0e, 0xa7, 0x38, 0x04, 0xd1, 0xb3, 0x77, - 0xce, 0xab, 0xe8, 0x63, 0xef, 0xc0, 0xaa, 0x05, 0x4d, 0xb3, 0x44, 0x50, 0xb5, 0x77, 0xce, 0x2b, - 0xf5, 0xa0, 0x20, 0x46, 0x93, 0x2c, 0x9e, 0x64, 0xbd, 0x20, 0x1c, 0xf0, 0x17, 0xb4, 0x67, 0xcb, - 0x9e, 0x05, 0xbb, 0xd3, 0x86, 0x96, 0xf9, 0x9d, 0xfb, 0x79, 0x58, 0x7d, 0x84, 0x12, 0x1a, 0x06, - 0xe1, 0xf0, 0xb6, 0x10, 0x23, 0x54, 0x1b, 0xf1, 0xe4, 0xf0, 0x39, 0x9f, 0xca, 0x73, 0x94, 0x2d, - 0x64, 0xf2, 0xe3, 0x28, 0xcd, 0xe4, 0xbe, 0xd0, 0x6f, 0xf7, 0x9f, 0x1d, 0x58, 0xc1, 0x4d, 0xff, - 0xd0, 0x0f, 0xa7, 0x6a, 0xc7, 0x1f, 0x41, 0x0b, 0x87, 0x7a, 0x12, 0xdd, 0x16, 0xca, 0x47, 0x08, - 0xd5, 0x35, 0xb9, 0x49, 0x05, 0xec, 0xeb, 0x26, 0x2a, 0xde, 0x97, 0x53, 0xcf, 0xfa, 0x1a, 0xc5, - 0x28, 0xf3, 0x93, 0x21, 0xcf, 0x48, 0x2d, 0x49, 0x35, 0x05, 0x02, 0x74, 0x37, 0x0a, 0x8f, 0xd8, - 0x65, 0x68, 0xa5, 0x7e, 0xd6, 0x8b, 0x79, 0x42, 0xbb, 0x46, 0xa2, 0x30, 0xe7, 0x41, 0xea, 0x67, - 0xfb, 0x3c, 0xb9, 0x33, 0xcd, 0x78, 0xf7, 0x0b, 0xb0, 0x56, 0x9a, 0x05, 0xa5, 0x2f, 0x5f, 0x22, - 0xfe, 0x64, 0x1b, 0x30, 0x7f, 0xe2, 0x8f, 0x26, 0x5c, 0x6a, 0x4b, 0xd1, 0xb8, 0x59, 0x7b, 0xdf, - 0x71, 0x3f, 0x09, 0xab, 0x39, 0xd9, 0x92, 0xe9, 0x19, 0xd4, 0x71, 0x07, 0xe5, 0x00, 0xf4, 0xdb, - 0xfd, 0x2d, 0x47, 0x20, 0xde, 0x8d, 0x02, 0xad, 0x79, 0x10, 0x11, 0x15, 0x94, 0x42, 0xc4, 0xdf, - 0x33, 0x35, 0xf3, 0x4f, 0xbf, 0x58, 0xf7, 0x2a, 0xac, 0x19, 0x24, 0xbc, 0x82, 0xd8, 0xef, 0x38, - 0xb0, 0xf6, 0x98, 0x9f, 0xca, 0x53, 0x57, 0xd4, 0xbe, 0x0f, 0xf5, 0x6c, 0x1a, 0x0b, 0x6b, 0xa7, - 0xbd, 0x7b, 0x45, 0x1e, 0x5a, 0x09, 0xef, 0xba, 0x6c, 0x3e, 0x99, 0xc6, 0xdc, 0xa3, 0x2f, 0xdc, - 0xcf, 0x43, 0xd3, 0x00, 0xb2, 0x2d, 0x58, 0x7f, 0xf6, 0xc1, 0x93, 0xc7, 0xf7, 0x0f, 0x0e, 0x7a, - 0xfb, 0x4f, 0xef, 0x7c, 0xe9, 0xfe, 0xaf, 0xf6, 0xf6, 0x6e, 0x1f, 0xec, 0xad, 0x9e, 0x63, 0x9b, - 0xc0, 0x1e, 0xdf, 0x3f, 0x78, 0x72, 0xff, 0x9e, 0x05, 0x77, 0xdc, 0x2e, 0x74, 0x1e, 0xf3, 0xd3, - 0x67, 0x41, 0x16, 0xf2, 0x34, 0xb5, 0x67, 0x73, 0xaf, 0x03, 0x33, 0x49, 0x90, 0xab, 0xea, 0xc0, - 0xa2, 0x54, 0xfd, 0xea, 0xe6, 0x93, 0x4d, 0xf7, 0x93, 0xc0, 0x0e, 0x82, 0x61, 0xf8, 0x21, 0x4f, - 0x53, 0x7f, 0xa8, 0x55, 0xc1, 0x2a, 0xcc, 0x8d, 0xd3, 0xa1, 0xd4, 0x00, 0xf8, 0xd3, 0xfd, 0x34, - 0xac, 0x5b, 0x78, 0x72, 0xe0, 0x8b, 0xd0, 0x48, 0x83, 0x61, 0xe8, 0x67, 0x93, 0x84, 0xcb, 0xa1, - 0x73, 0x80, 0xfb, 0x00, 0x36, 0xbe, 0xca, 0x93, 0xe0, 0x68, 0xfa, 0xba, 0xe1, 0xed, 0x71, 0x6a, - 0xc5, 0x71, 0xee, 0xc3, 0xf9, 0xc2, 0x38, 0x72, 0x7a, 0xc1, 0x88, 0xf2, 0xb8, 0x96, 0x3c, 0xd1, - 0x30, 0xc4, 0xb2, 0x66, 0x8a, 0xa5, 0xfb, 0x14, 0xd8, 0xdd, 0x28, 0x0c, 0x79, 0x3f, 0xdb, 0xe7, - 0x3c, 0xc9, 0x4d, 0xd8, 0x9c, 0xeb, 0x9a, 0xbb, 0x5b, 0xf2, 0x1c, 0x8b, 0xb2, 0x2e, 0xd9, 0x91, - 0x41, 0x3d, 0xe6, 0xc9, 0x98, 0x06, 0x5e, 0xf2, 0xe8, 0xb7, 0x7b, 0x1e, 0xd6, 0xad, 0x61, 0xa5, - 0xf5, 0xf1, 0x2e, 0x9c, 0xbf, 0x17, 0xa4, 0xfd, 0xf2, 0x84, 0x1d, 0x58, 0x8c, 0x27, 0x87, 0xbd, - 0x5c, 0xa6, 0x54, 0x13, 0x2f, 0xe5, 0xe2, 0x27, 0x72, 0xb0, 0xdf, 0x73, 0xa0, 0xbe, 0xf7, 0xe4, - 0xd1, 0x5d, 0xd6, 0x85, 0xa5, 0x20, 0xec, 0x47, 0x63, 0x54, 0xbb, 0x62, 0xd1, 0xba, 0x3d, 0x53, - 0x56, 0x2e, 0x42, 0x83, 0xb4, 0x35, 0xda, 0x19, 0xd2, 0xda, 0xcc, 0x01, 0x68, 0xe3, 0xf0, 0x17, - 0x71, 0x90, 0x90, 0x11, 0xa3, 0x4c, 0x93, 0x3a, 0x69, 0xc4, 0x72, 0x87, 0xfb, 0x3f, 0x75, 0x58, - 0x94, 0xba, 0x9a, 0xe6, 0xeb, 0x67, 0xc1, 0x09, 0x97, 0x94, 0xc8, 0x16, 0xde, 0x72, 0x09, 0x1f, - 0x47, 0x19, 0xef, 0x59, 0xc7, 0x60, 0x03, 0x11, 0xab, 0x2f, 0x06, 0xea, 0xc5, 0xa8, 0xf5, 0x89, - 0xb2, 0x86, 0x67, 0x03, 0x71, 0xb3, 0x10, 0xd0, 0x0b, 0x06, 0x44, 0x53, 0xdd, 0x53, 0x4d, 0xdc, - 0x89, 0xbe, 0x1f, 0xfb, 0xfd, 0x20, 0x9b, 0x4a, 0xe1, 0xd6, 0x6d, 0x1c, 0x7b, 0x14, 0xf5, 0xfd, - 0x51, 0xef, 0xd0, 0x1f, 0xf9, 0x61, 0x9f, 0x4b, 0x43, 0xca, 0x06, 0xa2, 0xad, 0x24, 0x49, 0x52, - 0x68, 0xc2, 0x9e, 0x2a, 0x40, 0xd1, 0xe6, 0xea, 0x47, 0xe3, 0x71, 0x90, 0xa1, 0x89, 0xd5, 0x59, - 0x12, 0x8a, 0x24, 0x87, 0xd0, 0x4a, 0x44, 0xeb, 0x54, 0xec, 0x5e, 0x43, 0xcc, 0x66, 0x01, 0x71, - 0x94, 0x23, 0xce, 0x49, 0x21, 0x3d, 0x3f, 0xed, 0x80, 0x18, 0x25, 0x87, 0xe0, 0x39, 0x4c, 0xc2, - 0x94, 0x67, 0xd9, 0x88, 0x0f, 0x34, 0x41, 0x4d, 0x42, 0x2b, 0x77, 0xb0, 0x1b, 0xb0, 0x2e, 0xac, - 0xbe, 0xd4, 0xcf, 0xa2, 0xf4, 0x38, 0x48, 0x7b, 0x29, 0x0f, 0xb3, 0x4e, 0x8b, 0xf0, 0xab, 0xba, - 0xd8, 0xfb, 0xb0, 0x55, 0x00, 0x27, 0xbc, 0xcf, 0x83, 0x13, 0x3e, 0xe8, 0x2c, 0xd3, 0x57, 0xb3, - 0xba, 0xd9, 0x65, 0x68, 0xa2, 0xb1, 0x3b, 0x89, 0x07, 0x3e, 0xde, 0xc3, 0x6d, 0x3a, 0x07, 0x13, - 0xc4, 0xde, 0x85, 0xe5, 0x98, 0x8b, 0xcb, 0xf2, 0x38, 0x1b, 0xf5, 0xd3, 0xce, 0x0a, 0xdd, 0x64, - 0x4d, 0x29, 0x4c, 0xc8, 0xb9, 0x9e, 0x8d, 0x81, 0x4c, 0xd9, 0x4f, 0xc9, 0x7c, 0xf2, 0xa7, 0x9d, - 0x55, 0x62, 0xb7, 0x1c, 0x40, 0x32, 0x92, 0x04, 0x27, 0x7e, 0xc6, 0x3b, 0x6b, 0xc4, 0x5b, 0xaa, - 0xe9, 0xfe, 0x99, 0x03, 0xeb, 0x8f, 0x82, 0x34, 0x93, 0x4c, 0xa8, 0xd5, 0xf1, 0x5b, 0xd0, 0x14, - 0xec, 0xd7, 0x8b, 0xc2, 0xd1, 0x54, 0x72, 0x24, 0x08, 0xd0, 0x97, 0xc3, 0xd1, 0x94, 0x7d, 0x02, - 0x96, 0x83, 0xd0, 0x44, 0x11, 0x32, 0xdc, 0x52, 0x40, 0x42, 0x7a, 0x0b, 0x9a, 0xf1, 0xe4, 0x70, - 0x14, 0xf4, 0x05, 0xca, 0x9c, 0x18, 0x45, 0x80, 0x08, 0x01, 0x8d, 0x24, 0x41, 0x89, 0xc0, 0xa8, - 0x13, 0x46, 0x53, 0xc2, 0x10, 0xc5, 0xbd, 0x03, 0x1b, 0x36, 0x81, 0x52, 0x59, 0x6d, 0xc3, 0x92, - 0xe4, 0xed, 0xb4, 0xd3, 0xa4, 0xfd, 0x69, 0xcb, 0xfd, 0x91, 0xa8, 0x9e, 0xee, 0x77, 0xff, 0xdd, - 0x81, 0x3a, 0x2a, 0x80, 0xd9, 0xca, 0xc2, 0xd4, 0xe9, 0x73, 0x96, 0x4e, 0x27, 0x3f, 0x04, 0xad, - 0x22, 0xc1, 0x12, 0x42, 0x6c, 0x0c, 0x48, 0xde, 0x9f, 0xf0, 0xfe, 0x09, 0xc9, 0x8e, 0xee, 0x47, - 0x08, 0x4a, 0x16, 0x5e, 0x9d, 0xf4, 0xb5, 0x10, 0x1c, 0xdd, 0x56, 0x7d, 0xf4, 0xe5, 0x62, 0xde, - 0x47, 0xdf, 0x75, 0x60, 0x31, 0x08, 0x0f, 0xa3, 0x49, 0x38, 0x20, 0x21, 0x59, 0xf2, 0x54, 0x13, - 0x0f, 0x3b, 0x26, 0x4b, 0x2a, 0x18, 0x73, 0x29, 0x1d, 0x39, 0xc0, 0x65, 0x68, 0x5a, 0xa5, 0xa4, - 0xf0, 0xf4, 0x3d, 0xf6, 0x1e, 0xac, 0x19, 0x30, 0xb9, 0x83, 0x6f, 0xc3, 0x7c, 0x8c, 0x00, 0x69, - 0x28, 0x29, 0xf6, 0x22, 0x4d, 0x29, 0x7a, 0xdc, 0x55, 0x68, 0x3f, 0xe4, 0xd9, 0x07, 0xe1, 0x51, - 0xa4, 0x46, 0xfa, 0xe1, 0x1c, 0xac, 0x68, 0x90, 0x1c, 0xe8, 0x1a, 0xac, 0x04, 0x03, 0x1e, 0x66, - 0x41, 0x36, 0xed, 0x59, 0x16, 0x5c, 0x11, 0x8c, 0x37, 0x8c, 0x3f, 0x0a, 0xfc, 0x54, 0xea, 0x30, - 0xd1, 0x60, 0xbb, 0xb0, 0x81, 0xec, 0xaf, 0x38, 0x5a, 0x1f, 0xab, 0x30, 0x24, 0x2b, 0xfb, 0x50, - 0x62, 0x11, 0x2e, 0x39, 0x50, 0x7f, 0x22, 0x34, 0x6d, 0x55, 0x17, 0xee, 0x9a, 0x18, 0x09, 0x97, - 0x3c, 0x2f, 0x44, 0x44, 0x03, 0x4a, 0xde, 0xe4, 0x82, 0x30, 0x62, 0x8b, 0xde, 0xa4, 0xe1, 0x91, - 0x2e, 0x95, 0x3c, 0xd2, 0x6b, 0xb0, 0x92, 0x4e, 0xc3, 0x3e, 0x1f, 0xf4, 0xb2, 0x08, 0xe7, 0x0d, - 0x42, 0x3a, 0x9d, 0x25, 0xaf, 0x08, 0x26, 0xdf, 0x99, 0xa7, 0x59, 0xc8, 0x33, 0x52, 0x5d, 0x4b, - 0x9e, 0x6a, 0xe2, 0x2d, 0x40, 0x28, 0x82, 0xa9, 0x1b, 0x9e, 0x6c, 0xe1, 0x55, 0x39, 0x49, 0x82, - 0xb4, 0xd3, 0x22, 0x28, 0xfd, 0x66, 0x9f, 0x81, 0xf3, 0x87, 0xe8, 0xe9, 0x1d, 0x73, 0x7f, 0xc0, - 0x13, 0x3a, 0x7d, 0xe1, 0xe8, 0x0a, 0x0d, 0x54, 0xdd, 0x89, 0x73, 0x9f, 0xf0, 0x24, 0x0d, 0xa2, - 0x90, 0x74, 0x4f, 0xc3, 0x53, 0x4d, 0xf7, 0xdb, 0x74, 0xa3, 0x6b, 0x17, 0xfc, 0x29, 0xa9, 0x23, - 0xf6, 0x06, 0x34, 0xc4, 0x1a, 0xd3, 0x63, 0x5f, 0x1a, 0x19, 0x4b, 0x04, 0x38, 0x38, 0xf6, 0x51, - 0x80, 0xad, 0x6d, 0x13, 0x31, 0x8d, 0x26, 0xc1, 0xf6, 0xc4, 0xae, 0x5d, 0x81, 0xb6, 0x72, 0xee, - 0xd3, 0xde, 0x88, 0x1f, 0x65, 0xca, 0x41, 0x08, 0x27, 0x63, 0x9c, 0x2e, 0x7d, 0xc4, 0x8f, 0x32, - 0xf7, 0x31, 0xac, 0x49, 0xb9, 0xfd, 0x72, 0xcc, 0xd5, 0xd4, 0x9f, 0x2b, 0x5e, 0x6a, 0xc2, 0xaa, - 0x58, 0xb7, 0x05, 0x9d, 0xbc, 0x9c, 0xc2, 0x4d, 0xe7, 0x7a, 0xc0, 0x64, 0xf7, 0xdd, 0x51, 0x94, - 0x72, 0x39, 0xa0, 0x0b, 0xad, 0xfe, 0x28, 0x4a, 0x95, 0x1b, 0x22, 0x97, 0x63, 0xc1, 0x70, 0x7f, - 0xd2, 0x49, 0xbf, 0x8f, 0x9a, 0x40, 0xe8, 0x34, 0xd5, 0x74, 0xff, 0xc2, 0x81, 0x75, 0x1a, 0x4d, - 0x69, 0x18, 0x6d, 0xbb, 0x9e, 0x9d, 0xcc, 0x56, 0xdf, 0x74, 0xcd, 0x36, 0x60, 0xfe, 0x28, 0x4a, - 0xfa, 0x5c, 0xce, 0x24, 0x1a, 0x3f, 0xbe, 0x35, 0x5e, 0x2f, 0x59, 0xe3, 0x3f, 0x74, 0x60, 0x8d, - 0x48, 0x3d, 0xc8, 0xfc, 0x6c, 0x92, 0xca, 0xe5, 0xff, 0x22, 0x2c, 0xe3, 0x52, 0xb9, 0x12, 0x27, - 0x49, 0xe8, 0x86, 0x96, 0x7c, 0x82, 0x0a, 0xe4, 0xbd, 0x73, 0x9e, 0x8d, 0xcc, 0xbe, 0x00, 0x2d, - 0x33, 0x42, 0x43, 0x34, 0x37, 0x77, 0x2f, 0xa8, 0x55, 0x96, 0x38, 0x67, 0xef, 0x9c, 0x67, 0x7d, - 0xc0, 0x6e, 0x01, 0x90, 0xb9, 0x41, 0xc3, 0x4a, 0xd7, 0xfa, 0x82, 0xbd, 0x49, 0xc6, 0x61, 0xed, - 0x9d, 0xf3, 0x0c, 0xf4, 0x3b, 0x4b, 0xb0, 0x20, 0xee, 0x47, 0xf7, 0x21, 0x2c, 0x5b, 0x94, 0x5a, - 0x5e, 0x46, 0x4b, 0x78, 0x19, 0x25, 0xa7, 0xb4, 0x56, 0x76, 0x4a, 0xdd, 0x7f, 0xad, 0x01, 0x43, - 0x6e, 0x2b, 0x1c, 0x27, 0x5e, 0xd0, 0xd1, 0xc0, 0x32, 0xb7, 0x5a, 0x9e, 0x09, 0x62, 0xd7, 0x81, - 0x19, 0x4d, 0xe5, 0xb7, 0x8b, 0x7b, 0xa3, 0xa2, 0x07, 0x15, 0x9c, 0xb0, 0x95, 0x94, 0x0f, 0x2c, - 0x0d, 0x4b, 0x71, 0x6e, 0x95, 0x7d, 0x78, 0x35, 0xc4, 0x93, 0xf4, 0x18, 0x0d, 0x08, 0x65, 0x90, - 0xa9, 0x76, 0x91, 0x41, 0x16, 0x5e, 0xcb, 0x20, 0x8b, 0x45, 0x06, 0x31, 0x4d, 0x82, 0x25, 0xcb, - 0x24, 0x40, 0xfb, 0x6b, 0x1c, 0x84, 0x64, 0x57, 0xf4, 0xc6, 0x38, 0xbb, 0xb4, 0xbf, 0x2c, 0x20, - 0xdb, 0x86, 0x55, 0x69, 0xd7, 0xe5, 0x76, 0x07, 0xd0, 0x1e, 0x97, 0xe0, 0xee, 0xc7, 0x0e, 0xac, - 0xe2, 0x3e, 0x5b, 0xbc, 0x78, 0x13, 0x48, 0x14, 0xce, 0xc8, 0x8a, 0x16, 0xee, 0x4f, 0xcf, 0x89, - 0xef, 0x43, 0x83, 0x06, 0x8c, 0x62, 0x1e, 0x4a, 0x46, 0xec, 0xd8, 0x8c, 0x98, 0x6b, 0xa1, 0xbd, - 0x73, 0x5e, 0x8e, 0x6c, 0xb0, 0xe1, 0x3f, 0x3a, 0xd0, 0x94, 0x64, 0xfe, 0xc4, 0xbe, 0x44, 0x17, - 0x96, 0x90, 0x23, 0x0d, 0x83, 0x5d, 0xb7, 0xf1, 0x36, 0x19, 0xa3, 0xc3, 0x86, 0xd7, 0xa7, 0xe5, - 0x47, 0x14, 0xc1, 0x78, 0x17, 0x92, 0xc2, 0x4d, 0x7b, 0x59, 0x30, 0xea, 0xa9, 0x5e, 0x19, 0x10, - 0xad, 0xea, 0x42, 0xbd, 0x93, 0x66, 0xfe, 0x90, 0xcb, 0x6b, 0x4e, 0x34, 0xd0, 0x61, 0x92, 0x0b, - 0x2a, 0x98, 0x83, 0xee, 0xdf, 0xb6, 0x60, 0xab, 0xd4, 0xa5, 0x33, 0x0a, 0xd2, 0x40, 0x1e, 0x05, - 0xe3, 0xc3, 0x48, 0xdb, 0xda, 0x8e, 0x69, 0x3b, 0x5b, 0x5d, 0x6c, 0x08, 0xe7, 0xd5, 0x7d, 0x8e, - 0x7b, 0x9a, 0xdf, 0xde, 0x35, 0x32, 0x44, 0xde, 0xb5, 0x79, 0xa0, 0x38, 0xa1, 0x82, 0x9b, 0x92, - 0x5b, 0x3d, 0x1e, 0x3b, 0x86, 0x8e, 0x36, 0x1c, 0xa4, 0x8a, 0x37, 0x8c, 0x0b, 0x9c, 0xeb, 0x9d, - 0xd7, 0xcc, 0x45, 0xfa, 0x68, 0xa0, 0xa6, 0x99, 0x39, 0x1a, 0x9b, 0xc2, 0x25, 0xd5, 0x47, 0x3a, - 0xbc, 0x3c, 0x5f, 0xfd, 0x4c, 0x6b, 0x7b, 0x80, 0x1f, 0xdb, 0x93, 0xbe, 0x66, 0x60, 0xf6, 0x4d, - 0xd8, 0x3c, 0xf5, 0x83, 0x4c, 0x91, 0x65, 0x18, 0x43, 0xf3, 0x34, 0xe5, 0xee, 0x6b, 0xa6, 0x7c, - 0x26, 0x3e, 0xb6, 0x2e, 0xb6, 0x19, 0x23, 0x76, 0xff, 0xde, 0x81, 0xb6, 0x3d, 0x0e, 0xb2, 0xa9, - 0x14, 0x78, 0xa5, 0xf8, 0x94, 0xf1, 0x57, 0x00, 0x97, 0x5d, 0xd4, 0x5a, 0x95, 0x8b, 0x6a, 0x3a, - 0xa2, 0x73, 0xaf, 0x73, 0x44, 0xeb, 0x67, 0x73, 0x44, 0xe7, 0xab, 0x1c, 0xd1, 0xee, 0x7f, 0x39, - 0xc0, 0xca, 0xbc, 0xc4, 0x1e, 0x0a, 0x1f, 0x39, 0xe4, 0x23, 0xa9, 0x93, 0x7e, 0xfe, 0x6c, 0xfc, - 0xa8, 0xf6, 0x4e, 0x7d, 0x8d, 0x82, 0x61, 0x2a, 0x1d, 0xd3, 0x44, 0x5a, 0xf6, 0xaa, 0xba, 0x0a, - 0xae, 0x71, 0xfd, 0xf5, 0xae, 0xf1, 0xfc, 0xeb, 0x5d, 0xe3, 0x85, 0xa2, 0x6b, 0xdc, 0xfd, 0x5d, - 0x07, 0xd6, 0x2b, 0x0e, 0xfd, 0x67, 0xb7, 0x70, 0x3c, 0x26, 0x4b, 0x17, 0xd4, 0xe4, 0x31, 0x99, - 0xc0, 0xee, 0x6f, 0xc0, 0xb2, 0xc5, 0xe8, 0x3f, 0xbb, 0xf9, 0x8b, 0x56, 0x9e, 0xe0, 0x33, 0x0b, - 0xd6, 0xfd, 0x51, 0x0d, 0x58, 0x59, 0xd8, 0xfe, 0x5f, 0x69, 0x28, 0xef, 0xd3, 0x5c, 0xc5, 0x3e, - 0xfd, 0x9f, 0xde, 0x03, 0xef, 0xc0, 0x9a, 0x4c, 0x3f, 0x1a, 0x51, 0x12, 0xc1, 0x31, 0xe5, 0x0e, - 0xb4, 0x73, 0xed, 0xb8, 0xc4, 0x92, 0x95, 0xb6, 0x32, 0x2e, 0xc3, 0x42, 0x78, 0xc2, 0xdd, 0x84, - 0x0d, 0x91, 0xce, 0xbc, 0x23, 0x86, 0x52, 0xf7, 0xca, 0x9f, 0x3a, 0x70, 0xbe, 0xd0, 0x91, 0xe7, - 0x76, 0xc4, 0xd5, 0x61, 0xdf, 0x27, 0x36, 0x10, 0xe9, 0x97, 0x72, 0x64, 0xd0, 0x2f, 0xb8, 0xad, - 0xdc, 0x81, 0xfb, 0x33, 0x09, 0xcb, 0xf8, 0x62, 0xd7, 0xab, 0xba, 0xdc, 0x2d, 0x91, 0x74, 0x0d, - 0xf9, 0xa8, 0x40, 0xf8, 0x91, 0x48, 0x93, 0x9a, 0x1d, 0x79, 0x70, 0xd8, 0x26, 0x59, 0x35, 0xd1, - 0x0a, 0xb4, 0xae, 0x29, 0x9b, 0xde, 0xca, 0x3e, 0xf7, 0xf7, 0x1d, 0x60, 0x5f, 0x99, 0xf0, 0x64, - 0x4a, 0x39, 0x1e, 0x1d, 0x9e, 0xd9, 0x2a, 0xc6, 0x31, 0x16, 0xe2, 0xc9, 0xe1, 0x97, 0xf8, 0x54, - 0xe5, 0xf6, 0x6a, 0x79, 0x6e, 0xef, 0x4d, 0x00, 0x74, 0xbf, 0x74, 0xe2, 0x08, 0x79, 0x01, 0xfd, - 0x5e, 0x31, 0x60, 0x65, 0xfa, 0xad, 0x5e, 0x99, 0x7e, 0xbb, 0x05, 0xeb, 0x16, 0x25, 0xfa, 0xa0, - 0x54, 0x52, 0xca, 0x79, 0x45, 0x52, 0xea, 0x3f, 0x1c, 0x98, 0xdb, 0x8b, 0x62, 0x33, 0x00, 0xe9, - 0xd8, 0x01, 0x48, 0x79, 0x3b, 0xf4, 0xb4, 0xf2, 0x97, 0x4a, 0xc3, 0x02, 0xb2, 0x6d, 0x68, 0xfb, - 0xe3, 0x0c, 0x1d, 0xe9, 0xa3, 0x28, 0x39, 0xf5, 0x93, 0x81, 0x38, 0xbd, 0x3b, 0xb5, 0x8e, 0xe3, - 0x15, 0x7a, 0xd8, 0x06, 0xcc, 0x69, 0x35, 0x4a, 0x08, 0xd8, 0x44, 0x53, 0x8c, 0xe2, 0xb0, 0x53, - 0x19, 0x03, 0x90, 0x2d, 0x64, 0x0e, 0xfb, 0x7b, 0x61, 0xfc, 0x0a, 0x61, 0xa8, 0xea, 0xc2, 0x9b, - 0x0a, 0xb5, 0x2a, 0xa1, 0xc9, 0xe0, 0x8d, 0x6a, 0xbb, 0xff, 0xe6, 0xc0, 0x3c, 0xed, 0x00, 0x8a, - 0xaf, 0xe0, 0x59, 0x4a, 0x3b, 0x53, 0xd0, 0xd8, 0x11, 0xe2, 0x5b, 0x00, 0x33, 0xd7, 0x4a, 0x46, - 0xd7, 0x34, 0xd9, 0x66, 0x42, 0xfa, 0x32, 0x34, 0x44, 0x4b, 0x67, 0x70, 0x09, 0x25, 0x07, 0xb2, - 0x4b, 0x50, 0x3f, 0x8e, 0x62, 0x65, 0x6f, 0x80, 0x8a, 0x19, 0x46, 0xb1, 0x47, 0xf0, 0x9c, 0x1e, - 0x1c, 0x4f, 0x10, 0x2f, 0x6e, 0x91, 0x22, 0x18, 0xef, 0x51, 0x3d, 0xac, 0xb9, 0x19, 0x05, 0xa8, - 0xbb, 0x0d, 0x2b, 0x8f, 0xa3, 0x01, 0x37, 0xa2, 0x44, 0x33, 0xf9, 0xd3, 0xfd, 0x4d, 0x07, 0x96, - 0x14, 0x32, 0xbb, 0x06, 0x75, 0x34, 0x0e, 0x0a, 0xa6, 0xbf, 0xce, 0x15, 0x20, 0x9e, 0x47, 0x18, - 0xa8, 0x4d, 0x29, 0x86, 0x90, 0x1b, 0x8a, 0x2a, 0x82, 0x90, 0xdb, 0x41, 0x9a, 0xdc, 0x82, 0xf9, - 0x50, 0x80, 0xba, 0x7f, 0xe9, 0xc0, 0xb2, 0x35, 0x07, 0x3a, 0x7c, 0x23, 0x3f, 0xcd, 0x64, 0xfc, - 0x55, 0x1e, 0x8f, 0x09, 0x32, 0xe3, 0x86, 0x35, 0x3b, 0x6e, 0xa8, 0x23, 0x5a, 0x73, 0x66, 0x44, - 0xeb, 0x06, 0x34, 0xf2, 0x92, 0x81, 0xba, 0xa5, 0x25, 0x71, 0x46, 0x95, 0x05, 0xc9, 0x91, 0x70, - 0x9c, 0x7e, 0x34, 0x8a, 0x12, 0x99, 0x51, 0x17, 0x0d, 0xf7, 0x16, 0x34, 0x0d, 0x7c, 0x24, 0x23, - 0xe4, 0xd9, 0x69, 0x94, 0x3c, 0x57, 0xe1, 0x4b, 0xd9, 0xd4, 0xc9, 0xbe, 0x5a, 0x9e, 0xec, 0x73, - 0xff, 0xca, 0x81, 0x65, 0xe4, 0xc1, 0x20, 0x1c, 0xee, 0x47, 0xa3, 0xa0, 0x3f, 0xa5, 0xb3, 0x57, - 0xec, 0x26, 0x65, 0x5d, 0xf1, 0xa2, 0x0d, 0x46, 0xde, 0x56, 0xfe, 0x9e, 0x14, 0x44, 0xdd, 0x46, - 0x49, 0x45, 0x3e, 0x3f, 0xf4, 0x53, 0xc9, 0xfc, 0xf2, 0xda, 0xb2, 0x80, 0x28, 0x4f, 0x08, 0x48, - 0xfc, 0x8c, 0xf7, 0xc6, 0xc1, 0x68, 0x14, 0x08, 0x5c, 0x61, 0xd4, 0x54, 0x75, 0xb9, 0x3f, 0xa8, - 0x41, 0x53, 0x2a, 0xd5, 0xfb, 0x83, 0xa1, 0x48, 0x14, 0x48, 0xd3, 0x50, 0xab, 0x0b, 0x03, 0xa2, - 0xfa, 0x2d, 0x63, 0xd2, 0x80, 0x14, 0x8f, 0x75, 0xae, 0x7c, 0xac, 0x17, 0xa1, 0x81, 0xec, 0xf5, - 0x2e, 0x59, 0xad, 0xa2, 0xc2, 0x24, 0x07, 0xa8, 0xde, 0x5d, 0xea, 0x9d, 0xcf, 0x7b, 0x09, 0x60, - 0xd9, 0xa9, 0x0b, 0x05, 0x3b, 0xf5, 0x7d, 0x68, 0xc9, 0x61, 0x68, 0xdf, 0x49, 0x3b, 0xe4, 0x0c, - 0x6e, 0x9d, 0x89, 0x67, 0x61, 0xaa, 0x2f, 0x77, 0xd5, 0x97, 0x4b, 0xaf, 0xfb, 0x52, 0x61, 0x52, - 0xde, 0x4c, 0xec, 0xcd, 0xc3, 0xc4, 0x8f, 0x8f, 0xd5, 0x45, 0x35, 0xd0, 0xc5, 0x00, 0x04, 0x66, - 0xdb, 0x30, 0x8f, 0x9f, 0x29, 0x6d, 0x5d, 0x2d, 0x74, 0x02, 0x85, 0x5d, 0x83, 0x79, 0x3e, 0x18, - 0x72, 0xe5, 0x97, 0x31, 0xdb, 0x43, 0xc6, 0x33, 0xf2, 0x04, 0x02, 0xaa, 0x00, 0x84, 0x16, 0x54, - 0x80, 0xad, 0xe9, 0x17, 0xb0, 0xf9, 0xc1, 0xc0, 0xdd, 0x00, 0xf6, 0x58, 0x70, 0xad, 0x19, 0x57, - 0xfe, 0x9d, 0x39, 0x68, 0x1a, 0x60, 0x94, 0xe6, 0x21, 0x12, 0xdc, 0x1b, 0x04, 0xfe, 0x98, 0x67, - 0x3c, 0x91, 0x9c, 0x5a, 0x80, 0x22, 0x9e, 0x7f, 0x32, 0xec, 0x45, 0x93, 0xac, 0x37, 0xe0, 0xc3, - 0x84, 0x8b, 0xeb, 0x14, 0x2f, 0x03, 0x0b, 0x8a, 0x78, 0x63, 0xff, 0x85, 0x89, 0x27, 0xf8, 0xa1, - 0x00, 0x55, 0x51, 0x62, 0xb1, 0x47, 0xf5, 0x3c, 0x4a, 0x2c, 0x76, 0xa4, 0xa8, 0x87, 0xe6, 0x2b, - 0xf4, 0xd0, 0x7b, 0xb0, 0x29, 0x34, 0x8e, 0x94, 0xcd, 0x5e, 0x81, 0x4d, 0x66, 0xf4, 0xb2, 0x6d, - 0x58, 0x45, 0x9a, 0x15, 0x83, 0xa7, 0xc1, 0xb7, 0x45, 0xdc, 0xc6, 0xf1, 0x4a, 0x70, 0xc4, 0x45, - 0x71, 0xb4, 0x70, 0x45, 0x26, 0xad, 0x04, 0x27, 0x5c, 0xff, 0x85, 0x8d, 0xdb, 0x90, 0xb8, 0x05, - 0xb8, 0xbb, 0x0c, 0xcd, 0x83, 0x2c, 0x8a, 0xd5, 0xa1, 0xb4, 0xa1, 0x25, 0x9a, 0x32, 0x6f, 0xfa, - 0x06, 0x5c, 0x20, 0x2e, 0x7a, 0x12, 0xc5, 0xd1, 0x28, 0x1a, 0x4e, 0x0f, 0x26, 0x87, 0x69, 0x3f, - 0x09, 0x62, 0xf4, 0x61, 0xdc, 0x7f, 0x70, 0x60, 0xdd, 0xea, 0x95, 0x81, 0x9e, 0xcf, 0x08, 0x96, - 0xd6, 0x09, 0x2f, 0xc1, 0x78, 0x6b, 0x86, 0x3a, 0x14, 0x88, 0x22, 0xc4, 0xf6, 0x54, 0xe6, 0xc0, - 0x6e, 0xc3, 0x8a, 0xa2, 0x4c, 0x7d, 0x28, 0xb8, 0xb0, 0x53, 0xe6, 0x42, 0xf9, 0x7d, 0x5b, 0x7e, - 0xa0, 0x86, 0xf8, 0x25, 0x61, 0x82, 0xf3, 0x01, 0xad, 0x51, 0x79, 0xfc, 0x5d, 0xf5, 0xbd, 0x69, - 0xf7, 0x2b, 0x0a, 0xfa, 0x1a, 0x98, 0xba, 0x7f, 0xe0, 0x00, 0xe4, 0xd4, 0x21, 0x63, 0xe4, 0x2a, - 0x5d, 0x54, 0x4b, 0x1a, 0xea, 0xfb, 0x6d, 0x68, 0xe9, 0x5c, 0x47, 0x7e, 0x4b, 0x34, 0x15, 0x0c, - 0x4d, 0xb3, 0xab, 0xb0, 0x32, 0x1c, 0x45, 0x87, 0x74, 0xc5, 0x52, 0x22, 0x3e, 0x95, 0xd9, 0xe3, - 0xb6, 0x00, 0x3f, 0x90, 0xd0, 0xfc, 0x4a, 0xa9, 0x1b, 0x57, 0x8a, 0xfb, 0x9d, 0x9a, 0x8e, 0x90, - 0xe7, 0x6b, 0x9e, 0x29, 0x65, 0x6c, 0xb7, 0xa4, 0x1c, 0x67, 0x04, 0xa4, 0x29, 0xb6, 0xb5, 0xff, - 0x5a, 0xd7, 0xfb, 0x16, 0xb4, 0x13, 0xa1, 0x7d, 0x94, 0x6a, 0xaa, 0xbf, 0x42, 0x35, 0x2d, 0x27, - 0xd6, 0xbd, 0xf3, 0x29, 0x58, 0xf5, 0x07, 0x27, 0x3c, 0xc9, 0x02, 0x72, 0x7e, 0xe8, 0xd2, 0x17, - 0x0a, 0x75, 0xc5, 0x80, 0xd3, 0x5d, 0x7c, 0x15, 0x56, 0x64, 0xc6, 0x5e, 0x63, 0xca, 0xba, 0xb1, - 0x1c, 0x8c, 0x88, 0xee, 0x9f, 0xab, 0x60, 0xbc, 0x7d, 0x86, 0xb3, 0x77, 0xc4, 0x5c, 0x5d, 0xad, - 0xb0, 0xba, 0x4f, 0xc8, 0xc0, 0xf8, 0x40, 0x79, 0x58, 0x32, 0x45, 0x21, 0x80, 0x32, 0x91, 0x61, - 0x6f, 0x69, 0xfd, 0x2c, 0x5b, 0xea, 0x7e, 0xec, 0xc0, 0xe2, 0x5e, 0x14, 0xef, 0xc9, 0xe4, 0x3b, - 0x09, 0x82, 0xae, 0x87, 0x51, 0x4d, 0xd3, 0x2a, 0xae, 0x95, 0xac, 0xe2, 0xf2, 0x5d, 0xbb, 0x5c, - 0xbc, 0x6b, 0x7f, 0x19, 0xde, 0x20, 0xff, 0x3e, 0x89, 0xe2, 0x28, 0x41, 0x61, 0xf4, 0x47, 0xe2, - 0x62, 0x8d, 0xc2, 0xec, 0x58, 0xa9, 0xb1, 0x57, 0xa1, 0x90, 0x23, 0x85, 0x0e, 0x80, 0x30, 0x86, - 0xa5, 0x6d, 0x20, 0xb4, 0x5b, 0xb9, 0xc3, 0xfd, 0x1c, 0x34, 0xc8, 0xb8, 0xa5, 0x65, 0xbd, 0x03, - 0x8d, 0xe3, 0x28, 0xee, 0x1d, 0x07, 0x61, 0xa6, 0x84, 0xbb, 0x9d, 0x5b, 0x9d, 0x7b, 0xb4, 0x21, - 0x1a, 0xc1, 0xfd, 0xd1, 0x1c, 0x2c, 0x7e, 0x10, 0x9e, 0x44, 0x41, 0x9f, 0xe2, 0xf6, 0x63, 0x3e, - 0x8e, 0x54, 0x75, 0x10, 0xfe, 0xc6, 0xad, 0xa0, 0x4c, 0x79, 0x9c, 0xc9, 0xc0, 0xbb, 0x6a, 0xe2, - 0x75, 0x9f, 0xe4, 0x15, 0x7c, 0x42, 0x74, 0x0c, 0x08, 0x1a, 0xf6, 0x89, 0x59, 0xbe, 0x28, 0x5b, - 0x79, 0x79, 0xd5, 0xbc, 0x51, 0x5e, 0x45, 0x59, 0x1e, 0x51, 0x04, 0x40, 0xfc, 0xb5, 0xe4, 0xa9, - 0x26, 0x39, 0x22, 0x09, 0x17, 0x71, 0x19, 0x32, 0x1c, 0x16, 0xa5, 0x23, 0x62, 0x02, 0xd1, 0xb8, - 0x10, 0x1f, 0x08, 0x1c, 0xa1, 0x7c, 0x4d, 0x10, 0x1a, 0x5b, 0xc5, 0x0a, 0xc8, 0x86, 0xe0, 0xf9, - 0x02, 0x18, 0x35, 0xf4, 0x80, 0x6b, 0x45, 0x2a, 0xd6, 0x00, 0xa2, 0x42, 0xb1, 0x08, 0x37, 0xdc, - 0x17, 0x51, 0xcc, 0xa0, 0xdc, 0x17, 0x64, 0x14, 0x7f, 0x34, 0x3a, 0xf4, 0xfb, 0xcf, 0xa9, 0x2e, - 0x95, 0x6a, 0x17, 0x1a, 0x9e, 0x0d, 0x44, 0xaa, 0x8d, 0xd3, 0xa4, 0x3c, 0x61, 0xdd, 0x33, 0x41, - 0x6c, 0x17, 0x9a, 0xe4, 0xb2, 0xc9, 0xf3, 0x6c, 0xd3, 0x79, 0xae, 0x9a, 0x3e, 0x1d, 0x9d, 0xa8, - 0x89, 0x64, 0xe6, 0x12, 0x56, 0xec, 0xf2, 0x82, 0xaf, 0x02, 0xbb, 0x3d, 0x18, 0xc8, 0xf3, 0xd6, - 0x2e, 0x63, 0x7e, 0x52, 0x8e, 0x75, 0x52, 0x15, 0x3b, 0x56, 0xab, 0xdc, 0x31, 0xf7, 0x3e, 0x34, - 0xf7, 0x8d, 0x42, 0x4a, 0x62, 0x0d, 0x55, 0x42, 0x29, 0xd9, 0xc9, 0x80, 0x18, 0x13, 0xd6, 0xcc, - 0x09, 0xdd, 0x5f, 0x00, 0xf6, 0x28, 0x48, 0x33, 0x4d, 0x5f, 0x5e, 0xb9, 0xa9, 0x7c, 0xf1, 0xbc, - 0xf8, 0xa1, 0x29, 0x61, 0x54, 0x94, 0x70, 0x5b, 0x54, 0x4d, 0x14, 0x17, 0xb6, 0x0d, 0x4b, 0x81, - 0x00, 0x15, 0x25, 0x41, 0x61, 0xea, 0x7e, 0xb4, 0xd7, 0x24, 0xd0, 0xba, 0x45, 0x7f, 0xe0, 0xc0, - 0xa2, 0x5c, 0x1a, 0x5a, 0x1b, 0xa5, 0x12, 0xd2, 0x86, 0x67, 0xc1, 0xaa, 0x8b, 0x07, 0xcb, 0x3c, - 0x3c, 0x57, 0xc5, 0xc3, 0x0c, 0xea, 0xb1, 0x9f, 0x1d, 0x93, 0x83, 0xd2, 0xf0, 0xe8, 0x37, 0x5b, - 0x15, 0x4e, 0xb3, 0x90, 0x15, 0x72, 0x98, 0xab, 0xea, 0x67, 0x85, 0x4a, 0x2e, 0xc1, 0x71, 0x51, - 0x54, 0x67, 0x20, 0xe0, 0x3a, 0x7d, 0x20, 0x6b, 0x38, 0x72, 0x70, 0xbe, 0x5f, 0x72, 0x88, 0xe2, - 0x7e, 0x49, 0x54, 0x4f, 0xf7, 0xbb, 0x5d, 0xe8, 0xdc, 0xe3, 0x23, 0x9e, 0xf1, 0xdb, 0xa3, 0x51, - 0x71, 0xfc, 0x37, 0xe0, 0x42, 0x45, 0x9f, 0x34, 0x5a, 0x1e, 0xc0, 0xda, 0x3d, 0x7e, 0x38, 0x19, - 0x3e, 0xe2, 0x27, 0x79, 0x8e, 0x8f, 0x41, 0x3d, 0x3d, 0x8e, 0x4e, 0xe5, 0xd9, 0xd2, 0x6f, 0xf6, - 0x26, 0xc0, 0x08, 0x71, 0x7a, 0x69, 0xcc, 0xfb, 0xaa, 0x6c, 0x8e, 0x20, 0x07, 0x31, 0xef, 0xbb, - 0xef, 0x01, 0x33, 0xc7, 0x91, 0x4b, 0x40, 0x3d, 0x30, 0x39, 0xec, 0xa5, 0xd3, 0x34, 0xe3, 0x63, - 0x55, 0x0f, 0x68, 0x82, 0xdc, 0xab, 0xd0, 0xda, 0xf7, 0xa7, 0x1e, 0xff, 0x96, 0xac, 0xe2, 0x45, - 0xdf, 0xd8, 0x9f, 0x22, 0x2b, 0x6b, 0xdf, 0x98, 0xba, 0xdd, 0xff, 0xac, 0xc1, 0x82, 0xc0, 0xc4, - 0x51, 0x07, 0x3c, 0xcd, 0x82, 0x50, 0xe4, 0xb7, 0xe4, 0xa8, 0x06, 0xa8, 0xc4, 0x1b, 0xb5, 0x0a, - 0xde, 0x90, 0xd6, 0xaa, 0x2a, 0x41, 0x92, 0x4c, 0x60, 0xc1, 0xd0, 0xac, 0xc9, 0xeb, 0x06, 0x84, - 0x73, 0x96, 0x03, 0x0a, 0xc1, 0x92, 0x5c, 0xdb, 0x08, 0xfa, 0x14, 0xd3, 0x4a, 0x76, 0x30, 0x41, - 0x95, 0x3a, 0x6d, 0x51, 0x70, 0x4d, 0x49, 0xa7, 0x95, 0x74, 0xd7, 0xd2, 0x19, 0x74, 0x97, 0x30, - 0x61, 0x5f, 0xa5, 0xbb, 0xe0, 0x0c, 0xba, 0xcb, 0x65, 0xb0, 0xfa, 0x80, 0x73, 0x8f, 0xe3, 0xad, - 0xa8, 0xd8, 0xe9, 0x7b, 0x0e, 0xac, 0xca, 0x0b, 0x5d, 0xf7, 0xb1, 0xb7, 0xad, 0xdb, 0xdf, 0xa9, - 0x4a, 0x5d, 0x5c, 0x81, 0x65, 0xba, 0x93, 0x75, 0x54, 0x48, 0x86, 0xb0, 0x2c, 0x20, 0xae, 0x43, - 0x05, 0xe3, 0xc7, 0xc1, 0x48, 0x1e, 0x8a, 0x09, 0x52, 0x81, 0x25, 0xf4, 0x8f, 0xe9, 0x48, 0x1c, - 0x4f, 0xb7, 0xdd, 0xbf, 0x71, 0x60, 0xcd, 0x20, 0x58, 0x72, 0xe1, 0x2d, 0x50, 0x75, 0x05, 0x22, - 0x78, 0x24, 0x84, 0x69, 0xcb, 0x36, 0x4e, 0xf2, 0xcf, 0x2c, 0x64, 0x3a, 0x4c, 0x7f, 0x4a, 0x04, - 0xa6, 0x93, 0xb1, 0xb4, 0x40, 0x4c, 0x10, 0x32, 0xd2, 0x29, 0xe7, 0xcf, 0x35, 0xca, 0x1c, 0xa1, - 0x58, 0x30, 0x4a, 0x1b, 0xa3, 0x2d, 0xa1, 0x91, 0x44, 0xa5, 0x94, 0x0d, 0x74, 0xff, 0xc9, 0x81, - 0x75, 0x61, 0x14, 0x4a, 0x93, 0x5b, 0x57, 0x71, 0x2e, 0x08, 0x2b, 0x58, 0x48, 0xe4, 0xde, 0x39, - 0x4f, 0xb6, 0xd9, 0x67, 0xcf, 0x68, 0xc8, 0xea, 0x72, 0x81, 0x19, 0x67, 0x31, 0x57, 0x75, 0x16, - 0xaf, 0xd8, 0xe9, 0xaa, 0x60, 0xc9, 0x7c, 0x65, 0xb0, 0xe4, 0xce, 0x22, 0xcc, 0xa7, 0xfd, 0x28, - 0xe6, 0xee, 0x26, 0x6c, 0xd8, 0x8b, 0x93, 0x2a, 0xe8, 0xfb, 0x0e, 0x74, 0x1e, 0x88, 0xd0, 0x61, - 0x10, 0x0e, 0xf7, 0x82, 0x34, 0x8b, 0x12, 0x5d, 0xb6, 0x7e, 0x09, 0x20, 0xcd, 0xfc, 0x24, 0x13, - 0xe5, 0x5c, 0x32, 0xcc, 0x91, 0x43, 0x90, 0x46, 0x1e, 0x0e, 0x44, 0xaf, 0x38, 0x1b, 0xdd, 0xc6, - 0x83, 0xa1, 0x52, 0x86, 0x5e, 0x74, 0x74, 0x94, 0x72, 0x6d, 0xb6, 0x9a, 0x30, 0xf4, 0x7c, 0x51, - 0xe2, 0xd1, 0xd7, 0xe3, 0x27, 0xa4, 0x6a, 0x85, 0x3d, 0x58, 0x80, 0xba, 0x7f, 0xed, 0xc0, 0x4a, - 0x4e, 0xe4, 0x7d, 0x04, 0xda, 0xda, 0x41, 0x90, 0x66, 0x68, 0x07, 0x15, 0x80, 0x09, 0x06, 0xbd, - 0x20, 0x94, 0xb4, 0x19, 0x10, 0x92, 0x58, 0xd9, 0x8a, 0x26, 0xaa, 0x74, 0xce, 0x04, 0x89, 0xbc, - 0x78, 0x86, 0x5f, 0x8b, 0xba, 0x39, 0xd9, 0xa2, 0x6a, 0xbc, 0x71, 0x46, 0x5f, 0x2d, 0x08, 0x83, - 0x58, 0x36, 0xd5, 0xfd, 0xb4, 0x48, 0x50, 0xfc, 0xe9, 0xfe, 0xa1, 0x03, 0x17, 0x2a, 0x36, 0x57, - 0x4a, 0xc6, 0x3d, 0x58, 0x3b, 0xd2, 0x9d, 0x6a, 0x03, 0x84, 0x78, 0x6c, 0x4a, 0x2e, 0x2a, 0x2c, - 0xda, 0x2b, 0x7f, 0x80, 0xe6, 0x31, 0xc5, 0x8d, 0xc4, 0x96, 0x5a, 0x25, 0x25, 0xe5, 0x8e, 0xdd, - 0x3f, 0x9a, 0x83, 0xb6, 0xc8, 0x6a, 0x88, 0x97, 0x5c, 0x3c, 0x61, 0x1f, 0xc2, 0xa2, 0x7c, 0x89, - 0xc7, 0xce, 0xcb, 0x69, 0xed, 0xb7, 0x7f, 0xdd, 0xcd, 0x22, 0x58, 0xf2, 0xce, 0xfa, 0x6f, 0x7f, - 0xfc, 0x2f, 0x7f, 0x5c, 0x5b, 0x66, 0xcd, 0x9d, 0x93, 0x77, 0x77, 0x86, 0x3c, 0x4c, 0x71, 0x8c, - 0x5f, 0x03, 0xc8, 0xdf, 0xa8, 0xb1, 0x8e, 0x36, 0x32, 0x0a, 0x8f, 0xef, 0xba, 0x17, 0x2a, 0x7a, - 0xe4, 0xb8, 0x17, 0x68, 0xdc, 0x75, 0xb7, 0x8d, 0xe3, 0x06, 0x61, 0x90, 0x89, 0x07, 0x6b, 0x37, - 0x9d, 0x6d, 0x36, 0x80, 0x96, 0xf9, 0x04, 0x8d, 0x29, 0x97, 0xb9, 0xe2, 0x01, 0x5c, 0xf7, 0x8d, - 0xca, 0x3e, 0x15, 0x2f, 0xa0, 0x39, 0xce, 0xbb, 0xab, 0x38, 0xc7, 0x84, 0x30, 0xf2, 0x59, 0x46, - 0xd0, 0xb6, 0x5f, 0x9a, 0xb1, 0x8b, 0x86, 0x58, 0x97, 0xde, 0xb9, 0x75, 0xdf, 0x9c, 0xd1, 0x2b, - 0xe7, 0x7a, 0x93, 0xe6, 0xda, 0x72, 0x19, 0xce, 0xd5, 0x27, 0x1c, 0xf5, 0xce, 0xed, 0xa6, 0xb3, - 0xbd, 0xfb, 0xdd, 0x37, 0xa1, 0xa1, 0x83, 0x5c, 0xec, 0x9b, 0xb0, 0x6c, 0xa5, 0x9d, 0x98, 0x5a, - 0x46, 0x55, 0x96, 0xaa, 0x7b, 0xb1, 0xba, 0x53, 0x4e, 0x7c, 0x89, 0x26, 0xee, 0xb0, 0x4d, 0x9c, - 0x58, 0xe6, 0x6d, 0x76, 0x28, 0xd9, 0x26, 0x6a, 0xfd, 0x9e, 0x8b, 0x75, 0xe6, 0xa9, 0x22, 0x6b, - 0x9d, 0xa5, 0xd4, 0x92, 0xb5, 0xce, 0x72, 0x7e, 0xc9, 0xbd, 0x48, 0xd3, 0x6d, 0xb2, 0x0d, 0x73, - 0x3a, 0x1d, 0x7c, 0xe2, 0x54, 0x9d, 0x69, 0x3e, 0x44, 0x63, 0x6f, 0x6a, 0xc6, 0xaa, 0x7a, 0xa0, - 0xa6, 0x59, 0xa4, 0xfc, 0x4a, 0xcd, 0xed, 0xd0, 0x54, 0x8c, 0xd1, 0xf1, 0x99, 0xef, 0xd0, 0xd8, - 0xd7, 0xa1, 0xa1, 0x1f, 0x7b, 0xb0, 0x2d, 0xe3, 0x85, 0x8d, 0xf9, 0x02, 0xa5, 0xdb, 0x29, 0x77, - 0x54, 0x31, 0x86, 0x39, 0x32, 0x32, 0xc6, 0x23, 0x38, 0x2f, 0x4d, 0xe2, 0x43, 0xfe, 0xe3, 0xac, - 0xa4, 0xe2, 0xf9, 0xdc, 0x0d, 0x87, 0xdd, 0x82, 0x25, 0xf5, 0x86, 0x86, 0x6d, 0x56, 0xbf, 0x05, - 0xea, 0x6e, 0x95, 0xe0, 0x52, 0x7b, 0xdc, 0x06, 0xc8, 0xdf, 0x7f, 0x68, 0x39, 0x2b, 0xbd, 0x4a, - 0xd1, 0x9b, 0x58, 0xf1, 0x58, 0x64, 0x48, 0xaf, 0x5d, 0xec, 0xe7, 0x25, 0xec, 0xad, 0x1c, 0xbf, - 0xf2, 0xe1, 0xc9, 0x2b, 0x06, 0x74, 0x37, 0x69, 0xef, 0x56, 0x19, 0x09, 0x6e, 0xc8, 0x4f, 0x55, - 0x9d, 0xf2, 0x3d, 0x68, 0x1a, 0x6f, 0x4a, 0x98, 0x1a, 0xa1, 0xfc, 0x1e, 0xa5, 0xdb, 0xad, 0xea, - 0x92, 0xe4, 0x7e, 0x11, 0x96, 0xad, 0xc7, 0x21, 0x5a, 0x32, 0xaa, 0x9e, 0x9e, 0x68, 0xc9, 0xa8, - 0x7e, 0x4f, 0xf2, 0x35, 0x68, 0x1a, 0x4f, 0x39, 0x98, 0x51, 0x9f, 0x55, 0x78, 0xc4, 0xa1, 0x29, - 0xaa, 0x7a, 0xf9, 0xb1, 0x41, 0xeb, 0x6d, 0xbb, 0x0d, 0x5c, 0x2f, 0x15, 0xeb, 0x22, 0x93, 0x7c, - 0x13, 0xda, 0xf6, 0xe3, 0x0e, 0x2d, 0x55, 0x95, 0xcf, 0x44, 0xb4, 0x54, 0xcd, 0x78, 0x11, 0x22, - 0x19, 0x72, 0x7b, 0x5d, 0x4f, 0xb2, 0xf3, 0x91, 0x4c, 0xf1, 0xbc, 0x64, 0x5f, 0x41, 0xd5, 0x21, - 0xab, 0xa7, 0x59, 0xfe, 0xa4, 0xc5, 0xae, 0xb1, 0xd6, 0xdc, 0x5e, 0x2a, 0xb4, 0x76, 0xd7, 0x68, - 0xf0, 0x26, 0xcb, 0x57, 0x20, 0xee, 0x03, 0xaa, 0xa2, 0x36, 0xee, 0x03, 0xb3, 0xd0, 0xda, 0xb8, - 0x0f, 0xac, 0x62, 0xeb, 0xe2, 0x7d, 0x90, 0x05, 0x38, 0x46, 0x08, 0x2b, 0x85, 0x02, 0x05, 0x2d, - 0x2c, 0xd5, 0x15, 0x5d, 0xdd, 0x4b, 0xaf, 0xae, 0x6b, 0xb0, 0xd5, 0x8c, 0x52, 0x2f, 0x3b, 0xaa, - 0x00, 0xef, 0xd7, 0xa1, 0x65, 0x16, 0xe5, 0xeb, 0x1b, 0xa2, 0xe2, 0x29, 0x81, 0xbe, 0x21, 0xaa, - 0xaa, 0xf8, 0xd5, 0xe1, 0xb2, 0x96, 0x39, 0x0d, 0xfb, 0x1a, 0xac, 0x18, 0x15, 0x39, 0x07, 0xd3, - 0xb0, 0xaf, 0x99, 0xa7, 0x5c, 0xaf, 0xd9, 0xad, 0xb2, 0x06, 0xdd, 0x2d, 0x1a, 0x78, 0xcd, 0xb5, - 0x06, 0x46, 0xc6, 0xb9, 0x0b, 0x4d, 0xb3, 0xda, 0xe7, 0x15, 0xe3, 0x6e, 0x19, 0x5d, 0x66, 0xe9, - 0xe2, 0x0d, 0x87, 0xfd, 0x89, 0x03, 0x2d, 0xab, 0x76, 0xc6, 0x8a, 0x2a, 0x17, 0xc6, 0xe9, 0x98, - 0x7d, 0xe6, 0x40, 0xae, 0x47, 0x44, 0x3e, 0xda, 0xfe, 0xa2, 0xb5, 0xc9, 0x1f, 0x59, 0x5e, 0xc5, - 0xf5, 0xe2, 0x7b, 0xcb, 0x97, 0x45, 0x04, 0xb3, 0xa6, 0xf5, 0xe5, 0x0d, 0x87, 0xdd, 0x14, 0x6f, - 0x84, 0x55, 0x14, 0x81, 0x19, 0xca, 0xad, 0xb8, 0x65, 0xe6, 0x73, 0xda, 0x6b, 0xce, 0x0d, 0x87, - 0x7d, 0x43, 0x3c, 0xab, 0x94, 0xdf, 0xd2, 0xce, 0x9f, 0xf5, 0x7b, 0xf7, 0x0a, 0xad, 0xe6, 0x92, - 0x7b, 0xc1, 0x5a, 0x4d, 0x51, 0xbb, 0xdf, 0x16, 0xd4, 0xc9, 0xd7, 0xb2, 0xb9, 0x9a, 0x2a, 0xbd, - 0xa0, 0x9d, 0x4d, 0xe4, 0x58, 0x10, 0x29, 0xd1, 0x2d, 0xf6, 0x38, 0xe3, 0x30, 0xee, 0x36, 0xd1, - 0x7a, 0xc5, 0x7d, 0x6b, 0x26, 0xad, 0x3b, 0xe4, 0x25, 0x22, 0xc5, 0xfb, 0x00, 0x79, 0x10, 0x8b, - 0x15, 0x22, 0x3a, 0x5a, 0x53, 0x97, 0xe3, 0x5c, 0x36, 0x0f, 0xaa, 0xc0, 0x0f, 0x8e, 0xf8, 0x75, - 0x21, 0x3e, 0x12, 0x3f, 0xd5, 0xd4, 0x97, 0x83, 0x51, 0xdd, 0x6e, 0x55, 0x57, 0x95, 0xf0, 0xa8, - 0xf1, 0xd9, 0x53, 0x58, 0x7e, 0x14, 0x45, 0xcf, 0x27, 0xb1, 0x0e, 0xb3, 0xda, 0x31, 0x95, 0x3d, - 0x3f, 0x3d, 0xee, 0x16, 0x56, 0xe1, 0x5e, 0xa6, 0xa1, 0xba, 0xac, 0x63, 0x0c, 0xb5, 0xf3, 0x51, - 0x1e, 0x42, 0x7b, 0xc9, 0x7c, 0x58, 0xd3, 0xb7, 0xb2, 0x26, 0xbc, 0x6b, 0x0f, 0x63, 0x46, 0xb2, - 0x4a, 0x53, 0x58, 0x76, 0x92, 0xa2, 0x76, 0x27, 0x55, 0x63, 0xde, 0x70, 0xd8, 0x3e, 0xb4, 0xee, - 0xf1, 0x7e, 0x34, 0xe0, 0x32, 0x0a, 0xb2, 0x9e, 0x13, 0xae, 0xc3, 0x27, 0xdd, 0x65, 0x0b, 0x68, - 0xeb, 0xa9, 0xd8, 0x9f, 0x26, 0xfc, 0x5b, 0x3b, 0x1f, 0xc9, 0xf8, 0xca, 0x4b, 0xa5, 0xa7, 0x54, - 0x4c, 0xc8, 0xd2, 0x53, 0x85, 0x20, 0x92, 0xa5, 0xa7, 0x4a, 0x41, 0x24, 0x6b, 0xab, 0x55, 0x4c, - 0x8a, 0x8d, 0x60, 0xad, 0x14, 0x77, 0xd2, 0x77, 0xfb, 0xac, 0x68, 0x55, 0xf7, 0xf2, 0x6c, 0x04, - 0x7b, 0xb6, 0x6d, 0x7b, 0xb6, 0x03, 0x58, 0xbe, 0xc7, 0xc5, 0x66, 0x89, 0x5c, 0x6e, 0xd7, 0x56, - 0x7c, 0x66, 0xde, 0xb7, 0xa8, 0x14, 0xa9, 0xcf, 0xbe, 0x88, 0x28, 0x91, 0xca, 0xbe, 0x0e, 0xcd, - 0x87, 0x3c, 0x53, 0xc9, 0x5b, 0x6d, 0x21, 0x15, 0xb2, 0xb9, 0xdd, 0x8a, 0xdc, 0xaf, 0xcd, 0x33, - 0x34, 0xda, 0x0e, 0x1f, 0x0c, 0xb9, 0x50, 0x4f, 0xbd, 0x60, 0xf0, 0x92, 0xfd, 0x0a, 0x0d, 0xae, - 0xeb, 0x3d, 0x36, 0x8d, 0x9c, 0x9f, 0x39, 0xf8, 0x4a, 0x01, 0x5e, 0x35, 0x72, 0x18, 0x0d, 0xb8, - 0x71, 0x25, 0x87, 0xd0, 0x34, 0x8a, 0x91, 0xb4, 0x00, 0x95, 0x4b, 0xa5, 0xb4, 0x00, 0x55, 0xd4, - 0x2e, 0xb9, 0xd7, 0x68, 0x1e, 0x97, 0x5d, 0xce, 0xe7, 0x11, 0xf5, 0x4a, 0xf9, 0x4c, 0x3b, 0x1f, - 0xf9, 0xe3, 0xec, 0x25, 0x7b, 0x46, 0x0f, 0xa1, 0xcc, 0x04, 0x75, 0x6e, 0xa1, 0x15, 0x73, 0xd9, - 0x7a, 0xb3, 0x8c, 0x2e, 0xdb, 0x6a, 0x13, 0x53, 0xd1, 0xcd, 0xfd, 0x59, 0x80, 0x83, 0x2c, 0x8a, - 0xef, 0xf9, 0x7c, 0x1c, 0x85, 0xb9, 0xae, 0xcd, 0x93, 0xb0, 0xb9, 0xfe, 0x32, 0x32, 0xb1, 0xec, - 0x99, 0x61, 0x23, 0x5b, 0xf9, 0x7d, 0xc5, 0x5c, 0x33, 0xf3, 0xb4, 0x7a, 0x43, 0x2a, 0x72, 0xb5, - 0x37, 0x1c, 0xb4, 0x78, 0xf3, 0x28, 0xa7, 0xb6, 0x78, 0x4b, 0x01, 0x54, 0xad, 0xf6, 0x2a, 0x42, - 0xa2, 0xfb, 0xd0, 0xc8, 0xc3, 0x66, 0xea, 0x12, 0x2d, 0x06, 0xd9, 0xf4, 0xad, 0x58, 0x0a, 0x66, - 0xb9, 0xab, 0xb4, 0x55, 0xc0, 0x96, 0x70, 0xab, 0x28, 0x42, 0x15, 0xc0, 0xba, 0x20, 0x50, 0x5f, - 0xf1, 0x94, 0x56, 0x54, 0x2b, 0xa9, 0x08, 0x28, 0x69, 0x69, 0xae, 0x8c, 0xc7, 0x58, 0xbe, 0x2f, - 0x72, 0xab, 0x48, 0x69, 0xa2, 0x6a, 0x1e, 0xc3, 0x5a, 0x29, 0x98, 0xa0, 0x45, 0x7a, 0x56, 0x0c, - 0x47, 0x8b, 0xf4, 0xcc, 0x38, 0x84, 0x7b, 0x9e, 0xa6, 0x5c, 0x71, 0x01, 0xa7, 0x4c, 0x4f, 0x83, - 0xac, 0x7f, 0x7c, 0xd3, 0xd9, 0x3e, 0x5c, 0xa0, 0xbf, 0x02, 0xfa, 0xf4, 0xff, 0x06, 0x00, 0x00, - 0xff, 0xff, 0x15, 0xdc, 0x6d, 0x7b, 0x3c, 0x48, 0x00, 0x00, + // 5813 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3c, 0x4b, 0x8c, 0x24, 0xc9, + 0x55, 0x93, 0xd5, 0xd5, 0x9f, 0x7a, 0x55, 0x5d, 0xdd, 0x1d, 0xdd, 0xd3, 0x53, 0x53, 0x3b, 0x3b, + 0x3b, 0x9b, 0x1e, 0x79, 0xc6, 0xcd, 0x32, 0x3d, 0xdb, 0xb6, 0x97, 0xf5, 0x2e, 0xd8, 0xcc, 0x6f, + 0xa7, 0xd7, 0x9e, 0x1d, 0xb7, 0xb3, 0x67, 0x3d, 0x60, 0x83, 0xca, 0xd9, 0x55, 0xd1, 0xd5, 0xe9, + 0xc9, 0xca, 0x4c, 0x67, 0x66, 0x75, 0x4f, 0x79, 0x19, 0x89, 0x9f, 0x38, 0x61, 0x21, 0x84, 0x0f, + 0x18, 0x09, 0x21, 0x19, 0x21, 0xc1, 0x81, 0x23, 0x27, 0xc3, 0x8d, 0x13, 0x12, 0xe2, 0xb0, 0x27, + 0x8b, 0x23, 0x70, 0x00, 0x8b, 0x0b, 0x12, 0x57, 0x84, 0xde, 0x8b, 0x4f, 0x46, 0x64, 0x66, 0xcd, + 0x8c, 0x3f, 0x70, 0xab, 0x78, 0xf1, 0x32, 0xe2, 0x45, 0xc4, 0x7b, 0x2f, 0xde, 0x2f, 0x0a, 0x5a, + 0x69, 0x32, 0xbc, 0x91, 0xa4, 0x71, 0x1e, 0xb3, 0xc5, 0x30, 0x4a, 0x93, 0x61, 0xff, 0xd2, 0x38, + 0x8e, 0xc7, 0x21, 0xdf, 0xf5, 0x93, 0x60, 0xd7, 0x8f, 0xa2, 0x38, 0xf7, 0xf3, 0x20, 0x8e, 0x32, + 0x81, 0xe4, 0x7e, 0x03, 0xba, 0xf7, 0x79, 0x74, 0xc8, 0xf9, 0xc8, 0xe3, 0xdf, 0x9a, 0xf2, 0x2c, + 0x67, 0x3f, 0x07, 0x1b, 0x3e, 0xff, 0x36, 0xe7, 0xa3, 0x41, 0xe2, 0x67, 0x59, 0x72, 0x92, 0xfa, + 0x19, 0xef, 0x39, 0x57, 0x9c, 0xeb, 0x1d, 0x6f, 0x5d, 0x74, 0x1c, 0x68, 0x38, 0x7b, 0x1d, 0x3a, + 0x19, 0xa2, 0xf2, 0x28, 0x4f, 0xe3, 0x64, 0xd6, 0x6b, 0x10, 0x5e, 0x1b, 0x61, 0xf7, 0x04, 0xc8, + 0x0d, 0x61, 0x4d, 0xcf, 0x90, 0x25, 0x71, 0x94, 0x71, 0x76, 0x13, 0xb6, 0x86, 0x41, 0x72, 0xc2, + 0xd3, 0x01, 0x7d, 0x3c, 0x89, 0xf8, 0x24, 0x8e, 0x82, 0x61, 0xcf, 0xb9, 0xb2, 0x70, 0xbd, 0xe5, + 0x31, 0xd1, 0x87, 0x5f, 0x7c, 0x20, 0x7b, 0xd8, 0x35, 0x58, 0xe3, 0x91, 0x80, 0xf3, 0x11, 0x7d, + 0x25, 0xa7, 0xea, 0x16, 0x60, 0xfc, 0xc0, 0xfd, 0x7b, 0x07, 0x36, 0xde, 0x8f, 0x82, 0xfc, 0xb1, + 0x1f, 0x86, 0x3c, 0x57, 0x6b, 0xba, 0x06, 0x6b, 0x67, 0x04, 0xa0, 0x35, 0x9d, 0xc5, 0xe9, 0x48, + 0xae, 0xa8, 0x2b, 0xc0, 0x07, 0x12, 0x3a, 0x97, 0xb2, 0xc6, 0x5c, 0xca, 0x6a, 0xb7, 0x6b, 0x61, + 0xce, 0x76, 0x5d, 0x83, 0xb5, 0x94, 0x0f, 0xe3, 0x53, 0x9e, 0xce, 0x06, 0x67, 0x41, 0x34, 0x8a, + 0xcf, 0x7a, 0xcd, 0x2b, 0xce, 0xf5, 0x45, 0xaf, 0xab, 0xc0, 0x8f, 0x09, 0xea, 0x6e, 0x01, 0x33, + 0x57, 0x21, 0xf6, 0xcd, 0x1d, 0xc3, 0xe6, 0x87, 0x51, 0x18, 0x0f, 0x9f, 0xfc, 0x84, 0xab, 0xab, + 0x99, 0xbe, 0x51, 0x3b, 0xfd, 0x36, 0x6c, 0xd9, 0x13, 0x49, 0x02, 0x38, 0x9c, 0xbf, 0x73, 0xe2, + 0x47, 0x63, 0xae, 0x86, 0x54, 0x24, 0x7c, 0x0a, 0xd6, 0x87, 0xd3, 0x34, 0xe5, 0x51, 0x85, 0x86, + 0x35, 0x09, 0xd7, 0x44, 0xbc, 0x0e, 0x9d, 0x88, 0x9f, 0x15, 0x68, 0x92, 0x65, 0x22, 0x7e, 0xa6, + 0x50, 0xdc, 0x1e, 0x6c, 0x97, 0xa7, 0x91, 0x04, 0x7c, 0xaf, 0x01, 0xed, 0x47, 0xa9, 0x1f, 0x65, + 0xfe, 0x10, 0xb9, 0x98, 0xf5, 0x60, 0x39, 0x7f, 0x3a, 0x38, 0xf1, 0xb3, 0x13, 0x9a, 0xae, 0xe5, + 0xa9, 0x26, 0xdb, 0x86, 0x25, 0x7f, 0x12, 0x4f, 0xa3, 0x9c, 0x26, 0x58, 0xf0, 0x64, 0x8b, 0xbd, + 0x01, 0x1b, 0xd1, 0x74, 0x32, 0x18, 0xc6, 0xd1, 0x71, 0x90, 0x4e, 0x84, 0x2c, 0xd0, 0x79, 0x2d, + 0x7a, 0xd5, 0x0e, 0x76, 0x19, 0xe0, 0x08, 0xf7, 0x41, 0x4c, 0xd1, 0xa4, 0x29, 0x0c, 0x08, 0x73, + 0xa1, 0x23, 0x5b, 0x3c, 0x18, 0x9f, 0xe4, 0xbd, 0x45, 0x1a, 0xc8, 0x82, 0xe1, 0x18, 0x79, 0x30, + 0xe1, 0x83, 0x2c, 0xf7, 0x27, 0x49, 0x6f, 0x89, 0xa8, 0x31, 0x20, 0xd4, 0x1f, 0xe7, 0x7e, 0x38, + 0x38, 0xe6, 0x3c, 0xeb, 0x2d, 0xcb, 0x7e, 0x0d, 0x61, 0x9f, 0x84, 0xee, 0x88, 0x67, 0xf9, 0xc0, + 0x1f, 0x8d, 0x52, 0x9e, 0x65, 0x3c, 0xeb, 0xad, 0x10, 0x37, 0x96, 0xa0, 0xb8, 0x6b, 0xf7, 0x79, + 0x6e, 0xec, 0x4e, 0x26, 0x4f, 0xc7, 0x7d, 0x00, 0xcc, 0x00, 0xdf, 0xe5, 0xb9, 0x1f, 0x84, 0x19, + 0x7b, 0x0b, 0x3a, 0xb9, 0x81, 0x4c, 0xd2, 0xd7, 0xde, 0x63, 0x37, 0x48, 0x6d, 0xdc, 0x30, 0x3e, + 0xf0, 0x2c, 0x3c, 0xf7, 0x8f, 0x1b, 0xd0, 0x3e, 0xe4, 0x91, 0x3e, 0x7b, 0x06, 0x4d, 0xa4, 0x44, + 0x9e, 0x37, 0xfd, 0x66, 0xaf, 0x41, 0x9b, 0xa8, 0xcb, 0xf2, 0x34, 0x88, 0xc6, 0x74, 0x04, 0x2d, + 0x0f, 0x10, 0x74, 0x48, 0x10, 0xb6, 0x0e, 0x0b, 0xfe, 0x24, 0xa7, 0x8d, 0x5f, 0xf0, 0xf0, 0x27, + 0xf2, 0x45, 0xe2, 0xcf, 0x26, 0xc8, 0x42, 0x7a, 0xb3, 0x3b, 0x5e, 0x5b, 0xc2, 0xf6, 0x71, 0xb7, + 0x6f, 0xc0, 0xa6, 0x89, 0xa2, 0x46, 0x5f, 0xa4, 0xd1, 0x37, 0x0c, 0x4c, 0x39, 0xc9, 0x35, 0x58, + 0x53, 0xf8, 0xa9, 0x20, 0x96, 0xb6, 0xbf, 0xe5, 0x75, 0x25, 0x58, 0x2d, 0xe1, 0x3a, 0xac, 0x1f, + 0x07, 0x91, 0x1f, 0x0e, 0x86, 0x61, 0x7e, 0x3a, 0x18, 0xf1, 0x30, 0xf7, 0xe9, 0x20, 0x16, 0xbd, + 0x2e, 0xc1, 0xef, 0x84, 0xf9, 0xe9, 0x5d, 0x84, 0xb2, 0x4b, 0xd0, 0x3a, 0xe6, 0x7c, 0x10, 0x06, + 0x93, 0x20, 0xef, 0xad, 0x10, 0xf5, 0x05, 0xc0, 0xfd, 0xae, 0x03, 0x1d, 0xb1, 0x35, 0x52, 0xd3, + 0x5d, 0x85, 0x55, 0x45, 0x01, 0x4f, 0xd3, 0x38, 0x95, 0x5c, 0x6a, 0x03, 0xd9, 0x0e, 0xac, 0x2b, + 0x40, 0x92, 0xf2, 0x60, 0xe2, 0x8f, 0xb9, 0x14, 0x8b, 0x0a, 0x9c, 0xed, 0x15, 0x23, 0xa6, 0xf1, + 0x34, 0x17, 0xba, 0xa6, 0xbd, 0xd7, 0x91, 0xc7, 0xe6, 0x21, 0xcc, 0xb3, 0x51, 0xdc, 0xef, 0x38, + 0xc0, 0x90, 0xac, 0x47, 0xb1, 0xe8, 0x96, 0xab, 0x2e, 0xef, 0xb8, 0xf3, 0xd2, 0x3b, 0xde, 0x98, + 0xb7, 0xe3, 0x57, 0x61, 0x89, 0xa6, 0x44, 0x91, 0x5a, 0xa8, 0x90, 0x25, 0xfb, 0xdc, 0xef, 0x3b, + 0xd0, 0x41, 0x01, 0x8f, 0x78, 0x78, 0x10, 0x07, 0x51, 0xce, 0x6e, 0x02, 0x3b, 0x9e, 0x46, 0xa3, + 0x20, 0x1a, 0x0f, 0xf2, 0xa7, 0xc1, 0x68, 0x70, 0x34, 0xc3, 0x21, 0x88, 0x9e, 0xfd, 0x73, 0x5e, + 0x4d, 0x1f, 0x7b, 0x03, 0xd6, 0x2d, 0x68, 0x96, 0xa7, 0x82, 0xaa, 0xfd, 0x73, 0x5e, 0xa5, 0x07, + 0xc5, 0x34, 0x9e, 0xe6, 0xc9, 0x34, 0x1f, 0x04, 0xd1, 0x88, 0x3f, 0xa5, 0x3d, 0x5b, 0xf5, 0x2c, + 0xd8, 0xed, 0x2e, 0x74, 0xcc, 0xef, 0xdc, 0xcf, 0xc3, 0xfa, 0x03, 0x94, 0xdf, 0x28, 0x88, 0xc6, + 0xb7, 0x84, 0x90, 0xa1, 0x52, 0x49, 0xa6, 0x47, 0x4f, 0xf8, 0x4c, 0x9e, 0xa3, 0x6c, 0xa1, 0x08, + 0x9c, 0xc4, 0x59, 0x2e, 0xf7, 0x85, 0x7e, 0xbb, 0xff, 0xe2, 0xc0, 0x1a, 0x6e, 0xfa, 0x07, 0x7e, + 0x34, 0x53, 0x3b, 0xfe, 0x00, 0x3a, 0x38, 0xd4, 0xa3, 0xf8, 0x96, 0x50, 0x4d, 0x42, 0xe4, 0xae, + 0xcb, 0x4d, 0x2a, 0x61, 0xdf, 0x30, 0x51, 0xf1, 0x36, 0x9d, 0x79, 0xd6, 0xd7, 0x28, 0x64, 0xb9, + 0x9f, 0x8e, 0x79, 0x4e, 0x4a, 0x4b, 0x2a, 0x31, 0x10, 0xa0, 0x3b, 0x71, 0x74, 0xcc, 0xae, 0x40, + 0x27, 0xf3, 0xf3, 0x41, 0xc2, 0x53, 0xda, 0x35, 0x12, 0x94, 0x05, 0x0f, 0x32, 0x3f, 0x3f, 0xe0, + 0xe9, 0xed, 0x59, 0xce, 0xfb, 0x5f, 0x80, 0x8d, 0xca, 0x2c, 0x28, 0x9b, 0xc5, 0x12, 0xf1, 0x27, + 0xdb, 0x82, 0xc5, 0x53, 0x3f, 0x9c, 0x72, 0xa9, 0x4b, 0x45, 0xe3, 0x9d, 0xc6, 0xdb, 0x8e, 0xfb, + 0x49, 0x58, 0x2f, 0xc8, 0x96, 0x4c, 0xcf, 0xa0, 0x89, 0x3b, 0x28, 0x07, 0xa0, 0xdf, 0xee, 0x6f, + 0x39, 0x02, 0xf1, 0x4e, 0x1c, 0x68, 0xbd, 0x84, 0x88, 0xa8, 0xbe, 0x14, 0x22, 0xfe, 0x9e, 0xab, + 0xb7, 0x7f, 0xfa, 0xc5, 0xba, 0xd7, 0x60, 0xc3, 0x20, 0xe1, 0x39, 0xc4, 0x7e, 0xc7, 0x81, 0x8d, + 0x87, 0xfc, 0x4c, 0x9e, 0xba, 0xa2, 0xf6, 0x6d, 0x68, 0xe6, 0xb3, 0x44, 0xd8, 0x42, 0xdd, 0xbd, + 0xab, 0xf2, 0xd0, 0x2a, 0x78, 0x37, 0x64, 0xf3, 0xd1, 0x2c, 0xe1, 0x1e, 0x7d, 0xe1, 0x7e, 0x1e, + 0xda, 0x06, 0x90, 0x5d, 0x80, 0xcd, 0xc7, 0xef, 0x3f, 0x7a, 0x78, 0xef, 0xf0, 0x70, 0x70, 0xf0, + 0xe1, 0xed, 0x2f, 0xdd, 0xfb, 0xd5, 0xc1, 0xfe, 0xad, 0xc3, 0xfd, 0xf5, 0x73, 0x6c, 0x1b, 0xd8, + 0xc3, 0x7b, 0x87, 0x8f, 0xee, 0xdd, 0xb5, 0xe0, 0x8e, 0xdb, 0x87, 0xde, 0x43, 0x7e, 0xf6, 0x38, + 0xc8, 0x23, 0x9e, 0x65, 0xf6, 0x6c, 0xee, 0x0d, 0x60, 0x26, 0x09, 0x72, 0x55, 0x3d, 0x58, 0x96, + 0x17, 0x83, 0xba, 0x17, 0x65, 0xd3, 0xfd, 0x24, 0xb0, 0xc3, 0x60, 0x1c, 0x7d, 0xc0, 0xb3, 0xcc, + 0x1f, 0x6b, 0x55, 0xb0, 0x0e, 0x0b, 0x93, 0x6c, 0x2c, 0x35, 0x00, 0xfe, 0x74, 0x3f, 0x0d, 0x9b, + 0x16, 0x9e, 0x1c, 0xf8, 0x12, 0xb4, 0xb2, 0x60, 0x1c, 0xf9, 0xf9, 0x34, 0xe5, 0x72, 0xe8, 0x02, + 0xe0, 0xbe, 0x07, 0x5b, 0x5f, 0xe5, 0x69, 0x70, 0x3c, 0x7b, 0xd1, 0xf0, 0xf6, 0x38, 0x8d, 0xf2, + 0x38, 0xf7, 0xe0, 0x7c, 0x69, 0x1c, 0x39, 0xbd, 0x60, 0x44, 0x79, 0x5c, 0x2b, 0x9e, 0x68, 0x18, + 0x62, 0xd9, 0x30, 0xc5, 0xd2, 0xfd, 0x10, 0xd8, 0x9d, 0x38, 0x8a, 0xf8, 0x30, 0x3f, 0xe0, 0x3c, + 0x2d, 0x0c, 0xdc, 0x82, 0xeb, 0xda, 0x7b, 0x17, 0xe4, 0x39, 0x96, 0x65, 0x5d, 0xb2, 0x23, 0x83, + 0x66, 0xc2, 0xd3, 0x09, 0x0d, 0xbc, 0xe2, 0xd1, 0x6f, 0xf7, 0x3c, 0x6c, 0x5a, 0xc3, 0x4a, 0xdb, + 0xe4, 0x4d, 0x38, 0x7f, 0x37, 0xc8, 0x86, 0xd5, 0x09, 0x7b, 0xb0, 0x9c, 0x4c, 0x8f, 0x06, 0x85, + 0x4c, 0xa9, 0x26, 0x5e, 0xd9, 0xe5, 0x4f, 0xe4, 0x60, 0xbf, 0xe7, 0x40, 0x73, 0xff, 0xd1, 0x83, + 0x3b, 0xac, 0x0f, 0x2b, 0x41, 0x34, 0x8c, 0x27, 0xa8, 0x76, 0xc5, 0xa2, 0x75, 0x7b, 0xae, 0xac, + 0x5c, 0x82, 0x16, 0x69, 0x6b, 0xb4, 0x42, 0xa4, 0x2d, 0x5a, 0x00, 0xd0, 0x02, 0xe2, 0x4f, 0x93, + 0x20, 0x25, 0x13, 0x47, 0x19, 0x2e, 0x4d, 0xd2, 0x88, 0xd5, 0x0e, 0xf7, 0x7f, 0x9a, 0xb0, 0x2c, + 0x75, 0x35, 0xcd, 0x37, 0xcc, 0x83, 0x53, 0x2e, 0x29, 0x91, 0x2d, 0xbc, 0xe5, 0x52, 0x3e, 0x89, + 0x73, 0x3e, 0xb0, 0x8e, 0xc1, 0x06, 0x22, 0xd6, 0x50, 0x0c, 0x34, 0x48, 0x50, 0xeb, 0x13, 0x65, + 0x2d, 0xcf, 0x06, 0xe2, 0x66, 0x21, 0x60, 0x10, 0x8c, 0x88, 0xa6, 0xa6, 0xa7, 0x9a, 0xb8, 0x13, + 0x43, 0x3f, 0xf1, 0x87, 0x41, 0x3e, 0x93, 0xc2, 0xad, 0xdb, 0x38, 0x76, 0x18, 0x0f, 0xfd, 0x70, + 0x70, 0xe4, 0x87, 0x7e, 0x34, 0xe4, 0xd2, 0xcc, 0xb2, 0x81, 0x68, 0x49, 0x49, 0x92, 0x14, 0x9a, + 0xb0, 0xb6, 0x4a, 0x50, 0xb4, 0xc8, 0x86, 0xf1, 0x64, 0x12, 0xe4, 0x68, 0x80, 0xc9, 0x5b, 0xde, + 0x80, 0xd0, 0x4a, 0x44, 0xeb, 0x4c, 0xec, 0x5e, 0x4b, 0xcc, 0x66, 0x01, 0x71, 0x14, 0xb4, 0x0c, + 0x50, 0x21, 0x3d, 0x39, 0xeb, 0x81, 0x18, 0xa5, 0x80, 0xe0, 0x39, 0x4c, 0xa3, 0x8c, 0xe7, 0x79, + 0xc8, 0x47, 0x9a, 0xa0, 0x36, 0xa1, 0x55, 0x3b, 0xd8, 0x4d, 0xd8, 0x14, 0x36, 0x61, 0xe6, 0xe7, + 0x71, 0x76, 0x12, 0x64, 0x83, 0x8c, 0x47, 0x79, 0xaf, 0x43, 0xf8, 0x75, 0x5d, 0xec, 0x6d, 0xb8, + 0x50, 0x02, 0xa7, 0x7c, 0xc8, 0x83, 0x53, 0x3e, 0xea, 0xad, 0xd2, 0x57, 0xf3, 0xba, 0xd9, 0x15, + 0x68, 0xa3, 0x29, 0x3c, 0x4d, 0x46, 0x3e, 0xde, 0xc3, 0x5d, 0x3a, 0x07, 0x13, 0xc4, 0xde, 0x84, + 0xd5, 0x84, 0x8b, 0xcb, 0xf2, 0x24, 0x0f, 0x87, 0x59, 0x6f, 0x8d, 0x6e, 0xb2, 0xb6, 0x14, 0x26, + 0xe4, 0x5c, 0xcf, 0xc6, 0x40, 0xa6, 0x1c, 0x66, 0x64, 0x5c, 0xf9, 0xb3, 0xde, 0x3a, 0xb1, 0x5b, + 0x01, 0x20, 0x19, 0x49, 0x83, 0x53, 0x3f, 0xe7, 0xbd, 0x0d, 0xe2, 0x2d, 0xd5, 0x74, 0xff, 0xcc, + 0x81, 0xcd, 0x07, 0x41, 0x96, 0x4b, 0x26, 0xd4, 0xea, 0xf8, 0x35, 0x68, 0x0b, 0xf6, 0x1b, 0xc4, + 0x51, 0x38, 0x93, 0x1c, 0x09, 0x02, 0xf4, 0xe5, 0x28, 0x9c, 0xb1, 0x4f, 0xc0, 0x6a, 0x10, 0x99, + 0x28, 0x42, 0x86, 0x3b, 0x0a, 0x48, 0x48, 0xaf, 0x41, 0x3b, 0x99, 0x1e, 0x85, 0xc1, 0x50, 0xa0, + 0x2c, 0x88, 0x51, 0x04, 0x88, 0x10, 0xd0, 0x48, 0x12, 0x94, 0x08, 0x8c, 0x26, 0x61, 0xb4, 0x25, + 0x0c, 0x51, 0xdc, 0xdb, 0xb0, 0x65, 0x13, 0x28, 0x95, 0xd5, 0x0e, 0xac, 0x48, 0xde, 0xce, 0x7a, + 0x6d, 0xda, 0x9f, 0xae, 0xdc, 0x1f, 0x89, 0xea, 0xe9, 0x7e, 0xf7, 0x3f, 0x1c, 0x68, 0xa2, 0x02, + 0x98, 0xaf, 0x2c, 0x4c, 0x9d, 0xbe, 0x60, 0xe9, 0x74, 0xf2, 0x52, 0xd0, 0x2a, 0x12, 0x2c, 0x21, + 0xc4, 0xc6, 0x80, 0x14, 0xfd, 0x29, 0x1f, 0x9e, 0x92, 0xec, 0xe8, 0x7e, 0x84, 0xa0, 0x64, 0xe1, + 0xd5, 0x49, 0x5f, 0x0b, 0xc1, 0xd1, 0x6d, 0xd5, 0x47, 0x5f, 0x2e, 0x17, 0x7d, 0xf4, 0x5d, 0x0f, + 0x96, 0x83, 0xe8, 0x28, 0x9e, 0x46, 0x23, 0x12, 0x92, 0x15, 0x4f, 0x35, 0xf1, 0xb0, 0x13, 0xb2, + 0xa4, 0x82, 0x09, 0x97, 0xd2, 0x51, 0x00, 0x5c, 0x86, 0xa6, 0x55, 0x46, 0x0a, 0x4f, 0xdf, 0x63, + 0x6f, 0xc1, 0x86, 0x01, 0x93, 0x3b, 0xf8, 0x3a, 0x2c, 0x26, 0x08, 0x90, 0x86, 0x92, 0x62, 0x2f, + 0xd2, 0x94, 0xa2, 0xc7, 0x5d, 0x87, 0xee, 0x7d, 0x9e, 0xbf, 0x1f, 0x1d, 0xc7, 0x6a, 0xa4, 0x1f, + 0x2e, 0xc0, 0x9a, 0x06, 0xc9, 0x81, 0xae, 0xc3, 0x5a, 0x30, 0xe2, 0x51, 0x1e, 0xe4, 0xb3, 0x81, + 0x65, 0xc1, 0x95, 0xc1, 0x78, 0xc3, 0xf8, 0x61, 0xe0, 0x67, 0x52, 0x87, 0x89, 0x06, 0xdb, 0x83, + 0x2d, 0x64, 0x7f, 0xc5, 0xd1, 0xfa, 0x58, 0x85, 0x21, 0x59, 0xdb, 0x87, 0x12, 0x8b, 0x70, 0xc9, + 0x81, 0xfa, 0x13, 0xa1, 0x69, 0xeb, 0xba, 0x70, 0xd7, 0xc4, 0x48, 0xb8, 0xe4, 0x45, 0x21, 0x22, + 0x1a, 0x50, 0xf1, 0x35, 0x97, 0x84, 0x11, 0x5b, 0xf6, 0x35, 0x0d, 0x7f, 0x75, 0xa5, 0xe2, 0xaf, + 0x5e, 0x87, 0xb5, 0x6c, 0x16, 0x0d, 0xf9, 0x68, 0x90, 0xc7, 0x38, 0x6f, 0x10, 0xd1, 0xe9, 0xac, + 0x78, 0x65, 0x30, 0x79, 0xd6, 0x3c, 0xcb, 0x23, 0x9e, 0x93, 0xea, 0x5a, 0xf1, 0x54, 0x13, 0x6f, + 0x01, 0x42, 0x11, 0x4c, 0xdd, 0xf2, 0x64, 0x0b, 0xaf, 0xca, 0x69, 0x1a, 0x64, 0xbd, 0x0e, 0x41, + 0xe9, 0x37, 0xfb, 0x0c, 0x9c, 0x3f, 0x42, 0x3f, 0xf0, 0x84, 0xfb, 0x23, 0x9e, 0xd2, 0xe9, 0x0b, + 0x37, 0x58, 0x68, 0xa0, 0xfa, 0x4e, 0x9c, 0xfb, 0x94, 0xa7, 0x59, 0x10, 0x47, 0xa4, 0x7b, 0x5a, + 0x9e, 0x6a, 0xba, 0xdf, 0xa6, 0x1b, 0x5d, 0x3b, 0xe8, 0x1f, 0x92, 0x3a, 0x62, 0xaf, 0x40, 0x4b, + 0xac, 0x31, 0x3b, 0xf1, 0xa5, 0x91, 0xb1, 0x42, 0x80, 0xc3, 0x13, 0x1f, 0x05, 0xd8, 0xda, 0x36, + 0x11, 0xf1, 0x68, 0x13, 0x6c, 0x5f, 0xec, 0xda, 0x55, 0xe8, 0x2a, 0xd7, 0x3f, 0x1b, 0x84, 0xfc, + 0x38, 0x57, 0x0e, 0x42, 0x34, 0x9d, 0xe0, 0x74, 0xd9, 0x03, 0x7e, 0x9c, 0xbb, 0x0f, 0x61, 0x43, + 0xca, 0xed, 0x97, 0x13, 0xae, 0xa6, 0xfe, 0x5c, 0xf9, 0x52, 0x13, 0x56, 0xc5, 0xa6, 0x2d, 0xe8, + 0xe4, 0xe5, 0x94, 0x6e, 0x3a, 0xd7, 0x03, 0x26, 0xbb, 0xef, 0x84, 0x71, 0xc6, 0xe5, 0x80, 0x2e, + 0x74, 0x86, 0x61, 0x9c, 0x29, 0x37, 0x44, 0x2e, 0xc7, 0x82, 0xe1, 0xfe, 0x64, 0xd3, 0xe1, 0x10, + 0x35, 0x81, 0xd0, 0x69, 0xaa, 0xe9, 0xfe, 0xa5, 0x03, 0x9b, 0x34, 0x9a, 0xd2, 0x30, 0xda, 0x76, + 0x7d, 0x79, 0x32, 0x3b, 0x43, 0xd3, 0x35, 0xdb, 0x82, 0xc5, 0xe3, 0x38, 0x1d, 0x72, 0x39, 0x93, + 0x68, 0xfc, 0xf8, 0xd6, 0x78, 0xb3, 0x62, 0x8d, 0xff, 0xd0, 0x81, 0x0d, 0x22, 0xf5, 0x30, 0xf7, + 0xf3, 0x69, 0x26, 0x97, 0xff, 0x8b, 0xb0, 0x8a, 0x4b, 0xe5, 0x4a, 0x9c, 0x24, 0xa1, 0x5b, 0x5a, + 0xf2, 0x09, 0x2a, 0x90, 0xf7, 0xcf, 0x79, 0x36, 0x32, 0xfb, 0x02, 0x74, 0xcc, 0xf8, 0x0d, 0xd1, + 0xdc, 0xde, 0xbb, 0xa8, 0x56, 0x59, 0xe1, 0x9c, 0xfd, 0x73, 0x9e, 0xf5, 0x01, 0x7b, 0x17, 0x80, + 0xcc, 0x0d, 0x1a, 0x56, 0xba, 0xd6, 0x17, 0xed, 0x4d, 0x32, 0x0e, 0x6b, 0xff, 0x9c, 0x67, 0xa0, + 0xdf, 0x5e, 0x81, 0x25, 0x71, 0x3f, 0xba, 0xf7, 0x61, 0xd5, 0xa2, 0xd4, 0xf2, 0x32, 0x3a, 0xc2, + 0xcb, 0xa8, 0x38, 0xa5, 0x8d, 0xaa, 0x53, 0xea, 0xfe, 0x5b, 0x03, 0x18, 0x72, 0x5b, 0xe9, 0x38, + 0xf1, 0x82, 0x8e, 0x47, 0x96, 0xb9, 0xd5, 0xf1, 0x4c, 0x10, 0xbb, 0x01, 0xcc, 0x68, 0x2a, 0xbf, + 0x5d, 0xdc, 0x1b, 0x35, 0x3d, 0xa8, 0xe0, 0x84, 0xad, 0xa4, 0x7c, 0x60, 0x69, 0x58, 0x8a, 0x73, + 0xab, 0xed, 0xc3, 0xab, 0x21, 0x99, 0x66, 0x27, 0x68, 0x40, 0x28, 0x83, 0x4c, 0xb5, 0xcb, 0x0c, + 0xb2, 0xf4, 0x42, 0x06, 0x59, 0x2e, 0x33, 0x88, 0x69, 0x12, 0xac, 0x58, 0x26, 0x01, 0xda, 0x5f, + 0x93, 0x20, 0x22, 0xbb, 0x62, 0x30, 0xc1, 0xd9, 0xa5, 0xfd, 0x65, 0x01, 0xd9, 0x0e, 0xac, 0x4b, + 0xbb, 0xae, 0xb0, 0x3b, 0x80, 0xf6, 0xb8, 0x02, 0x77, 0x3f, 0x76, 0x60, 0x1d, 0xf7, 0xd9, 0xe2, + 0xc5, 0x77, 0x80, 0x44, 0xe1, 0x25, 0x59, 0xd1, 0xc2, 0xfd, 0xe9, 0x39, 0xf1, 0x6d, 0x68, 0xd1, + 0x80, 0x71, 0xc2, 0x23, 0xc9, 0x88, 0x3d, 0x9b, 0x11, 0x0b, 0x2d, 0xb4, 0x7f, 0xce, 0x2b, 0x90, + 0x0d, 0x36, 0xfc, 0x27, 0x07, 0xda, 0x92, 0xcc, 0x9f, 0xd8, 0x97, 0xe8, 0xc3, 0x0a, 0x72, 0xa4, + 0x61, 0xb0, 0xeb, 0x36, 0xde, 0x26, 0x13, 0x74, 0xd8, 0xf0, 0xfa, 0xb4, 0xfc, 0x88, 0x32, 0x18, + 0xef, 0x42, 0x52, 0xb8, 0xd9, 0x20, 0x0f, 0xc2, 0x81, 0xea, 0x95, 0xe1, 0xd2, 0xba, 0x2e, 0xd4, + 0x3b, 0x59, 0xee, 0x8f, 0xb9, 0xbc, 0xe6, 0x44, 0x03, 0x1d, 0x26, 0xb9, 0xa0, 0x92, 0x39, 0xe8, + 0xfe, 0x5d, 0x07, 0x2e, 0x54, 0xba, 0x74, 0xbe, 0x41, 0x1a, 0xc8, 0x61, 0x30, 0x39, 0x8a, 0xb5, + 0xad, 0xed, 0x98, 0xb6, 0xb3, 0xd5, 0xc5, 0xc6, 0x70, 0x5e, 0xdd, 0xe7, 0xb8, 0xa7, 0xc5, 0xed, + 0xdd, 0x20, 0x43, 0xe4, 0x4d, 0x9b, 0x07, 0xca, 0x13, 0x2a, 0xb8, 0x29, 0xb9, 0xf5, 0xe3, 0xb1, + 0x13, 0xe8, 0x69, 0xc3, 0x41, 0xaa, 0x78, 0xc3, 0xb8, 0xc0, 0xb9, 0xde, 0x78, 0xc1, 0x5c, 0xa4, + 0x8f, 0x46, 0x6a, 0x9a, 0xb9, 0xa3, 0xb1, 0x19, 0x5c, 0x56, 0x7d, 0xa4, 0xc3, 0xab, 0xf3, 0x35, + 0x5f, 0x6a, 0x6d, 0xef, 0xe1, 0xc7, 0xf6, 0xa4, 0x2f, 0x18, 0x98, 0x7d, 0x13, 0xb6, 0xcf, 0xfc, + 0x20, 0x57, 0x64, 0x19, 0xc6, 0xd0, 0x22, 0x4d, 0xb9, 0xf7, 0x82, 0x29, 0x1f, 0x8b, 0x8f, 0xad, + 0x8b, 0x6d, 0xce, 0x88, 0xfd, 0x7f, 0x70, 0xa0, 0x6b, 0x8f, 0x83, 0x6c, 0x2a, 0x05, 0x5e, 0x29, + 0x3e, 0x65, 0xfc, 0x95, 0xc0, 0x55, 0x17, 0xb5, 0x51, 0xe7, 0xa2, 0x9a, 0x8e, 0xe8, 0xc2, 0x8b, + 0x1c, 0xd1, 0xe6, 0xcb, 0x39, 0xa2, 0x8b, 0x75, 0x8e, 0x68, 0xff, 0xbf, 0x1d, 0x60, 0x55, 0x5e, + 0x62, 0xf7, 0x85, 0x8f, 0x1c, 0xf1, 0x50, 0xea, 0xa4, 0x9f, 0x7f, 0x39, 0x7e, 0x54, 0x7b, 0xa7, + 0xbe, 0x46, 0xc1, 0x30, 0x95, 0x8e, 0x69, 0x22, 0xad, 0x7a, 0x75, 0x5d, 0x25, 0xd7, 0xb8, 0xf9, + 0x62, 0xd7, 0x78, 0xf1, 0xc5, 0xae, 0xf1, 0x52, 0xd9, 0x35, 0xee, 0xff, 0xae, 0x03, 0x9b, 0x35, + 0x87, 0xfe, 0xb3, 0x5b, 0x38, 0x1e, 0x93, 0xa5, 0x0b, 0x1a, 0xf2, 0x98, 0x4c, 0x60, 0xff, 0x37, + 0x60, 0xd5, 0x62, 0xf4, 0x9f, 0xdd, 0xfc, 0x65, 0x2b, 0x4f, 0xf0, 0x99, 0x05, 0xeb, 0xff, 0xa8, + 0x01, 0xac, 0x2a, 0x6c, 0xff, 0xaf, 0x34, 0x54, 0xf7, 0x69, 0xa1, 0x66, 0x9f, 0xfe, 0x4f, 0xef, + 0x81, 0x37, 0x60, 0x43, 0x26, 0x27, 0x8d, 0x28, 0x89, 0xe0, 0x98, 0x6a, 0x07, 0xda, 0xb9, 0x76, + 0x5c, 0x62, 0xc5, 0x4a, 0x6a, 0x19, 0x97, 0x61, 0x29, 0x3c, 0xe1, 0x6e, 0xc3, 0x96, 0x48, 0x76, + 0xde, 0x16, 0x43, 0xa9, 0x7b, 0xe5, 0x4f, 0x1d, 0x38, 0x5f, 0xea, 0x28, 0x72, 0x3b, 0xe2, 0xea, + 0xb0, 0xef, 0x13, 0x1b, 0x88, 0xf4, 0x4b, 0x39, 0x32, 0xe8, 0x17, 0xdc, 0x56, 0xed, 0xc0, 0xfd, + 0x99, 0x46, 0x55, 0x7c, 0xb1, 0xeb, 0x75, 0x5d, 0xee, 0x05, 0x91, 0x92, 0x8d, 0x78, 0x58, 0x22, + 0xfc, 0x58, 0x24, 0x51, 0xcd, 0x8e, 0x22, 0x38, 0x6c, 0x93, 0xac, 0x9a, 0x68, 0x05, 0x5a, 0xd7, + 0x94, 0x4d, 0x6f, 0x6d, 0x9f, 0xfb, 0x17, 0x0e, 0xb0, 0xaf, 0x4c, 0x79, 0x3a, 0xa3, 0x1c, 0x8f, + 0x0e, 0xcf, 0x5c, 0x28, 0xc7, 0x31, 0x96, 0x92, 0xe9, 0xd1, 0x97, 0xf8, 0x4c, 0x65, 0xfe, 0x1a, + 0x45, 0xe6, 0xef, 0x55, 0x00, 0x74, 0xbf, 0x74, 0xe2, 0x08, 0x79, 0x01, 0xfd, 0x5e, 0x31, 0x60, + 0x6d, 0x72, 0xae, 0x59, 0x9b, 0x9c, 0x7b, 0xc5, 0x4c, 0xce, 0x49, 0x8b, 0xf4, 0x98, 0xf3, 0x07, + 0x94, 0x9b, 0x7b, 0x17, 0x36, 0x2d, 0x32, 0xf5, 0x29, 0xaa, 0x8c, 0x95, 0xf3, 0x9c, 0x8c, 0xd5, + 0x7f, 0x3a, 0xb0, 0xb0, 0x1f, 0x27, 0x66, 0x74, 0xd2, 0xb1, 0xa3, 0x93, 0xf2, 0xea, 0x18, 0xe8, + 0x9b, 0x41, 0x6a, 0x14, 0x0b, 0xc8, 0x76, 0xa0, 0xeb, 0x4f, 0x72, 0xf4, 0xb2, 0x8f, 0xe3, 0xf4, + 0xcc, 0x4f, 0x47, 0xe2, 0x68, 0x6f, 0x37, 0x7a, 0x8e, 0x57, 0xea, 0x61, 0x5b, 0xb0, 0xa0, 0x75, + 0x2c, 0x21, 0x60, 0x13, 0xed, 0x34, 0x0a, 0xd2, 0xce, 0x64, 0x80, 0x40, 0xb6, 0x90, 0x73, 0xec, + 0xef, 0x85, 0x65, 0x2c, 0x24, 0xa5, 0xae, 0x0b, 0xaf, 0x31, 0xdc, 0x2d, 0x42, 0x5b, 0xd6, 0x9b, + 0x45, 0x6d, 0xf7, 0xdf, 0x1d, 0x58, 0xa4, 0x1d, 0x40, 0xd9, 0x16, 0x0c, 0x4d, 0x19, 0x6b, 0x8a, + 0x28, 0x3b, 0x42, 0xb6, 0x4b, 0x60, 0xe6, 0x5a, 0x79, 0xec, 0x86, 0x26, 0xdb, 0xcc, 0x65, 0x5f, + 0x81, 0x96, 0x68, 0xe9, 0xe4, 0x2f, 0xa1, 0x14, 0x40, 0x76, 0x19, 0x9a, 0x27, 0x71, 0xa2, 0x8c, + 0x11, 0x50, 0x01, 0xc5, 0x38, 0xf1, 0x08, 0x5e, 0xd0, 0x83, 0xe3, 0x09, 0xe2, 0xc5, 0x49, 0x97, + 0xc1, 0x78, 0xc9, 0xea, 0x61, 0xcd, 0xcd, 0x28, 0x41, 0xdd, 0x1d, 0x58, 0x7b, 0x18, 0x8f, 0xb8, + 0x11, 0x42, 0x9a, 0xcb, 0xbc, 0xee, 0x6f, 0x3a, 0xb0, 0xa2, 0x90, 0xd9, 0x75, 0x68, 0xa2, 0xe5, + 0x50, 0xf2, 0x0b, 0x74, 0x22, 0x01, 0xf1, 0x3c, 0xc2, 0x40, 0x55, 0x4b, 0x01, 0x86, 0xc2, 0x8a, + 0x54, 0xe1, 0x85, 0xc2, 0x48, 0xd2, 0xe4, 0x96, 0x6c, 0x8b, 0x12, 0xd4, 0xfd, 0x2b, 0x07, 0x56, + 0xad, 0x39, 0xd0, 0x1b, 0x0c, 0xfd, 0x2c, 0x97, 0xc1, 0x59, 0x79, 0x3c, 0x26, 0xc8, 0x0c, 0x2a, + 0x36, 0xec, 0xa0, 0xa2, 0x0e, 0x77, 0x2d, 0x98, 0xe1, 0xae, 0x9b, 0xd0, 0x2a, 0xaa, 0x0d, 0x9a, + 0x96, 0x0a, 0xc5, 0x19, 0x55, 0x8a, 0xa4, 0x40, 0xc2, 0x71, 0x86, 0x71, 0x18, 0xa7, 0x32, 0x19, + 0x2f, 0x1a, 0xee, 0xbb, 0xd0, 0x36, 0xf0, 0x91, 0x8c, 0x88, 0xe7, 0x67, 0x71, 0xfa, 0x44, 0xc5, + 0x36, 0x65, 0x53, 0x67, 0x02, 0x1b, 0x45, 0x26, 0xd0, 0xfd, 0x6b, 0x07, 0x56, 0x91, 0x07, 0x83, + 0x68, 0x7c, 0x10, 0x87, 0xc1, 0x70, 0x46, 0x67, 0xaf, 0xd8, 0x4d, 0x2a, 0x02, 0xc5, 0x8b, 0x36, + 0x18, 0x79, 0x5b, 0x39, 0x83, 0x52, 0x10, 0x75, 0x1b, 0x25, 0x15, 0xf9, 0xfc, 0xc8, 0xcf, 0x24, + 0xf3, 0xcb, 0x3b, 0xcd, 0x02, 0xa2, 0x3c, 0x21, 0x20, 0xf5, 0x73, 0x3e, 0x98, 0x04, 0x61, 0x18, + 0x08, 0x5c, 0x61, 0xf1, 0xd4, 0x75, 0xb9, 0x3f, 0x68, 0x40, 0x5b, 0x6a, 0xdc, 0x7b, 0xa3, 0xb1, + 0xc8, 0x22, 0x48, 0xbb, 0x51, 0xab, 0x0b, 0x03, 0xa2, 0xfa, 0x2d, 0x4b, 0xd3, 0x80, 0x94, 0x8f, + 0x75, 0xa1, 0x7a, 0xac, 0x97, 0xa0, 0x85, 0xec, 0xf5, 0x26, 0x99, 0xb4, 0xa2, 0x38, 0xa5, 0x00, + 0xa8, 0xde, 0x3d, 0xea, 0x5d, 0x2c, 0x7a, 0x09, 0x60, 0x19, 0xb1, 0x4b, 0x25, 0x23, 0xf6, 0x6d, + 0xe8, 0xc8, 0x61, 0x68, 0xdf, 0x49, 0x3b, 0x14, 0x0c, 0x6e, 0x9d, 0x89, 0x67, 0x61, 0xaa, 0x2f, + 0xf7, 0xd4, 0x97, 0x2b, 0x2f, 0xfa, 0x52, 0x61, 0x52, 0x52, 0x4d, 0xec, 0xcd, 0xfd, 0xd4, 0x4f, + 0x4e, 0xd4, 0x2d, 0x36, 0xd2, 0x95, 0x02, 0x04, 0x66, 0x3b, 0xb0, 0x88, 0x9f, 0x29, 0x6d, 0x5d, + 0x2f, 0x74, 0x02, 0x85, 0x5d, 0x87, 0x45, 0x3e, 0x1a, 0x73, 0xe5, 0xb4, 0x31, 0xdb, 0x7d, 0xc6, + 0x33, 0xf2, 0x04, 0x02, 0xaa, 0x00, 0x84, 0x96, 0x54, 0x80, 0xad, 0xe9, 0x97, 0xb0, 0xf9, 0xfe, + 0xc8, 0xdd, 0x02, 0xf6, 0x50, 0x70, 0xad, 0x19, 0x74, 0xfe, 0x9d, 0x05, 0x68, 0x1b, 0x60, 0x94, + 0xe6, 0x31, 0x12, 0x3c, 0x18, 0x05, 0xfe, 0x84, 0xe7, 0x3c, 0x95, 0x9c, 0x5a, 0x82, 0x22, 0x9e, + 0x7f, 0x3a, 0x1e, 0xc4, 0xd3, 0x7c, 0x30, 0xe2, 0xe3, 0x94, 0x8b, 0xbb, 0x16, 0x2f, 0x03, 0x0b, + 0x8a, 0x78, 0x13, 0xff, 0xa9, 0x89, 0x27, 0xf8, 0xa1, 0x04, 0x55, 0x21, 0x64, 0xb1, 0x47, 0xcd, + 0x22, 0x84, 0x2c, 0x76, 0xa4, 0xac, 0x87, 0x16, 0x6b, 0xf4, 0xd0, 0x5b, 0xb0, 0x2d, 0x34, 0x8e, + 0x94, 0xcd, 0x41, 0x89, 0x4d, 0xe6, 0xf4, 0xb2, 0x1d, 0x58, 0x47, 0x9a, 0x15, 0x83, 0x67, 0xc1, + 0xb7, 0x45, 0x50, 0xc7, 0xf1, 0x2a, 0x70, 0xc4, 0x45, 0x71, 0xb4, 0x70, 0x45, 0x9a, 0xad, 0x02, + 0x27, 0x5c, 0xff, 0xa9, 0x8d, 0xdb, 0x92, 0xb8, 0x25, 0xb8, 0xbb, 0x0a, 0xed, 0xc3, 0x3c, 0x4e, + 0xd4, 0xa1, 0x74, 0xa1, 0x23, 0x9a, 0x32, 0xa9, 0xfa, 0x0a, 0x5c, 0x24, 0x2e, 0x7a, 0x14, 0x27, + 0x71, 0x18, 0x8f, 0x67, 0x87, 0xd3, 0xa3, 0x6c, 0x98, 0x06, 0x09, 0x3a, 0x38, 0xee, 0x3f, 0x3a, + 0xb0, 0x69, 0xf5, 0xca, 0x28, 0xd0, 0x67, 0x04, 0x4b, 0xeb, 0x6c, 0x98, 0x60, 0xbc, 0x0d, 0x43, + 0x1d, 0x0a, 0x44, 0x11, 0x7f, 0xfb, 0x50, 0x26, 0xc8, 0x6e, 0xc1, 0x9a, 0xa2, 0x4c, 0x7d, 0x28, + 0xb8, 0xb0, 0x57, 0xe5, 0x42, 0xf9, 0x7d, 0x57, 0x7e, 0xa0, 0x86, 0xf8, 0x25, 0x61, 0x9f, 0xf3, + 0x11, 0xad, 0x51, 0x85, 0x03, 0xfa, 0xea, 0x7b, 0xd3, 0x29, 0x50, 0x14, 0x0c, 0x35, 0x30, 0x73, + 0x7f, 0xdf, 0x01, 0x28, 0xa8, 0x43, 0xc6, 0x28, 0x54, 0xba, 0x28, 0xb4, 0x34, 0xd4, 0xf7, 0xeb, + 0xd0, 0xd1, 0x89, 0x90, 0xe2, 0x96, 0x68, 0x2b, 0x18, 0xda, 0x6d, 0xd7, 0x60, 0x6d, 0x1c, 0xc6, + 0x47, 0x74, 0xc5, 0x52, 0x96, 0x3e, 0x93, 0xa9, 0xe5, 0xae, 0x00, 0xbf, 0x27, 0xa1, 0xc5, 0x95, + 0xd2, 0x34, 0xae, 0x14, 0xf7, 0x3b, 0x0d, 0x1d, 0x3e, 0x2f, 0xd6, 0x3c, 0x57, 0xca, 0xd8, 0x5e, + 0x45, 0x39, 0xce, 0x89, 0x56, 0x53, 0xe0, 0xeb, 0xe0, 0x85, 0x7e, 0xf9, 0xbb, 0xd0, 0x4d, 0x85, + 0xf6, 0x51, 0xaa, 0xa9, 0xf9, 0x1c, 0xd5, 0xb4, 0x9a, 0x5a, 0xf7, 0xce, 0xa7, 0x60, 0xdd, 0x1f, + 0x9d, 0xf2, 0x34, 0x0f, 0xc8, 0x33, 0xa2, 0x4b, 0x5f, 0x28, 0xd4, 0x35, 0x03, 0x4e, 0x77, 0xf1, + 0x35, 0x58, 0x93, 0xe9, 0x7c, 0x8d, 0x29, 0x4b, 0xce, 0x0a, 0x30, 0x22, 0xba, 0x7f, 0xae, 0x22, + 0xf5, 0xf6, 0x19, 0xce, 0xdf, 0x11, 0x73, 0x75, 0x8d, 0xd2, 0xea, 0x3e, 0x21, 0xa3, 0xe6, 0x23, + 0xe5, 0x7e, 0xc9, 0xfc, 0x85, 0x00, 0xca, 0x2c, 0x87, 0xbd, 0xa5, 0xcd, 0x97, 0xd9, 0x52, 0xf7, + 0x63, 0x07, 0x96, 0xf7, 0xe3, 0x64, 0x5f, 0x66, 0xe6, 0x49, 0x10, 0x74, 0xb1, 0x8c, 0x6a, 0x9a, + 0x56, 0x71, 0xa3, 0x62, 0x15, 0x57, 0xef, 0xda, 0xd5, 0xf2, 0x5d, 0xfb, 0xcb, 0xf0, 0x0a, 0x39, + 0xff, 0x69, 0x9c, 0xc4, 0x29, 0x0a, 0xa3, 0x1f, 0x8a, 0x8b, 0x35, 0x8e, 0xf2, 0x13, 0xa5, 0xc6, + 0x9e, 0x87, 0x42, 0x5e, 0x16, 0x7a, 0x07, 0xc2, 0x18, 0x96, 0xb6, 0x81, 0xd0, 0x6e, 0xd5, 0x0e, + 0xf7, 0x73, 0xd0, 0x22, 0xe3, 0x96, 0x96, 0xf5, 0x06, 0xb4, 0x4e, 0xe2, 0x64, 0x70, 0x12, 0x44, + 0xb9, 0x12, 0xee, 0x6e, 0x61, 0x75, 0xee, 0xd3, 0x86, 0x68, 0x04, 0xf7, 0x47, 0x0b, 0xb0, 0xfc, + 0x7e, 0x74, 0x1a, 0x07, 0x43, 0x0a, 0xea, 0x4f, 0xf8, 0x24, 0x56, 0xa5, 0x43, 0xf8, 0x1b, 0xb7, + 0x82, 0xd2, 0xe8, 0x49, 0x2e, 0xa3, 0xf2, 0xaa, 0x89, 0xd7, 0x7d, 0x5a, 0x94, 0xf7, 0x09, 0xd1, + 0x31, 0x20, 0x68, 0xd8, 0xa7, 0x66, 0xe5, 0xa3, 0x6c, 0x15, 0xb5, 0x57, 0x8b, 0x46, 0xed, 0x15, + 0xa5, 0x80, 0x44, 0x85, 0x00, 0xf1, 0xd7, 0x8a, 0xa7, 0x9a, 0xe4, 0x88, 0xa4, 0x5c, 0x04, 0x6d, + 0xc8, 0x70, 0x58, 0x96, 0x8e, 0x88, 0x09, 0x44, 0xe3, 0x42, 0x7c, 0x20, 0x70, 0x84, 0xf2, 0x35, + 0x41, 0x68, 0x6c, 0x95, 0x8b, 0x27, 0x5b, 0x82, 0xe7, 0x4b, 0x60, 0xd4, 0xd0, 0x23, 0xae, 0x15, + 0xa9, 0x58, 0x03, 0x88, 0xf2, 0xc5, 0x32, 0xdc, 0x70, 0x5f, 0x44, 0xa5, 0x83, 0x72, 0x5f, 0x90, + 0x51, 0xfc, 0x30, 0x3c, 0xf2, 0x87, 0x4f, 0xa8, 0xa4, 0x95, 0x0a, 0x1b, 0x5a, 0x9e, 0x0d, 0x44, + 0xaa, 0x8d, 0xd3, 0xa4, 0x24, 0x62, 0xd3, 0x33, 0x41, 0x6c, 0x0f, 0xda, 0xe4, 0xb2, 0xc9, 0xf3, + 0xec, 0xd2, 0x79, 0xae, 0x9b, 0x3e, 0x1d, 0x9d, 0xa8, 0x89, 0x64, 0x26, 0x1a, 0xd6, 0xec, 0xda, + 0x83, 0xaf, 0x02, 0xbb, 0x35, 0x1a, 0xc9, 0xf3, 0xd6, 0x2e, 0x63, 0x71, 0x52, 0x8e, 0x75, 0x52, + 0x35, 0x3b, 0xd6, 0xa8, 0xdd, 0x31, 0xf7, 0x1e, 0xb4, 0x0f, 0x8c, 0x2a, 0x4b, 0x62, 0x0d, 0x55, + 0x5f, 0x29, 0xd9, 0xc9, 0x80, 0x18, 0x13, 0x36, 0xcc, 0x09, 0xdd, 0x5f, 0x00, 0xf6, 0x20, 0xc8, + 0x72, 0x4d, 0x5f, 0x51, 0xd6, 0xa9, 0x1c, 0xf5, 0xa2, 0x32, 0xa2, 0x2d, 0x61, 0x54, 0xb1, 0x70, + 0x4b, 0x94, 0x54, 0x94, 0x17, 0xb6, 0x03, 0x2b, 0x81, 0x00, 0x95, 0x25, 0x41, 0x61, 0xea, 0x7e, + 0xb4, 0xd7, 0x24, 0xd0, 0xba, 0x45, 0x7f, 0xe0, 0xc0, 0xb2, 0x5c, 0x1a, 0x5a, 0x1b, 0x95, 0xfa, + 0xd2, 0x96, 0x67, 0xc1, 0xea, 0x2b, 0x0b, 0xab, 0x3c, 0xbc, 0x50, 0xc7, 0xc3, 0x0c, 0x9a, 0x89, + 0x9f, 0x9f, 0x90, 0x83, 0xd2, 0xf2, 0xe8, 0x37, 0x5b, 0x17, 0x4e, 0xb3, 0x90, 0x15, 0x72, 0x98, + 0xeb, 0x8a, 0x6b, 0x85, 0x4a, 0xae, 0xc0, 0x71, 0x51, 0x54, 0x84, 0x20, 0xe0, 0x3a, 0xb7, 0x20, + 0x0b, 0x3c, 0x0a, 0x70, 0xb1, 0x5f, 0x72, 0x88, 0xf2, 0x7e, 0x49, 0x54, 0x4f, 0xf7, 0xbb, 0x7d, + 0xe8, 0xdd, 0xe5, 0x21, 0xcf, 0xf9, 0xad, 0x30, 0x2c, 0x8f, 0xff, 0x0a, 0x5c, 0xac, 0xe9, 0x93, + 0x46, 0xcb, 0x7b, 0xb0, 0x71, 0x97, 0x1f, 0x4d, 0xc7, 0x0f, 0xf8, 0x69, 0x91, 0x00, 0x64, 0xd0, + 0xcc, 0x4e, 0xe2, 0x33, 0x79, 0xb6, 0xf4, 0x9b, 0xbd, 0x0a, 0x10, 0x22, 0xce, 0x20, 0x4b, 0xf8, + 0x50, 0xd5, 0xd4, 0x11, 0xe4, 0x30, 0xe1, 0x43, 0xf7, 0x2d, 0x60, 0xe6, 0x38, 0x72, 0x09, 0xa8, + 0x07, 0xa6, 0x47, 0x83, 0x6c, 0x96, 0xe5, 0x7c, 0xa2, 0x8a, 0x05, 0x4d, 0x90, 0x7b, 0x0d, 0x3a, + 0x07, 0xfe, 0xcc, 0xe3, 0xdf, 0x92, 0x25, 0xbe, 0xe8, 0x1b, 0xfb, 0x33, 0x64, 0x65, 0xed, 0x1b, + 0x53, 0xb7, 0xfb, 0x5f, 0x0d, 0x58, 0x12, 0x98, 0x38, 0xea, 0x88, 0x67, 0x79, 0x10, 0x89, 0xe4, + 0x97, 0x1c, 0xd5, 0x00, 0x55, 0x78, 0xa3, 0x51, 0xc3, 0x1b, 0xd2, 0x5a, 0x55, 0xf5, 0x49, 0x92, + 0x09, 0x2c, 0x18, 0x9a, 0x35, 0x45, 0x51, 0x81, 0x70, 0xce, 0x0a, 0x40, 0x29, 0x58, 0x52, 0x68, + 0x1b, 0x41, 0x9f, 0x62, 0x5a, 0xc9, 0x0e, 0x26, 0xa8, 0x56, 0xa7, 0x2d, 0x0b, 0xae, 0xa9, 0xe8, + 0xb4, 0x8a, 0xee, 0x5a, 0x79, 0x09, 0xdd, 0x25, 0x4c, 0xd8, 0xe7, 0xe9, 0x2e, 0x78, 0x09, 0xdd, + 0xe5, 0x32, 0x58, 0x7f, 0x8f, 0x73, 0x8f, 0xe3, 0xad, 0xa8, 0xd8, 0xe9, 0x7b, 0x0e, 0xac, 0xcb, + 0x0b, 0x5d, 0xf7, 0xb1, 0xd7, 0xad, 0xdb, 0xdf, 0xa9, 0xcb, 0x6b, 0x5c, 0x85, 0x55, 0xba, 0x93, + 0x75, 0x54, 0x48, 0x86, 0xb0, 0x2c, 0x20, 0xae, 0x43, 0x45, 0xea, 0x27, 0x41, 0x28, 0x0f, 0xc5, + 0x04, 0xa9, 0xc0, 0x12, 0xfa, 0xc7, 0x74, 0x24, 0x8e, 0xa7, 0xdb, 0xee, 0xdf, 0x3a, 0xb0, 0x61, + 0x10, 0x2c, 0xb9, 0xf0, 0x5d, 0x50, 0x45, 0x07, 0x22, 0x78, 0x24, 0x84, 0xe9, 0x82, 0x6d, 0x9c, + 0x14, 0x9f, 0x59, 0xc8, 0x74, 0x98, 0xfe, 0x8c, 0x08, 0xcc, 0xa6, 0x13, 0x69, 0x81, 0x98, 0x20, + 0x64, 0xa4, 0x33, 0xce, 0x9f, 0x68, 0x94, 0x05, 0x42, 0xb1, 0x60, 0x94, 0x53, 0x46, 0x5b, 0x42, + 0x23, 0x89, 0x32, 0x2a, 0x1b, 0xe8, 0xfe, 0xb3, 0x03, 0x9b, 0xc2, 0x28, 0x94, 0x26, 0xb7, 0x2e, + 0xf1, 0x5c, 0x12, 0x56, 0xb0, 0x90, 0xc8, 0xfd, 0x73, 0x9e, 0x6c, 0xb3, 0xcf, 0xbe, 0xa4, 0x21, + 0xab, 0x6b, 0x09, 0xe6, 0x9c, 0xc5, 0x42, 0xdd, 0x59, 0x3c, 0x67, 0xa7, 0xeb, 0x82, 0x25, 0x8b, + 0xb5, 0xc1, 0x92, 0xdb, 0xcb, 0xb0, 0x98, 0x0d, 0xe3, 0x84, 0xbb, 0xdb, 0xb0, 0x65, 0x2f, 0x4e, + 0xaa, 0xa0, 0xef, 0x3b, 0xd0, 0x7b, 0x4f, 0x84, 0x0e, 0x83, 0x68, 0xbc, 0x1f, 0x64, 0x79, 0x9c, + 0xea, 0x9a, 0xf6, 0xcb, 0x00, 0x59, 0xee, 0xa7, 0xb9, 0xa8, 0xf5, 0x92, 0x61, 0x8e, 0x02, 0x82, + 0x34, 0xf2, 0x68, 0x24, 0x7a, 0xc5, 0xd9, 0xe8, 0x36, 0x1e, 0x0c, 0xd5, 0x39, 0x0c, 0xe2, 0xe3, + 0xe3, 0x8c, 0x6b, 0xb3, 0xd5, 0x84, 0xa1, 0xe7, 0x8b, 0x12, 0x8f, 0xbe, 0x1e, 0x3f, 0x25, 0x55, + 0x2b, 0xec, 0xc1, 0x12, 0xd4, 0xfd, 0x1b, 0x07, 0xd6, 0x0a, 0x22, 0xef, 0x21, 0xd0, 0xd6, 0x0e, + 0x82, 0x34, 0x43, 0x3b, 0xa8, 0x00, 0x4c, 0x30, 0x1a, 0x04, 0x91, 0xa4, 0xcd, 0x80, 0x90, 0xc4, + 0xca, 0x56, 0x3c, 0x55, 0x75, 0x75, 0x26, 0x48, 0x24, 0xcd, 0x73, 0xfc, 0x5a, 0x14, 0xd5, 0xc9, + 0x16, 0x95, 0xea, 0x4d, 0x72, 0xfa, 0x6a, 0x49, 0x18, 0xc4, 0xb2, 0xa9, 0xee, 0xa7, 0x65, 0x82, + 0xe2, 0x4f, 0xf7, 0x0f, 0x1c, 0xb8, 0x58, 0xb3, 0xb9, 0x52, 0x32, 0xee, 0xc2, 0xc6, 0xb1, 0xee, + 0x54, 0x1b, 0x20, 0xc4, 0x63, 0x5b, 0x72, 0x51, 0x69, 0xd1, 0x5e, 0xf5, 0x03, 0x34, 0x8f, 0x29, + 0x6e, 0x24, 0xb6, 0xd4, 0xaa, 0x37, 0xa9, 0x76, 0xec, 0xfd, 0xe1, 0x02, 0x74, 0x45, 0xca, 0x43, + 0x3c, 0x02, 0xe3, 0x29, 0xfb, 0x00, 0x96, 0xe5, 0x23, 0x3e, 0x76, 0x5e, 0x4e, 0x6b, 0x3f, 0x1b, + 0xec, 0x6f, 0x97, 0xc1, 0x92, 0x77, 0x36, 0x7f, 0xfb, 0xe3, 0x7f, 0xfd, 0xa3, 0xc6, 0x2a, 0x6b, + 0xef, 0x9e, 0xbe, 0xb9, 0x3b, 0xe6, 0x51, 0x86, 0x63, 0xfc, 0x1a, 0x40, 0xf1, 0xbc, 0x8d, 0xf5, + 0xb4, 0x91, 0x51, 0x7a, 0xb7, 0xd7, 0xbf, 0x58, 0xd3, 0x23, 0xc7, 0xbd, 0x48, 0xe3, 0x6e, 0xba, + 0x5d, 0x1c, 0x37, 0x88, 0x82, 0x5c, 0xbc, 0x75, 0x7b, 0xc7, 0xd9, 0x61, 0x23, 0xe8, 0x98, 0xaf, + 0xd7, 0x98, 0x72, 0x99, 0x6b, 0xde, 0xce, 0xf5, 0x5f, 0xa9, 0xed, 0x53, 0xf1, 0x02, 0x9a, 0xe3, + 0xbc, 0xbb, 0x8e, 0x73, 0x4c, 0x09, 0xa3, 0x98, 0x25, 0x84, 0xae, 0xfd, 0x48, 0x8d, 0x5d, 0x32, + 0xc4, 0xba, 0xf2, 0x44, 0xae, 0xff, 0xea, 0x9c, 0x5e, 0x39, 0xd7, 0xab, 0x34, 0xd7, 0x05, 0x97, + 0xe1, 0x5c, 0x43, 0xc2, 0x51, 0x4f, 0xe4, 0xde, 0x71, 0x76, 0xf6, 0xbe, 0xfb, 0x2a, 0xb4, 0x74, + 0x90, 0x8b, 0x7d, 0x13, 0x56, 0xad, 0x9c, 0x14, 0x53, 0xcb, 0xa8, 0x4b, 0x61, 0xf5, 0x2f, 0xd5, + 0x77, 0xca, 0x89, 0x2f, 0xd3, 0xc4, 0x3d, 0xb6, 0x8d, 0x13, 0xcb, 0xa4, 0xce, 0x2e, 0x65, 0xe2, + 0x44, 0x21, 0xe0, 0x13, 0xb1, 0xce, 0x22, 0x8f, 0x64, 0xad, 0xb3, 0x92, 0x77, 0xb2, 0xd6, 0x59, + 0x4d, 0x3e, 0xb9, 0x97, 0x68, 0xba, 0x6d, 0xb6, 0x65, 0x4e, 0xa7, 0x83, 0x4f, 0x9c, 0x4a, 0x37, + 0xcd, 0x37, 0x6c, 0xec, 0x55, 0xcd, 0x58, 0x75, 0x6f, 0xdb, 0x34, 0x8b, 0x54, 0x1f, 0xb8, 0xb9, + 0x3d, 0x9a, 0x8a, 0x31, 0x3a, 0x3e, 0xf3, 0x09, 0x1b, 0xfb, 0x3a, 0xb4, 0xf4, 0x4b, 0x10, 0x76, + 0xc1, 0x78, 0x7e, 0x63, 0x3e, 0x4f, 0xe9, 0xf7, 0xaa, 0x1d, 0x75, 0x8c, 0x61, 0x8e, 0x8c, 0x8c, + 0xf1, 0x00, 0xce, 0x4b, 0x93, 0xf8, 0x88, 0xff, 0x38, 0x2b, 0xa9, 0x79, 0x79, 0x77, 0xd3, 0x61, + 0xef, 0xc2, 0x8a, 0x7a, 0x60, 0xc3, 0xb6, 0xeb, 0x1f, 0x0a, 0xf5, 0x2f, 0x54, 0xe0, 0x52, 0x7b, + 0xdc, 0x02, 0x28, 0x1e, 0x87, 0x68, 0x39, 0xab, 0x3c, 0x59, 0xd1, 0x9b, 0x58, 0xf3, 0x92, 0x64, + 0x4c, 0x4f, 0x61, 0xec, 0xb7, 0x27, 0xec, 0xb5, 0x02, 0xbf, 0xf6, 0x55, 0xca, 0x73, 0x06, 0x74, + 0xb7, 0x69, 0xef, 0xd6, 0x19, 0x09, 0x6e, 0xc4, 0xcf, 0x54, 0x11, 0xf3, 0x5d, 0x68, 0x1b, 0x0f, + 0x4e, 0x98, 0x1a, 0xa1, 0xfa, 0x58, 0xa5, 0xdf, 0xaf, 0xeb, 0x92, 0xe4, 0x7e, 0x11, 0x56, 0xad, + 0x97, 0x23, 0x5a, 0x32, 0xea, 0xde, 0xa5, 0x68, 0xc9, 0xa8, 0x7f, 0x6c, 0xf2, 0x35, 0x68, 0x1b, + 0xef, 0x3c, 0x98, 0x51, 0xbc, 0x55, 0x7a, 0xe1, 0xa1, 0x29, 0xaa, 0x7b, 0x16, 0xb2, 0x45, 0xeb, + 0xed, 0xba, 0x2d, 0x5c, 0x2f, 0x55, 0xf2, 0x22, 0x93, 0x7c, 0x13, 0xba, 0xf6, 0xcb, 0x0f, 0x2d, + 0x55, 0xb5, 0x6f, 0x48, 0xb4, 0x54, 0xcd, 0x79, 0x2e, 0x22, 0x19, 0x72, 0x67, 0x53, 0x4f, 0xb2, + 0xfb, 0x91, 0x4c, 0xf1, 0x3c, 0x63, 0x5f, 0x41, 0xd5, 0x21, 0x4b, 0xab, 0x59, 0xf1, 0xde, 0xc5, + 0x2e, 0xc0, 0xd6, 0xdc, 0x5e, 0xa9, 0xc2, 0x76, 0x37, 0x68, 0xf0, 0x36, 0x2b, 0x56, 0x20, 0xee, + 0x03, 0x2a, 0xb1, 0x36, 0xee, 0x03, 0xb3, 0x0a, 0xdb, 0xb8, 0x0f, 0xac, 0x4a, 0xec, 0xf2, 0x7d, + 0x90, 0x07, 0x38, 0x46, 0x04, 0x6b, 0xa5, 0xea, 0x05, 0x2d, 0x2c, 0xf5, 0xe5, 0x5e, 0xfd, 0xcb, + 0xcf, 0x2f, 0x7a, 0xb0, 0xd5, 0x8c, 0x52, 0x2f, 0xbb, 0xaa, 0x3a, 0xef, 0xd7, 0xa1, 0x63, 0x56, + 0xec, 0xeb, 0x1b, 0xa2, 0xe6, 0x9d, 0x81, 0xbe, 0x21, 0xea, 0x4a, 0xfc, 0xd5, 0xe1, 0xb2, 0x8e, + 0x39, 0x0d, 0xfb, 0x1a, 0xac, 0x19, 0xe5, 0x3a, 0x87, 0xb3, 0x68, 0xa8, 0x99, 0xa7, 0x5a, 0xcc, + 0xd9, 0xaf, 0xb3, 0x06, 0xdd, 0x0b, 0x34, 0xf0, 0x86, 0x6b, 0x0d, 0x8c, 0x8c, 0x73, 0x07, 0xda, + 0x66, 0x29, 0xd0, 0x73, 0xc6, 0xbd, 0x60, 0x74, 0x99, 0x75, 0x8d, 0x37, 0x1d, 0xf6, 0x27, 0x0e, + 0x74, 0xac, 0xc2, 0x1a, 0x2b, 0xaa, 0x5c, 0x1a, 0xa7, 0x67, 0xf6, 0x99, 0x03, 0xb9, 0x1e, 0x11, + 0xf9, 0x60, 0xe7, 0x8b, 0xd6, 0x26, 0x7f, 0x64, 0x79, 0x15, 0x37, 0xca, 0x8f, 0x31, 0x9f, 0x95, + 0x11, 0xcc, 0x82, 0xd7, 0x67, 0x37, 0x1d, 0xf6, 0x8e, 0x78, 0x5e, 0xac, 0xa2, 0x08, 0xcc, 0x50, + 0x6e, 0xe5, 0x2d, 0x33, 0xdf, 0xda, 0x5e, 0x77, 0x6e, 0x3a, 0xec, 0x1b, 0xe2, 0xcd, 0xa5, 0xfc, + 0x96, 0x76, 0xfe, 0x65, 0xbf, 0x77, 0xaf, 0xd2, 0x6a, 0x2e, 0xbb, 0x17, 0xad, 0xd5, 0x94, 0xb5, + 0xfb, 0x2d, 0x41, 0x9d, 0x7c, 0x4a, 0x5b, 0xa8, 0xa9, 0xca, 0xf3, 0xda, 0xf9, 0x44, 0x4e, 0x04, + 0x91, 0x12, 0xdd, 0x62, 0x8f, 0x97, 0x1c, 0xc6, 0xdd, 0x21, 0x5a, 0xaf, 0xba, 0xaf, 0xcd, 0xa5, + 0x75, 0x97, 0xbc, 0x44, 0xa4, 0xf8, 0x00, 0xa0, 0x08, 0x62, 0xb1, 0x52, 0x44, 0x47, 0x6b, 0xea, + 0x6a, 0x9c, 0xcb, 0xe6, 0x41, 0x15, 0xf8, 0xc1, 0x11, 0xbf, 0x2e, 0xc4, 0x47, 0xe2, 0x67, 0x9a, + 0xfa, 0x6a, 0x30, 0xaa, 0xdf, 0xaf, 0xeb, 0xaa, 0x13, 0x1e, 0x35, 0x3e, 0xfb, 0x10, 0x56, 0x1f, + 0xc4, 0xf1, 0x93, 0x69, 0xa2, 0xc3, 0xac, 0x76, 0x4c, 0x65, 0xdf, 0xcf, 0x4e, 0xfa, 0xa5, 0x55, + 0xb8, 0x57, 0x68, 0xa8, 0x3e, 0xeb, 0x19, 0x43, 0xed, 0x7e, 0x54, 0x84, 0xd0, 0x9e, 0x31, 0x1f, + 0x36, 0xf4, 0xad, 0xac, 0x09, 0xef, 0xdb, 0xc3, 0x98, 0x91, 0xac, 0xca, 0x14, 0x96, 0x9d, 0xa4, + 0xa8, 0xdd, 0xcd, 0xd4, 0x98, 0x37, 0x1d, 0x76, 0x00, 0x9d, 0xbb, 0x7c, 0x18, 0x8f, 0xb8, 0x8c, + 0x82, 0x6c, 0x16, 0x84, 0xeb, 0xf0, 0x49, 0x7f, 0xd5, 0x02, 0xda, 0x7a, 0x2a, 0xf1, 0x67, 0x29, + 0xff, 0xd6, 0xee, 0x47, 0x32, 0xbe, 0xf2, 0x4c, 0xe9, 0x29, 0x15, 0x13, 0xb2, 0xf4, 0x54, 0x29, + 0x88, 0x64, 0xe9, 0xa9, 0x4a, 0x10, 0xc9, 0xda, 0x6a, 0x15, 0x93, 0x62, 0x21, 0x6c, 0x54, 0xe2, + 0x4e, 0xfa, 0x6e, 0x9f, 0x17, 0xad, 0xea, 0x5f, 0x99, 0x8f, 0x60, 0xcf, 0xb6, 0x63, 0xcf, 0x76, + 0x08, 0xab, 0x77, 0xb9, 0xd8, 0x2c, 0x91, 0xcb, 0xed, 0xdb, 0x8a, 0xcf, 0xcc, 0xfb, 0x96, 0x95, + 0x22, 0xf5, 0xd9, 0x17, 0x11, 0x25, 0x52, 0xd9, 0xd7, 0xa1, 0x7d, 0x9f, 0xe7, 0x2a, 0x79, 0xab, + 0x2d, 0xa4, 0x52, 0x36, 0xb7, 0x5f, 0x93, 0xfb, 0xb5, 0x79, 0x86, 0x46, 0xdb, 0xe5, 0xa3, 0x31, + 0x17, 0xea, 0x69, 0x10, 0x8c, 0x9e, 0xb1, 0x5f, 0xa1, 0xc1, 0x75, 0xbd, 0xc7, 0xb6, 0x91, 0xf3, + 0x33, 0x07, 0x5f, 0x2b, 0xc1, 0xeb, 0x46, 0x8e, 0xe2, 0x11, 0x37, 0xae, 0xe4, 0x08, 0xda, 0x46, + 0x31, 0x92, 0x16, 0xa0, 0x6a, 0x1d, 0x95, 0x16, 0xa0, 0x9a, 0xda, 0x25, 0xf7, 0x3a, 0xcd, 0xe3, + 0xb2, 0x2b, 0xc5, 0x3c, 0xa2, 0x5e, 0xa9, 0x98, 0x69, 0xf7, 0x23, 0x7f, 0x92, 0x3f, 0x63, 0x8f, + 0xe9, 0x95, 0x94, 0x99, 0xa0, 0x2e, 0x2c, 0xb4, 0x72, 0x2e, 0x5b, 0x6f, 0x96, 0xd1, 0x65, 0x5b, + 0x6d, 0x62, 0x2a, 0xba, 0xb9, 0x3f, 0x0b, 0x70, 0x98, 0xc7, 0xc9, 0x5d, 0x9f, 0x4f, 0xe2, 0xa8, + 0xd0, 0xb5, 0x45, 0x12, 0xb6, 0xd0, 0x5f, 0x46, 0x26, 0x96, 0x3d, 0x36, 0x6c, 0x64, 0x2b, 0xbf, + 0xaf, 0x98, 0x6b, 0x6e, 0x9e, 0x56, 0x6f, 0x48, 0x4d, 0xae, 0xf6, 0xa6, 0x83, 0x16, 0x6f, 0x11, + 0xe5, 0xd4, 0x16, 0x6f, 0x25, 0x80, 0xaa, 0xd5, 0x5e, 0x4d, 0x48, 0xf4, 0x00, 0x5a, 0x45, 0xd8, + 0x4c, 0x5d, 0xa2, 0xe5, 0x20, 0x9b, 0xbe, 0x15, 0x2b, 0xc1, 0x2c, 0x77, 0x9d, 0xb6, 0x0a, 0xd8, + 0x0a, 0x6e, 0x15, 0x45, 0xa8, 0x02, 0xd8, 0x14, 0x04, 0xea, 0x2b, 0x9e, 0xd2, 0x8a, 0x6a, 0x25, + 0x35, 0x01, 0x25, 0x2d, 0xcd, 0xb5, 0xf1, 0x18, 0xcb, 0xf7, 0x45, 0x6e, 0x15, 0x29, 0x4d, 0x54, + 0xcd, 0x13, 0xd8, 0xa8, 0x04, 0x13, 0xb4, 0x48, 0xcf, 0x8b, 0xe1, 0x68, 0x91, 0x9e, 0x1b, 0x87, + 0x70, 0xcf, 0xd3, 0x94, 0x6b, 0x2e, 0xe0, 0x94, 0xd9, 0x59, 0x90, 0x0f, 0x4f, 0xde, 0x71, 0x76, + 0x8e, 0x96, 0xe8, 0x5f, 0x84, 0x3e, 0xfd, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf8, 0xaf, 0xef, + 0x4c, 0x77, 0x48, 0x00, 0x00, } diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index 1fbc4991..6f8ce4cc 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -671,6 +671,10 @@ message SendRequest { /// The CLTV delta from the current height that should be used to set the timelock for the final hop. int32 final_cltv_delta = 7; + + /// The maximum total fees for the payment in satoshis. + int64 fee_limit = 8 [json_name = "fee_limit"]; + } message SendResponse { string payment_error = 1 [json_name = "payment_error"]; @@ -1230,6 +1234,9 @@ message QueryRoutesRequest { /// An optional CLTV delta from the current height that should be used for the timelock of the final hop int32 final_cltv_delta = 4; + + /// The maximum total fees for the route in satoshis. + int64 fee_limit = 5; } message QueryRoutesResponse { repeated Route routes = 1 [ json_name = "routes"]; diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index 4d3c58c6..9ab24251 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -474,6 +474,14 @@ "required": false, "type": "integer", "format": "int32" + }, + { + "name": "fee_limit", + "description": "/ The maximum total fees for the route in satoshis.", + "in": "query", + "required": false, + "type": "string", + "format": "int64" } ], "tags": [ @@ -2381,6 +2389,11 @@ "type": "integer", "format": "int32", "description": "/ The CLTV delta from the current height that should be used to set the timelock for the final hop." + }, + "fee_limit": { + "type": "string", + "format": "int64", + "description": "/ The maximum total fees for the payment in satoshis." } } }, diff --git a/routing/errors.go b/routing/errors.go index 736a047c..a879cfe7 100644 --- a/routing/errors.go +++ b/routing/errors.go @@ -42,6 +42,10 @@ const ( // ErrPaymentAttemptTimeout is an error that indicates that a payment // attempt timed out before we were able to successfully route an HTLC. ErrPaymentAttemptTimeout + + // ErrFeeCutoffExceeded is returned when the total fees of a route + // exceed the user-specified maximum payment for the fee. + ErrFeeCutoffExceeded ) // routerError is a structure that represent the error inside the routing package, diff --git a/routing/pathfind.go b/routing/pathfind.go index 2446182d..18a6cce8 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -250,7 +250,7 @@ func (r *Route) ToHopPayloads() []sphinx.HopData { // the source to the target node of the path finding attempt. func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex, pathEdges []*ChannelHop, currentHeight uint32, - finalCLTVDelta uint16) (*Route, error) { + finalCLTVDelta uint16, feeLimit btcutil.Amount) (*Route, error) { // First, we'll create a new empty route with enough hops to match the // amount of path edges. We set the TotalTimeLock to the current block @@ -265,9 +265,6 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex, prevHopMap: make(map[Vertex]*ChannelHop), } - // TODO(roasbeef): need to do sanity check to ensure we don't make a - // "dust" payment: over x% of money sending to fees - // We'll populate the next hop map for the _source_ node with the // information for the first hop so the mapping is sound. route.nextHopMap[sourceVertex] = pathEdges[0] @@ -342,6 +339,14 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex, route.TotalFees += nextHop.Fee + // If the total fees exceed the fee limit established for this + // payment, stop hopping the route and return + if route.TotalFees.ToSatoshis() > feeLimit { + err := fmt.Sprintf("Route fee exceeded fee limit of %v", + feeLimit) + return nil, newErrf(ErrFeeCutoffExceeded, err) + } + // As a sanity check, we ensure that the selected channel has // enough capacity to forward the required amount which // includes the fee dictated at each hop. diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 3b4332d7..f3a4d006 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -310,6 +310,7 @@ func TestBasicGraphPathFinding(t *testing.T) { ) paymentAmt := lnwire.NewMSatFromSatoshis(100) + feeLimit := paymentAmt.ToSatoshis() target := aliases["sophon"] path, err := findPath( nil, graph, nil, sourceNode, target, ignoredVertexes, @@ -318,8 +319,9 @@ func TestBasicGraphPathFinding(t *testing.T) { if err != nil { t.Fatalf("unable to find path: %v", err) } + route, err := newRoute(paymentAmt, sourceVertex, path, startingHeight, - finalHopCLTV) + finalHopCLTV, feeLimit) if err != nil { t.Fatalf("unable to create path: %v", err) } @@ -460,8 +462,9 @@ func TestBasicGraphPathFinding(t *testing.T) { if err != nil { t.Fatalf("unable to find route: %v", err) } + route, err = newRoute(paymentAmt, sourceVertex, path, startingHeight, - finalHopCLTV) + finalHopCLTV, feeLimit) if err != nil { t.Fatalf("unable to create path: %v", err) } @@ -852,7 +855,8 @@ func TestPathFindSpecExample(t *testing.T) { // Query for a route of 4,999,999 mSAT to carol. carol := ctx.aliases["C"] const amt lnwire.MilliSatoshi = 4999999 - routes, err := ctx.router.FindRoutes(carol, amt, 100) + feeLimit := amt.ToSatoshis() + routes, err := ctx.router.FindRoutes(carol, amt, feeLimit, 100) if err != nil { t.Fatalf("unable to find route: %v", err) } @@ -912,7 +916,7 @@ func TestPathFindSpecExample(t *testing.T) { // We'll now request a route from A -> B -> C. ctx.router.routeCache = make(map[routeTuple][]*Route) - routes, err = ctx.router.FindRoutes(carol, amt, 100) + routes, err = ctx.router.FindRoutes(carol, amt, feeLimit, 100) if err != nil { t.Fatalf("unable to find routes: %v", err) } diff --git a/routing/router.go b/routing/router.go index 2ed754e2..57ae4350 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1259,7 +1259,8 @@ func pruneChannelFromRoutes(routes []*Route, skipChan uint64) []*Route { // 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. func pathsToFeeSortedRoutes(source Vertex, paths [][]*ChannelHop, finalCLTVDelta uint16, - amt lnwire.MilliSatoshi, currentHeight uint32) ([]*Route, error) { + amt lnwire.MilliSatoshi, feeLimit btcutil.Amount, + currentHeight uint32) ([]*Route, error) { validRoutes := make([]*Route, 0, len(paths)) for _, path := range paths { @@ -1268,6 +1269,7 @@ func pathsToFeeSortedRoutes(source Vertex, paths [][]*ChannelHop, finalCLTVDelta // by our KSP algorithm. route, err := newRoute( amt, source, path[1:], currentHeight, finalCLTVDelta, + feeLimit, ) if err != nil { // TODO(roasbeef): report straw breaking edge? @@ -1316,7 +1318,8 @@ func pathsToFeeSortedRoutes(source Vertex, paths [][]*ChannelHop, finalCLTVDelta // route that will be ranked the highest is the one with the lowest cumulative // fee along the route. func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey, - amt lnwire.MilliSatoshi, numPaths uint32, finalExpiry ...uint16) ([]*Route, error) { + amt lnwire.MilliSatoshi, feeLimit btcutil.Amount, numPaths uint32, + finalExpiry ...uint16) ([]*Route, error) { var finalCLTVDelta uint16 if len(finalExpiry) == 0 { @@ -1402,7 +1405,7 @@ func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey, // factored in. sourceVertex := Vertex(r.selfNode.PubKeyBytes) validRoutes, err := pathsToFeeSortedRoutes( - sourceVertex, shortestPaths, finalCLTVDelta, amt, + sourceVertex, shortestPaths, finalCLTVDelta, amt, feeLimit, uint32(currentHeight), ) if err != nil { @@ -1502,6 +1505,9 @@ type LightningPayment struct { // milli-satoshis. Amount lnwire.MilliSatoshi + // FeeLimit is a user-specified maximum fee for this payment in satoshis. + FeeLimit btcutil.Amount + // PaymentHash is the r-hash value to use within the HTLC extended to // the first hop. PaymentHash [32]byte diff --git a/routing/router_test.go b/routing/router_test.go index 387c5053..511842eb 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -174,9 +174,12 @@ func TestFindRoutesFeeSorting(t *testing.T) { // Execute a query for all possible routes between roasbeef and luo ji. paymentAmt := lnwire.NewMSatFromSatoshis(100) + feeLimit := paymentAmt.ToSatoshis() target := ctx.aliases["luoji"] - routes, err := ctx.router.FindRoutes(target, paymentAmt, - defaultNumRoutes, DefaultFinalCLTVDelta) + routes, err := ctx.router.FindRoutes( + target, paymentAmt, feeLimit, defaultNumRoutes, + DefaultFinalCLTVDelta, + ) if err != nil { t.Fatalf("unable to find any routes: %v", err) } @@ -221,12 +224,15 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) { } // Craft a LightningPayment struct that'll send a payment from roasbeef - // to luo ji for 100 satoshis. + // to luo ji for 1000 satoshis, with a maximum of 1000 satoshis in fees. var payHash [32]byte + paymentAmt := lnwire.NewMSatFromSatoshis(1000) + feeLimit := paymentAmt.ToSatoshis() payment := LightningPayment{ Target: ctx.aliases["luoji"], - Amount: lnwire.NewMSatFromSatoshis(1000), + Amount: paymentAmt, PaymentHash: payHash, + FeeLimit: feeLimit, } var preImage [32]byte @@ -524,12 +530,15 @@ func TestSendPaymentErrorPathPruning(t *testing.T) { } // Craft a LightningPayment struct that'll send a payment from roasbeef - // to luo ji for 100 satoshis. + // to luo ji for 1000 satoshis, with a maximum of 1000 satoshis in fees. var payHash [32]byte + paymentAmt := lnwire.NewMSatFromSatoshis(1000) + feeLimit := paymentAmt.ToSatoshis() payment := LightningPayment{ Target: ctx.aliases["luoji"], - Amount: lnwire.NewMSatFromSatoshis(1000), + Amount: paymentAmt, PaymentHash: payHash, + FeeLimit: feeLimit, } var preImage [32]byte @@ -965,9 +974,12 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { // We should now be able to find two routes to node 2. paymentAmt := lnwire.NewMSatFromSatoshis(100) + feeLimit := paymentAmt.ToSatoshis() targetNode := priv2.PubKey() - routes, err := ctx.router.FindRoutes(targetNode, paymentAmt, - defaultNumRoutes, DefaultFinalCLTVDelta) + routes, err := ctx.router.FindRoutes( + targetNode, paymentAmt, feeLimit, defaultNumRoutes, + DefaultFinalCLTVDelta, + ) if err != nil { t.Fatalf("unable to find any routes: %v", err) } @@ -1009,8 +1021,10 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { // Should still be able to find the routes, and the info should be // updated. - routes, err = ctx.router.FindRoutes(targetNode, paymentAmt, - defaultNumRoutes, DefaultFinalCLTVDelta) + routes, err = ctx.router.FindRoutes( + targetNode, paymentAmt, feeLimit, defaultNumRoutes, + DefaultFinalCLTVDelta, + ) if err != nil { t.Fatalf("unable to find any routes: %v", err) } diff --git a/rpcserver.go b/rpcserver.go index 8383b6e0..549a91b2 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -3047,6 +3047,7 @@ func (r *rpcServer) QueryRoutes(ctx context.Context, // largest payment size allotted to (2^32) - 1 mSAT or 4.29 million // satoshis. amt := btcutil.Amount(in.Amt) + feeLimit := btcutil.Amount(in.FeeLimit) amtMSat := lnwire.NewMSatFromSatoshis(amt) if amtMSat > maxPaymentMSat { return nil, fmt.Errorf("payment of %v is too large, max payment "+ From df6d75a0547adb5f2face84f7ffc7f5908245bba Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Wed, 18 Apr 2018 18:13:55 -0400 Subject: [PATCH 2/8] lnrpc: use a protobuf oneof for the different types of fee limits --- lnrpc/rpc.pb.go | 1066 ++++++++++++++++++++++------------------ lnrpc/rpc.proto | 38 +- lnrpc/rpc.swagger.json | 34 +- 3 files changed, 653 insertions(+), 485 deletions(-) diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index b48d21bc..bceba06d 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -19,6 +19,7 @@ It has these top-level messages: Transaction GetTransactionsRequest TransactionDetails + FeeLimit SendRequest SendResponse SendToRouteRequest @@ -154,7 +155,7 @@ func (x NewAddressRequest_AddressType) String() string { return proto.EnumName(NewAddressRequest_AddressType_name, int32(x)) } func (NewAddressRequest_AddressType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor0, []int{20, 0} + return fileDescriptor0, []int{21, 0} } type GenSeedRequest struct { @@ -470,6 +471,115 @@ func (m *TransactionDetails) GetTransactions() []*Transaction { return nil } +type FeeLimit struct { + // Types that are valid to be assigned to Limit: + // *FeeLimit_Fixed + // *FeeLimit_Percent + Limit isFeeLimit_Limit `protobuf_oneof:"limit"` +} + +func (m *FeeLimit) Reset() { *m = FeeLimit{} } +func (m *FeeLimit) String() string { return proto.CompactTextString(m) } +func (*FeeLimit) ProtoMessage() {} +func (*FeeLimit) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +type isFeeLimit_Limit interface{ isFeeLimit_Limit() } + +type FeeLimit_Fixed struct { + Fixed int64 `protobuf:"varint,1,opt,name=fixed,oneof"` +} +type FeeLimit_Percent struct { + Percent int64 `protobuf:"varint,2,opt,name=percent,oneof"` +} + +func (*FeeLimit_Fixed) isFeeLimit_Limit() {} +func (*FeeLimit_Percent) isFeeLimit_Limit() {} + +func (m *FeeLimit) GetLimit() isFeeLimit_Limit { + if m != nil { + return m.Limit + } + return nil +} + +func (m *FeeLimit) GetFixed() int64 { + if x, ok := m.GetLimit().(*FeeLimit_Fixed); ok { + return x.Fixed + } + return 0 +} + +func (m *FeeLimit) GetPercent() int64 { + if x, ok := m.GetLimit().(*FeeLimit_Percent); ok { + return x.Percent + } + return 0 +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*FeeLimit) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _FeeLimit_OneofMarshaler, _FeeLimit_OneofUnmarshaler, _FeeLimit_OneofSizer, []interface{}{ + (*FeeLimit_Fixed)(nil), + (*FeeLimit_Percent)(nil), + } +} + +func _FeeLimit_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*FeeLimit) + // limit + switch x := m.Limit.(type) { + case *FeeLimit_Fixed: + b.EncodeVarint(1<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Fixed)) + case *FeeLimit_Percent: + b.EncodeVarint(2<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Percent)) + case nil: + default: + return fmt.Errorf("FeeLimit.Limit has unexpected type %T", x) + } + return nil +} + +func _FeeLimit_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*FeeLimit) + switch tag { + case 1: // limit.fixed + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Limit = &FeeLimit_Fixed{int64(x)} + return true, err + case 2: // limit.percent + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Limit = &FeeLimit_Percent{int64(x)} + return true, err + default: + return false, nil + } +} + +func _FeeLimit_OneofSizer(msg proto.Message) (n int) { + m := msg.(*FeeLimit) + // limit + switch x := m.Limit.(type) { + case *FeeLimit_Fixed: + n += proto.SizeVarint(1<<3 | proto.WireVarint) + n += proto.SizeVarint(uint64(x.Fixed)) + case *FeeLimit_Percent: + n += proto.SizeVarint(2<<3 | proto.WireVarint) + n += proto.SizeVarint(uint64(x.Percent)) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + type SendRequest struct { // / The identity pubkey of the payment recipient Dest []byte `protobuf:"bytes,1,opt,name=dest,proto3" json:"dest,omitempty"` @@ -486,16 +596,22 @@ type SendRequest struct { // details of the invoice, the sender has all the data necessary to send a // payment to the recipient. PaymentRequest string `protobuf:"bytes,6,opt,name=payment_request,json=paymentRequest" json:"payment_request,omitempty"` - // / The CLTV delta from the current height that should be used to set the timelock for the final hop. + // * + // The CLTV delta from the current height that should be used to set the + // timelock for the final hop. FinalCltvDelta int32 `protobuf:"varint,7,opt,name=final_cltv_delta,json=finalCltvDelta" json:"final_cltv_delta,omitempty"` - // / The maximum total fees for the payment in satoshis. - FeeLimit int64 `protobuf:"varint,8,opt,name=fee_limit" json:"fee_limit,omitempty"` + // * + // The maximum number of satoshis that will be paid as a fee of the payment. + // This value can be represented either as a percentage of the amount being + // sent, or as a fixed amount of the maximum fee the user is willing the pay to + // send the payment. + FeeLimit *FeeLimit `protobuf:"bytes,8,opt,name=fee_limit,json=feeLimit" json:"fee_limit,omitempty"` } func (m *SendRequest) Reset() { *m = SendRequest{} } func (m *SendRequest) String() string { return proto.CompactTextString(m) } func (*SendRequest) ProtoMessage() {} -func (*SendRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } +func (*SendRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } func (m *SendRequest) GetDest() []byte { if m != nil { @@ -546,11 +662,11 @@ func (m *SendRequest) GetFinalCltvDelta() int32 { return 0 } -func (m *SendRequest) GetFeeLimit() int64 { +func (m *SendRequest) GetFeeLimit() *FeeLimit { if m != nil { return m.FeeLimit } - return 0 + return nil } type SendResponse struct { @@ -562,7 +678,7 @@ type SendResponse struct { func (m *SendResponse) Reset() { *m = SendResponse{} } func (m *SendResponse) String() string { return proto.CompactTextString(m) } func (*SendResponse) ProtoMessage() {} -func (*SendResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } +func (*SendResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } func (m *SendResponse) GetPaymentError() string { if m != nil { @@ -597,7 +713,7 @@ type SendToRouteRequest struct { func (m *SendToRouteRequest) Reset() { *m = SendToRouteRequest{} } func (m *SendToRouteRequest) String() string { return proto.CompactTextString(m) } func (*SendToRouteRequest) ProtoMessage() {} -func (*SendToRouteRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } +func (*SendToRouteRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } func (m *SendToRouteRequest) GetPaymentHash() []byte { if m != nil { @@ -632,7 +748,7 @@ type ChannelPoint struct { func (m *ChannelPoint) Reset() { *m = ChannelPoint{} } func (m *ChannelPoint) String() string { return proto.CompactTextString(m) } func (*ChannelPoint) ProtoMessage() {} -func (*ChannelPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } +func (*ChannelPoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } type isChannelPoint_FundingTxid interface{ isChannelPoint_FundingTxid() } @@ -750,7 +866,7 @@ type LightningAddress struct { func (m *LightningAddress) Reset() { *m = LightningAddress{} } func (m *LightningAddress) String() string { return proto.CompactTextString(m) } func (*LightningAddress) ProtoMessage() {} -func (*LightningAddress) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } +func (*LightningAddress) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } func (m *LightningAddress) GetPubkey() string { if m != nil { @@ -778,7 +894,7 @@ type SendManyRequest struct { func (m *SendManyRequest) Reset() { *m = SendManyRequest{} } func (m *SendManyRequest) String() string { return proto.CompactTextString(m) } func (*SendManyRequest) ProtoMessage() {} -func (*SendManyRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } +func (*SendManyRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } func (m *SendManyRequest) GetAddrToAmount() map[string]int64 { if m != nil { @@ -809,7 +925,7 @@ type SendManyResponse struct { func (m *SendManyResponse) Reset() { *m = SendManyResponse{} } func (m *SendManyResponse) String() string { return proto.CompactTextString(m) } func (*SendManyResponse) ProtoMessage() {} -func (*SendManyResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } +func (*SendManyResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } func (m *SendManyResponse) GetTxid() string { if m != nil { @@ -832,7 +948,7 @@ type SendCoinsRequest struct { func (m *SendCoinsRequest) Reset() { *m = SendCoinsRequest{} } func (m *SendCoinsRequest) String() string { return proto.CompactTextString(m) } func (*SendCoinsRequest) ProtoMessage() {} -func (*SendCoinsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } +func (*SendCoinsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } func (m *SendCoinsRequest) GetAddr() string { if m != nil { @@ -870,7 +986,7 @@ type SendCoinsResponse struct { func (m *SendCoinsResponse) Reset() { *m = SendCoinsResponse{} } func (m *SendCoinsResponse) String() string { return proto.CompactTextString(m) } func (*SendCoinsResponse) ProtoMessage() {} -func (*SendCoinsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } +func (*SendCoinsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} } func (m *SendCoinsResponse) GetTxid() string { if m != nil { @@ -893,7 +1009,7 @@ type NewAddressRequest struct { func (m *NewAddressRequest) Reset() { *m = NewAddressRequest{} } func (m *NewAddressRequest) String() string { return proto.CompactTextString(m) } func (*NewAddressRequest) ProtoMessage() {} -func (*NewAddressRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} } +func (*NewAddressRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} } func (m *NewAddressRequest) GetType() NewAddressRequest_AddressType { if m != nil { @@ -908,7 +1024,7 @@ type NewWitnessAddressRequest struct { func (m *NewWitnessAddressRequest) Reset() { *m = NewWitnessAddressRequest{} } func (m *NewWitnessAddressRequest) String() string { return proto.CompactTextString(m) } func (*NewWitnessAddressRequest) ProtoMessage() {} -func (*NewWitnessAddressRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} } +func (*NewWitnessAddressRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } type NewAddressResponse struct { // / The newly generated wallet address @@ -918,7 +1034,7 @@ type NewAddressResponse struct { func (m *NewAddressResponse) Reset() { *m = NewAddressResponse{} } func (m *NewAddressResponse) String() string { return proto.CompactTextString(m) } func (*NewAddressResponse) ProtoMessage() {} -func (*NewAddressResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } +func (*NewAddressResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } func (m *NewAddressResponse) GetAddress() string { if m != nil { @@ -935,7 +1051,7 @@ type SignMessageRequest struct { func (m *SignMessageRequest) Reset() { *m = SignMessageRequest{} } func (m *SignMessageRequest) String() string { return proto.CompactTextString(m) } func (*SignMessageRequest) ProtoMessage() {} -func (*SignMessageRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } +func (*SignMessageRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } func (m *SignMessageRequest) GetMsg() []byte { if m != nil { @@ -952,7 +1068,7 @@ type SignMessageResponse struct { func (m *SignMessageResponse) Reset() { *m = SignMessageResponse{} } func (m *SignMessageResponse) String() string { return proto.CompactTextString(m) } func (*SignMessageResponse) ProtoMessage() {} -func (*SignMessageResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } +func (*SignMessageResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} } func (m *SignMessageResponse) GetSignature() string { if m != nil { @@ -971,7 +1087,7 @@ type VerifyMessageRequest struct { func (m *VerifyMessageRequest) Reset() { *m = VerifyMessageRequest{} } func (m *VerifyMessageRequest) String() string { return proto.CompactTextString(m) } func (*VerifyMessageRequest) ProtoMessage() {} -func (*VerifyMessageRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} } +func (*VerifyMessageRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} } func (m *VerifyMessageRequest) GetMsg() []byte { if m != nil { @@ -997,7 +1113,7 @@ type VerifyMessageResponse struct { func (m *VerifyMessageResponse) Reset() { *m = VerifyMessageResponse{} } func (m *VerifyMessageResponse) String() string { return proto.CompactTextString(m) } func (*VerifyMessageResponse) ProtoMessage() {} -func (*VerifyMessageResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} } +func (*VerifyMessageResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} } func (m *VerifyMessageResponse) GetValid() bool { if m != nil { @@ -1024,7 +1140,7 @@ type ConnectPeerRequest struct { func (m *ConnectPeerRequest) Reset() { *m = ConnectPeerRequest{} } func (m *ConnectPeerRequest) String() string { return proto.CompactTextString(m) } func (*ConnectPeerRequest) ProtoMessage() {} -func (*ConnectPeerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} } +func (*ConnectPeerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} } func (m *ConnectPeerRequest) GetAddr() *LightningAddress { if m != nil { @@ -1046,7 +1162,7 @@ type ConnectPeerResponse struct { func (m *ConnectPeerResponse) Reset() { *m = ConnectPeerResponse{} } func (m *ConnectPeerResponse) String() string { return proto.CompactTextString(m) } func (*ConnectPeerResponse) ProtoMessage() {} -func (*ConnectPeerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} } +func (*ConnectPeerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} } type DisconnectPeerRequest struct { // / The pubkey of the node to disconnect from @@ -1056,7 +1172,7 @@ type DisconnectPeerRequest struct { func (m *DisconnectPeerRequest) Reset() { *m = DisconnectPeerRequest{} } func (m *DisconnectPeerRequest) String() string { return proto.CompactTextString(m) } func (*DisconnectPeerRequest) ProtoMessage() {} -func (*DisconnectPeerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} } +func (*DisconnectPeerRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} } func (m *DisconnectPeerRequest) GetPubKey() string { if m != nil { @@ -1071,7 +1187,7 @@ type DisconnectPeerResponse struct { func (m *DisconnectPeerResponse) Reset() { *m = DisconnectPeerResponse{} } func (m *DisconnectPeerResponse) String() string { return proto.CompactTextString(m) } func (*DisconnectPeerResponse) ProtoMessage() {} -func (*DisconnectPeerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} } +func (*DisconnectPeerResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} } type HTLC struct { Incoming bool `protobuf:"varint,1,opt,name=incoming" json:"incoming,omitempty"` @@ -1083,7 +1199,7 @@ type HTLC struct { func (m *HTLC) Reset() { *m = HTLC{} } func (m *HTLC) String() string { return proto.CompactTextString(m) } func (*HTLC) ProtoMessage() {} -func (*HTLC) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} } +func (*HTLC) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} } func (m *HTLC) GetIncoming() bool { if m != nil { @@ -1173,7 +1289,7 @@ type Channel struct { func (m *Channel) Reset() { *m = Channel{} } func (m *Channel) String() string { return proto.CompactTextString(m) } func (*Channel) ProtoMessage() {} -func (*Channel) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} } +func (*Channel) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } func (m *Channel) GetActive() bool { if m != nil { @@ -1304,7 +1420,7 @@ type ListChannelsRequest struct { func (m *ListChannelsRequest) Reset() { *m = ListChannelsRequest{} } func (m *ListChannelsRequest) String() string { return proto.CompactTextString(m) } func (*ListChannelsRequest) ProtoMessage() {} -func (*ListChannelsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{33} } +func (*ListChannelsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } func (m *ListChannelsRequest) GetActiveOnly() bool { if m != nil { @@ -1342,7 +1458,7 @@ type ListChannelsResponse struct { func (m *ListChannelsResponse) Reset() { *m = ListChannelsResponse{} } func (m *ListChannelsResponse) String() string { return proto.CompactTextString(m) } func (*ListChannelsResponse) ProtoMessage() {} -func (*ListChannelsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{34} } +func (*ListChannelsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } func (m *ListChannelsResponse) GetChannels() []*Channel { if m != nil { @@ -1373,7 +1489,7 @@ type Peer struct { func (m *Peer) Reset() { *m = Peer{} } func (m *Peer) String() string { return proto.CompactTextString(m) } func (*Peer) ProtoMessage() {} -func (*Peer) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } +func (*Peer) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } func (m *Peer) GetPubKey() string { if m != nil { @@ -1437,7 +1553,7 @@ type ListPeersRequest struct { func (m *ListPeersRequest) Reset() { *m = ListPeersRequest{} } func (m *ListPeersRequest) String() string { return proto.CompactTextString(m) } func (*ListPeersRequest) ProtoMessage() {} -func (*ListPeersRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } +func (*ListPeersRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } type ListPeersResponse struct { // / The list of currently connected peers @@ -1447,7 +1563,7 @@ type ListPeersResponse struct { func (m *ListPeersResponse) Reset() { *m = ListPeersResponse{} } func (m *ListPeersResponse) String() string { return proto.CompactTextString(m) } func (*ListPeersResponse) ProtoMessage() {} -func (*ListPeersResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } +func (*ListPeersResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} } func (m *ListPeersResponse) GetPeers() []*Peer { if m != nil { @@ -1462,7 +1578,7 @@ type GetInfoRequest struct { func (m *GetInfoRequest) Reset() { *m = GetInfoRequest{} } func (m *GetInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetInfoRequest) ProtoMessage() {} -func (*GetInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} } +func (*GetInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} } type GetInfoResponse struct { // / The identity pubkey of the current node. @@ -1496,7 +1612,7 @@ type GetInfoResponse struct { func (m *GetInfoResponse) Reset() { *m = GetInfoResponse{} } func (m *GetInfoResponse) String() string { return proto.CompactTextString(m) } func (*GetInfoResponse) ProtoMessage() {} -func (*GetInfoResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} } +func (*GetInfoResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} } func (m *GetInfoResponse) GetIdentityPubkey() string { if m != nil { @@ -1598,7 +1714,7 @@ type ConfirmationUpdate struct { func (m *ConfirmationUpdate) Reset() { *m = ConfirmationUpdate{} } func (m *ConfirmationUpdate) String() string { return proto.CompactTextString(m) } func (*ConfirmationUpdate) ProtoMessage() {} -func (*ConfirmationUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} } +func (*ConfirmationUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} } func (m *ConfirmationUpdate) GetBlockSha() []byte { if m != nil { @@ -1628,7 +1744,7 @@ type ChannelOpenUpdate struct { func (m *ChannelOpenUpdate) Reset() { *m = ChannelOpenUpdate{} } func (m *ChannelOpenUpdate) String() string { return proto.CompactTextString(m) } func (*ChannelOpenUpdate) ProtoMessage() {} -func (*ChannelOpenUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} } +func (*ChannelOpenUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{42} } func (m *ChannelOpenUpdate) GetChannelPoint() *ChannelPoint { if m != nil { @@ -1645,7 +1761,7 @@ type ChannelCloseUpdate struct { func (m *ChannelCloseUpdate) Reset() { *m = ChannelCloseUpdate{} } func (m *ChannelCloseUpdate) String() string { return proto.CompactTextString(m) } func (*ChannelCloseUpdate) ProtoMessage() {} -func (*ChannelCloseUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{42} } +func (*ChannelCloseUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{43} } func (m *ChannelCloseUpdate) GetClosingTxid() []byte { if m != nil { @@ -1678,7 +1794,7 @@ type CloseChannelRequest struct { func (m *CloseChannelRequest) Reset() { *m = CloseChannelRequest{} } func (m *CloseChannelRequest) String() string { return proto.CompactTextString(m) } func (*CloseChannelRequest) ProtoMessage() {} -func (*CloseChannelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{43} } +func (*CloseChannelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} } func (m *CloseChannelRequest) GetChannelPoint() *ChannelPoint { if m != nil { @@ -1719,7 +1835,7 @@ type CloseStatusUpdate struct { func (m *CloseStatusUpdate) Reset() { *m = CloseStatusUpdate{} } func (m *CloseStatusUpdate) String() string { return proto.CompactTextString(m) } func (*CloseStatusUpdate) ProtoMessage() {} -func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} } +func (*CloseStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{45} } type isCloseStatusUpdate_Update interface{ isCloseStatusUpdate_Update() } @@ -1866,7 +1982,7 @@ type PendingUpdate struct { func (m *PendingUpdate) Reset() { *m = PendingUpdate{} } func (m *PendingUpdate) String() string { return proto.CompactTextString(m) } func (*PendingUpdate) ProtoMessage() {} -func (*PendingUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{45} } +func (*PendingUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{46} } func (m *PendingUpdate) GetTxid() []byte { if m != nil { @@ -1906,7 +2022,7 @@ type OpenChannelRequest struct { func (m *OpenChannelRequest) Reset() { *m = OpenChannelRequest{} } func (m *OpenChannelRequest) String() string { return proto.CompactTextString(m) } func (*OpenChannelRequest) ProtoMessage() {} -func (*OpenChannelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{46} } +func (*OpenChannelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{47} } func (m *OpenChannelRequest) GetNodePubkey() []byte { if m != nil { @@ -1982,7 +2098,7 @@ type OpenStatusUpdate struct { func (m *OpenStatusUpdate) Reset() { *m = OpenStatusUpdate{} } func (m *OpenStatusUpdate) String() string { return proto.CompactTextString(m) } func (*OpenStatusUpdate) ProtoMessage() {} -func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{47} } +func (*OpenStatusUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{48} } type isOpenStatusUpdate_Update interface{ isOpenStatusUpdate_Update() } @@ -2142,7 +2258,7 @@ type PendingHTLC struct { func (m *PendingHTLC) Reset() { *m = PendingHTLC{} } func (m *PendingHTLC) String() string { return proto.CompactTextString(m) } func (*PendingHTLC) ProtoMessage() {} -func (*PendingHTLC) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{48} } +func (*PendingHTLC) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{49} } func (m *PendingHTLC) GetIncoming() bool { if m != nil { @@ -2192,7 +2308,7 @@ type PendingChannelsRequest struct { func (m *PendingChannelsRequest) Reset() { *m = PendingChannelsRequest{} } func (m *PendingChannelsRequest) String() string { return proto.CompactTextString(m) } func (*PendingChannelsRequest) ProtoMessage() {} -func (*PendingChannelsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{49} } +func (*PendingChannelsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{50} } type PendingChannelsResponse struct { // / The balance in satoshis encumbered in pending channels @@ -2210,7 +2326,7 @@ type PendingChannelsResponse struct { func (m *PendingChannelsResponse) Reset() { *m = PendingChannelsResponse{} } func (m *PendingChannelsResponse) String() string { return proto.CompactTextString(m) } func (*PendingChannelsResponse) ProtoMessage() {} -func (*PendingChannelsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{50} } +func (*PendingChannelsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{51} } func (m *PendingChannelsResponse) GetTotalLimboBalance() int64 { if m != nil { @@ -2261,7 +2377,7 @@ func (m *PendingChannelsResponse_PendingChannel) Reset() { func (m *PendingChannelsResponse_PendingChannel) String() string { return proto.CompactTextString(m) } func (*PendingChannelsResponse_PendingChannel) ProtoMessage() {} func (*PendingChannelsResponse_PendingChannel) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{50, 0} + return fileDescriptor0, []int{51, 0} } func (m *PendingChannelsResponse_PendingChannel) GetRemoteNodePub() string { @@ -2328,7 +2444,7 @@ func (m *PendingChannelsResponse_PendingOpenChannel) String() string { } func (*PendingChannelsResponse_PendingOpenChannel) ProtoMessage() {} func (*PendingChannelsResponse_PendingOpenChannel) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{50, 1} + return fileDescriptor0, []int{51, 1} } func (m *PendingChannelsResponse_PendingOpenChannel) GetChannel() *PendingChannelsResponse_PendingChannel { @@ -2381,7 +2497,7 @@ func (m *PendingChannelsResponse_WaitingCloseChannel) String() string { } func (*PendingChannelsResponse_WaitingCloseChannel) ProtoMessage() {} func (*PendingChannelsResponse_WaitingCloseChannel) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{50, 2} + return fileDescriptor0, []int{51, 2} } func (m *PendingChannelsResponse_WaitingCloseChannel) GetChannel() *PendingChannelsResponse_PendingChannel { @@ -2409,7 +2525,7 @@ func (m *PendingChannelsResponse_ClosedChannel) Reset() { *m = PendingCh func (m *PendingChannelsResponse_ClosedChannel) String() string { return proto.CompactTextString(m) } func (*PendingChannelsResponse_ClosedChannel) ProtoMessage() {} func (*PendingChannelsResponse_ClosedChannel) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{50, 3} + return fileDescriptor0, []int{51, 3} } func (m *PendingChannelsResponse_ClosedChannel) GetChannel() *PendingChannelsResponse_PendingChannel { @@ -2453,7 +2569,7 @@ func (m *PendingChannelsResponse_ForceClosedChannel) String() string { } func (*PendingChannelsResponse_ForceClosedChannel) ProtoMessage() {} func (*PendingChannelsResponse_ForceClosedChannel) Descriptor() ([]byte, []int) { - return fileDescriptor0, []int{50, 4} + return fileDescriptor0, []int{51, 4} } func (m *PendingChannelsResponse_ForceClosedChannel) GetChannel() *PendingChannelsResponse_PendingChannel { @@ -2511,7 +2627,7 @@ type WalletBalanceRequest struct { func (m *WalletBalanceRequest) Reset() { *m = WalletBalanceRequest{} } func (m *WalletBalanceRequest) String() string { return proto.CompactTextString(m) } func (*WalletBalanceRequest) ProtoMessage() {} -func (*WalletBalanceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{51} } +func (*WalletBalanceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{52} } type WalletBalanceResponse struct { // / The balance of the wallet @@ -2525,7 +2641,7 @@ type WalletBalanceResponse struct { func (m *WalletBalanceResponse) Reset() { *m = WalletBalanceResponse{} } func (m *WalletBalanceResponse) String() string { return proto.CompactTextString(m) } func (*WalletBalanceResponse) ProtoMessage() {} -func (*WalletBalanceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{52} } +func (*WalletBalanceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{53} } func (m *WalletBalanceResponse) GetTotalBalance() int64 { if m != nil { @@ -2554,7 +2670,7 @@ type ChannelBalanceRequest struct { func (m *ChannelBalanceRequest) Reset() { *m = ChannelBalanceRequest{} } func (m *ChannelBalanceRequest) String() string { return proto.CompactTextString(m) } func (*ChannelBalanceRequest) ProtoMessage() {} -func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{53} } +func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{54} } type ChannelBalanceResponse struct { // / Sum of channels balances denominated in satoshis @@ -2566,7 +2682,7 @@ type ChannelBalanceResponse struct { func (m *ChannelBalanceResponse) Reset() { *m = ChannelBalanceResponse{} } func (m *ChannelBalanceResponse) String() string { return proto.CompactTextString(m) } func (*ChannelBalanceResponse) ProtoMessage() {} -func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{54} } +func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{55} } func (m *ChannelBalanceResponse) GetBalance() int64 { if m != nil { @@ -2591,14 +2707,18 @@ type QueryRoutesRequest struct { NumRoutes int32 `protobuf:"varint,3,opt,name=num_routes,json=numRoutes" json:"num_routes,omitempty"` // / 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" json:"final_cltv_delta,omitempty"` - // / The maximum total fees for the route in satoshis. - FeeLimit int64 `protobuf:"varint,5,opt,name=fee_limit,json=feeLimit" json:"fee_limit,omitempty"` + // * + // The maximum number of satoshis that will be paid as a fee of the payment. + // This value can be represented either as a percentage of the amount being + // sent, or as a fixed amount of the maximum fee the user is willing the pay to + // send the payment. + FeeLimit *FeeLimit `protobuf:"bytes,5,opt,name=fee_limit,json=feeLimit" json:"fee_limit,omitempty"` } func (m *QueryRoutesRequest) Reset() { *m = QueryRoutesRequest{} } func (m *QueryRoutesRequest) String() string { return proto.CompactTextString(m) } func (*QueryRoutesRequest) ProtoMessage() {} -func (*QueryRoutesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{55} } +func (*QueryRoutesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{56} } func (m *QueryRoutesRequest) GetPubKey() string { if m != nil { @@ -2628,11 +2748,11 @@ func (m *QueryRoutesRequest) GetFinalCltvDelta() int32 { return 0 } -func (m *QueryRoutesRequest) GetFeeLimit() int64 { +func (m *QueryRoutesRequest) GetFeeLimit() *FeeLimit { if m != nil { return m.FeeLimit } - return 0 + return nil } type QueryRoutesResponse struct { @@ -2642,7 +2762,7 @@ type QueryRoutesResponse struct { func (m *QueryRoutesResponse) Reset() { *m = QueryRoutesResponse{} } func (m *QueryRoutesResponse) String() string { return proto.CompactTextString(m) } func (*QueryRoutesResponse) ProtoMessage() {} -func (*QueryRoutesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{56} } +func (*QueryRoutesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{57} } func (m *QueryRoutesResponse) GetRoutes() []*Route { if m != nil { @@ -2668,7 +2788,7 @@ type Hop struct { func (m *Hop) Reset() { *m = Hop{} } func (m *Hop) String() string { return proto.CompactTextString(m) } func (*Hop) ProtoMessage() {} -func (*Hop) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{57} } +func (*Hop) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{58} } func (m *Hop) GetChanId() uint64 { if m != nil { @@ -2758,7 +2878,7 @@ type Route struct { func (m *Route) Reset() { *m = Route{} } func (m *Route) String() string { return proto.CompactTextString(m) } func (*Route) ProtoMessage() {} -func (*Route) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{58} } +func (*Route) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{59} } func (m *Route) GetTotalTimeLock() uint32 { if m != nil { @@ -2810,7 +2930,7 @@ type NodeInfoRequest struct { func (m *NodeInfoRequest) Reset() { *m = NodeInfoRequest{} } func (m *NodeInfoRequest) String() string { return proto.CompactTextString(m) } func (*NodeInfoRequest) ProtoMessage() {} -func (*NodeInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{59} } +func (*NodeInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{60} } func (m *NodeInfoRequest) GetPubKey() string { if m != nil { @@ -2833,7 +2953,7 @@ type NodeInfo struct { func (m *NodeInfo) Reset() { *m = NodeInfo{} } func (m *NodeInfo) String() string { return proto.CompactTextString(m) } func (*NodeInfo) ProtoMessage() {} -func (*NodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{60} } +func (*NodeInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{61} } func (m *NodeInfo) GetNode() *LightningNode { if m != nil { @@ -2872,7 +2992,7 @@ type LightningNode struct { func (m *LightningNode) Reset() { *m = LightningNode{} } func (m *LightningNode) String() string { return proto.CompactTextString(m) } func (*LightningNode) ProtoMessage() {} -func (*LightningNode) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{61} } +func (*LightningNode) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{62} } func (m *LightningNode) GetLastUpdate() uint32 { if m != nil { @@ -2917,7 +3037,7 @@ type NodeAddress struct { func (m *NodeAddress) Reset() { *m = NodeAddress{} } func (m *NodeAddress) String() string { return proto.CompactTextString(m) } func (*NodeAddress) ProtoMessage() {} -func (*NodeAddress) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{62} } +func (*NodeAddress) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{63} } func (m *NodeAddress) GetNetwork() string { if m != nil { @@ -2943,7 +3063,7 @@ type RoutingPolicy struct { func (m *RoutingPolicy) Reset() { *m = RoutingPolicy{} } func (m *RoutingPolicy) String() string { return proto.CompactTextString(m) } func (*RoutingPolicy) ProtoMessage() {} -func (*RoutingPolicy) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{63} } +func (*RoutingPolicy) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{64} } func (m *RoutingPolicy) GetTimeLockDelta() uint32 { if m != nil { @@ -2997,7 +3117,7 @@ type ChannelEdge struct { func (m *ChannelEdge) Reset() { *m = ChannelEdge{} } func (m *ChannelEdge) String() string { return proto.CompactTextString(m) } func (*ChannelEdge) ProtoMessage() {} -func (*ChannelEdge) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{64} } +func (*ChannelEdge) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{65} } func (m *ChannelEdge) GetChannelId() uint64 { if m != nil { @@ -3061,7 +3181,7 @@ type ChannelGraphRequest struct { func (m *ChannelGraphRequest) Reset() { *m = ChannelGraphRequest{} } func (m *ChannelGraphRequest) String() string { return proto.CompactTextString(m) } func (*ChannelGraphRequest) ProtoMessage() {} -func (*ChannelGraphRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{65} } +func (*ChannelGraphRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{66} } // / Returns a new instance of the directed channel graph. type ChannelGraph struct { @@ -3074,7 +3194,7 @@ type ChannelGraph struct { func (m *ChannelGraph) Reset() { *m = ChannelGraph{} } func (m *ChannelGraph) String() string { return proto.CompactTextString(m) } func (*ChannelGraph) ProtoMessage() {} -func (*ChannelGraph) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{66} } +func (*ChannelGraph) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{67} } func (m *ChannelGraph) GetNodes() []*LightningNode { if m != nil { @@ -3101,7 +3221,7 @@ type ChanInfoRequest struct { func (m *ChanInfoRequest) Reset() { *m = ChanInfoRequest{} } func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) } func (*ChanInfoRequest) ProtoMessage() {} -func (*ChanInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{67} } +func (*ChanInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{68} } func (m *ChanInfoRequest) GetChanId() uint64 { if m != nil { @@ -3116,7 +3236,7 @@ type NetworkInfoRequest struct { func (m *NetworkInfoRequest) Reset() { *m = NetworkInfoRequest{} } func (m *NetworkInfoRequest) String() string { return proto.CompactTextString(m) } func (*NetworkInfoRequest) ProtoMessage() {} -func (*NetworkInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{68} } +func (*NetworkInfoRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{69} } type NetworkInfo struct { GraphDiameter uint32 `protobuf:"varint,1,opt,name=graph_diameter" json:"graph_diameter,omitempty"` @@ -3133,7 +3253,7 @@ type NetworkInfo struct { func (m *NetworkInfo) Reset() { *m = NetworkInfo{} } func (m *NetworkInfo) String() string { return proto.CompactTextString(m) } func (*NetworkInfo) ProtoMessage() {} -func (*NetworkInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{69} } +func (*NetworkInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{70} } func (m *NetworkInfo) GetGraphDiameter() uint32 { if m != nil { @@ -3204,7 +3324,7 @@ type StopRequest struct { func (m *StopRequest) Reset() { *m = StopRequest{} } func (m *StopRequest) String() string { return proto.CompactTextString(m) } func (*StopRequest) ProtoMessage() {} -func (*StopRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{70} } +func (*StopRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{71} } type StopResponse struct { } @@ -3212,7 +3332,7 @@ type StopResponse struct { func (m *StopResponse) Reset() { *m = StopResponse{} } func (m *StopResponse) String() string { return proto.CompactTextString(m) } func (*StopResponse) ProtoMessage() {} -func (*StopResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{71} } +func (*StopResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{72} } type GraphTopologySubscription struct { } @@ -3220,7 +3340,7 @@ type GraphTopologySubscription struct { func (m *GraphTopologySubscription) Reset() { *m = GraphTopologySubscription{} } func (m *GraphTopologySubscription) String() string { return proto.CompactTextString(m) } func (*GraphTopologySubscription) ProtoMessage() {} -func (*GraphTopologySubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{72} } +func (*GraphTopologySubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{73} } type GraphTopologyUpdate struct { NodeUpdates []*NodeUpdate `protobuf:"bytes,1,rep,name=node_updates,json=nodeUpdates" json:"node_updates,omitempty"` @@ -3231,7 +3351,7 @@ type GraphTopologyUpdate struct { func (m *GraphTopologyUpdate) Reset() { *m = GraphTopologyUpdate{} } func (m *GraphTopologyUpdate) String() string { return proto.CompactTextString(m) } func (*GraphTopologyUpdate) ProtoMessage() {} -func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{73} } +func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{74} } func (m *GraphTopologyUpdate) GetNodeUpdates() []*NodeUpdate { if m != nil { @@ -3264,7 +3384,7 @@ type NodeUpdate struct { func (m *NodeUpdate) Reset() { *m = NodeUpdate{} } func (m *NodeUpdate) String() string { return proto.CompactTextString(m) } func (*NodeUpdate) ProtoMessage() {} -func (*NodeUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{74} } +func (*NodeUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{75} } func (m *NodeUpdate) GetAddresses() []string { if m != nil { @@ -3310,7 +3430,7 @@ type ChannelEdgeUpdate struct { func (m *ChannelEdgeUpdate) Reset() { *m = ChannelEdgeUpdate{} } func (m *ChannelEdgeUpdate) String() string { return proto.CompactTextString(m) } func (*ChannelEdgeUpdate) ProtoMessage() {} -func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{75} } +func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{76} } func (m *ChannelEdgeUpdate) GetChanId() uint64 { if m != nil { @@ -3368,7 +3488,7 @@ type ClosedChannelUpdate struct { func (m *ClosedChannelUpdate) Reset() { *m = ClosedChannelUpdate{} } func (m *ClosedChannelUpdate) String() string { return proto.CompactTextString(m) } func (*ClosedChannelUpdate) ProtoMessage() {} -func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{76} } +func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{77} } func (m *ClosedChannelUpdate) GetChanId() uint64 { if m != nil { @@ -3416,7 +3536,7 @@ type HopHint struct { func (m *HopHint) Reset() { *m = HopHint{} } func (m *HopHint) String() string { return proto.CompactTextString(m) } func (*HopHint) ProtoMessage() {} -func (*HopHint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{77} } +func (*HopHint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{78} } func (m *HopHint) GetNodeId() string { if m != nil { @@ -3463,7 +3583,7 @@ type RouteHint struct { func (m *RouteHint) Reset() { *m = RouteHint{} } func (m *RouteHint) String() string { return proto.CompactTextString(m) } func (*RouteHint) ProtoMessage() {} -func (*RouteHint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{78} } +func (*RouteHint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{79} } func (m *RouteHint) GetHopHints() []*HopHint { if m != nil { @@ -3522,7 +3642,7 @@ type Invoice struct { func (m *Invoice) Reset() { *m = Invoice{} } func (m *Invoice) String() string { return proto.CompactTextString(m) } func (*Invoice) ProtoMessage() {} -func (*Invoice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{79} } +func (*Invoice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{80} } func (m *Invoice) GetMemo() string { if m != nil { @@ -3641,7 +3761,7 @@ type AddInvoiceResponse struct { func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} } func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*AddInvoiceResponse) ProtoMessage() {} -func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{80} } +func (*AddInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{81} } func (m *AddInvoiceResponse) GetRHash() []byte { if m != nil { @@ -3669,7 +3789,7 @@ type PaymentHash struct { func (m *PaymentHash) Reset() { *m = PaymentHash{} } func (m *PaymentHash) String() string { return proto.CompactTextString(m) } func (*PaymentHash) ProtoMessage() {} -func (*PaymentHash) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{81} } +func (*PaymentHash) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{82} } func (m *PaymentHash) GetRHashStr() string { if m != nil { @@ -3693,7 +3813,7 @@ type ListInvoiceRequest struct { func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} } func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) } func (*ListInvoiceRequest) ProtoMessage() {} -func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{82} } +func (*ListInvoiceRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{83} } func (m *ListInvoiceRequest) GetPendingOnly() bool { if m != nil { @@ -3709,7 +3829,7 @@ type ListInvoiceResponse struct { func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} } func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) } func (*ListInvoiceResponse) ProtoMessage() {} -func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{83} } +func (*ListInvoiceResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{84} } func (m *ListInvoiceResponse) GetInvoices() []*Invoice { if m != nil { @@ -3724,7 +3844,7 @@ type InvoiceSubscription struct { func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} } func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) } func (*InvoiceSubscription) ProtoMessage() {} -func (*InvoiceSubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{84} } +func (*InvoiceSubscription) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{85} } type Payment struct { // / The payment hash @@ -3744,7 +3864,7 @@ type Payment struct { func (m *Payment) Reset() { *m = Payment{} } func (m *Payment) String() string { return proto.CompactTextString(m) } func (*Payment) ProtoMessage() {} -func (*Payment) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{85} } +func (*Payment) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{86} } func (m *Payment) GetPaymentHash() string { if m != nil { @@ -3794,7 +3914,7 @@ type ListPaymentsRequest struct { func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} } func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*ListPaymentsRequest) ProtoMessage() {} -func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{86} } +func (*ListPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{87} } type ListPaymentsResponse struct { // / The list of payments @@ -3804,7 +3924,7 @@ type ListPaymentsResponse struct { func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} } func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*ListPaymentsResponse) ProtoMessage() {} -func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{87} } +func (*ListPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{88} } func (m *ListPaymentsResponse) GetPayments() []*Payment { if m != nil { @@ -3819,7 +3939,7 @@ type DeleteAllPaymentsRequest struct { func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsRequest{} } func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsRequest) ProtoMessage() {} -func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{88} } +func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{89} } type DeleteAllPaymentsResponse struct { } @@ -3827,7 +3947,7 @@ type DeleteAllPaymentsResponse struct { func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResponse{} } func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) } func (*DeleteAllPaymentsResponse) ProtoMessage() {} -func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{89} } +func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{90} } type DebugLevelRequest struct { Show bool `protobuf:"varint,1,opt,name=show" json:"show,omitempty"` @@ -3837,7 +3957,7 @@ type DebugLevelRequest struct { func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} } func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) } func (*DebugLevelRequest) ProtoMessage() {} -func (*DebugLevelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{90} } +func (*DebugLevelRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{91} } func (m *DebugLevelRequest) GetShow() bool { if m != nil { @@ -3860,7 +3980,7 @@ type DebugLevelResponse struct { func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} } func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) } func (*DebugLevelResponse) ProtoMessage() {} -func (*DebugLevelResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{91} } +func (*DebugLevelResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{92} } func (m *DebugLevelResponse) GetSubSystems() string { if m != nil { @@ -3877,7 +3997,7 @@ type PayReqString struct { func (m *PayReqString) Reset() { *m = PayReqString{} } func (m *PayReqString) String() string { return proto.CompactTextString(m) } func (*PayReqString) ProtoMessage() {} -func (*PayReqString) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{92} } +func (*PayReqString) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{93} } func (m *PayReqString) GetPayReq() string { if m != nil { @@ -3902,7 +4022,7 @@ type PayReq struct { func (m *PayReq) Reset() { *m = PayReq{} } func (m *PayReq) String() string { return proto.CompactTextString(m) } func (*PayReq) ProtoMessage() {} -func (*PayReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{93} } +func (*PayReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{94} } func (m *PayReq) GetDestination() string { if m != nil { @@ -3980,7 +4100,7 @@ type FeeReportRequest struct { func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} } func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) } func (*FeeReportRequest) ProtoMessage() {} -func (*FeeReportRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{94} } +func (*FeeReportRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{95} } type ChannelFeeReport struct { // / The channel that this fee report belongs to. @@ -3996,7 +4116,7 @@ type ChannelFeeReport struct { func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} } func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) } func (*ChannelFeeReport) ProtoMessage() {} -func (*ChannelFeeReport) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{95} } +func (*ChannelFeeReport) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{96} } func (m *ChannelFeeReport) GetChanPoint() string { if m != nil { @@ -4040,7 +4160,7 @@ type FeeReportResponse struct { func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} } func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) } func (*FeeReportResponse) ProtoMessage() {} -func (*FeeReportResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{96} } +func (*FeeReportResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{97} } func (m *FeeReportResponse) GetChannelFees() []*ChannelFeeReport { if m != nil { @@ -4086,7 +4206,7 @@ type PolicyUpdateRequest struct { func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} } func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateRequest) ProtoMessage() {} -func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{97} } +func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{98} } type isPolicyUpdateRequest_Scope interface{ isPolicyUpdateRequest_Scope() } @@ -4221,7 +4341,7 @@ type PolicyUpdateResponse struct { func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} } func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) } func (*PolicyUpdateResponse) ProtoMessage() {} -func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{98} } +func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{99} } type ForwardingHistoryRequest struct { // / Start time is the starting point of the forwarding history request. All records beyond this point will be included, respecting the end time, and the index offset. @@ -4237,7 +4357,7 @@ type ForwardingHistoryRequest struct { func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryRequest{} } func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryRequest) ProtoMessage() {} -func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{99} } +func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{100} } func (m *ForwardingHistoryRequest) GetStartTime() uint64 { if m != nil { @@ -4285,7 +4405,7 @@ type ForwardingEvent struct { func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} } func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) } func (*ForwardingEvent) ProtoMessage() {} -func (*ForwardingEvent) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{100} } +func (*ForwardingEvent) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{101} } func (m *ForwardingEvent) GetTimestamp() uint64 { if m != nil { @@ -4339,7 +4459,7 @@ type ForwardingHistoryResponse struct { func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResponse{} } func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) } func (*ForwardingHistoryResponse) ProtoMessage() {} -func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{101} } +func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{102} } func (m *ForwardingHistoryResponse) GetForwardingEvents() []*ForwardingEvent { if m != nil { @@ -4367,6 +4487,7 @@ func init() { proto.RegisterType((*Transaction)(nil), "lnrpc.Transaction") proto.RegisterType((*GetTransactionsRequest)(nil), "lnrpc.GetTransactionsRequest") proto.RegisterType((*TransactionDetails)(nil), "lnrpc.TransactionDetails") + proto.RegisterType((*FeeLimit)(nil), "lnrpc.FeeLimit") proto.RegisterType((*SendRequest)(nil), "lnrpc.SendRequest") proto.RegisterType((*SendResponse)(nil), "lnrpc.SendResponse") proto.RegisterType((*SendToRouteRequest)(nil), "lnrpc.SendToRouteRequest") @@ -6630,369 +6751,372 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 5813 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3c, 0x4b, 0x8c, 0x24, 0xc9, - 0x55, 0x93, 0xd5, 0xd5, 0x9f, 0x7a, 0x55, 0x5d, 0xdd, 0x1d, 0xdd, 0xd3, 0x53, 0x53, 0x3b, 0x3b, - 0x3b, 0x9b, 0x1e, 0x79, 0xc6, 0xcd, 0x32, 0x3d, 0xdb, 0xb6, 0x97, 0xf5, 0x2e, 0xd8, 0xcc, 0x6f, - 0xa7, 0xd7, 0x9e, 0x1d, 0xb7, 0xb3, 0x67, 0x3d, 0x60, 0x83, 0xca, 0xd9, 0x55, 0xd1, 0xd5, 0xe9, - 0xc9, 0xca, 0x4c, 0x67, 0x66, 0x75, 0x4f, 0x79, 0x19, 0x89, 0x9f, 0x38, 0x61, 0x21, 0x84, 0x0f, - 0x18, 0x09, 0x21, 0x19, 0x21, 0xc1, 0x81, 0x23, 0x27, 0xc3, 0x8d, 0x13, 0x12, 0xe2, 0xb0, 0x27, - 0x8b, 0x23, 0x70, 0x00, 0x8b, 0x0b, 0x12, 0x57, 0x84, 0xde, 0x8b, 0x4f, 0x46, 0x64, 0x66, 0xcd, - 0x8c, 0x3f, 0x70, 0xab, 0x78, 0xf1, 0x32, 0xe2, 0x45, 0xc4, 0x7b, 0x2f, 0xde, 0x2f, 0x0a, 0x5a, - 0x69, 0x32, 0xbc, 0x91, 0xa4, 0x71, 0x1e, 0xb3, 0xc5, 0x30, 0x4a, 0x93, 0x61, 0xff, 0xd2, 0x38, - 0x8e, 0xc7, 0x21, 0xdf, 0xf5, 0x93, 0x60, 0xd7, 0x8f, 0xa2, 0x38, 0xf7, 0xf3, 0x20, 0x8e, 0x32, - 0x81, 0xe4, 0x7e, 0x03, 0xba, 0xf7, 0x79, 0x74, 0xc8, 0xf9, 0xc8, 0xe3, 0xdf, 0x9a, 0xf2, 0x2c, - 0x67, 0x3f, 0x07, 0x1b, 0x3e, 0xff, 0x36, 0xe7, 0xa3, 0x41, 0xe2, 0x67, 0x59, 0x72, 0x92, 0xfa, - 0x19, 0xef, 0x39, 0x57, 0x9c, 0xeb, 0x1d, 0x6f, 0x5d, 0x74, 0x1c, 0x68, 0x38, 0x7b, 0x1d, 0x3a, - 0x19, 0xa2, 0xf2, 0x28, 0x4f, 0xe3, 0x64, 0xd6, 0x6b, 0x10, 0x5e, 0x1b, 0x61, 0xf7, 0x04, 0xc8, - 0x0d, 0x61, 0x4d, 0xcf, 0x90, 0x25, 0x71, 0x94, 0x71, 0x76, 0x13, 0xb6, 0x86, 0x41, 0x72, 0xc2, - 0xd3, 0x01, 0x7d, 0x3c, 0x89, 0xf8, 0x24, 0x8e, 0x82, 0x61, 0xcf, 0xb9, 0xb2, 0x70, 0xbd, 0xe5, - 0x31, 0xd1, 0x87, 0x5f, 0x7c, 0x20, 0x7b, 0xd8, 0x35, 0x58, 0xe3, 0x91, 0x80, 0xf3, 0x11, 0x7d, - 0x25, 0xa7, 0xea, 0x16, 0x60, 0xfc, 0xc0, 0xfd, 0x7b, 0x07, 0x36, 0xde, 0x8f, 0x82, 0xfc, 0xb1, - 0x1f, 0x86, 0x3c, 0x57, 0x6b, 0xba, 0x06, 0x6b, 0x67, 0x04, 0xa0, 0x35, 0x9d, 0xc5, 0xe9, 0x48, - 0xae, 0xa8, 0x2b, 0xc0, 0x07, 0x12, 0x3a, 0x97, 0xb2, 0xc6, 0x5c, 0xca, 0x6a, 0xb7, 0x6b, 0x61, - 0xce, 0x76, 0x5d, 0x83, 0xb5, 0x94, 0x0f, 0xe3, 0x53, 0x9e, 0xce, 0x06, 0x67, 0x41, 0x34, 0x8a, - 0xcf, 0x7a, 0xcd, 0x2b, 0xce, 0xf5, 0x45, 0xaf, 0xab, 0xc0, 0x8f, 0x09, 0xea, 0x6e, 0x01, 0x33, - 0x57, 0x21, 0xf6, 0xcd, 0x1d, 0xc3, 0xe6, 0x87, 0x51, 0x18, 0x0f, 0x9f, 0xfc, 0x84, 0xab, 0xab, - 0x99, 0xbe, 0x51, 0x3b, 0xfd, 0x36, 0x6c, 0xd9, 0x13, 0x49, 0x02, 0x38, 0x9c, 0xbf, 0x73, 0xe2, - 0x47, 0x63, 0xae, 0x86, 0x54, 0x24, 0x7c, 0x0a, 0xd6, 0x87, 0xd3, 0x34, 0xe5, 0x51, 0x85, 0x86, - 0x35, 0x09, 0xd7, 0x44, 0xbc, 0x0e, 0x9d, 0x88, 0x9f, 0x15, 0x68, 0x92, 0x65, 0x22, 0x7e, 0xa6, - 0x50, 0xdc, 0x1e, 0x6c, 0x97, 0xa7, 0x91, 0x04, 0x7c, 0xaf, 0x01, 0xed, 0x47, 0xa9, 0x1f, 0x65, - 0xfe, 0x10, 0xb9, 0x98, 0xf5, 0x60, 0x39, 0x7f, 0x3a, 0x38, 0xf1, 0xb3, 0x13, 0x9a, 0xae, 0xe5, - 0xa9, 0x26, 0xdb, 0x86, 0x25, 0x7f, 0x12, 0x4f, 0xa3, 0x9c, 0x26, 0x58, 0xf0, 0x64, 0x8b, 0xbd, - 0x01, 0x1b, 0xd1, 0x74, 0x32, 0x18, 0xc6, 0xd1, 0x71, 0x90, 0x4e, 0x84, 0x2c, 0xd0, 0x79, 0x2d, - 0x7a, 0xd5, 0x0e, 0x76, 0x19, 0xe0, 0x08, 0xf7, 0x41, 0x4c, 0xd1, 0xa4, 0x29, 0x0c, 0x08, 0x73, - 0xa1, 0x23, 0x5b, 0x3c, 0x18, 0x9f, 0xe4, 0xbd, 0x45, 0x1a, 0xc8, 0x82, 0xe1, 0x18, 0x79, 0x30, - 0xe1, 0x83, 0x2c, 0xf7, 0x27, 0x49, 0x6f, 0x89, 0xa8, 0x31, 0x20, 0xd4, 0x1f, 0xe7, 0x7e, 0x38, - 0x38, 0xe6, 0x3c, 0xeb, 0x2d, 0xcb, 0x7e, 0x0d, 0x61, 0x9f, 0x84, 0xee, 0x88, 0x67, 0xf9, 0xc0, - 0x1f, 0x8d, 0x52, 0x9e, 0x65, 0x3c, 0xeb, 0xad, 0x10, 0x37, 0x96, 0xa0, 0xb8, 0x6b, 0xf7, 0x79, - 0x6e, 0xec, 0x4e, 0x26, 0x4f, 0xc7, 0x7d, 0x00, 0xcc, 0x00, 0xdf, 0xe5, 0xb9, 0x1f, 0x84, 0x19, - 0x7b, 0x0b, 0x3a, 0xb9, 0x81, 0x4c, 0xd2, 0xd7, 0xde, 0x63, 0x37, 0x48, 0x6d, 0xdc, 0x30, 0x3e, - 0xf0, 0x2c, 0x3c, 0xf7, 0x8f, 0x1b, 0xd0, 0x3e, 0xe4, 0x91, 0x3e, 0x7b, 0x06, 0x4d, 0xa4, 0x44, - 0x9e, 0x37, 0xfd, 0x66, 0xaf, 0x41, 0x9b, 0xa8, 0xcb, 0xf2, 0x34, 0x88, 0xc6, 0x74, 0x04, 0x2d, - 0x0f, 0x10, 0x74, 0x48, 0x10, 0xb6, 0x0e, 0x0b, 0xfe, 0x24, 0xa7, 0x8d, 0x5f, 0xf0, 0xf0, 0x27, - 0xf2, 0x45, 0xe2, 0xcf, 0x26, 0xc8, 0x42, 0x7a, 0xb3, 0x3b, 0x5e, 0x5b, 0xc2, 0xf6, 0x71, 0xb7, - 0x6f, 0xc0, 0xa6, 0x89, 0xa2, 0x46, 0x5f, 0xa4, 0xd1, 0x37, 0x0c, 0x4c, 0x39, 0xc9, 0x35, 0x58, - 0x53, 0xf8, 0xa9, 0x20, 0x96, 0xb6, 0xbf, 0xe5, 0x75, 0x25, 0x58, 0x2d, 0xe1, 0x3a, 0xac, 0x1f, - 0x07, 0x91, 0x1f, 0x0e, 0x86, 0x61, 0x7e, 0x3a, 0x18, 0xf1, 0x30, 0xf7, 0xe9, 0x20, 0x16, 0xbd, - 0x2e, 0xc1, 0xef, 0x84, 0xf9, 0xe9, 0x5d, 0x84, 0xb2, 0x4b, 0xd0, 0x3a, 0xe6, 0x7c, 0x10, 0x06, - 0x93, 0x20, 0xef, 0xad, 0x10, 0xf5, 0x05, 0xc0, 0xfd, 0xae, 0x03, 0x1d, 0xb1, 0x35, 0x52, 0xd3, - 0x5d, 0x85, 0x55, 0x45, 0x01, 0x4f, 0xd3, 0x38, 0x95, 0x5c, 0x6a, 0x03, 0xd9, 0x0e, 0xac, 0x2b, - 0x40, 0x92, 0xf2, 0x60, 0xe2, 0x8f, 0xb9, 0x14, 0x8b, 0x0a, 0x9c, 0xed, 0x15, 0x23, 0xa6, 0xf1, - 0x34, 0x17, 0xba, 0xa6, 0xbd, 0xd7, 0x91, 0xc7, 0xe6, 0x21, 0xcc, 0xb3, 0x51, 0xdc, 0xef, 0x38, - 0xc0, 0x90, 0xac, 0x47, 0xb1, 0xe8, 0x96, 0xab, 0x2e, 0xef, 0xb8, 0xf3, 0xd2, 0x3b, 0xde, 0x98, - 0xb7, 0xe3, 0x57, 0x61, 0x89, 0xa6, 0x44, 0x91, 0x5a, 0xa8, 0x90, 0x25, 0xfb, 0xdc, 0xef, 0x3b, - 0xd0, 0x41, 0x01, 0x8f, 0x78, 0x78, 0x10, 0x07, 0x51, 0xce, 0x6e, 0x02, 0x3b, 0x9e, 0x46, 0xa3, - 0x20, 0x1a, 0x0f, 0xf2, 0xa7, 0xc1, 0x68, 0x70, 0x34, 0xc3, 0x21, 0x88, 0x9e, 0xfd, 0x73, 0x5e, - 0x4d, 0x1f, 0x7b, 0x03, 0xd6, 0x2d, 0x68, 0x96, 0xa7, 0x82, 0xaa, 0xfd, 0x73, 0x5e, 0xa5, 0x07, - 0xc5, 0x34, 0x9e, 0xe6, 0xc9, 0x34, 0x1f, 0x04, 0xd1, 0x88, 0x3f, 0xa5, 0x3d, 0x5b, 0xf5, 0x2c, - 0xd8, 0xed, 0x2e, 0x74, 0xcc, 0xef, 0xdc, 0xcf, 0xc3, 0xfa, 0x03, 0x94, 0xdf, 0x28, 0x88, 0xc6, - 0xb7, 0x84, 0x90, 0xa1, 0x52, 0x49, 0xa6, 0x47, 0x4f, 0xf8, 0x4c, 0x9e, 0xa3, 0x6c, 0xa1, 0x08, - 0x9c, 0xc4, 0x59, 0x2e, 0xf7, 0x85, 0x7e, 0xbb, 0xff, 0xe2, 0xc0, 0x1a, 0x6e, 0xfa, 0x07, 0x7e, - 0x34, 0x53, 0x3b, 0xfe, 0x00, 0x3a, 0x38, 0xd4, 0xa3, 0xf8, 0x96, 0x50, 0x4d, 0x42, 0xe4, 0xae, - 0xcb, 0x4d, 0x2a, 0x61, 0xdf, 0x30, 0x51, 0xf1, 0x36, 0x9d, 0x79, 0xd6, 0xd7, 0x28, 0x64, 0xb9, - 0x9f, 0x8e, 0x79, 0x4e, 0x4a, 0x4b, 0x2a, 0x31, 0x10, 0xa0, 0x3b, 0x71, 0x74, 0xcc, 0xae, 0x40, - 0x27, 0xf3, 0xf3, 0x41, 0xc2, 0x53, 0xda, 0x35, 0x12, 0x94, 0x05, 0x0f, 0x32, 0x3f, 0x3f, 0xe0, - 0xe9, 0xed, 0x59, 0xce, 0xfb, 0x5f, 0x80, 0x8d, 0xca, 0x2c, 0x28, 0x9b, 0xc5, 0x12, 0xf1, 0x27, - 0xdb, 0x82, 0xc5, 0x53, 0x3f, 0x9c, 0x72, 0xa9, 0x4b, 0x45, 0xe3, 0x9d, 0xc6, 0xdb, 0x8e, 0xfb, - 0x49, 0x58, 0x2f, 0xc8, 0x96, 0x4c, 0xcf, 0xa0, 0x89, 0x3b, 0x28, 0x07, 0xa0, 0xdf, 0xee, 0x6f, - 0x39, 0x02, 0xf1, 0x4e, 0x1c, 0x68, 0xbd, 0x84, 0x88, 0xa8, 0xbe, 0x14, 0x22, 0xfe, 0x9e, 0xab, - 0xb7, 0x7f, 0xfa, 0xc5, 0xba, 0xd7, 0x60, 0xc3, 0x20, 0xe1, 0x39, 0xc4, 0x7e, 0xc7, 0x81, 0x8d, - 0x87, 0xfc, 0x4c, 0x9e, 0xba, 0xa2, 0xf6, 0x6d, 0x68, 0xe6, 0xb3, 0x44, 0xd8, 0x42, 0xdd, 0xbd, - 0xab, 0xf2, 0xd0, 0x2a, 0x78, 0x37, 0x64, 0xf3, 0xd1, 0x2c, 0xe1, 0x1e, 0x7d, 0xe1, 0x7e, 0x1e, - 0xda, 0x06, 0x90, 0x5d, 0x80, 0xcd, 0xc7, 0xef, 0x3f, 0x7a, 0x78, 0xef, 0xf0, 0x70, 0x70, 0xf0, - 0xe1, 0xed, 0x2f, 0xdd, 0xfb, 0xd5, 0xc1, 0xfe, 0xad, 0xc3, 0xfd, 0xf5, 0x73, 0x6c, 0x1b, 0xd8, - 0xc3, 0x7b, 0x87, 0x8f, 0xee, 0xdd, 0xb5, 0xe0, 0x8e, 0xdb, 0x87, 0xde, 0x43, 0x7e, 0xf6, 0x38, - 0xc8, 0x23, 0x9e, 0x65, 0xf6, 0x6c, 0xee, 0x0d, 0x60, 0x26, 0x09, 0x72, 0x55, 0x3d, 0x58, 0x96, - 0x17, 0x83, 0xba, 0x17, 0x65, 0xd3, 0xfd, 0x24, 0xb0, 0xc3, 0x60, 0x1c, 0x7d, 0xc0, 0xb3, 0xcc, - 0x1f, 0x6b, 0x55, 0xb0, 0x0e, 0x0b, 0x93, 0x6c, 0x2c, 0x35, 0x00, 0xfe, 0x74, 0x3f, 0x0d, 0x9b, - 0x16, 0x9e, 0x1c, 0xf8, 0x12, 0xb4, 0xb2, 0x60, 0x1c, 0xf9, 0xf9, 0x34, 0xe5, 0x72, 0xe8, 0x02, - 0xe0, 0xbe, 0x07, 0x5b, 0x5f, 0xe5, 0x69, 0x70, 0x3c, 0x7b, 0xd1, 0xf0, 0xf6, 0x38, 0x8d, 0xf2, - 0x38, 0xf7, 0xe0, 0x7c, 0x69, 0x1c, 0x39, 0xbd, 0x60, 0x44, 0x79, 0x5c, 0x2b, 0x9e, 0x68, 0x18, - 0x62, 0xd9, 0x30, 0xc5, 0xd2, 0xfd, 0x10, 0xd8, 0x9d, 0x38, 0x8a, 0xf8, 0x30, 0x3f, 0xe0, 0x3c, - 0x2d, 0x0c, 0xdc, 0x82, 0xeb, 0xda, 0x7b, 0x17, 0xe4, 0x39, 0x96, 0x65, 0x5d, 0xb2, 0x23, 0x83, - 0x66, 0xc2, 0xd3, 0x09, 0x0d, 0xbc, 0xe2, 0xd1, 0x6f, 0xf7, 0x3c, 0x6c, 0x5a, 0xc3, 0x4a, 0xdb, - 0xe4, 0x4d, 0x38, 0x7f, 0x37, 0xc8, 0x86, 0xd5, 0x09, 0x7b, 0xb0, 0x9c, 0x4c, 0x8f, 0x06, 0x85, - 0x4c, 0xa9, 0x26, 0x5e, 0xd9, 0xe5, 0x4f, 0xe4, 0x60, 0xbf, 0xe7, 0x40, 0x73, 0xff, 0xd1, 0x83, - 0x3b, 0xac, 0x0f, 0x2b, 0x41, 0x34, 0x8c, 0x27, 0xa8, 0x76, 0xc5, 0xa2, 0x75, 0x7b, 0xae, 0xac, - 0x5c, 0x82, 0x16, 0x69, 0x6b, 0xb4, 0x42, 0xa4, 0x2d, 0x5a, 0x00, 0xd0, 0x02, 0xe2, 0x4f, 0x93, - 0x20, 0x25, 0x13, 0x47, 0x19, 0x2e, 0x4d, 0xd2, 0x88, 0xd5, 0x0e, 0xf7, 0x7f, 0x9a, 0xb0, 0x2c, - 0x75, 0x35, 0xcd, 0x37, 0xcc, 0x83, 0x53, 0x2e, 0x29, 0x91, 0x2d, 0xbc, 0xe5, 0x52, 0x3e, 0x89, - 0x73, 0x3e, 0xb0, 0x8e, 0xc1, 0x06, 0x22, 0xd6, 0x50, 0x0c, 0x34, 0x48, 0x50, 0xeb, 0x13, 0x65, - 0x2d, 0xcf, 0x06, 0xe2, 0x66, 0x21, 0x60, 0x10, 0x8c, 0x88, 0xa6, 0xa6, 0xa7, 0x9a, 0xb8, 0x13, - 0x43, 0x3f, 0xf1, 0x87, 0x41, 0x3e, 0x93, 0xc2, 0xad, 0xdb, 0x38, 0x76, 0x18, 0x0f, 0xfd, 0x70, - 0x70, 0xe4, 0x87, 0x7e, 0x34, 0xe4, 0xd2, 0xcc, 0xb2, 0x81, 0x68, 0x49, 0x49, 0x92, 0x14, 0x9a, - 0xb0, 0xb6, 0x4a, 0x50, 0xb4, 0xc8, 0x86, 0xf1, 0x64, 0x12, 0xe4, 0x68, 0x80, 0xc9, 0x5b, 0xde, - 0x80, 0xd0, 0x4a, 0x44, 0xeb, 0x4c, 0xec, 0x5e, 0x4b, 0xcc, 0x66, 0x01, 0x71, 0x14, 0xb4, 0x0c, - 0x50, 0x21, 0x3d, 0x39, 0xeb, 0x81, 0x18, 0xa5, 0x80, 0xe0, 0x39, 0x4c, 0xa3, 0x8c, 0xe7, 0x79, - 0xc8, 0x47, 0x9a, 0xa0, 0x36, 0xa1, 0x55, 0x3b, 0xd8, 0x4d, 0xd8, 0x14, 0x36, 0x61, 0xe6, 0xe7, - 0x71, 0x76, 0x12, 0x64, 0x83, 0x8c, 0x47, 0x79, 0xaf, 0x43, 0xf8, 0x75, 0x5d, 0xec, 0x6d, 0xb8, - 0x50, 0x02, 0xa7, 0x7c, 0xc8, 0x83, 0x53, 0x3e, 0xea, 0xad, 0xd2, 0x57, 0xf3, 0xba, 0xd9, 0x15, - 0x68, 0xa3, 0x29, 0x3c, 0x4d, 0x46, 0x3e, 0xde, 0xc3, 0x5d, 0x3a, 0x07, 0x13, 0xc4, 0xde, 0x84, - 0xd5, 0x84, 0x8b, 0xcb, 0xf2, 0x24, 0x0f, 0x87, 0x59, 0x6f, 0x8d, 0x6e, 0xb2, 0xb6, 0x14, 0x26, - 0xe4, 0x5c, 0xcf, 0xc6, 0x40, 0xa6, 0x1c, 0x66, 0x64, 0x5c, 0xf9, 0xb3, 0xde, 0x3a, 0xb1, 0x5b, - 0x01, 0x20, 0x19, 0x49, 0x83, 0x53, 0x3f, 0xe7, 0xbd, 0x0d, 0xe2, 0x2d, 0xd5, 0x74, 0xff, 0xcc, - 0x81, 0xcd, 0x07, 0x41, 0x96, 0x4b, 0x26, 0xd4, 0xea, 0xf8, 0x35, 0x68, 0x0b, 0xf6, 0x1b, 0xc4, - 0x51, 0x38, 0x93, 0x1c, 0x09, 0x02, 0xf4, 0xe5, 0x28, 0x9c, 0xb1, 0x4f, 0xc0, 0x6a, 0x10, 0x99, - 0x28, 0x42, 0x86, 0x3b, 0x0a, 0x48, 0x48, 0xaf, 0x41, 0x3b, 0x99, 0x1e, 0x85, 0xc1, 0x50, 0xa0, - 0x2c, 0x88, 0x51, 0x04, 0x88, 0x10, 0xd0, 0x48, 0x12, 0x94, 0x08, 0x8c, 0x26, 0x61, 0xb4, 0x25, - 0x0c, 0x51, 0xdc, 0xdb, 0xb0, 0x65, 0x13, 0x28, 0x95, 0xd5, 0x0e, 0xac, 0x48, 0xde, 0xce, 0x7a, - 0x6d, 0xda, 0x9f, 0xae, 0xdc, 0x1f, 0x89, 0xea, 0xe9, 0x7e, 0xf7, 0x3f, 0x1c, 0x68, 0xa2, 0x02, - 0x98, 0xaf, 0x2c, 0x4c, 0x9d, 0xbe, 0x60, 0xe9, 0x74, 0xf2, 0x52, 0xd0, 0x2a, 0x12, 0x2c, 0x21, - 0xc4, 0xc6, 0x80, 0x14, 0xfd, 0x29, 0x1f, 0x9e, 0x92, 0xec, 0xe8, 0x7e, 0x84, 0xa0, 0x64, 0xe1, - 0xd5, 0x49, 0x5f, 0x0b, 0xc1, 0xd1, 0x6d, 0xd5, 0x47, 0x5f, 0x2e, 0x17, 0x7d, 0xf4, 0x5d, 0x0f, - 0x96, 0x83, 0xe8, 0x28, 0x9e, 0x46, 0x23, 0x12, 0x92, 0x15, 0x4f, 0x35, 0xf1, 0xb0, 0x13, 0xb2, - 0xa4, 0x82, 0x09, 0x97, 0xd2, 0x51, 0x00, 0x5c, 0x86, 0xa6, 0x55, 0x46, 0x0a, 0x4f, 0xdf, 0x63, - 0x6f, 0xc1, 0x86, 0x01, 0x93, 0x3b, 0xf8, 0x3a, 0x2c, 0x26, 0x08, 0x90, 0x86, 0x92, 0x62, 0x2f, - 0xd2, 0x94, 0xa2, 0xc7, 0x5d, 0x87, 0xee, 0x7d, 0x9e, 0xbf, 0x1f, 0x1d, 0xc7, 0x6a, 0xa4, 0x1f, - 0x2e, 0xc0, 0x9a, 0x06, 0xc9, 0x81, 0xae, 0xc3, 0x5a, 0x30, 0xe2, 0x51, 0x1e, 0xe4, 0xb3, 0x81, - 0x65, 0xc1, 0x95, 0xc1, 0x78, 0xc3, 0xf8, 0x61, 0xe0, 0x67, 0x52, 0x87, 0x89, 0x06, 0xdb, 0x83, - 0x2d, 0x64, 0x7f, 0xc5, 0xd1, 0xfa, 0x58, 0x85, 0x21, 0x59, 0xdb, 0x87, 0x12, 0x8b, 0x70, 0xc9, - 0x81, 0xfa, 0x13, 0xa1, 0x69, 0xeb, 0xba, 0x70, 0xd7, 0xc4, 0x48, 0xb8, 0xe4, 0x45, 0x21, 0x22, - 0x1a, 0x50, 0xf1, 0x35, 0x97, 0x84, 0x11, 0x5b, 0xf6, 0x35, 0x0d, 0x7f, 0x75, 0xa5, 0xe2, 0xaf, - 0x5e, 0x87, 0xb5, 0x6c, 0x16, 0x0d, 0xf9, 0x68, 0x90, 0xc7, 0x38, 0x6f, 0x10, 0xd1, 0xe9, 0xac, - 0x78, 0x65, 0x30, 0x79, 0xd6, 0x3c, 0xcb, 0x23, 0x9e, 0x93, 0xea, 0x5a, 0xf1, 0x54, 0x13, 0x6f, - 0x01, 0x42, 0x11, 0x4c, 0xdd, 0xf2, 0x64, 0x0b, 0xaf, 0xca, 0x69, 0x1a, 0x64, 0xbd, 0x0e, 0x41, - 0xe9, 0x37, 0xfb, 0x0c, 0x9c, 0x3f, 0x42, 0x3f, 0xf0, 0x84, 0xfb, 0x23, 0x9e, 0xd2, 0xe9, 0x0b, - 0x37, 0x58, 0x68, 0xa0, 0xfa, 0x4e, 0x9c, 0xfb, 0x94, 0xa7, 0x59, 0x10, 0x47, 0xa4, 0x7b, 0x5a, - 0x9e, 0x6a, 0xba, 0xdf, 0xa6, 0x1b, 0x5d, 0x3b, 0xe8, 0x1f, 0x92, 0x3a, 0x62, 0xaf, 0x40, 0x4b, - 0xac, 0x31, 0x3b, 0xf1, 0xa5, 0x91, 0xb1, 0x42, 0x80, 0xc3, 0x13, 0x1f, 0x05, 0xd8, 0xda, 0x36, - 0x11, 0xf1, 0x68, 0x13, 0x6c, 0x5f, 0xec, 0xda, 0x55, 0xe8, 0x2a, 0xd7, 0x3f, 0x1b, 0x84, 0xfc, - 0x38, 0x57, 0x0e, 0x42, 0x34, 0x9d, 0xe0, 0x74, 0xd9, 0x03, 0x7e, 0x9c, 0xbb, 0x0f, 0x61, 0x43, - 0xca, 0xed, 0x97, 0x13, 0xae, 0xa6, 0xfe, 0x5c, 0xf9, 0x52, 0x13, 0x56, 0xc5, 0xa6, 0x2d, 0xe8, - 0xe4, 0xe5, 0x94, 0x6e, 0x3a, 0xd7, 0x03, 0x26, 0xbb, 0xef, 0x84, 0x71, 0xc6, 0xe5, 0x80, 0x2e, - 0x74, 0x86, 0x61, 0x9c, 0x29, 0x37, 0x44, 0x2e, 0xc7, 0x82, 0xe1, 0xfe, 0x64, 0xd3, 0xe1, 0x10, - 0x35, 0x81, 0xd0, 0x69, 0xaa, 0xe9, 0xfe, 0xa5, 0x03, 0x9b, 0x34, 0x9a, 0xd2, 0x30, 0xda, 0x76, - 0x7d, 0x79, 0x32, 0x3b, 0x43, 0xd3, 0x35, 0xdb, 0x82, 0xc5, 0xe3, 0x38, 0x1d, 0x72, 0x39, 0x93, - 0x68, 0xfc, 0xf8, 0xd6, 0x78, 0xb3, 0x62, 0x8d, 0xff, 0xd0, 0x81, 0x0d, 0x22, 0xf5, 0x30, 0xf7, - 0xf3, 0x69, 0x26, 0x97, 0xff, 0x8b, 0xb0, 0x8a, 0x4b, 0xe5, 0x4a, 0x9c, 0x24, 0xa1, 0x5b, 0x5a, - 0xf2, 0x09, 0x2a, 0x90, 0xf7, 0xcf, 0x79, 0x36, 0x32, 0xfb, 0x02, 0x74, 0xcc, 0xf8, 0x0d, 0xd1, - 0xdc, 0xde, 0xbb, 0xa8, 0x56, 0x59, 0xe1, 0x9c, 0xfd, 0x73, 0x9e, 0xf5, 0x01, 0x7b, 0x17, 0x80, - 0xcc, 0x0d, 0x1a, 0x56, 0xba, 0xd6, 0x17, 0xed, 0x4d, 0x32, 0x0e, 0x6b, 0xff, 0x9c, 0x67, 0xa0, - 0xdf, 0x5e, 0x81, 0x25, 0x71, 0x3f, 0xba, 0xf7, 0x61, 0xd5, 0xa2, 0xd4, 0xf2, 0x32, 0x3a, 0xc2, - 0xcb, 0xa8, 0x38, 0xa5, 0x8d, 0xaa, 0x53, 0xea, 0xfe, 0x5b, 0x03, 0x18, 0x72, 0x5b, 0xe9, 0x38, - 0xf1, 0x82, 0x8e, 0x47, 0x96, 0xb9, 0xd5, 0xf1, 0x4c, 0x10, 0xbb, 0x01, 0xcc, 0x68, 0x2a, 0xbf, - 0x5d, 0xdc, 0x1b, 0x35, 0x3d, 0xa8, 0xe0, 0x84, 0xad, 0xa4, 0x7c, 0x60, 0x69, 0x58, 0x8a, 0x73, - 0xab, 0xed, 0xc3, 0xab, 0x21, 0x99, 0x66, 0x27, 0x68, 0x40, 0x28, 0x83, 0x4c, 0xb5, 0xcb, 0x0c, - 0xb2, 0xf4, 0x42, 0x06, 0x59, 0x2e, 0x33, 0x88, 0x69, 0x12, 0xac, 0x58, 0x26, 0x01, 0xda, 0x5f, - 0x93, 0x20, 0x22, 0xbb, 0x62, 0x30, 0xc1, 0xd9, 0xa5, 0xfd, 0x65, 0x01, 0xd9, 0x0e, 0xac, 0x4b, - 0xbb, 0xae, 0xb0, 0x3b, 0x80, 0xf6, 0xb8, 0x02, 0x77, 0x3f, 0x76, 0x60, 0x1d, 0xf7, 0xd9, 0xe2, - 0xc5, 0x77, 0x80, 0x44, 0xe1, 0x25, 0x59, 0xd1, 0xc2, 0xfd, 0xe9, 0x39, 0xf1, 0x6d, 0x68, 0xd1, - 0x80, 0x71, 0xc2, 0x23, 0xc9, 0x88, 0x3d, 0x9b, 0x11, 0x0b, 0x2d, 0xb4, 0x7f, 0xce, 0x2b, 0x90, - 0x0d, 0x36, 0xfc, 0x27, 0x07, 0xda, 0x92, 0xcc, 0x9f, 0xd8, 0x97, 0xe8, 0xc3, 0x0a, 0x72, 0xa4, - 0x61, 0xb0, 0xeb, 0x36, 0xde, 0x26, 0x13, 0x74, 0xd8, 0xf0, 0xfa, 0xb4, 0xfc, 0x88, 0x32, 0x18, - 0xef, 0x42, 0x52, 0xb8, 0xd9, 0x20, 0x0f, 0xc2, 0x81, 0xea, 0x95, 0xe1, 0xd2, 0xba, 0x2e, 0xd4, - 0x3b, 0x59, 0xee, 0x8f, 0xb9, 0xbc, 0xe6, 0x44, 0x03, 0x1d, 0x26, 0xb9, 0xa0, 0x92, 0x39, 0xe8, - 0xfe, 0x5d, 0x07, 0x2e, 0x54, 0xba, 0x74, 0xbe, 0x41, 0x1a, 0xc8, 0x61, 0x30, 0x39, 0x8a, 0xb5, - 0xad, 0xed, 0x98, 0xb6, 0xb3, 0xd5, 0xc5, 0xc6, 0x70, 0x5e, 0xdd, 0xe7, 0xb8, 0xa7, 0xc5, 0xed, - 0xdd, 0x20, 0x43, 0xe4, 0x4d, 0x9b, 0x07, 0xca, 0x13, 0x2a, 0xb8, 0x29, 0xb9, 0xf5, 0xe3, 0xb1, - 0x13, 0xe8, 0x69, 0xc3, 0x41, 0xaa, 0x78, 0xc3, 0xb8, 0xc0, 0xb9, 0xde, 0x78, 0xc1, 0x5c, 0xa4, - 0x8f, 0x46, 0x6a, 0x9a, 0xb9, 0xa3, 0xb1, 0x19, 0x5c, 0x56, 0x7d, 0xa4, 0xc3, 0xab, 0xf3, 0x35, - 0x5f, 0x6a, 0x6d, 0xef, 0xe1, 0xc7, 0xf6, 0xa4, 0x2f, 0x18, 0x98, 0x7d, 0x13, 0xb6, 0xcf, 0xfc, - 0x20, 0x57, 0x64, 0x19, 0xc6, 0xd0, 0x22, 0x4d, 0xb9, 0xf7, 0x82, 0x29, 0x1f, 0x8b, 0x8f, 0xad, - 0x8b, 0x6d, 0xce, 0x88, 0xfd, 0x7f, 0x70, 0xa0, 0x6b, 0x8f, 0x83, 0x6c, 0x2a, 0x05, 0x5e, 0x29, - 0x3e, 0x65, 0xfc, 0x95, 0xc0, 0x55, 0x17, 0xb5, 0x51, 0xe7, 0xa2, 0x9a, 0x8e, 0xe8, 0xc2, 0x8b, - 0x1c, 0xd1, 0xe6, 0xcb, 0x39, 0xa2, 0x8b, 0x75, 0x8e, 0x68, 0xff, 0xbf, 0x1d, 0x60, 0x55, 0x5e, - 0x62, 0xf7, 0x85, 0x8f, 0x1c, 0xf1, 0x50, 0xea, 0xa4, 0x9f, 0x7f, 0x39, 0x7e, 0x54, 0x7b, 0xa7, - 0xbe, 0x46, 0xc1, 0x30, 0x95, 0x8e, 0x69, 0x22, 0xad, 0x7a, 0x75, 0x5d, 0x25, 0xd7, 0xb8, 0xf9, - 0x62, 0xd7, 0x78, 0xf1, 0xc5, 0xae, 0xf1, 0x52, 0xd9, 0x35, 0xee, 0xff, 0xae, 0x03, 0x9b, 0x35, - 0x87, 0xfe, 0xb3, 0x5b, 0x38, 0x1e, 0x93, 0xa5, 0x0b, 0x1a, 0xf2, 0x98, 0x4c, 0x60, 0xff, 0x37, - 0x60, 0xd5, 0x62, 0xf4, 0x9f, 0xdd, 0xfc, 0x65, 0x2b, 0x4f, 0xf0, 0x99, 0x05, 0xeb, 0xff, 0xa8, - 0x01, 0xac, 0x2a, 0x6c, 0xff, 0xaf, 0x34, 0x54, 0xf7, 0x69, 0xa1, 0x66, 0x9f, 0xfe, 0x4f, 0xef, - 0x81, 0x37, 0x60, 0x43, 0x26, 0x27, 0x8d, 0x28, 0x89, 0xe0, 0x98, 0x6a, 0x07, 0xda, 0xb9, 0x76, - 0x5c, 0x62, 0xc5, 0x4a, 0x6a, 0x19, 0x97, 0x61, 0x29, 0x3c, 0xe1, 0x6e, 0xc3, 0x96, 0x48, 0x76, - 0xde, 0x16, 0x43, 0xa9, 0x7b, 0xe5, 0x4f, 0x1d, 0x38, 0x5f, 0xea, 0x28, 0x72, 0x3b, 0xe2, 0xea, - 0xb0, 0xef, 0x13, 0x1b, 0x88, 0xf4, 0x4b, 0x39, 0x32, 0xe8, 0x17, 0xdc, 0x56, 0xed, 0xc0, 0xfd, - 0x99, 0x46, 0x55, 0x7c, 0xb1, 0xeb, 0x75, 0x5d, 0xee, 0x05, 0x91, 0x92, 0x8d, 0x78, 0x58, 0x22, - 0xfc, 0x58, 0x24, 0x51, 0xcd, 0x8e, 0x22, 0x38, 0x6c, 0x93, 0xac, 0x9a, 0x68, 0x05, 0x5a, 0xd7, - 0x94, 0x4d, 0x6f, 0x6d, 0x9f, 0xfb, 0x17, 0x0e, 0xb0, 0xaf, 0x4c, 0x79, 0x3a, 0xa3, 0x1c, 0x8f, - 0x0e, 0xcf, 0x5c, 0x28, 0xc7, 0x31, 0x96, 0x92, 0xe9, 0xd1, 0x97, 0xf8, 0x4c, 0x65, 0xfe, 0x1a, - 0x45, 0xe6, 0xef, 0x55, 0x00, 0x74, 0xbf, 0x74, 0xe2, 0x08, 0x79, 0x01, 0xfd, 0x5e, 0x31, 0x60, - 0x6d, 0x72, 0xae, 0x59, 0x9b, 0x9c, 0x7b, 0xc5, 0x4c, 0xce, 0x49, 0x8b, 0xf4, 0x98, 0xf3, 0x07, - 0x94, 0x9b, 0x7b, 0x17, 0x36, 0x2d, 0x32, 0xf5, 0x29, 0xaa, 0x8c, 0x95, 0xf3, 0x9c, 0x8c, 0xd5, - 0x7f, 0x3a, 0xb0, 0xb0, 0x1f, 0x27, 0x66, 0x74, 0xd2, 0xb1, 0xa3, 0x93, 0xf2, 0xea, 0x18, 0xe8, - 0x9b, 0x41, 0x6a, 0x14, 0x0b, 0xc8, 0x76, 0xa0, 0xeb, 0x4f, 0x72, 0xf4, 0xb2, 0x8f, 0xe3, 0xf4, - 0xcc, 0x4f, 0x47, 0xe2, 0x68, 0x6f, 0x37, 0x7a, 0x8e, 0x57, 0xea, 0x61, 0x5b, 0xb0, 0xa0, 0x75, - 0x2c, 0x21, 0x60, 0x13, 0xed, 0x34, 0x0a, 0xd2, 0xce, 0x64, 0x80, 0x40, 0xb6, 0x90, 0x73, 0xec, - 0xef, 0x85, 0x65, 0x2c, 0x24, 0xa5, 0xae, 0x0b, 0xaf, 0x31, 0xdc, 0x2d, 0x42, 0x5b, 0xd6, 0x9b, - 0x45, 0x6d, 0xf7, 0xdf, 0x1d, 0x58, 0xa4, 0x1d, 0x40, 0xd9, 0x16, 0x0c, 0x4d, 0x19, 0x6b, 0x8a, - 0x28, 0x3b, 0x42, 0xb6, 0x4b, 0x60, 0xe6, 0x5a, 0x79, 0xec, 0x86, 0x26, 0xdb, 0xcc, 0x65, 0x5f, - 0x81, 0x96, 0x68, 0xe9, 0xe4, 0x2f, 0xa1, 0x14, 0x40, 0x76, 0x19, 0x9a, 0x27, 0x71, 0xa2, 0x8c, - 0x11, 0x50, 0x01, 0xc5, 0x38, 0xf1, 0x08, 0x5e, 0xd0, 0x83, 0xe3, 0x09, 0xe2, 0xc5, 0x49, 0x97, - 0xc1, 0x78, 0xc9, 0xea, 0x61, 0xcd, 0xcd, 0x28, 0x41, 0xdd, 0x1d, 0x58, 0x7b, 0x18, 0x8f, 0xb8, - 0x11, 0x42, 0x9a, 0xcb, 0xbc, 0xee, 0x6f, 0x3a, 0xb0, 0xa2, 0x90, 0xd9, 0x75, 0x68, 0xa2, 0xe5, - 0x50, 0xf2, 0x0b, 0x74, 0x22, 0x01, 0xf1, 0x3c, 0xc2, 0x40, 0x55, 0x4b, 0x01, 0x86, 0xc2, 0x8a, - 0x54, 0xe1, 0x85, 0xc2, 0x48, 0xd2, 0xe4, 0x96, 0x6c, 0x8b, 0x12, 0xd4, 0xfd, 0x2b, 0x07, 0x56, - 0xad, 0x39, 0xd0, 0x1b, 0x0c, 0xfd, 0x2c, 0x97, 0xc1, 0x59, 0x79, 0x3c, 0x26, 0xc8, 0x0c, 0x2a, - 0x36, 0xec, 0xa0, 0xa2, 0x0e, 0x77, 0x2d, 0x98, 0xe1, 0xae, 0x9b, 0xd0, 0x2a, 0xaa, 0x0d, 0x9a, - 0x96, 0x0a, 0xc5, 0x19, 0x55, 0x8a, 0xa4, 0x40, 0xc2, 0x71, 0x86, 0x71, 0x18, 0xa7, 0x32, 0x19, - 0x2f, 0x1a, 0xee, 0xbb, 0xd0, 0x36, 0xf0, 0x91, 0x8c, 0x88, 0xe7, 0x67, 0x71, 0xfa, 0x44, 0xc5, - 0x36, 0x65, 0x53, 0x67, 0x02, 0x1b, 0x45, 0x26, 0xd0, 0xfd, 0x6b, 0x07, 0x56, 0x91, 0x07, 0x83, - 0x68, 0x7c, 0x10, 0x87, 0xc1, 0x70, 0x46, 0x67, 0xaf, 0xd8, 0x4d, 0x2a, 0x02, 0xc5, 0x8b, 0x36, - 0x18, 0x79, 0x5b, 0x39, 0x83, 0x52, 0x10, 0x75, 0x1b, 0x25, 0x15, 0xf9, 0xfc, 0xc8, 0xcf, 0x24, - 0xf3, 0xcb, 0x3b, 0xcd, 0x02, 0xa2, 0x3c, 0x21, 0x20, 0xf5, 0x73, 0x3e, 0x98, 0x04, 0x61, 0x18, - 0x08, 0x5c, 0x61, 0xf1, 0xd4, 0x75, 0xb9, 0x3f, 0x68, 0x40, 0x5b, 0x6a, 0xdc, 0x7b, 0xa3, 0xb1, - 0xc8, 0x22, 0x48, 0xbb, 0x51, 0xab, 0x0b, 0x03, 0xa2, 0xfa, 0x2d, 0x4b, 0xd3, 0x80, 0x94, 0x8f, - 0x75, 0xa1, 0x7a, 0xac, 0x97, 0xa0, 0x85, 0xec, 0xf5, 0x26, 0x99, 0xb4, 0xa2, 0x38, 0xa5, 0x00, - 0xa8, 0xde, 0x3d, 0xea, 0x5d, 0x2c, 0x7a, 0x09, 0x60, 0x19, 0xb1, 0x4b, 0x25, 0x23, 0xf6, 0x6d, - 0xe8, 0xc8, 0x61, 0x68, 0xdf, 0x49, 0x3b, 0x14, 0x0c, 0x6e, 0x9d, 0x89, 0x67, 0x61, 0xaa, 0x2f, - 0xf7, 0xd4, 0x97, 0x2b, 0x2f, 0xfa, 0x52, 0x61, 0x52, 0x52, 0x4d, 0xec, 0xcd, 0xfd, 0xd4, 0x4f, - 0x4e, 0xd4, 0x2d, 0x36, 0xd2, 0x95, 0x02, 0x04, 0x66, 0x3b, 0xb0, 0x88, 0x9f, 0x29, 0x6d, 0x5d, - 0x2f, 0x74, 0x02, 0x85, 0x5d, 0x87, 0x45, 0x3e, 0x1a, 0x73, 0xe5, 0xb4, 0x31, 0xdb, 0x7d, 0xc6, - 0x33, 0xf2, 0x04, 0x02, 0xaa, 0x00, 0x84, 0x96, 0x54, 0x80, 0xad, 0xe9, 0x97, 0xb0, 0xf9, 0xfe, - 0xc8, 0xdd, 0x02, 0xf6, 0x50, 0x70, 0xad, 0x19, 0x74, 0xfe, 0x9d, 0x05, 0x68, 0x1b, 0x60, 0x94, - 0xe6, 0x31, 0x12, 0x3c, 0x18, 0x05, 0xfe, 0x84, 0xe7, 0x3c, 0x95, 0x9c, 0x5a, 0x82, 0x22, 0x9e, - 0x7f, 0x3a, 0x1e, 0xc4, 0xd3, 0x7c, 0x30, 0xe2, 0xe3, 0x94, 0x8b, 0xbb, 0x16, 0x2f, 0x03, 0x0b, - 0x8a, 0x78, 0x13, 0xff, 0xa9, 0x89, 0x27, 0xf8, 0xa1, 0x04, 0x55, 0x21, 0x64, 0xb1, 0x47, 0xcd, - 0x22, 0x84, 0x2c, 0x76, 0xa4, 0xac, 0x87, 0x16, 0x6b, 0xf4, 0xd0, 0x5b, 0xb0, 0x2d, 0x34, 0x8e, - 0x94, 0xcd, 0x41, 0x89, 0x4d, 0xe6, 0xf4, 0xb2, 0x1d, 0x58, 0x47, 0x9a, 0x15, 0x83, 0x67, 0xc1, - 0xb7, 0x45, 0x50, 0xc7, 0xf1, 0x2a, 0x70, 0xc4, 0x45, 0x71, 0xb4, 0x70, 0x45, 0x9a, 0xad, 0x02, - 0x27, 0x5c, 0xff, 0xa9, 0x8d, 0xdb, 0x92, 0xb8, 0x25, 0xb8, 0xbb, 0x0a, 0xed, 0xc3, 0x3c, 0x4e, - 0xd4, 0xa1, 0x74, 0xa1, 0x23, 0x9a, 0x32, 0xa9, 0xfa, 0x0a, 0x5c, 0x24, 0x2e, 0x7a, 0x14, 0x27, - 0x71, 0x18, 0x8f, 0x67, 0x87, 0xd3, 0xa3, 0x6c, 0x98, 0x06, 0x09, 0x3a, 0x38, 0xee, 0x3f, 0x3a, - 0xb0, 0x69, 0xf5, 0xca, 0x28, 0xd0, 0x67, 0x04, 0x4b, 0xeb, 0x6c, 0x98, 0x60, 0xbc, 0x0d, 0x43, - 0x1d, 0x0a, 0x44, 0x11, 0x7f, 0xfb, 0x50, 0x26, 0xc8, 0x6e, 0xc1, 0x9a, 0xa2, 0x4c, 0x7d, 0x28, - 0xb8, 0xb0, 0x57, 0xe5, 0x42, 0xf9, 0x7d, 0x57, 0x7e, 0xa0, 0x86, 0xf8, 0x25, 0x61, 0x9f, 0xf3, - 0x11, 0xad, 0x51, 0x85, 0x03, 0xfa, 0xea, 0x7b, 0xd3, 0x29, 0x50, 0x14, 0x0c, 0x35, 0x30, 0x73, - 0x7f, 0xdf, 0x01, 0x28, 0xa8, 0x43, 0xc6, 0x28, 0x54, 0xba, 0x28, 0xb4, 0x34, 0xd4, 0xf7, 0xeb, - 0xd0, 0xd1, 0x89, 0x90, 0xe2, 0x96, 0x68, 0x2b, 0x18, 0xda, 0x6d, 0xd7, 0x60, 0x6d, 0x1c, 0xc6, - 0x47, 0x74, 0xc5, 0x52, 0x96, 0x3e, 0x93, 0xa9, 0xe5, 0xae, 0x00, 0xbf, 0x27, 0xa1, 0xc5, 0x95, - 0xd2, 0x34, 0xae, 0x14, 0xf7, 0x3b, 0x0d, 0x1d, 0x3e, 0x2f, 0xd6, 0x3c, 0x57, 0xca, 0xd8, 0x5e, - 0x45, 0x39, 0xce, 0x89, 0x56, 0x53, 0xe0, 0xeb, 0xe0, 0x85, 0x7e, 0xf9, 0xbb, 0xd0, 0x4d, 0x85, - 0xf6, 0x51, 0xaa, 0xa9, 0xf9, 0x1c, 0xd5, 0xb4, 0x9a, 0x5a, 0xf7, 0xce, 0xa7, 0x60, 0xdd, 0x1f, - 0x9d, 0xf2, 0x34, 0x0f, 0xc8, 0x33, 0xa2, 0x4b, 0x5f, 0x28, 0xd4, 0x35, 0x03, 0x4e, 0x77, 0xf1, - 0x35, 0x58, 0x93, 0xe9, 0x7c, 0x8d, 0x29, 0x4b, 0xce, 0x0a, 0x30, 0x22, 0xba, 0x7f, 0xae, 0x22, - 0xf5, 0xf6, 0x19, 0xce, 0xdf, 0x11, 0x73, 0x75, 0x8d, 0xd2, 0xea, 0x3e, 0x21, 0xa3, 0xe6, 0x23, - 0xe5, 0x7e, 0xc9, 0xfc, 0x85, 0x00, 0xca, 0x2c, 0x87, 0xbd, 0xa5, 0xcd, 0x97, 0xd9, 0x52, 0xf7, - 0x63, 0x07, 0x96, 0xf7, 0xe3, 0x64, 0x5f, 0x66, 0xe6, 0x49, 0x10, 0x74, 0xb1, 0x8c, 0x6a, 0x9a, - 0x56, 0x71, 0xa3, 0x62, 0x15, 0x57, 0xef, 0xda, 0xd5, 0xf2, 0x5d, 0xfb, 0xcb, 0xf0, 0x0a, 0x39, - 0xff, 0x69, 0x9c, 0xc4, 0x29, 0x0a, 0xa3, 0x1f, 0x8a, 0x8b, 0x35, 0x8e, 0xf2, 0x13, 0xa5, 0xc6, - 0x9e, 0x87, 0x42, 0x5e, 0x16, 0x7a, 0x07, 0xc2, 0x18, 0x96, 0xb6, 0x81, 0xd0, 0x6e, 0xd5, 0x0e, - 0xf7, 0x73, 0xd0, 0x22, 0xe3, 0x96, 0x96, 0xf5, 0x06, 0xb4, 0x4e, 0xe2, 0x64, 0x70, 0x12, 0x44, - 0xb9, 0x12, 0xee, 0x6e, 0x61, 0x75, 0xee, 0xd3, 0x86, 0x68, 0x04, 0xf7, 0x47, 0x0b, 0xb0, 0xfc, - 0x7e, 0x74, 0x1a, 0x07, 0x43, 0x0a, 0xea, 0x4f, 0xf8, 0x24, 0x56, 0xa5, 0x43, 0xf8, 0x1b, 0xb7, - 0x82, 0xd2, 0xe8, 0x49, 0x2e, 0xa3, 0xf2, 0xaa, 0x89, 0xd7, 0x7d, 0x5a, 0x94, 0xf7, 0x09, 0xd1, - 0x31, 0x20, 0x68, 0xd8, 0xa7, 0x66, 0xe5, 0xa3, 0x6c, 0x15, 0xb5, 0x57, 0x8b, 0x46, 0xed, 0x15, - 0xa5, 0x80, 0x44, 0x85, 0x00, 0xf1, 0xd7, 0x8a, 0xa7, 0x9a, 0xe4, 0x88, 0xa4, 0x5c, 0x04, 0x6d, - 0xc8, 0x70, 0x58, 0x96, 0x8e, 0x88, 0x09, 0x44, 0xe3, 0x42, 0x7c, 0x20, 0x70, 0x84, 0xf2, 0x35, - 0x41, 0x68, 0x6c, 0x95, 0x8b, 0x27, 0x5b, 0x82, 0xe7, 0x4b, 0x60, 0xd4, 0xd0, 0x23, 0xae, 0x15, - 0xa9, 0x58, 0x03, 0x88, 0xf2, 0xc5, 0x32, 0xdc, 0x70, 0x5f, 0x44, 0xa5, 0x83, 0x72, 0x5f, 0x90, - 0x51, 0xfc, 0x30, 0x3c, 0xf2, 0x87, 0x4f, 0xa8, 0xa4, 0x95, 0x0a, 0x1b, 0x5a, 0x9e, 0x0d, 0x44, - 0xaa, 0x8d, 0xd3, 0xa4, 0x24, 0x62, 0xd3, 0x33, 0x41, 0x6c, 0x0f, 0xda, 0xe4, 0xb2, 0xc9, 0xf3, - 0xec, 0xd2, 0x79, 0xae, 0x9b, 0x3e, 0x1d, 0x9d, 0xa8, 0x89, 0x64, 0x26, 0x1a, 0xd6, 0xec, 0xda, - 0x83, 0xaf, 0x02, 0xbb, 0x35, 0x1a, 0xc9, 0xf3, 0xd6, 0x2e, 0x63, 0x71, 0x52, 0x8e, 0x75, 0x52, - 0x35, 0x3b, 0xd6, 0xa8, 0xdd, 0x31, 0xf7, 0x1e, 0xb4, 0x0f, 0x8c, 0x2a, 0x4b, 0x62, 0x0d, 0x55, - 0x5f, 0x29, 0xd9, 0xc9, 0x80, 0x18, 0x13, 0x36, 0xcc, 0x09, 0xdd, 0x5f, 0x00, 0xf6, 0x20, 0xc8, - 0x72, 0x4d, 0x5f, 0x51, 0xd6, 0xa9, 0x1c, 0xf5, 0xa2, 0x32, 0xa2, 0x2d, 0x61, 0x54, 0xb1, 0x70, - 0x4b, 0x94, 0x54, 0x94, 0x17, 0xb6, 0x03, 0x2b, 0x81, 0x00, 0x95, 0x25, 0x41, 0x61, 0xea, 0x7e, - 0xb4, 0xd7, 0x24, 0xd0, 0xba, 0x45, 0x7f, 0xe0, 0xc0, 0xb2, 0x5c, 0x1a, 0x5a, 0x1b, 0x95, 0xfa, - 0xd2, 0x96, 0x67, 0xc1, 0xea, 0x2b, 0x0b, 0xab, 0x3c, 0xbc, 0x50, 0xc7, 0xc3, 0x0c, 0x9a, 0x89, - 0x9f, 0x9f, 0x90, 0x83, 0xd2, 0xf2, 0xe8, 0x37, 0x5b, 0x17, 0x4e, 0xb3, 0x90, 0x15, 0x72, 0x98, - 0xeb, 0x8a, 0x6b, 0x85, 0x4a, 0xae, 0xc0, 0x71, 0x51, 0x54, 0x84, 0x20, 0xe0, 0x3a, 0xb7, 0x20, - 0x0b, 0x3c, 0x0a, 0x70, 0xb1, 0x5f, 0x72, 0x88, 0xf2, 0x7e, 0x49, 0x54, 0x4f, 0xf7, 0xbb, 0x7d, - 0xe8, 0xdd, 0xe5, 0x21, 0xcf, 0xf9, 0xad, 0x30, 0x2c, 0x8f, 0xff, 0x0a, 0x5c, 0xac, 0xe9, 0x93, - 0x46, 0xcb, 0x7b, 0xb0, 0x71, 0x97, 0x1f, 0x4d, 0xc7, 0x0f, 0xf8, 0x69, 0x91, 0x00, 0x64, 0xd0, - 0xcc, 0x4e, 0xe2, 0x33, 0x79, 0xb6, 0xf4, 0x9b, 0xbd, 0x0a, 0x10, 0x22, 0xce, 0x20, 0x4b, 0xf8, - 0x50, 0xd5, 0xd4, 0x11, 0xe4, 0x30, 0xe1, 0x43, 0xf7, 0x2d, 0x60, 0xe6, 0x38, 0x72, 0x09, 0xa8, - 0x07, 0xa6, 0x47, 0x83, 0x6c, 0x96, 0xe5, 0x7c, 0xa2, 0x8a, 0x05, 0x4d, 0x90, 0x7b, 0x0d, 0x3a, - 0x07, 0xfe, 0xcc, 0xe3, 0xdf, 0x92, 0x25, 0xbe, 0xe8, 0x1b, 0xfb, 0x33, 0x64, 0x65, 0xed, 0x1b, - 0x53, 0xb7, 0xfb, 0x5f, 0x0d, 0x58, 0x12, 0x98, 0x38, 0xea, 0x88, 0x67, 0x79, 0x10, 0x89, 0xe4, - 0x97, 0x1c, 0xd5, 0x00, 0x55, 0x78, 0xa3, 0x51, 0xc3, 0x1b, 0xd2, 0x5a, 0x55, 0xf5, 0x49, 0x92, - 0x09, 0x2c, 0x18, 0x9a, 0x35, 0x45, 0x51, 0x81, 0x70, 0xce, 0x0a, 0x40, 0x29, 0x58, 0x52, 0x68, - 0x1b, 0x41, 0x9f, 0x62, 0x5a, 0xc9, 0x0e, 0x26, 0xa8, 0x56, 0xa7, 0x2d, 0x0b, 0xae, 0xa9, 0xe8, - 0xb4, 0x8a, 0xee, 0x5a, 0x79, 0x09, 0xdd, 0x25, 0x4c, 0xd8, 0xe7, 0xe9, 0x2e, 0x78, 0x09, 0xdd, - 0xe5, 0x32, 0x58, 0x7f, 0x8f, 0x73, 0x8f, 0xe3, 0xad, 0xa8, 0xd8, 0xe9, 0x7b, 0x0e, 0xac, 0xcb, - 0x0b, 0x5d, 0xf7, 0xb1, 0xd7, 0xad, 0xdb, 0xdf, 0xa9, 0xcb, 0x6b, 0x5c, 0x85, 0x55, 0xba, 0x93, - 0x75, 0x54, 0x48, 0x86, 0xb0, 0x2c, 0x20, 0xae, 0x43, 0x45, 0xea, 0x27, 0x41, 0x28, 0x0f, 0xc5, - 0x04, 0xa9, 0xc0, 0x12, 0xfa, 0xc7, 0x74, 0x24, 0x8e, 0xa7, 0xdb, 0xee, 0xdf, 0x3a, 0xb0, 0x61, - 0x10, 0x2c, 0xb9, 0xf0, 0x5d, 0x50, 0x45, 0x07, 0x22, 0x78, 0x24, 0x84, 0xe9, 0x82, 0x6d, 0x9c, - 0x14, 0x9f, 0x59, 0xc8, 0x74, 0x98, 0xfe, 0x8c, 0x08, 0xcc, 0xa6, 0x13, 0x69, 0x81, 0x98, 0x20, - 0x64, 0xa4, 0x33, 0xce, 0x9f, 0x68, 0x94, 0x05, 0x42, 0xb1, 0x60, 0x94, 0x53, 0x46, 0x5b, 0x42, - 0x23, 0x89, 0x32, 0x2a, 0x1b, 0xe8, 0xfe, 0xb3, 0x03, 0x9b, 0xc2, 0x28, 0x94, 0x26, 0xb7, 0x2e, - 0xf1, 0x5c, 0x12, 0x56, 0xb0, 0x90, 0xc8, 0xfd, 0x73, 0x9e, 0x6c, 0xb3, 0xcf, 0xbe, 0xa4, 0x21, - 0xab, 0x6b, 0x09, 0xe6, 0x9c, 0xc5, 0x42, 0xdd, 0x59, 0x3c, 0x67, 0xa7, 0xeb, 0x82, 0x25, 0x8b, - 0xb5, 0xc1, 0x92, 0xdb, 0xcb, 0xb0, 0x98, 0x0d, 0xe3, 0x84, 0xbb, 0xdb, 0xb0, 0x65, 0x2f, 0x4e, - 0xaa, 0xa0, 0xef, 0x3b, 0xd0, 0x7b, 0x4f, 0x84, 0x0e, 0x83, 0x68, 0xbc, 0x1f, 0x64, 0x79, 0x9c, - 0xea, 0x9a, 0xf6, 0xcb, 0x00, 0x59, 0xee, 0xa7, 0xb9, 0xa8, 0xf5, 0x92, 0x61, 0x8e, 0x02, 0x82, - 0x34, 0xf2, 0x68, 0x24, 0x7a, 0xc5, 0xd9, 0xe8, 0x36, 0x1e, 0x0c, 0xd5, 0x39, 0x0c, 0xe2, 0xe3, - 0xe3, 0x8c, 0x6b, 0xb3, 0xd5, 0x84, 0xa1, 0xe7, 0x8b, 0x12, 0x8f, 0xbe, 0x1e, 0x3f, 0x25, 0x55, - 0x2b, 0xec, 0xc1, 0x12, 0xd4, 0xfd, 0x1b, 0x07, 0xd6, 0x0a, 0x22, 0xef, 0x21, 0xd0, 0xd6, 0x0e, - 0x82, 0x34, 0x43, 0x3b, 0xa8, 0x00, 0x4c, 0x30, 0x1a, 0x04, 0x91, 0xa4, 0xcd, 0x80, 0x90, 0xc4, - 0xca, 0x56, 0x3c, 0x55, 0x75, 0x75, 0x26, 0x48, 0x24, 0xcd, 0x73, 0xfc, 0x5a, 0x14, 0xd5, 0xc9, - 0x16, 0x95, 0xea, 0x4d, 0x72, 0xfa, 0x6a, 0x49, 0x18, 0xc4, 0xb2, 0xa9, 0xee, 0xa7, 0x65, 0x82, - 0xe2, 0x4f, 0xf7, 0x0f, 0x1c, 0xb8, 0x58, 0xb3, 0xb9, 0x52, 0x32, 0xee, 0xc2, 0xc6, 0xb1, 0xee, - 0x54, 0x1b, 0x20, 0xc4, 0x63, 0x5b, 0x72, 0x51, 0x69, 0xd1, 0x5e, 0xf5, 0x03, 0x34, 0x8f, 0x29, - 0x6e, 0x24, 0xb6, 0xd4, 0xaa, 0x37, 0xa9, 0x76, 0xec, 0xfd, 0xe1, 0x02, 0x74, 0x45, 0xca, 0x43, - 0x3c, 0x02, 0xe3, 0x29, 0xfb, 0x00, 0x96, 0xe5, 0x23, 0x3e, 0x76, 0x5e, 0x4e, 0x6b, 0x3f, 0x1b, - 0xec, 0x6f, 0x97, 0xc1, 0x92, 0x77, 0x36, 0x7f, 0xfb, 0xe3, 0x7f, 0xfd, 0xa3, 0xc6, 0x2a, 0x6b, - 0xef, 0x9e, 0xbe, 0xb9, 0x3b, 0xe6, 0x51, 0x86, 0x63, 0xfc, 0x1a, 0x40, 0xf1, 0xbc, 0x8d, 0xf5, - 0xb4, 0x91, 0x51, 0x7a, 0xb7, 0xd7, 0xbf, 0x58, 0xd3, 0x23, 0xc7, 0xbd, 0x48, 0xe3, 0x6e, 0xba, - 0x5d, 0x1c, 0x37, 0x88, 0x82, 0x5c, 0xbc, 0x75, 0x7b, 0xc7, 0xd9, 0x61, 0x23, 0xe8, 0x98, 0xaf, - 0xd7, 0x98, 0x72, 0x99, 0x6b, 0xde, 0xce, 0xf5, 0x5f, 0xa9, 0xed, 0x53, 0xf1, 0x02, 0x9a, 0xe3, - 0xbc, 0xbb, 0x8e, 0x73, 0x4c, 0x09, 0xa3, 0x98, 0x25, 0x84, 0xae, 0xfd, 0x48, 0x8d, 0x5d, 0x32, - 0xc4, 0xba, 0xf2, 0x44, 0xae, 0xff, 0xea, 0x9c, 0x5e, 0x39, 0xd7, 0xab, 0x34, 0xd7, 0x05, 0x97, - 0xe1, 0x5c, 0x43, 0xc2, 0x51, 0x4f, 0xe4, 0xde, 0x71, 0x76, 0xf6, 0xbe, 0xfb, 0x2a, 0xb4, 0x74, - 0x90, 0x8b, 0x7d, 0x13, 0x56, 0xad, 0x9c, 0x14, 0x53, 0xcb, 0xa8, 0x4b, 0x61, 0xf5, 0x2f, 0xd5, - 0x77, 0xca, 0x89, 0x2f, 0xd3, 0xc4, 0x3d, 0xb6, 0x8d, 0x13, 0xcb, 0xa4, 0xce, 0x2e, 0x65, 0xe2, - 0x44, 0x21, 0xe0, 0x13, 0xb1, 0xce, 0x22, 0x8f, 0x64, 0xad, 0xb3, 0x92, 0x77, 0xb2, 0xd6, 0x59, - 0x4d, 0x3e, 0xb9, 0x97, 0x68, 0xba, 0x6d, 0xb6, 0x65, 0x4e, 0xa7, 0x83, 0x4f, 0x9c, 0x4a, 0x37, - 0xcd, 0x37, 0x6c, 0xec, 0x55, 0xcd, 0x58, 0x75, 0x6f, 0xdb, 0x34, 0x8b, 0x54, 0x1f, 0xb8, 0xb9, - 0x3d, 0x9a, 0x8a, 0x31, 0x3a, 0x3e, 0xf3, 0x09, 0x1b, 0xfb, 0x3a, 0xb4, 0xf4, 0x4b, 0x10, 0x76, - 0xc1, 0x78, 0x7e, 0x63, 0x3e, 0x4f, 0xe9, 0xf7, 0xaa, 0x1d, 0x75, 0x8c, 0x61, 0x8e, 0x8c, 0x8c, - 0xf1, 0x00, 0xce, 0x4b, 0x93, 0xf8, 0x88, 0xff, 0x38, 0x2b, 0xa9, 0x79, 0x79, 0x77, 0xd3, 0x61, - 0xef, 0xc2, 0x8a, 0x7a, 0x60, 0xc3, 0xb6, 0xeb, 0x1f, 0x0a, 0xf5, 0x2f, 0x54, 0xe0, 0x52, 0x7b, - 0xdc, 0x02, 0x28, 0x1e, 0x87, 0x68, 0x39, 0xab, 0x3c, 0x59, 0xd1, 0x9b, 0x58, 0xf3, 0x92, 0x64, - 0x4c, 0x4f, 0x61, 0xec, 0xb7, 0x27, 0xec, 0xb5, 0x02, 0xbf, 0xf6, 0x55, 0xca, 0x73, 0x06, 0x74, - 0xb7, 0x69, 0xef, 0xd6, 0x19, 0x09, 0x6e, 0xc4, 0xcf, 0x54, 0x11, 0xf3, 0x5d, 0x68, 0x1b, 0x0f, - 0x4e, 0x98, 0x1a, 0xa1, 0xfa, 0x58, 0xa5, 0xdf, 0xaf, 0xeb, 0x92, 0xe4, 0x7e, 0x11, 0x56, 0xad, - 0x97, 0x23, 0x5a, 0x32, 0xea, 0xde, 0xa5, 0x68, 0xc9, 0xa8, 0x7f, 0x6c, 0xf2, 0x35, 0x68, 0x1b, - 0xef, 0x3c, 0x98, 0x51, 0xbc, 0x55, 0x7a, 0xe1, 0xa1, 0x29, 0xaa, 0x7b, 0x16, 0xb2, 0x45, 0xeb, - 0xed, 0xba, 0x2d, 0x5c, 0x2f, 0x55, 0xf2, 0x22, 0x93, 0x7c, 0x13, 0xba, 0xf6, 0xcb, 0x0f, 0x2d, - 0x55, 0xb5, 0x6f, 0x48, 0xb4, 0x54, 0xcd, 0x79, 0x2e, 0x22, 0x19, 0x72, 0x67, 0x53, 0x4f, 0xb2, - 0xfb, 0x91, 0x4c, 0xf1, 0x3c, 0x63, 0x5f, 0x41, 0xd5, 0x21, 0x4b, 0xab, 0x59, 0xf1, 0xde, 0xc5, - 0x2e, 0xc0, 0xd6, 0xdc, 0x5e, 0xa9, 0xc2, 0x76, 0x37, 0x68, 0xf0, 0x36, 0x2b, 0x56, 0x20, 0xee, - 0x03, 0x2a, 0xb1, 0x36, 0xee, 0x03, 0xb3, 0x0a, 0xdb, 0xb8, 0x0f, 0xac, 0x4a, 0xec, 0xf2, 0x7d, - 0x90, 0x07, 0x38, 0x46, 0x04, 0x6b, 0xa5, 0xea, 0x05, 0x2d, 0x2c, 0xf5, 0xe5, 0x5e, 0xfd, 0xcb, - 0xcf, 0x2f, 0x7a, 0xb0, 0xd5, 0x8c, 0x52, 0x2f, 0xbb, 0xaa, 0x3a, 0xef, 0xd7, 0xa1, 0x63, 0x56, - 0xec, 0xeb, 0x1b, 0xa2, 0xe6, 0x9d, 0x81, 0xbe, 0x21, 0xea, 0x4a, 0xfc, 0xd5, 0xe1, 0xb2, 0x8e, - 0x39, 0x0d, 0xfb, 0x1a, 0xac, 0x19, 0xe5, 0x3a, 0x87, 0xb3, 0x68, 0xa8, 0x99, 0xa7, 0x5a, 0xcc, - 0xd9, 0xaf, 0xb3, 0x06, 0xdd, 0x0b, 0x34, 0xf0, 0x86, 0x6b, 0x0d, 0x8c, 0x8c, 0x73, 0x07, 0xda, - 0x66, 0x29, 0xd0, 0x73, 0xc6, 0xbd, 0x60, 0x74, 0x99, 0x75, 0x8d, 0x37, 0x1d, 0xf6, 0x27, 0x0e, - 0x74, 0xac, 0xc2, 0x1a, 0x2b, 0xaa, 0x5c, 0x1a, 0xa7, 0x67, 0xf6, 0x99, 0x03, 0xb9, 0x1e, 0x11, - 0xf9, 0x60, 0xe7, 0x8b, 0xd6, 0x26, 0x7f, 0x64, 0x79, 0x15, 0x37, 0xca, 0x8f, 0x31, 0x9f, 0x95, - 0x11, 0xcc, 0x82, 0xd7, 0x67, 0x37, 0x1d, 0xf6, 0x8e, 0x78, 0x5e, 0xac, 0xa2, 0x08, 0xcc, 0x50, - 0x6e, 0xe5, 0x2d, 0x33, 0xdf, 0xda, 0x5e, 0x77, 0x6e, 0x3a, 0xec, 0x1b, 0xe2, 0xcd, 0xa5, 0xfc, - 0x96, 0x76, 0xfe, 0x65, 0xbf, 0x77, 0xaf, 0xd2, 0x6a, 0x2e, 0xbb, 0x17, 0xad, 0xd5, 0x94, 0xb5, - 0xfb, 0x2d, 0x41, 0x9d, 0x7c, 0x4a, 0x5b, 0xa8, 0xa9, 0xca, 0xf3, 0xda, 0xf9, 0x44, 0x4e, 0x04, - 0x91, 0x12, 0xdd, 0x62, 0x8f, 0x97, 0x1c, 0xc6, 0xdd, 0x21, 0x5a, 0xaf, 0xba, 0xaf, 0xcd, 0xa5, - 0x75, 0x97, 0xbc, 0x44, 0xa4, 0xf8, 0x00, 0xa0, 0x08, 0x62, 0xb1, 0x52, 0x44, 0x47, 0x6b, 0xea, - 0x6a, 0x9c, 0xcb, 0xe6, 0x41, 0x15, 0xf8, 0xc1, 0x11, 0xbf, 0x2e, 0xc4, 0x47, 0xe2, 0x67, 0x9a, - 0xfa, 0x6a, 0x30, 0xaa, 0xdf, 0xaf, 0xeb, 0xaa, 0x13, 0x1e, 0x35, 0x3e, 0xfb, 0x10, 0x56, 0x1f, - 0xc4, 0xf1, 0x93, 0x69, 0xa2, 0xc3, 0xac, 0x76, 0x4c, 0x65, 0xdf, 0xcf, 0x4e, 0xfa, 0xa5, 0x55, - 0xb8, 0x57, 0x68, 0xa8, 0x3e, 0xeb, 0x19, 0x43, 0xed, 0x7e, 0x54, 0x84, 0xd0, 0x9e, 0x31, 0x1f, - 0x36, 0xf4, 0xad, 0xac, 0x09, 0xef, 0xdb, 0xc3, 0x98, 0x91, 0xac, 0xca, 0x14, 0x96, 0x9d, 0xa4, - 0xa8, 0xdd, 0xcd, 0xd4, 0x98, 0x37, 0x1d, 0x76, 0x00, 0x9d, 0xbb, 0x7c, 0x18, 0x8f, 0xb8, 0x8c, - 0x82, 0x6c, 0x16, 0x84, 0xeb, 0xf0, 0x49, 0x7f, 0xd5, 0x02, 0xda, 0x7a, 0x2a, 0xf1, 0x67, 0x29, - 0xff, 0xd6, 0xee, 0x47, 0x32, 0xbe, 0xf2, 0x4c, 0xe9, 0x29, 0x15, 0x13, 0xb2, 0xf4, 0x54, 0x29, - 0x88, 0x64, 0xe9, 0xa9, 0x4a, 0x10, 0xc9, 0xda, 0x6a, 0x15, 0x93, 0x62, 0x21, 0x6c, 0x54, 0xe2, - 0x4e, 0xfa, 0x6e, 0x9f, 0x17, 0xad, 0xea, 0x5f, 0x99, 0x8f, 0x60, 0xcf, 0xb6, 0x63, 0xcf, 0x76, - 0x08, 0xab, 0x77, 0xb9, 0xd8, 0x2c, 0x91, 0xcb, 0xed, 0xdb, 0x8a, 0xcf, 0xcc, 0xfb, 0x96, 0x95, - 0x22, 0xf5, 0xd9, 0x17, 0x11, 0x25, 0x52, 0xd9, 0xd7, 0xa1, 0x7d, 0x9f, 0xe7, 0x2a, 0x79, 0xab, - 0x2d, 0xa4, 0x52, 0x36, 0xb7, 0x5f, 0x93, 0xfb, 0xb5, 0x79, 0x86, 0x46, 0xdb, 0xe5, 0xa3, 0x31, - 0x17, 0xea, 0x69, 0x10, 0x8c, 0x9e, 0xb1, 0x5f, 0xa1, 0xc1, 0x75, 0xbd, 0xc7, 0xb6, 0x91, 0xf3, - 0x33, 0x07, 0x5f, 0x2b, 0xc1, 0xeb, 0x46, 0x8e, 0xe2, 0x11, 0x37, 0xae, 0xe4, 0x08, 0xda, 0x46, - 0x31, 0x92, 0x16, 0xa0, 0x6a, 0x1d, 0x95, 0x16, 0xa0, 0x9a, 0xda, 0x25, 0xf7, 0x3a, 0xcd, 0xe3, - 0xb2, 0x2b, 0xc5, 0x3c, 0xa2, 0x5e, 0xa9, 0x98, 0x69, 0xf7, 0x23, 0x7f, 0x92, 0x3f, 0x63, 0x8f, - 0xe9, 0x95, 0x94, 0x99, 0xa0, 0x2e, 0x2c, 0xb4, 0x72, 0x2e, 0x5b, 0x6f, 0x96, 0xd1, 0x65, 0x5b, - 0x6d, 0x62, 0x2a, 0xba, 0xb9, 0x3f, 0x0b, 0x70, 0x98, 0xc7, 0xc9, 0x5d, 0x9f, 0x4f, 0xe2, 0xa8, - 0xd0, 0xb5, 0x45, 0x12, 0xb6, 0xd0, 0x5f, 0x46, 0x26, 0x96, 0x3d, 0x36, 0x6c, 0x64, 0x2b, 0xbf, - 0xaf, 0x98, 0x6b, 0x6e, 0x9e, 0x56, 0x6f, 0x48, 0x4d, 0xae, 0xf6, 0xa6, 0x83, 0x16, 0x6f, 0x11, - 0xe5, 0xd4, 0x16, 0x6f, 0x25, 0x80, 0xaa, 0xd5, 0x5e, 0x4d, 0x48, 0xf4, 0x00, 0x5a, 0x45, 0xd8, - 0x4c, 0x5d, 0xa2, 0xe5, 0x20, 0x9b, 0xbe, 0x15, 0x2b, 0xc1, 0x2c, 0x77, 0x9d, 0xb6, 0x0a, 0xd8, - 0x0a, 0x6e, 0x15, 0x45, 0xa8, 0x02, 0xd8, 0x14, 0x04, 0xea, 0x2b, 0x9e, 0xd2, 0x8a, 0x6a, 0x25, - 0x35, 0x01, 0x25, 0x2d, 0xcd, 0xb5, 0xf1, 0x18, 0xcb, 0xf7, 0x45, 0x6e, 0x15, 0x29, 0x4d, 0x54, - 0xcd, 0x13, 0xd8, 0xa8, 0x04, 0x13, 0xb4, 0x48, 0xcf, 0x8b, 0xe1, 0x68, 0x91, 0x9e, 0x1b, 0x87, - 0x70, 0xcf, 0xd3, 0x94, 0x6b, 0x2e, 0xe0, 0x94, 0xd9, 0x59, 0x90, 0x0f, 0x4f, 0xde, 0x71, 0x76, - 0x8e, 0x96, 0xe8, 0x5f, 0x84, 0x3e, 0xfd, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf8, 0xaf, 0xef, - 0x4c, 0x77, 0x48, 0x00, 0x00, + // 5859 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3c, 0x4b, 0x90, 0x1c, 0xc9, + 0x55, 0xaa, 0xee, 0x9e, 0x4f, 0xbf, 0xee, 0xe9, 0x99, 0xc9, 0x19, 0xcd, 0xb4, 0x7a, 0xb5, 0x5a, + 0x6d, 0x59, 0x61, 0xc9, 0xc3, 0xa2, 0xd1, 0x8e, 0xed, 0x65, 0xbd, 0x0b, 0x36, 0xfa, 0xcf, 0xda, + 0x5a, 0x79, 0x5c, 0x23, 0x59, 0x60, 0x43, 0xb4, 0x6b, 0xba, 0x73, 0x7a, 0xca, 0xea, 0xae, 0x2a, + 0x57, 0x55, 0xcf, 0xa8, 0xbd, 0x28, 0x82, 0x5f, 0x70, 0xc2, 0x41, 0x10, 0xf8, 0x62, 0x22, 0x08, + 0x22, 0xcc, 0xc5, 0x1c, 0x38, 0xc2, 0xc5, 0x70, 0xe3, 0x44, 0x04, 0xc1, 0x61, 0x4f, 0x0e, 0x8e, + 0xc0, 0x01, 0x1c, 0x5c, 0x88, 0xe0, 0x4a, 0x10, 0xef, 0xe5, 0xa7, 0x32, 0xab, 0xaa, 0x25, 0xf9, + 0x03, 0xb7, 0xce, 0x97, 0xaf, 0x32, 0x5f, 0x66, 0xbe, 0x5f, 0xbe, 0xf7, 0xb2, 0xa1, 0x99, 0xc4, + 0x83, 0xeb, 0x71, 0x12, 0x65, 0x11, 0x5b, 0x18, 0x87, 0x49, 0x3c, 0xe8, 0x5d, 0x1c, 0x45, 0xd1, + 0x68, 0xcc, 0x77, 0xfd, 0x38, 0xd8, 0xf5, 0xc3, 0x30, 0xca, 0xfc, 0x2c, 0x88, 0xc2, 0x54, 0x20, + 0xb9, 0xdf, 0x80, 0xce, 0x7d, 0x1e, 0x1e, 0x72, 0x3e, 0xf4, 0xf8, 0xb7, 0xa6, 0x3c, 0xcd, 0xd8, + 0x2f, 0xc0, 0xba, 0xcf, 0xbf, 0xcd, 0xf9, 0xb0, 0x1f, 0xfb, 0x69, 0x1a, 0x9f, 0x24, 0x7e, 0xca, + 0xbb, 0xce, 0x65, 0xe7, 0x5a, 0xdb, 0x5b, 0x13, 0x1d, 0x07, 0x1a, 0xce, 0xde, 0x84, 0x76, 0x8a, + 0xa8, 0x3c, 0xcc, 0x92, 0x28, 0x9e, 0x75, 0x6b, 0x84, 0xd7, 0x42, 0xd8, 0x5d, 0x01, 0x72, 0xc7, + 0xb0, 0xaa, 0x67, 0x48, 0xe3, 0x28, 0x4c, 0x39, 0xbb, 0x01, 0x9b, 0x83, 0x20, 0x3e, 0xe1, 0x49, + 0x9f, 0x3e, 0x9e, 0x84, 0x7c, 0x12, 0x85, 0xc1, 0xa0, 0xeb, 0x5c, 0xae, 0x5f, 0x6b, 0x7a, 0x4c, + 0xf4, 0xe1, 0x17, 0x1f, 0xca, 0x1e, 0x76, 0x15, 0x56, 0x79, 0x28, 0xe0, 0x7c, 0x48, 0x5f, 0xc9, + 0xa9, 0x3a, 0x39, 0x18, 0x3f, 0x70, 0xff, 0xde, 0x81, 0xf5, 0x0f, 0xc2, 0x20, 0x7b, 0xe2, 0x8f, + 0xc7, 0x3c, 0x53, 0x6b, 0xba, 0x0a, 0xab, 0x67, 0x04, 0xa0, 0x35, 0x9d, 0x45, 0xc9, 0x50, 0xae, + 0xa8, 0x23, 0xc0, 0x07, 0x12, 0x3a, 0x97, 0xb2, 0xda, 0x5c, 0xca, 0x2a, 0xb7, 0xab, 0x3e, 0x67, + 0xbb, 0xae, 0xc2, 0x6a, 0xc2, 0x07, 0xd1, 0x29, 0x4f, 0x66, 0xfd, 0xb3, 0x20, 0x1c, 0x46, 0x67, + 0xdd, 0xc6, 0x65, 0xe7, 0xda, 0x82, 0xd7, 0x51, 0xe0, 0x27, 0x04, 0x75, 0x37, 0x81, 0x99, 0xab, + 0x10, 0xfb, 0xe6, 0x8e, 0x60, 0xe3, 0x71, 0x38, 0x8e, 0x06, 0x4f, 0x7f, 0xca, 0xd5, 0x55, 0x4c, + 0x5f, 0xab, 0x9c, 0x7e, 0x0b, 0x36, 0xed, 0x89, 0x24, 0x01, 0x1c, 0xce, 0xdf, 0x3e, 0xf1, 0xc3, + 0x11, 0x57, 0x43, 0x2a, 0x12, 0x3e, 0x05, 0x6b, 0x83, 0x69, 0x92, 0xf0, 0xb0, 0x44, 0xc3, 0xaa, + 0x84, 0x6b, 0x22, 0xde, 0x84, 0x76, 0xc8, 0xcf, 0x72, 0x34, 0xc9, 0x32, 0x21, 0x3f, 0x53, 0x28, + 0x6e, 0x17, 0xb6, 0x8a, 0xd3, 0x48, 0x02, 0xbe, 0x57, 0x83, 0xd6, 0xa3, 0xc4, 0x0f, 0x53, 0x7f, + 0x80, 0x5c, 0xcc, 0xba, 0xb0, 0x94, 0x3d, 0xeb, 0x9f, 0xf8, 0xe9, 0x09, 0x4d, 0xd7, 0xf4, 0x54, + 0x93, 0x6d, 0xc1, 0xa2, 0x3f, 0x89, 0xa6, 0x61, 0x46, 0x13, 0xd4, 0x3d, 0xd9, 0x62, 0x6f, 0xc1, + 0x7a, 0x38, 0x9d, 0xf4, 0x07, 0x51, 0x78, 0x1c, 0x24, 0x13, 0x21, 0x0b, 0x74, 0x5e, 0x0b, 0x5e, + 0xb9, 0x83, 0x5d, 0x02, 0x38, 0xc2, 0x7d, 0x10, 0x53, 0x34, 0x68, 0x0a, 0x03, 0xc2, 0x5c, 0x68, + 0xcb, 0x16, 0x0f, 0x46, 0x27, 0x59, 0x77, 0x81, 0x06, 0xb2, 0x60, 0x38, 0x46, 0x16, 0x4c, 0x78, + 0x3f, 0xcd, 0xfc, 0x49, 0xdc, 0x5d, 0x24, 0x6a, 0x0c, 0x08, 0xf5, 0x47, 0x99, 0x3f, 0xee, 0x1f, + 0x73, 0x9e, 0x76, 0x97, 0x64, 0xbf, 0x86, 0xb0, 0x4f, 0x42, 0x67, 0xc8, 0xd3, 0xac, 0xef, 0x0f, + 0x87, 0x09, 0x4f, 0x53, 0x9e, 0x76, 0x97, 0x89, 0x1b, 0x0b, 0x50, 0xdc, 0xb5, 0xfb, 0x3c, 0x33, + 0x76, 0x27, 0x95, 0xa7, 0xe3, 0x3e, 0x00, 0x66, 0x80, 0xef, 0xf0, 0xcc, 0x0f, 0xc6, 0x29, 0x7b, + 0x07, 0xda, 0x99, 0x81, 0x4c, 0xd2, 0xd7, 0xda, 0x63, 0xd7, 0x49, 0x6d, 0x5c, 0x37, 0x3e, 0xf0, + 0x2c, 0x3c, 0xf7, 0x3e, 0x2c, 0xdf, 0xe3, 0xfc, 0x41, 0x30, 0x09, 0x32, 0xb6, 0x05, 0x0b, 0xc7, + 0xc1, 0x33, 0x2e, 0x0e, 0xbb, 0xbe, 0x7f, 0xce, 0x13, 0x4d, 0xd6, 0x83, 0xa5, 0x98, 0x27, 0x03, + 0xae, 0xb6, 0x7f, 0xff, 0x9c, 0xa7, 0x00, 0xb7, 0x96, 0x60, 0x61, 0x8c, 0x1f, 0xbb, 0x3f, 0xa8, + 0x41, 0xeb, 0x90, 0x87, 0x9a, 0x89, 0x18, 0x34, 0x70, 0x49, 0x92, 0x71, 0xe8, 0x37, 0x7b, 0x03, + 0x5a, 0xb4, 0xcc, 0x34, 0x4b, 0x82, 0x70, 0x44, 0x83, 0x35, 0x3d, 0x40, 0xd0, 0x21, 0x41, 0xd8, + 0x1a, 0xd4, 0xfd, 0x49, 0x46, 0x27, 0x58, 0xf7, 0xf0, 0x27, 0x32, 0x58, 0xec, 0xcf, 0x26, 0xc8, + 0x8b, 0xfa, 0xd4, 0xda, 0x5e, 0x4b, 0xc2, 0xf6, 0xf1, 0xd8, 0xae, 0xc3, 0x86, 0x89, 0xa2, 0x46, + 0x5f, 0xa0, 0xd1, 0xd7, 0x0d, 0x4c, 0x39, 0xc9, 0x55, 0x58, 0x55, 0xf8, 0x89, 0x20, 0x96, 0xce, + 0xb1, 0xe9, 0x75, 0x24, 0x58, 0x2d, 0xe1, 0x1a, 0xac, 0x1d, 0x07, 0xa1, 0x3f, 0xee, 0x0f, 0xc6, + 0xd9, 0x69, 0x7f, 0xc8, 0xc7, 0x99, 0x4f, 0x27, 0xba, 0xe0, 0x75, 0x08, 0x7e, 0x7b, 0x9c, 0x9d, + 0xde, 0x41, 0x28, 0x7b, 0x0b, 0x9a, 0xc7, 0x9c, 0xf7, 0x69, 0x27, 0xba, 0xcb, 0x97, 0x9d, 0x6b, + 0xad, 0xbd, 0x55, 0xb9, 0xf5, 0x6a, 0x77, 0xbd, 0xe5, 0x63, 0xf9, 0xcb, 0xfd, 0xae, 0x03, 0x6d, + 0xb1, 0x55, 0x52, 0x85, 0x5e, 0x81, 0x15, 0x45, 0x11, 0x4f, 0x92, 0x28, 0x91, 0xec, 0x6f, 0x03, + 0xd9, 0x0e, 0xac, 0x29, 0x40, 0x9c, 0xf0, 0x60, 0xe2, 0x8f, 0xb8, 0x94, 0xb7, 0x12, 0x9c, 0xed, + 0xe5, 0x23, 0x26, 0xd1, 0x34, 0x13, 0x4a, 0xac, 0xb5, 0xd7, 0x96, 0x44, 0x79, 0x08, 0xf3, 0x6c, + 0x14, 0xf7, 0x3b, 0x0e, 0x30, 0x24, 0xeb, 0x51, 0x24, 0xba, 0xe5, 0x2e, 0x14, 0x4f, 0xc0, 0x79, + 0xe5, 0x13, 0xa8, 0xcd, 0x3b, 0x81, 0x2b, 0xb0, 0x48, 0x53, 0xa2, 0xac, 0xd6, 0x4b, 0x64, 0xc9, + 0x3e, 0xf7, 0xfb, 0x0e, 0xb4, 0x51, 0x73, 0x84, 0x7c, 0x7c, 0x10, 0x05, 0x61, 0xc6, 0x6e, 0x00, + 0x3b, 0x9e, 0x86, 0xc3, 0x20, 0x1c, 0xf5, 0xb3, 0x67, 0xc1, 0xb0, 0x7f, 0x34, 0xc3, 0x21, 0x88, + 0x9e, 0xfd, 0x73, 0x5e, 0x45, 0x1f, 0x7b, 0x0b, 0xd6, 0x2c, 0x68, 0x9a, 0x25, 0x82, 0xaa, 0xfd, + 0x73, 0x5e, 0xa9, 0x07, 0xe5, 0x3f, 0x9a, 0x66, 0xf1, 0x34, 0xeb, 0x07, 0xe1, 0x90, 0x3f, 0xa3, + 0x3d, 0x5b, 0xf1, 0x2c, 0xd8, 0xad, 0x0e, 0xb4, 0xcd, 0xef, 0xdc, 0xcf, 0xc3, 0xda, 0x03, 0x54, + 0x0c, 0x61, 0x10, 0x8e, 0x6e, 0x0a, 0xe9, 0x45, 0x6d, 0x15, 0x4f, 0x8f, 0x9e, 0xf2, 0x99, 0x3c, + 0x47, 0xd9, 0x42, 0x91, 0x38, 0x89, 0xd2, 0x4c, 0xee, 0x0b, 0xfd, 0x76, 0xff, 0xc5, 0x81, 0x55, + 0xdc, 0xf4, 0x0f, 0xfd, 0x70, 0xa6, 0x76, 0xfc, 0x01, 0xb4, 0x71, 0xa8, 0x47, 0xd1, 0x4d, 0xa1, + 0xf3, 0x84, 0x2c, 0x5f, 0x93, 0x9b, 0x54, 0xc0, 0xbe, 0x6e, 0xa2, 0xa2, 0x99, 0x9e, 0x79, 0xd6, + 0xd7, 0x28, 0x74, 0x99, 0x9f, 0x8c, 0x78, 0x46, 0xda, 0x50, 0x6a, 0x47, 0x10, 0xa0, 0xdb, 0x51, + 0x78, 0xcc, 0x2e, 0x43, 0x3b, 0xf5, 0xb3, 0x7e, 0xcc, 0x13, 0xda, 0x35, 0x12, 0x9c, 0xba, 0x07, + 0xa9, 0x9f, 0x1d, 0xf0, 0xe4, 0xd6, 0x2c, 0xe3, 0xbd, 0x2f, 0xc0, 0x7a, 0x69, 0x16, 0x94, 0xd5, + 0x7c, 0x89, 0xf8, 0x93, 0x6d, 0xc2, 0xc2, 0xa9, 0x3f, 0x9e, 0x72, 0xa9, 0xa4, 0x45, 0xe3, 0xbd, + 0xda, 0xbb, 0x8e, 0xfb, 0x49, 0x58, 0xcb, 0xc9, 0x96, 0x4c, 0xcf, 0xa0, 0x81, 0x3b, 0x28, 0x07, + 0xa0, 0xdf, 0xee, 0xef, 0x38, 0x02, 0xf1, 0x76, 0x14, 0x68, 0x85, 0x87, 0x88, 0xa8, 0x17, 0x15, + 0x22, 0xfe, 0x9e, 0x6b, 0x10, 0x7e, 0xf6, 0xc5, 0xba, 0x57, 0x61, 0xdd, 0x20, 0xe1, 0x05, 0xc4, + 0x7e, 0xc7, 0x81, 0xf5, 0x87, 0xfc, 0x4c, 0x9e, 0xba, 0xa2, 0xf6, 0x5d, 0x68, 0x64, 0xb3, 0x58, + 0x38, 0x59, 0x9d, 0xbd, 0x2b, 0xf2, 0xd0, 0x4a, 0x78, 0xd7, 0x65, 0xf3, 0xd1, 0x2c, 0xe6, 0x1e, + 0x7d, 0xe1, 0x7e, 0x1e, 0x5a, 0x06, 0x90, 0x6d, 0xc3, 0xc6, 0x93, 0x0f, 0x1e, 0x3d, 0xbc, 0x7b, + 0x78, 0xd8, 0x3f, 0x78, 0x7c, 0xeb, 0x4b, 0x77, 0x7f, 0xbd, 0xbf, 0x7f, 0xf3, 0x70, 0x7f, 0xed, + 0x1c, 0xdb, 0x02, 0xf6, 0xf0, 0xee, 0xe1, 0xa3, 0xbb, 0x77, 0x2c, 0xb8, 0xe3, 0xf6, 0xa0, 0xfb, + 0x90, 0x9f, 0x3d, 0x09, 0xb2, 0x90, 0xa7, 0xa9, 0x3d, 0x9b, 0x7b, 0x1d, 0x98, 0x49, 0x82, 0x5c, + 0x55, 0x17, 0x96, 0xa4, 0xc5, 0x51, 0x06, 0x57, 0x36, 0xdd, 0x4f, 0x02, 0x3b, 0x0c, 0x46, 0xe1, + 0x87, 0x3c, 0x4d, 0xfd, 0x91, 0x56, 0x05, 0x6b, 0x50, 0x9f, 0xa4, 0x23, 0xa9, 0x01, 0xf0, 0xa7, + 0xfb, 0x69, 0xd8, 0xb0, 0xf0, 0xe4, 0xc0, 0x17, 0xa1, 0x99, 0x06, 0xa3, 0xd0, 0xcf, 0xa6, 0x09, + 0x97, 0x43, 0xe7, 0x00, 0xf7, 0x1e, 0x6c, 0x7e, 0x95, 0x27, 0xc1, 0xf1, 0xec, 0x65, 0xc3, 0xdb, + 0xe3, 0xd4, 0x8a, 0xe3, 0xdc, 0x85, 0xf3, 0x85, 0x71, 0xe4, 0xf4, 0x82, 0x11, 0xe5, 0x71, 0x2d, + 0x7b, 0xa2, 0x61, 0x88, 0x65, 0xcd, 0x14, 0x4b, 0xf7, 0x31, 0xb0, 0xdb, 0x51, 0x18, 0xf2, 0x41, + 0x76, 0xc0, 0x79, 0x92, 0x7b, 0xce, 0x39, 0xd7, 0xb5, 0xf6, 0xb6, 0xe5, 0x39, 0x16, 0x65, 0x5d, + 0xb2, 0x23, 0x83, 0x46, 0xcc, 0x93, 0x09, 0x0d, 0xbc, 0xec, 0xd1, 0x6f, 0xf7, 0x3c, 0x6c, 0x58, + 0xc3, 0x4a, 0xa7, 0xe7, 0x6d, 0x38, 0x7f, 0x27, 0x48, 0x07, 0xe5, 0x09, 0xbb, 0xb0, 0x14, 0x4f, + 0x8f, 0xfa, 0xb9, 0x4c, 0xa9, 0x26, 0xfa, 0x02, 0xc5, 0x4f, 0xe4, 0x60, 0x7f, 0xe0, 0x40, 0x63, + 0xff, 0xd1, 0x83, 0xdb, 0xac, 0x07, 0xcb, 0x41, 0x38, 0x88, 0x26, 0xa8, 0x76, 0xc5, 0xa2, 0x75, + 0x7b, 0xae, 0xac, 0x5c, 0x84, 0x26, 0x69, 0x6b, 0x74, 0x6f, 0xa4, 0x93, 0x9b, 0x03, 0xd0, 0xb5, + 0xe2, 0xcf, 0xe2, 0x20, 0x21, 0xdf, 0x49, 0x79, 0x44, 0x0d, 0xd2, 0x88, 0xe5, 0x0e, 0xf7, 0x7f, + 0x1a, 0xb0, 0x24, 0x75, 0x35, 0xcd, 0x37, 0xc8, 0x82, 0x53, 0x2e, 0x29, 0x91, 0x2d, 0xb4, 0x72, + 0x09, 0x9f, 0x44, 0x19, 0xef, 0x5b, 0xc7, 0x60, 0x03, 0x11, 0x6b, 0x20, 0x06, 0xea, 0xc7, 0xa8, + 0xf5, 0x89, 0xb2, 0xa6, 0x67, 0x03, 0x71, 0xb3, 0x10, 0xd0, 0x0f, 0x86, 0x44, 0x53, 0xc3, 0x53, + 0x4d, 0xdc, 0x89, 0x81, 0x1f, 0xfb, 0x83, 0x20, 0x9b, 0x49, 0xe1, 0xd6, 0x6d, 0x1c, 0x7b, 0x1c, + 0x0d, 0xfc, 0x71, 0xff, 0xc8, 0x1f, 0xfb, 0xe1, 0x80, 0x4b, 0xff, 0xcd, 0x06, 0xa2, 0x8b, 0x26, + 0x49, 0x52, 0x68, 0xc2, 0x8d, 0x2b, 0x40, 0xd1, 0xd5, 0x1b, 0x44, 0x93, 0x49, 0x90, 0xa1, 0x67, + 0x47, 0x56, 0xbf, 0xee, 0x19, 0x10, 0x5a, 0x89, 0x68, 0x9d, 0x89, 0xdd, 0x6b, 0x8a, 0xd9, 0x2c, + 0x20, 0x8e, 0x82, 0xae, 0x03, 0x2a, 0xa4, 0xa7, 0x67, 0x5d, 0x10, 0xa3, 0xe4, 0x10, 0x3c, 0x87, + 0x69, 0x98, 0xf2, 0x2c, 0x1b, 0xf3, 0xa1, 0x26, 0xa8, 0x45, 0x68, 0xe5, 0x0e, 0x76, 0x03, 0x36, + 0x84, 0xb3, 0x99, 0xfa, 0x59, 0x94, 0x9e, 0x04, 0x69, 0x3f, 0x45, 0xb7, 0xad, 0x4d, 0xf8, 0x55, + 0x5d, 0xec, 0x5d, 0xd8, 0x2e, 0x80, 0x13, 0x3e, 0xe0, 0xc1, 0x29, 0x1f, 0x76, 0x57, 0xe8, 0xab, + 0x79, 0xdd, 0xec, 0x32, 0xb4, 0xd0, 0xc7, 0x9e, 0xc6, 0x43, 0x1f, 0xed, 0x70, 0x87, 0xce, 0xc1, + 0x04, 0xb1, 0xb7, 0x61, 0x25, 0xe6, 0xc2, 0x58, 0x9e, 0x64, 0xe3, 0x41, 0xda, 0x5d, 0x25, 0x4b, + 0xd6, 0x92, 0xc2, 0x84, 0x9c, 0xeb, 0xd9, 0x18, 0xc8, 0x94, 0x83, 0x94, 0x9c, 0x2d, 0x7f, 0xd6, + 0x5d, 0x23, 0x76, 0xcb, 0x01, 0x24, 0x23, 0x49, 0x70, 0xea, 0x67, 0xbc, 0xbb, 0x4e, 0xbc, 0xa5, + 0x9a, 0xee, 0x9f, 0x3b, 0xb0, 0xf1, 0x20, 0x48, 0x33, 0xc9, 0x84, 0x5a, 0x1d, 0xbf, 0x01, 0x2d, + 0xc1, 0x7e, 0xfd, 0x28, 0x1c, 0xcf, 0x24, 0x47, 0x82, 0x00, 0x7d, 0x39, 0x1c, 0xcf, 0xd8, 0x27, + 0x60, 0x25, 0x08, 0x4d, 0x14, 0x21, 0xc3, 0x6d, 0x05, 0x24, 0xa4, 0x37, 0xa0, 0x15, 0x4f, 0x8f, + 0xc6, 0xc1, 0x40, 0xa0, 0xd4, 0xc5, 0x28, 0x02, 0x44, 0x08, 0xe8, 0x24, 0x09, 0x4a, 0x04, 0x46, + 0x83, 0x30, 0x5a, 0x12, 0x86, 0x28, 0xee, 0x2d, 0xd8, 0xb4, 0x09, 0x94, 0xca, 0x6a, 0x07, 0x96, + 0x25, 0x6f, 0xa7, 0xdd, 0x16, 0xed, 0x4f, 0x47, 0xee, 0x8f, 0x44, 0xf5, 0x74, 0xbf, 0xfb, 0x1f, + 0x0e, 0x34, 0x50, 0x01, 0xcc, 0x57, 0x16, 0xa6, 0x4e, 0xaf, 0x5b, 0x3a, 0x9d, 0xae, 0x3f, 0xe8, + 0x15, 0x09, 0x96, 0x10, 0x62, 0x63, 0x40, 0xf2, 0xfe, 0x84, 0x0f, 0x4e, 0x49, 0x76, 0x74, 0x3f, + 0x42, 0x50, 0xb2, 0xd0, 0x74, 0xd2, 0xd7, 0x42, 0x70, 0x74, 0x5b, 0xf5, 0xd1, 0x97, 0x4b, 0x79, + 0x1f, 0x7d, 0xd7, 0x85, 0xa5, 0x20, 0x3c, 0x8a, 0xa6, 0xe1, 0x90, 0x84, 0x64, 0xd9, 0x53, 0x4d, + 0x3c, 0xec, 0x98, 0x3c, 0xa9, 0x60, 0xc2, 0xa5, 0x74, 0xe4, 0x00, 0x97, 0xa1, 0x6b, 0x95, 0x92, + 0xc2, 0xd3, 0x76, 0xec, 0x1d, 0x58, 0x37, 0x60, 0x72, 0x07, 0xdf, 0x84, 0x85, 0x18, 0x01, 0xd2, + 0x51, 0x52, 0xec, 0x45, 0x9a, 0x52, 0xf4, 0xb8, 0x6b, 0xd0, 0xb9, 0xcf, 0xb3, 0x0f, 0xc2, 0xe3, + 0x48, 0x8d, 0xf4, 0xa3, 0x3a, 0xac, 0x6a, 0x90, 0x1c, 0xe8, 0x1a, 0xac, 0x06, 0x43, 0x1e, 0x66, + 0x41, 0x36, 0xeb, 0x5b, 0x1e, 0x5c, 0x11, 0x8c, 0x16, 0xc6, 0x1f, 0x07, 0x7e, 0x2a, 0x75, 0x98, + 0x68, 0xb0, 0x3d, 0xd8, 0x44, 0xf6, 0x57, 0x1c, 0xad, 0x8f, 0x55, 0x38, 0x92, 0x95, 0x7d, 0x28, + 0xb1, 0x08, 0x97, 0x1c, 0xa8, 0x3f, 0x11, 0x9a, 0xb6, 0xaa, 0x0b, 0x77, 0x4d, 0x8c, 0x84, 0x4b, + 0x5e, 0x10, 0x22, 0xa2, 0x01, 0xa5, 0x4b, 0xec, 0xa2, 0x70, 0x62, 0x8b, 0x97, 0x58, 0xe3, 0x22, + 0xbc, 0x5c, 0xba, 0x08, 0x5f, 0x83, 0xd5, 0x74, 0x16, 0x0e, 0xf8, 0xb0, 0x9f, 0x45, 0x38, 0x6f, + 0x10, 0xd2, 0xe9, 0x2c, 0x7b, 0x45, 0x30, 0x5d, 0xd9, 0x79, 0x9a, 0x85, 0x3c, 0x23, 0xd5, 0xb5, + 0xec, 0xa9, 0x26, 0x5a, 0x01, 0x42, 0x11, 0x4c, 0xdd, 0xf4, 0x64, 0x0b, 0x4d, 0xe5, 0x34, 0x09, + 0xd2, 0x6e, 0x9b, 0xa0, 0xf4, 0x9b, 0x7d, 0x06, 0xce, 0x1f, 0xe1, 0xbd, 0xf0, 0x84, 0xfb, 0x43, + 0x9e, 0xd0, 0xe9, 0x8b, 0xfb, 0xb5, 0xd0, 0x40, 0xd5, 0x9d, 0x38, 0xf7, 0x29, 0x4f, 0xd2, 0x20, + 0x0a, 0x49, 0xf7, 0x34, 0x3d, 0xd5, 0x74, 0xbf, 0x4d, 0x16, 0x5d, 0xdf, 0xfc, 0x1f, 0x93, 0x3a, + 0x62, 0xaf, 0x41, 0x53, 0xac, 0x31, 0x3d, 0xf1, 0xa5, 0x93, 0xb1, 0x4c, 0x80, 0xc3, 0x13, 0x1f, + 0x05, 0xd8, 0xda, 0x36, 0x11, 0x4a, 0x69, 0x11, 0x6c, 0x5f, 0xec, 0xda, 0x15, 0xe8, 0xa8, 0x98, + 0x42, 0xda, 0x1f, 0xf3, 0xe3, 0x4c, 0x5d, 0x10, 0xc2, 0xe9, 0x04, 0xa7, 0x4b, 0x1f, 0xf0, 0xe3, + 0xcc, 0x7d, 0x08, 0xeb, 0x52, 0x6e, 0xbf, 0x1c, 0x73, 0x35, 0xf5, 0xe7, 0x8a, 0x46, 0x4d, 0x78, + 0x15, 0x1b, 0xb6, 0xa0, 0xd3, 0x2d, 0xa7, 0x60, 0xe9, 0x5c, 0x0f, 0x98, 0xec, 0xbe, 0x3d, 0x8e, + 0x52, 0x2e, 0x07, 0x74, 0xa1, 0x3d, 0x18, 0x47, 0xa9, 0xba, 0x86, 0xc8, 0xe5, 0x58, 0x30, 0xdc, + 0x9f, 0x74, 0x3a, 0x18, 0xa0, 0x26, 0x10, 0x3a, 0x4d, 0x35, 0xdd, 0x1f, 0x38, 0xb0, 0x41, 0xa3, + 0x29, 0x0d, 0xa3, 0x7d, 0xd7, 0x57, 0x27, 0xb3, 0x3d, 0x30, 0xaf, 0x66, 0x9b, 0xb0, 0x70, 0x1c, + 0x25, 0x03, 0x2e, 0x67, 0x12, 0x8d, 0x9f, 0xdc, 0x1b, 0x6f, 0x94, 0xbc, 0xf1, 0x1f, 0x39, 0xb0, + 0x4e, 0xa4, 0x1e, 0x66, 0x7e, 0x36, 0x4d, 0xe5, 0xf2, 0x7f, 0x19, 0x56, 0x70, 0xa9, 0x5c, 0x89, + 0x93, 0x24, 0x74, 0x53, 0x4b, 0x3e, 0x41, 0x05, 0xf2, 0xfe, 0x39, 0xcf, 0x46, 0x66, 0x5f, 0x80, + 0xb6, 0x19, 0x18, 0x22, 0x9a, 0x5b, 0x7b, 0x17, 0xd4, 0x2a, 0x4b, 0x9c, 0xb3, 0x7f, 0xce, 0xb3, + 0x3e, 0x60, 0xef, 0x03, 0x90, 0xbb, 0x41, 0xc3, 0xca, 0xab, 0xf5, 0x05, 0x7b, 0x93, 0x8c, 0xc3, + 0xda, 0x3f, 0xe7, 0x19, 0xe8, 0xb7, 0x96, 0x61, 0x51, 0xd8, 0x47, 0xf7, 0x3e, 0xac, 0x58, 0x94, + 0x5a, 0xb7, 0x8c, 0xb6, 0xb8, 0x65, 0x94, 0x2e, 0xa5, 0xb5, 0xf2, 0xa5, 0xd4, 0xfd, 0xb7, 0x1a, + 0x30, 0xe4, 0xb6, 0xc2, 0x71, 0xa2, 0x81, 0x8e, 0x86, 0x96, 0xbb, 0xd5, 0xf6, 0x4c, 0x10, 0xbb, + 0x0e, 0xcc, 0x68, 0xaa, 0x7b, 0xbb, 0xb0, 0x1b, 0x15, 0x3d, 0xa8, 0xe0, 0x84, 0xaf, 0xa4, 0xee, + 0xc0, 0xd2, 0xb1, 0x14, 0xe7, 0x56, 0xd9, 0x87, 0xa6, 0x21, 0x9e, 0xa6, 0x27, 0xe8, 0x40, 0x28, + 0x87, 0x4c, 0xb5, 0x8b, 0x0c, 0xb2, 0xf8, 0x52, 0x06, 0x59, 0x2a, 0x32, 0x88, 0xe9, 0x12, 0x2c, + 0x5b, 0x2e, 0x01, 0xfa, 0x5f, 0x93, 0x20, 0x24, 0xbf, 0xa2, 0x3f, 0xc1, 0xd9, 0xa5, 0xff, 0x65, + 0x01, 0xd9, 0x0e, 0xac, 0x49, 0xbf, 0x2e, 0xf7, 0x3b, 0x80, 0xf6, 0xb8, 0x04, 0x77, 0x3f, 0x76, + 0x60, 0x0d, 0xf7, 0xd9, 0xe2, 0xc5, 0xf7, 0x80, 0x44, 0xe1, 0x15, 0x59, 0xd1, 0xc2, 0xfd, 0xd9, + 0x39, 0xf1, 0x5d, 0x68, 0xd2, 0x80, 0x51, 0xcc, 0x43, 0xc9, 0x88, 0x5d, 0x9b, 0x11, 0x73, 0x2d, + 0xb4, 0x7f, 0xce, 0xcb, 0x91, 0x0d, 0x36, 0xfc, 0x27, 0x07, 0x5a, 0x92, 0xcc, 0x9f, 0xfa, 0x2e, + 0xd1, 0x83, 0x65, 0xe4, 0x48, 0xc3, 0x61, 0xd7, 0x6d, 0xb4, 0x26, 0x13, 0xbc, 0xb0, 0xa1, 0xf9, + 0xb4, 0xee, 0x11, 0x45, 0x30, 0xda, 0x42, 0x52, 0xb8, 0x69, 0x3f, 0x0b, 0xc6, 0x7d, 0xd5, 0x2b, + 0xe3, 0xb0, 0x55, 0x5d, 0xa8, 0x77, 0xd2, 0xcc, 0x1f, 0x71, 0x69, 0xe6, 0x44, 0x03, 0x2f, 0x4c, + 0x72, 0x41, 0x05, 0x77, 0xd0, 0xfd, 0xbb, 0x36, 0x6c, 0x97, 0xba, 0x74, 0x22, 0x43, 0x3a, 0xc8, + 0xe3, 0x60, 0x72, 0x14, 0x69, 0x5f, 0xdb, 0x31, 0x7d, 0x67, 0xab, 0x8b, 0x8d, 0xe0, 0xbc, 0xb2, + 0xe7, 0xb8, 0xa7, 0xb9, 0xf5, 0xae, 0x91, 0x23, 0xf2, 0xb6, 0xcd, 0x03, 0xc5, 0x09, 0x15, 0xdc, + 0x94, 0xdc, 0xea, 0xf1, 0xd8, 0x09, 0x74, 0xb5, 0xe3, 0x20, 0x55, 0xbc, 0xe1, 0x5c, 0xe0, 0x5c, + 0x6f, 0xbd, 0x64, 0x2e, 0xd2, 0x47, 0x43, 0x35, 0xcd, 0xdc, 0xd1, 0xd8, 0x0c, 0x2e, 0xa9, 0x3e, + 0xd2, 0xe1, 0xe5, 0xf9, 0x1a, 0xaf, 0xb4, 0xb6, 0x7b, 0xf8, 0xb1, 0x3d, 0xe9, 0x4b, 0x06, 0x66, + 0xdf, 0x84, 0xad, 0x33, 0x3f, 0xc8, 0x14, 0x59, 0x86, 0x33, 0xb4, 0x40, 0x53, 0xee, 0xbd, 0x64, + 0xca, 0x27, 0xe2, 0x63, 0xcb, 0xb0, 0xcd, 0x19, 0xb1, 0xf7, 0x0f, 0x0e, 0x74, 0xec, 0x71, 0x90, + 0x4d, 0xa5, 0xc0, 0x2b, 0xc5, 0xa7, 0x9c, 0xbf, 0x02, 0xb8, 0x7c, 0x45, 0xad, 0x55, 0x5d, 0x51, + 0xcd, 0x8b, 0x68, 0xfd, 0x65, 0x17, 0xd1, 0xc6, 0xab, 0x5d, 0x44, 0x17, 0xaa, 0x2e, 0xa2, 0xbd, + 0xff, 0x76, 0x80, 0x95, 0x79, 0x89, 0xdd, 0x17, 0x77, 0xe4, 0x90, 0x8f, 0xa5, 0x4e, 0xfa, 0xc5, + 0x57, 0xe3, 0x47, 0xb5, 0x77, 0xea, 0x6b, 0x14, 0x0c, 0x53, 0xe9, 0x98, 0x2e, 0xd2, 0x8a, 0x57, + 0xd5, 0x55, 0xb8, 0x1a, 0x37, 0x5e, 0x7e, 0x35, 0x5e, 0x78, 0xf9, 0xd5, 0x78, 0xb1, 0x78, 0x35, + 0xee, 0xfd, 0xbe, 0x03, 0x1b, 0x15, 0x87, 0xfe, 0xf3, 0x5b, 0x38, 0x1e, 0x93, 0xa5, 0x0b, 0x6a, + 0xf2, 0x98, 0x4c, 0x60, 0xef, 0xb7, 0x60, 0xc5, 0x62, 0xf4, 0x9f, 0xdf, 0xfc, 0x45, 0x2f, 0x4f, + 0xf0, 0x99, 0x05, 0xeb, 0xfd, 0xb8, 0x06, 0xac, 0x2c, 0x6c, 0xff, 0xaf, 0x34, 0x94, 0xf7, 0xa9, + 0x5e, 0xb1, 0x4f, 0xff, 0xa7, 0x76, 0xe0, 0x2d, 0x58, 0x97, 0x59, 0x4f, 0x23, 0x4a, 0x22, 0x38, + 0xa6, 0xdc, 0x81, 0x7e, 0xae, 0x1d, 0x97, 0x58, 0xb6, 0xb2, 0x65, 0x86, 0x31, 0x2c, 0x84, 0x27, + 0xdc, 0x2d, 0xd8, 0x14, 0x59, 0xd4, 0x5b, 0x62, 0x28, 0x65, 0x57, 0xfe, 0xcc, 0x81, 0xf3, 0x85, + 0x8e, 0x3c, 0xb7, 0x23, 0x4c, 0x87, 0x6d, 0x4f, 0x6c, 0x20, 0xd2, 0x2f, 0xe5, 0xc8, 0xa0, 0x5f, + 0x70, 0x5b, 0xb9, 0x03, 0xf7, 0x67, 0x1a, 0x96, 0xf1, 0xc5, 0xae, 0x57, 0x75, 0xb9, 0xdb, 0x22, + 0xd7, 0x1b, 0xf2, 0x71, 0x81, 0xf0, 0x63, 0x91, 0x9d, 0x35, 0x3b, 0xf2, 0xe0, 0xb0, 0x4d, 0xb2, + 0x6a, 0xa2, 0x17, 0x68, 0x99, 0x29, 0x9b, 0xde, 0xca, 0x3e, 0xf7, 0x6f, 0x1c, 0x60, 0x5f, 0x99, + 0xf2, 0x64, 0x46, 0x39, 0x1e, 0x1d, 0x9e, 0xd9, 0x2e, 0xc6, 0x31, 0x16, 0xe3, 0xe9, 0xd1, 0x97, + 0xf8, 0x4c, 0x65, 0x02, 0x6b, 0x79, 0x26, 0xf0, 0x75, 0x00, 0xbc, 0x7e, 0xe9, 0xc4, 0x11, 0xf2, + 0x02, 0xde, 0x7b, 0xc5, 0x80, 0x95, 0xc9, 0xba, 0xc6, 0xcb, 0x93, 0x75, 0x0b, 0x2f, 0x4b, 0xd6, + 0xbd, 0x0f, 0x1b, 0x16, 0xdd, 0xfa, 0x58, 0x55, 0x0a, 0xcb, 0x79, 0x41, 0x0a, 0xeb, 0x3f, 0x1d, + 0xa8, 0xef, 0x47, 0xb1, 0x19, 0xae, 0x74, 0xec, 0x70, 0xa5, 0xb4, 0x25, 0x7d, 0x6d, 0x2a, 0xa4, + 0x8a, 0xb1, 0x80, 0x6c, 0x07, 0x3a, 0xfe, 0x24, 0xc3, 0x6b, 0xf7, 0x71, 0x94, 0x9c, 0xf9, 0xc9, + 0x50, 0x9c, 0xf5, 0xad, 0x5a, 0xd7, 0xf1, 0x0a, 0x3d, 0x6c, 0x13, 0xea, 0x5a, 0xe9, 0x12, 0x02, + 0x36, 0xd1, 0x71, 0xa3, 0xa8, 0xed, 0x4c, 0x46, 0x0c, 0x64, 0x0b, 0x59, 0xc9, 0xfe, 0x5e, 0xb8, + 0xca, 0x42, 0x74, 0xaa, 0xba, 0xd0, 0xae, 0xe1, 0xf6, 0x11, 0x9a, 0x0c, 0xf5, 0xa8, 0xb6, 0xfb, + 0xef, 0x0e, 0x2c, 0xd0, 0x0e, 0xa0, 0xb0, 0x0b, 0x0e, 0xa7, 0xdc, 0x38, 0x85, 0x98, 0x1d, 0x21, + 0xec, 0x05, 0x30, 0x73, 0xad, 0x8c, 0x79, 0x4d, 0x93, 0x6d, 0x66, 0xcd, 0x2f, 0x43, 0x53, 0xb4, + 0x74, 0x76, 0x98, 0x50, 0x72, 0x20, 0xbb, 0x04, 0x8d, 0x93, 0x28, 0x56, 0xde, 0x09, 0xa8, 0x08, + 0x63, 0x14, 0x7b, 0x04, 0xcf, 0xe9, 0xc1, 0xf1, 0x04, 0xf1, 0xc2, 0xe6, 0x14, 0xc1, 0x68, 0x75, + 0xf5, 0xb0, 0xe6, 0x66, 0x14, 0xa0, 0xee, 0x0e, 0xac, 0x3e, 0x8c, 0x86, 0xdc, 0x88, 0x29, 0xcd, + 0xe5, 0x66, 0xf7, 0xb7, 0x1d, 0x58, 0x56, 0xc8, 0xec, 0x1a, 0x34, 0xd0, 0x95, 0x28, 0x5c, 0x14, + 0x74, 0x66, 0x01, 0xf1, 0x3c, 0xc2, 0x40, 0xdd, 0x4b, 0x11, 0x87, 0xdc, 0xad, 0x54, 0xf1, 0x86, + 0xdc, 0x6b, 0xd2, 0xe4, 0x16, 0x9c, 0x8d, 0x02, 0xd4, 0xfd, 0x4b, 0x07, 0x56, 0xac, 0x39, 0xf0, + 0x7a, 0x38, 0xf6, 0xd3, 0x4c, 0x46, 0x6b, 0xe5, 0xf1, 0x98, 0x20, 0x33, 0xca, 0x58, 0xb3, 0xa3, + 0x8c, 0x3a, 0xfe, 0x55, 0x37, 0xe3, 0x5f, 0x37, 0xa0, 0x99, 0xd7, 0x35, 0x34, 0x2c, 0x9d, 0x8a, + 0x33, 0xaa, 0x9c, 0x49, 0x8e, 0x84, 0xe3, 0x0c, 0xa2, 0x71, 0x94, 0xc8, 0x6c, 0xbd, 0x68, 0xb8, + 0xef, 0x43, 0xcb, 0xc0, 0x47, 0x32, 0x42, 0x9e, 0x9d, 0x45, 0xc9, 0x53, 0x15, 0xec, 0x94, 0x4d, + 0x9d, 0x1a, 0xac, 0xe5, 0xa9, 0x41, 0xf7, 0xaf, 0x1c, 0x58, 0x41, 0x1e, 0x0c, 0xc2, 0xd1, 0x41, + 0x34, 0x0e, 0x06, 0x33, 0x3a, 0x7b, 0xc5, 0x6e, 0x52, 0x33, 0x28, 0x5e, 0xb4, 0xc1, 0xc8, 0xdb, + 0xea, 0x76, 0x28, 0x05, 0x51, 0xb7, 0x51, 0x52, 0x91, 0xcf, 0x8f, 0xfc, 0x54, 0x32, 0xbf, 0x34, + 0x72, 0x16, 0x10, 0xe5, 0x09, 0x01, 0x89, 0x9f, 0xf1, 0xfe, 0x24, 0x18, 0x8f, 0x03, 0x81, 0x2b, + 0x5c, 0xa0, 0xaa, 0x2e, 0xf7, 0x87, 0x35, 0x68, 0x49, 0x15, 0x7c, 0x77, 0x38, 0x12, 0x69, 0x05, + 0xe9, 0x48, 0x6a, 0x75, 0x61, 0x40, 0x54, 0xbf, 0xe5, 0x7a, 0x1a, 0x90, 0xe2, 0xb1, 0xd6, 0xcb, + 0xc7, 0x7a, 0x11, 0x9a, 0xc8, 0x5e, 0x6f, 0x93, 0x8f, 0x2b, 0xca, 0x60, 0x72, 0x80, 0xea, 0xdd, + 0xa3, 0xde, 0x85, 0xbc, 0x97, 0x00, 0x96, 0x57, 0xbb, 0x58, 0xf0, 0x6a, 0xdf, 0x85, 0xb6, 0x1c, + 0x86, 0xf6, 0x9d, 0xb4, 0x43, 0xce, 0xe0, 0xd6, 0x99, 0x78, 0x16, 0xa6, 0xfa, 0x72, 0x4f, 0x7d, + 0xb9, 0xfc, 0xb2, 0x2f, 0x15, 0x26, 0x65, 0xd9, 0xc4, 0xde, 0xdc, 0x4f, 0xfc, 0xf8, 0x44, 0x99, + 0xb5, 0xa1, 0x2e, 0x1d, 0x20, 0x30, 0xdb, 0x81, 0x05, 0xfc, 0x4c, 0x69, 0xeb, 0x6a, 0xa1, 0x13, + 0x28, 0xec, 0x1a, 0x2c, 0xf0, 0xe1, 0x88, 0xab, 0x5b, 0x1c, 0xb3, 0xef, 0xd3, 0x78, 0x46, 0x9e, + 0x40, 0x40, 0x15, 0x80, 0xd0, 0x82, 0x0a, 0xb0, 0x35, 0xfd, 0x22, 0x36, 0x3f, 0x18, 0xba, 0x9b, + 0xc0, 0x1e, 0x0a, 0xae, 0x35, 0xa3, 0xd0, 0xbf, 0x57, 0x87, 0x96, 0x01, 0x46, 0x69, 0x1e, 0x21, + 0xc1, 0xfd, 0x61, 0xe0, 0x4f, 0x78, 0xc6, 0x13, 0xc9, 0xa9, 0x05, 0x28, 0xe2, 0xf9, 0xa7, 0xa3, + 0x7e, 0x34, 0xcd, 0xfa, 0x43, 0x3e, 0x4a, 0xb8, 0x30, 0xbe, 0x68, 0x0c, 0x2c, 0x28, 0xe2, 0x4d, + 0xfc, 0x67, 0x26, 0x9e, 0xe0, 0x87, 0x02, 0x54, 0xc5, 0x94, 0xc5, 0x1e, 0x35, 0xf2, 0x98, 0xb2, + 0xd8, 0x91, 0xa2, 0x1e, 0x5a, 0xa8, 0xd0, 0x43, 0xef, 0xc0, 0x96, 0xd0, 0x38, 0x52, 0x36, 0xfb, + 0x05, 0x36, 0x99, 0xd3, 0xcb, 0x76, 0x60, 0x0d, 0x69, 0x56, 0x0c, 0x9e, 0x06, 0xdf, 0x16, 0x51, + 0x1e, 0xc7, 0x2b, 0xc1, 0x11, 0x17, 0xc5, 0xd1, 0xc2, 0x15, 0x79, 0xb7, 0x12, 0x9c, 0x70, 0xfd, + 0x67, 0x36, 0x6e, 0x53, 0xe2, 0x16, 0xe0, 0xee, 0x0a, 0xb4, 0x0e, 0xb3, 0x28, 0x56, 0x87, 0xd2, + 0x81, 0xb6, 0x68, 0xca, 0x2c, 0xeb, 0x6b, 0x70, 0x81, 0xb8, 0xe8, 0x51, 0x14, 0x47, 0xe3, 0x68, + 0x34, 0x3b, 0x9c, 0x1e, 0xa5, 0x83, 0x24, 0x88, 0xf1, 0xc6, 0xe3, 0xfe, 0xa3, 0x03, 0x1b, 0x56, + 0xaf, 0x0c, 0x0b, 0x7d, 0x46, 0xb0, 0xb4, 0x4e, 0x8f, 0x09, 0xc6, 0x5b, 0x37, 0xd4, 0xa1, 0x40, + 0x14, 0x01, 0xb9, 0xc7, 0x32, 0x63, 0x76, 0x13, 0x56, 0x15, 0x65, 0xea, 0x43, 0xc1, 0x85, 0xdd, + 0x32, 0x17, 0xca, 0xef, 0x3b, 0xf2, 0x03, 0x35, 0xc4, 0xaf, 0x08, 0x87, 0x9d, 0x0f, 0x69, 0x8d, + 0x2a, 0x3e, 0xd0, 0x53, 0xdf, 0x9b, 0xb7, 0x04, 0x45, 0xc1, 0x40, 0x03, 0x53, 0xf7, 0x0f, 0x1d, + 0x80, 0x9c, 0x3a, 0x64, 0x8c, 0x5c, 0xa5, 0x8b, 0x92, 0x4e, 0x43, 0x7d, 0xbf, 0x09, 0x6d, 0x9d, + 0x19, 0xc9, 0xad, 0x44, 0x4b, 0xc1, 0xd0, 0x91, 0xbb, 0x0a, 0xab, 0xa3, 0x71, 0x74, 0x44, 0x26, + 0x96, 0xd2, 0xf6, 0xa9, 0xcc, 0x35, 0x77, 0x04, 0xf8, 0x9e, 0x84, 0xe6, 0x26, 0xa5, 0x61, 0x98, + 0x14, 0xf7, 0x3b, 0x35, 0x1d, 0x4f, 0xcf, 0xd7, 0x3c, 0x57, 0xca, 0xd8, 0x5e, 0x49, 0x39, 0xce, + 0x09, 0x5f, 0x53, 0x24, 0xec, 0xe0, 0xa5, 0x17, 0xf5, 0xf7, 0xa1, 0x93, 0x08, 0xed, 0xa3, 0x54, + 0x53, 0xe3, 0x05, 0xaa, 0x69, 0x25, 0xb1, 0xec, 0xce, 0xa7, 0x60, 0xcd, 0x1f, 0x9e, 0xf2, 0x24, + 0x0b, 0xe8, 0xaa, 0x44, 0x46, 0x5f, 0x28, 0xd4, 0x55, 0x03, 0x4e, 0xb6, 0xf8, 0x2a, 0xac, 0xca, + 0xfc, 0xbe, 0xc6, 0x94, 0x35, 0x69, 0x39, 0x18, 0x11, 0xdd, 0xbf, 0x50, 0xa1, 0x7b, 0xfb, 0x0c, + 0xe7, 0xef, 0x88, 0xb9, 0xba, 0x5a, 0x61, 0x75, 0x9f, 0x90, 0x61, 0xf4, 0xa1, 0xba, 0x8f, 0xc9, + 0x84, 0x86, 0x00, 0xca, 0xb4, 0x87, 0xbd, 0xa5, 0x8d, 0x57, 0xd9, 0x52, 0xf7, 0x63, 0x07, 0x96, + 0xf6, 0xa3, 0x78, 0x5f, 0xa6, 0xea, 0x49, 0x10, 0x74, 0xf5, 0x8c, 0x6a, 0x9a, 0x5e, 0x71, 0xad, + 0xe4, 0x15, 0x97, 0x6d, 0xed, 0x4a, 0xd1, 0xd6, 0xfe, 0x2a, 0xbc, 0x46, 0xd1, 0x80, 0x24, 0x8a, + 0xa3, 0x04, 0x85, 0xd1, 0x1f, 0x0b, 0xc3, 0x1a, 0x85, 0xd9, 0x89, 0x52, 0x63, 0x2f, 0x42, 0xa1, + 0x6b, 0x17, 0x5e, 0x17, 0x84, 0x33, 0x2c, 0x7d, 0x03, 0xa1, 0xdd, 0xca, 0x1d, 0xee, 0xe7, 0xa0, + 0x49, 0xce, 0x2d, 0x2d, 0xeb, 0x2d, 0x68, 0x9e, 0x44, 0x71, 0xff, 0x24, 0x08, 0x33, 0x25, 0xdc, + 0x9d, 0xdc, 0xeb, 0xdc, 0xa7, 0x0d, 0xd1, 0x08, 0xee, 0x8f, 0xeb, 0xb0, 0xf4, 0x41, 0x78, 0x1a, + 0x05, 0x03, 0x8a, 0xf2, 0x4f, 0xf8, 0x24, 0x52, 0xb5, 0x44, 0xf8, 0x1b, 0xb7, 0x82, 0xf2, 0xea, + 0x71, 0x26, 0xc3, 0xf4, 0xaa, 0x89, 0xe6, 0x3e, 0xc9, 0xeb, 0xfd, 0x84, 0xe8, 0x18, 0x10, 0x74, + 0xec, 0x13, 0xb3, 0x34, 0x52, 0xb6, 0xf2, 0x62, 0xac, 0x05, 0xa3, 0x18, 0x8b, 0x72, 0x42, 0xa2, + 0x64, 0x80, 0xf8, 0x6b, 0xd9, 0x53, 0x4d, 0xba, 0x88, 0x24, 0x5c, 0x44, 0x71, 0xc8, 0x71, 0x58, + 0x92, 0x17, 0x11, 0x13, 0x88, 0xce, 0x85, 0xf8, 0x40, 0xe0, 0x08, 0xe5, 0x6b, 0x82, 0xd0, 0xd9, + 0x2a, 0x56, 0x57, 0x36, 0x05, 0xcf, 0x17, 0xc0, 0xa8, 0xa1, 0x87, 0x5c, 0x2b, 0x52, 0xb1, 0x06, + 0x10, 0xf5, 0x8c, 0x45, 0xb8, 0x71, 0x7d, 0x11, 0xa5, 0x0f, 0xea, 0xfa, 0x82, 0x8c, 0xe2, 0x8f, + 0xc7, 0x47, 0xfe, 0xe0, 0x29, 0x15, 0xcf, 0x52, 0xa5, 0x43, 0xd3, 0xb3, 0x81, 0x48, 0xb5, 0x71, + 0x9a, 0x94, 0x55, 0x6c, 0x78, 0x26, 0x88, 0xed, 0x41, 0x8b, 0xae, 0x6c, 0xf2, 0x3c, 0x3b, 0x74, + 0x9e, 0x6b, 0xe6, 0x9d, 0x8e, 0x4e, 0xd4, 0x44, 0x32, 0x33, 0x0f, 0xab, 0x76, 0x31, 0xc2, 0x57, + 0x81, 0xdd, 0x1c, 0x0e, 0xe5, 0x79, 0xeb, 0x2b, 0x63, 0x7e, 0x52, 0x8e, 0x75, 0x52, 0x15, 0x3b, + 0x56, 0xab, 0xdc, 0x31, 0xf7, 0x2e, 0xb4, 0x0e, 0x8c, 0xb2, 0x4b, 0x62, 0x0d, 0x55, 0x70, 0x29, + 0xd9, 0xc9, 0x80, 0x18, 0x13, 0xd6, 0xcc, 0x09, 0xdd, 0x5f, 0x02, 0xf6, 0x20, 0x48, 0x33, 0x4d, + 0x5f, 0x5e, 0xe7, 0xa9, 0x6e, 0xee, 0x79, 0xa9, 0x44, 0x4b, 0xc2, 0xa8, 0x84, 0xe1, 0xa6, 0xa8, + 0xb1, 0x28, 0x2e, 0x6c, 0x07, 0x96, 0x03, 0x01, 0x2a, 0x4a, 0x82, 0xc2, 0xd4, 0xfd, 0xe8, 0xaf, + 0x49, 0xa0, 0x65, 0x45, 0x7f, 0xe8, 0xc0, 0x92, 0x5c, 0x1a, 0x7a, 0x1b, 0xa5, 0x82, 0xd3, 0xa6, + 0x67, 0xc1, 0xaa, 0x4b, 0x0d, 0xcb, 0x3c, 0x5c, 0xaf, 0xe2, 0x61, 0x06, 0x8d, 0xd8, 0xcf, 0x4e, + 0xe8, 0x82, 0xd2, 0xf4, 0xe8, 0x37, 0x5b, 0x13, 0x97, 0x66, 0x21, 0x2b, 0x74, 0x61, 0xae, 0xaa, + 0xb6, 0x15, 0x2a, 0xb9, 0x04, 0xc7, 0x45, 0x51, 0x55, 0x82, 0x80, 0xeb, 0x64, 0x83, 0xac, 0xf8, + 0xc8, 0xc1, 0xf9, 0x7e, 0xc9, 0x21, 0x8a, 0xfb, 0x25, 0x51, 0x3d, 0xdd, 0xef, 0xf6, 0xa0, 0x7b, + 0x87, 0x8f, 0x79, 0xc6, 0x6f, 0x8e, 0xc7, 0xc5, 0xf1, 0x5f, 0x83, 0x0b, 0x15, 0x7d, 0xd2, 0x69, + 0xb9, 0x07, 0xeb, 0x77, 0xf8, 0xd1, 0x74, 0xf4, 0x80, 0x9f, 0xe6, 0x19, 0x41, 0x06, 0x8d, 0xf4, + 0x24, 0x3a, 0x93, 0x67, 0x4b, 0xbf, 0xd9, 0xeb, 0x00, 0x63, 0xc4, 0xe9, 0xa7, 0x31, 0x1f, 0xa8, + 0x22, 0x3b, 0x82, 0x1c, 0xc6, 0x7c, 0xe0, 0xbe, 0x03, 0xcc, 0x1c, 0x47, 0x2e, 0x01, 0xf5, 0xc0, + 0xf4, 0xa8, 0x9f, 0xce, 0xd2, 0x8c, 0x4f, 0x54, 0xf5, 0xa0, 0x09, 0x72, 0xaf, 0x42, 0xfb, 0xc0, + 0x9f, 0x79, 0xfc, 0x5b, 0xb2, 0xe6, 0x17, 0xef, 0xc6, 0xfe, 0x0c, 0x59, 0x59, 0xdf, 0x8d, 0xa9, + 0xdb, 0xfd, 0xaf, 0x1a, 0x2c, 0x0a, 0x4c, 0x1c, 0x75, 0xc8, 0xd3, 0x2c, 0x08, 0x45, 0x36, 0x4c, + 0x8e, 0x6a, 0x80, 0x4a, 0xbc, 0x51, 0xab, 0xe0, 0x0d, 0xe9, 0xad, 0xaa, 0x82, 0x25, 0xc9, 0x04, + 0x16, 0x0c, 0xdd, 0x9a, 0xbc, 0xca, 0x40, 0x5c, 0xce, 0x72, 0x40, 0x21, 0x58, 0x92, 0x6b, 0x1b, + 0x41, 0x9f, 0x62, 0x5a, 0xc9, 0x0e, 0x26, 0xa8, 0x52, 0xa7, 0x2d, 0x09, 0xae, 0x29, 0xe9, 0xb4, + 0x92, 0xee, 0x5a, 0x7e, 0x05, 0xdd, 0x25, 0x5c, 0xd8, 0x17, 0xe9, 0x2e, 0x78, 0x05, 0xdd, 0xe5, + 0x32, 0x58, 0xbb, 0xc7, 0xb9, 0xc7, 0xd1, 0x2a, 0x2a, 0x76, 0xfa, 0x9e, 0x03, 0x6b, 0xd2, 0xa0, + 0xeb, 0x3e, 0xf6, 0xa6, 0x65, 0xfd, 0x9d, 0xaa, 0x44, 0xc7, 0x15, 0x58, 0x21, 0x9b, 0xac, 0xa3, + 0x42, 0x32, 0x84, 0x65, 0x01, 0x71, 0x1d, 0x2a, 0x74, 0x3f, 0x09, 0xc6, 0xf2, 0x50, 0x4c, 0x90, + 0x0a, 0x2c, 0xe1, 0xfd, 0x98, 0x8e, 0xc4, 0xf1, 0x74, 0xdb, 0xfd, 0x5b, 0x07, 0xd6, 0x0d, 0x82, + 0x25, 0x17, 0xbe, 0x0f, 0xaa, 0x0a, 0x41, 0x04, 0x8f, 0x84, 0x30, 0x6d, 0xdb, 0xce, 0x49, 0xfe, + 0x99, 0x85, 0x4c, 0x87, 0xe9, 0xcf, 0x88, 0xc0, 0x74, 0x3a, 0x91, 0x1e, 0x88, 0x09, 0x42, 0x46, + 0x3a, 0xe3, 0xfc, 0xa9, 0x46, 0xa9, 0x13, 0x8a, 0x05, 0xa3, 0x24, 0x33, 0xfa, 0x12, 0x1a, 0x49, + 0xd4, 0x55, 0xd9, 0x40, 0xf7, 0x9f, 0x1d, 0xd8, 0x10, 0x4e, 0xa1, 0x74, 0xb9, 0x75, 0xcd, 0xe7, + 0xa2, 0xf0, 0x82, 0x85, 0x44, 0xee, 0x9f, 0xf3, 0x64, 0x9b, 0x7d, 0xf6, 0x15, 0x1d, 0x59, 0x5d, + 0x5c, 0x30, 0xe7, 0x2c, 0xea, 0x55, 0x67, 0xf1, 0x82, 0x9d, 0xae, 0x0a, 0x96, 0x2c, 0x54, 0x06, + 0x4b, 0x6e, 0x2d, 0xc1, 0x42, 0x3a, 0x88, 0x62, 0xee, 0x6e, 0xc1, 0xa6, 0xbd, 0x38, 0xa9, 0x82, + 0xbe, 0xef, 0x40, 0xf7, 0x9e, 0x08, 0x1d, 0x06, 0xe1, 0x68, 0x3f, 0x48, 0xb3, 0x28, 0xd1, 0x45, + 0xee, 0x97, 0x00, 0xd2, 0xcc, 0x4f, 0x32, 0x51, 0xfc, 0x25, 0xc3, 0x1c, 0x39, 0x04, 0x69, 0xe4, + 0xe1, 0x50, 0xf4, 0x8a, 0xb3, 0xd1, 0x6d, 0x3c, 0x18, 0x2a, 0x7c, 0xe8, 0x47, 0xc7, 0xc7, 0x29, + 0xd7, 0x6e, 0xab, 0x09, 0xc3, 0x9b, 0x2f, 0x4a, 0x3c, 0xde, 0xf5, 0xf8, 0x29, 0xa9, 0x5a, 0xe1, + 0x0f, 0x16, 0xa0, 0xee, 0x5f, 0x3b, 0xb0, 0x9a, 0x13, 0x79, 0x17, 0x81, 0xb6, 0x76, 0x10, 0xa4, + 0x19, 0xda, 0x41, 0x05, 0x60, 0x82, 0x61, 0x3f, 0x08, 0x25, 0x6d, 0x06, 0x84, 0x24, 0x56, 0xb6, + 0xa2, 0xa9, 0x2a, 0xb4, 0x33, 0x41, 0x22, 0x8b, 0x9e, 0xe1, 0xd7, 0xa2, 0xca, 0x4e, 0xb6, 0xa8, + 0x76, 0x6f, 0x92, 0xd1, 0x57, 0x8b, 0xc2, 0x21, 0x96, 0x4d, 0x65, 0x9f, 0x96, 0x08, 0x8a, 0x3f, + 0xdd, 0x3f, 0x72, 0xe0, 0x42, 0xc5, 0xe6, 0x4a, 0xc9, 0xb8, 0x03, 0xeb, 0xc7, 0xba, 0x53, 0x6d, + 0x80, 0x10, 0x8f, 0x2d, 0x15, 0xeb, 0xb6, 0x17, 0xed, 0x95, 0x3f, 0x40, 0xf7, 0x98, 0xe2, 0x46, + 0x62, 0x4b, 0xad, 0x02, 0x94, 0x72, 0xc7, 0xde, 0x1f, 0xd7, 0xa1, 0x23, 0x72, 0x20, 0xe2, 0xb9, + 0x19, 0x4f, 0xd8, 0x87, 0xb0, 0x24, 0x9f, 0x0b, 0xb2, 0xf3, 0x72, 0x5a, 0xfb, 0x81, 0x62, 0x6f, + 0xab, 0x08, 0x96, 0xbc, 0xb3, 0xf1, 0xbb, 0x1f, 0xff, 0xeb, 0x9f, 0xd4, 0x56, 0x58, 0x6b, 0xf7, + 0xf4, 0xed, 0xdd, 0x11, 0x0f, 0x53, 0x1c, 0xe3, 0x37, 0x00, 0xf2, 0x87, 0x74, 0xac, 0xab, 0x9d, + 0x8c, 0xc2, 0x0b, 0xc1, 0xde, 0x85, 0x8a, 0x1e, 0x39, 0xee, 0x05, 0x1a, 0x77, 0xc3, 0xed, 0xe0, + 0xb8, 0x41, 0x18, 0x64, 0xe2, 0x55, 0xdd, 0x7b, 0xce, 0x0e, 0x1b, 0x42, 0xdb, 0x7c, 0x27, 0xc7, + 0xd4, 0x95, 0xb9, 0xe2, 0x95, 0x5e, 0xef, 0xb5, 0xca, 0x3e, 0x15, 0x2f, 0xa0, 0x39, 0xce, 0xbb, + 0x6b, 0x38, 0xc7, 0x94, 0x30, 0xf2, 0x59, 0xc6, 0xd0, 0xb1, 0x9f, 0xc3, 0xb1, 0x8b, 0x86, 0x58, + 0x97, 0x1e, 0xe3, 0xf5, 0x5e, 0x9f, 0xd3, 0x2b, 0xe7, 0x7a, 0x9d, 0xe6, 0xda, 0x76, 0x19, 0xce, + 0x35, 0x20, 0x1c, 0xf5, 0x18, 0xef, 0x3d, 0x67, 0x67, 0xef, 0xbb, 0xaf, 0x43, 0x53, 0x07, 0xb9, + 0xd8, 0x37, 0x61, 0xc5, 0x4a, 0x52, 0x31, 0xb5, 0x8c, 0xaa, 0x9c, 0x56, 0xef, 0x62, 0x75, 0xa7, + 0x9c, 0xf8, 0x12, 0x4d, 0xdc, 0x65, 0x5b, 0x38, 0xb1, 0xcc, 0xf2, 0xec, 0x52, 0x6a, 0x4e, 0x54, + 0x06, 0x3e, 0x15, 0xeb, 0xcc, 0x13, 0x4b, 0xd6, 0x3a, 0x4b, 0x89, 0x28, 0x6b, 0x9d, 0xe5, 0x6c, + 0x94, 0x7b, 0x91, 0xa6, 0xdb, 0x62, 0x9b, 0xe6, 0x74, 0x3a, 0xf8, 0xc4, 0xa9, 0x96, 0xd3, 0x7c, + 0x2d, 0xc7, 0x5e, 0xd7, 0x8c, 0x55, 0xf5, 0x8a, 0x4e, 0xb3, 0x48, 0xf9, 0x29, 0x9d, 0xdb, 0xa5, + 0xa9, 0x18, 0xa3, 0xe3, 0x33, 0x1f, 0xcb, 0xb1, 0xaf, 0x43, 0x53, 0x3f, 0x0d, 0x61, 0xdb, 0xc6, + 0x7b, 0x1c, 0xf3, 0xbd, 0x4a, 0xaf, 0x5b, 0xee, 0xa8, 0x62, 0x0c, 0x73, 0x64, 0x64, 0x8c, 0x07, + 0x70, 0x5e, 0xba, 0xc4, 0x47, 0xfc, 0x27, 0x59, 0x49, 0xc5, 0x1b, 0xbf, 0x1b, 0x0e, 0x7b, 0x1f, + 0x96, 0xd5, 0x8b, 0x1b, 0xb6, 0x55, 0xfd, 0x72, 0xa8, 0xb7, 0x5d, 0x82, 0x4b, 0xed, 0x71, 0x13, + 0x20, 0x7f, 0x2d, 0xa2, 0xe5, 0xac, 0xf4, 0x86, 0x45, 0x6f, 0x62, 0xc5, 0xd3, 0x92, 0x11, 0xbd, + 0x8d, 0xb1, 0x1f, 0xa3, 0xb0, 0x37, 0x72, 0xfc, 0xca, 0x67, 0x2a, 0x2f, 0x18, 0xd0, 0xdd, 0xa2, + 0xbd, 0x5b, 0x63, 0x24, 0xb8, 0x21, 0x3f, 0x53, 0x55, 0xcd, 0x77, 0xa0, 0x65, 0xbc, 0x40, 0x61, + 0x6a, 0x84, 0xf2, 0xeb, 0x95, 0x5e, 0xaf, 0xaa, 0x4b, 0x92, 0xfb, 0x45, 0x58, 0xb1, 0x9e, 0x92, + 0x68, 0xc9, 0xa8, 0x7a, 0xa8, 0xa2, 0x25, 0xa3, 0xfa, 0xf5, 0xc9, 0xd7, 0xa0, 0x65, 0x3c, 0xfc, + 0x60, 0x46, 0x35, 0x57, 0xe1, 0xc9, 0x87, 0xa6, 0xa8, 0xea, 0x9d, 0xc8, 0x26, 0xad, 0xb7, 0xe3, + 0x36, 0x71, 0xbd, 0x54, 0xda, 0x8b, 0x4c, 0xf2, 0x4d, 0xe8, 0xd8, 0x4f, 0x41, 0xb4, 0x54, 0x55, + 0x3e, 0x2a, 0xd1, 0x52, 0x35, 0xe7, 0xfd, 0x88, 0x64, 0xc8, 0x9d, 0x0d, 0x3d, 0xc9, 0xee, 0x47, + 0x32, 0xc5, 0xf3, 0x9c, 0x7d, 0x05, 0x55, 0x87, 0xac, 0xb5, 0x66, 0xf9, 0x03, 0x18, 0xbb, 0x22, + 0x5b, 0x73, 0x7b, 0xa9, 0x2c, 0xdb, 0x5d, 0xa7, 0xc1, 0x5b, 0x2c, 0x5f, 0x81, 0xb0, 0x07, 0x54, + 0x73, 0x6d, 0xd8, 0x03, 0xb3, 0x2c, 0xdb, 0xb0, 0x07, 0x56, 0x69, 0x76, 0xd1, 0x1e, 0x64, 0x01, + 0x8e, 0x11, 0xc2, 0x6a, 0xa1, 0x9c, 0x41, 0x0b, 0x4b, 0x75, 0xfd, 0x57, 0xef, 0xd2, 0x8b, 0xab, + 0x20, 0x6c, 0x35, 0xa3, 0xd4, 0xcb, 0xae, 0x2a, 0xd7, 0xfb, 0x4d, 0x68, 0x9b, 0x25, 0xfc, 0xda, + 0x42, 0x54, 0x3c, 0x3c, 0xd0, 0x16, 0xa2, 0xaa, 0xe6, 0x5f, 0x1d, 0x2e, 0x6b, 0x9b, 0xd3, 0xb0, + 0xaf, 0xc1, 0xaa, 0x51, 0xbf, 0x73, 0x38, 0x0b, 0x07, 0x9a, 0x79, 0xca, 0xd5, 0x9d, 0xbd, 0x2a, + 0x6f, 0xd0, 0xdd, 0xa6, 0x81, 0xd7, 0x5d, 0x6b, 0x60, 0x64, 0x9c, 0xdb, 0xd0, 0x32, 0x6b, 0x83, + 0x5e, 0x30, 0xee, 0xb6, 0xd1, 0x65, 0x16, 0x3a, 0xde, 0x70, 0xd8, 0x9f, 0x3a, 0xd0, 0xb6, 0x2a, + 0x6d, 0xac, 0xa8, 0x72, 0x61, 0x9c, 0xae, 0xd9, 0x67, 0x0e, 0xe4, 0x7a, 0x44, 0xe4, 0x83, 0x9d, + 0x2f, 0x5a, 0x9b, 0xfc, 0x91, 0x75, 0xab, 0xb8, 0x5e, 0x7c, 0x9d, 0xf9, 0xbc, 0x88, 0x60, 0x56, + 0xc0, 0x3e, 0xbf, 0xe1, 0xb0, 0xf7, 0xc4, 0xfb, 0x63, 0x15, 0x45, 0x60, 0x86, 0x72, 0x2b, 0x6e, + 0x99, 0xf9, 0xf8, 0xf6, 0x9a, 0x73, 0xc3, 0x61, 0xdf, 0x10, 0x8f, 0x30, 0xe5, 0xb7, 0xb4, 0xf3, + 0xaf, 0xfa, 0xbd, 0x7b, 0x85, 0x56, 0x73, 0xc9, 0xbd, 0x60, 0xad, 0xa6, 0xa8, 0xdd, 0x6f, 0x0a, + 0xea, 0xe4, 0xdb, 0xda, 0x5c, 0x4d, 0x95, 0xde, 0xdb, 0xce, 0x27, 0x72, 0x22, 0x88, 0x94, 0xe8, + 0x16, 0x7b, 0xbc, 0xe2, 0x30, 0xee, 0x0e, 0xd1, 0x7a, 0xc5, 0x7d, 0x63, 0x2e, 0xad, 0xbb, 0x74, + 0x4b, 0x44, 0x8a, 0x0f, 0x00, 0xf2, 0x20, 0x16, 0x2b, 0x44, 0x74, 0xb4, 0xa6, 0x2e, 0xc7, 0xb9, + 0x6c, 0x1e, 0x54, 0x81, 0x1f, 0x1c, 0xf1, 0xeb, 0x42, 0x7c, 0x24, 0x7e, 0xaa, 0xa9, 0x2f, 0x07, + 0xa3, 0x7a, 0xbd, 0xaa, 0xae, 0x2a, 0xe1, 0x51, 0xe3, 0xb3, 0xc7, 0xb0, 0xf2, 0x20, 0x8a, 0x9e, + 0x4e, 0x63, 0x1d, 0x66, 0xb5, 0x63, 0x2a, 0xfb, 0x7e, 0x7a, 0xd2, 0x2b, 0xac, 0xc2, 0xbd, 0x4c, + 0x43, 0xf5, 0x58, 0xd7, 0x18, 0x6a, 0xf7, 0xa3, 0x3c, 0x84, 0xf6, 0x9c, 0xf9, 0xb0, 0xae, 0xad, + 0xb2, 0x26, 0xbc, 0x67, 0x0f, 0x63, 0x46, 0xb2, 0x4a, 0x53, 0x58, 0x7e, 0x92, 0xa2, 0x76, 0x37, + 0x55, 0x63, 0xde, 0x70, 0xd8, 0x01, 0xb4, 0xef, 0xf0, 0x41, 0x34, 0xe4, 0x32, 0x0a, 0xb2, 0x91, + 0x13, 0xae, 0xc3, 0x27, 0xbd, 0x15, 0x0b, 0x68, 0xeb, 0xa9, 0xd8, 0x9f, 0x25, 0xfc, 0x5b, 0xbb, + 0x1f, 0xc9, 0xf8, 0xca, 0x73, 0xa5, 0xa7, 0x54, 0x4c, 0xc8, 0xd2, 0x53, 0x85, 0x20, 0x92, 0xa5, + 0xa7, 0x4a, 0x41, 0x24, 0x6b, 0xab, 0x55, 0x4c, 0x8a, 0x8d, 0x61, 0xbd, 0x14, 0x77, 0xd2, 0xb6, + 0x7d, 0x5e, 0xb4, 0xaa, 0x77, 0x79, 0x3e, 0x82, 0x3d, 0xdb, 0x8e, 0x3d, 0xdb, 0x21, 0xac, 0xdc, + 0xe1, 0x62, 0xb3, 0x44, 0x2e, 0xb7, 0x67, 0x2b, 0x3e, 0x33, 0xef, 0x5b, 0x54, 0x8a, 0xd4, 0x67, + 0x1b, 0x22, 0x4a, 0xa4, 0xb2, 0xaf, 0x43, 0xeb, 0x3e, 0xcf, 0x54, 0xf2, 0x56, 0x7b, 0x48, 0x85, + 0x6c, 0x6e, 0xaf, 0x22, 0xf7, 0x6b, 0xf3, 0x0c, 0x8d, 0xb6, 0xcb, 0x87, 0x23, 0x2e, 0xd4, 0x53, + 0x3f, 0x18, 0x3e, 0x67, 0xbf, 0x46, 0x83, 0xeb, 0x7a, 0x8f, 0x2d, 0x23, 0xe7, 0x67, 0x0e, 0xbe, + 0x5a, 0x80, 0x57, 0x8d, 0x1c, 0x46, 0x43, 0x6e, 0x98, 0xe4, 0x10, 0x5a, 0x46, 0x31, 0x92, 0x16, + 0xa0, 0x72, 0x61, 0x95, 0x16, 0xa0, 0x8a, 0xda, 0x25, 0xf7, 0x1a, 0xcd, 0xe3, 0xb2, 0xcb, 0xf9, + 0x3c, 0xa2, 0x5e, 0x29, 0x9f, 0x69, 0xf7, 0x23, 0x7f, 0x92, 0x3d, 0x67, 0x4f, 0xe8, 0xd9, 0x94, + 0x99, 0xa0, 0xce, 0x3d, 0xb4, 0x62, 0x2e, 0x5b, 0x6f, 0x96, 0xd1, 0x65, 0x7b, 0x6d, 0x62, 0x2a, + 0xb2, 0xdc, 0x9f, 0x05, 0x38, 0xcc, 0xa2, 0xf8, 0x8e, 0xcf, 0x27, 0x51, 0x98, 0xeb, 0xda, 0x3c, + 0x09, 0x9b, 0xeb, 0x2f, 0x23, 0x13, 0xcb, 0x9e, 0x18, 0x3e, 0xb2, 0x95, 0xdf, 0x57, 0xcc, 0x35, + 0x37, 0x4f, 0xab, 0x37, 0xa4, 0x22, 0x57, 0x7b, 0xc3, 0x41, 0x8f, 0x37, 0x8f, 0x72, 0x6a, 0x8f, + 0xb7, 0x14, 0x40, 0xd5, 0x6a, 0xaf, 0x22, 0x24, 0x7a, 0x00, 0xcd, 0x3c, 0x6c, 0xb6, 0x9d, 0x17, + 0x94, 0x59, 0x41, 0x36, 0x6d, 0x15, 0x4b, 0xc1, 0x2c, 0x77, 0x8d, 0xb6, 0x0a, 0xd8, 0x32, 0x6e, + 0x15, 0x45, 0xa8, 0x02, 0xd8, 0x10, 0x04, 0x6a, 0x13, 0x4f, 0x69, 0x45, 0xb5, 0x92, 0x8a, 0x80, + 0x92, 0x96, 0xe6, 0xca, 0x78, 0x8c, 0x75, 0xf7, 0x45, 0x6e, 0x15, 0x29, 0x4d, 0x54, 0xcd, 0x13, + 0x58, 0x2f, 0x05, 0x13, 0xb4, 0x48, 0xcf, 0x8b, 0xe1, 0x68, 0x91, 0x9e, 0x1b, 0x87, 0x70, 0xcf, + 0xd3, 0x94, 0xab, 0x2e, 0xe0, 0x94, 0xe9, 0x59, 0x90, 0x0d, 0x4e, 0xde, 0x73, 0x76, 0x8e, 0x16, + 0xe9, 0xff, 0x8a, 0x3e, 0xfd, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd5, 0xa1, 0x16, 0xf4, 0xe1, + 0x48, 0x00, 0x00, } diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index 6f8ce4cc..e3b1ed8f 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -646,6 +646,16 @@ message TransactionDetails { repeated Transaction transactions = 1 [json_name = "transactions"]; } +message FeeLimit { + oneof limit { + /// The fee limit expressed as a fixed amount of satoshis. + int64 fixed = 1; + + /// The fee limit expressed as a percentage of the payment amount. + int64 percent = 2; + } +} + message SendRequest { /// The identity pubkey of the payment recipient bytes dest = 1; @@ -653,7 +663,7 @@ message SendRequest { /// The hex-encoded identity pubkey of the payment recipient string dest_string = 2; - /// Number of satoshis to send. + /// Number of satoshis to send. int64 amt = 3; /// The hash to use within the payment's HTLC @@ -669,12 +679,19 @@ message SendRequest { */ string payment_request = 6; - /// The CLTV delta from the current height that should be used to set the timelock for the final hop. + /** + The CLTV delta from the current height that should be used to set the + timelock for the final hop. + */ int32 final_cltv_delta = 7; - /// The maximum total fees for the payment in satoshis. - int64 fee_limit = 8 [json_name = "fee_limit"]; - + /** + The maximum number of satoshis that will be paid as a fee of the payment. + This value can be represented either as a percentage of the amount being + sent, or as a fixed amount of the maximum fee the user is willing the pay to + send the payment. + */ + FeeLimit fee_limit = 8; } message SendResponse { string payment_error = 1 [json_name = "payment_error"]; @@ -1235,11 +1252,16 @@ message QueryRoutesRequest { /// An optional CLTV delta from the current height that should be used for the timelock of the final hop int32 final_cltv_delta = 4; - /// The maximum total fees for the route in satoshis. - int64 fee_limit = 5; + /** + The maximum number of satoshis that will be paid as a fee of the payment. + This value can be represented either as a percentage of the amount being + sent, or as a fixed amount of the maximum fee the user is willing the pay to + send the payment. + */ + FeeLimit fee_limit = 5; } message QueryRoutesResponse { - repeated Route routes = 1 [ json_name = "routes"]; + repeated Route routes = 1 [json_name = "routes"]; } message Hop { diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index 9ab24251..65876c1e 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -476,8 +476,16 @@ "format": "int32" }, { - "name": "fee_limit", - "description": "/ The maximum total fees for the route in satoshis.", + "name": "fee_limit.fixed", + "description": "/ The fee limit expressed as a fixed amount of satoshis.", + "in": "query", + "required": false, + "type": "string", + "format": "int64" + }, + { + "name": "fee_limit.percent", + "description": "/ The fee limit expressed as a percentage of the payment amount.", "in": "query", "required": false, "type": "string", @@ -1340,6 +1348,21 @@ "lnrpcDisconnectPeerResponse": { "type": "object" }, + "lnrpcFeeLimit": { + "type": "object", + "properties": { + "fixed": { + "type": "string", + "format": "int64", + "description": "/ The fee limit expressed as a fixed amount of satoshis." + }, + "percent": { + "type": "string", + "format": "int64", + "description": "/ The fee limit expressed as a percentage of the payment amount." + } + } + }, "lnrpcFeeReportResponse": { "type": "object", "properties": { @@ -2388,12 +2411,11 @@ "final_cltv_delta": { "type": "integer", "format": "int32", - "description": "/ The CLTV delta from the current height that should be used to set the timelock for the final hop." + "description": "*\nThe CLTV delta from the current height that should be used to set the\ntimelock for the final hop." }, "fee_limit": { - "type": "string", - "format": "int64", - "description": "/ The maximum total fees for the payment in satoshis." + "$ref": "#/definitions/lnrpcFeeLimit", + "description": "*\nThe maximum number of satoshis that will be paid as a fee of the payment.\nThis value can be represented either as a percentage of the amount being\nsent, or as a fixed amount of the maximum fee the user is willing the pay to\nsend the payment." } } }, From 6a6de812ba945ac849e820ef11b69343af98d58e Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 19 Apr 2018 10:26:41 -0400 Subject: [PATCH 3/8] routing: denote a payment's fee limit in millisatoshis instead --- routing/router.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/routing/router.go b/routing/router.go index 57ae4350..eef768b6 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1505,8 +1505,10 @@ type LightningPayment struct { // milli-satoshis. Amount lnwire.MilliSatoshi - // FeeLimit is a user-specified maximum fee for this payment in satoshis. - FeeLimit btcutil.Amount + // FeeLimit is the maximum fee in millisatoshis that the payment should + // accept when sending it through the network. The payment will fail + // if there isn't a route with lower fees than this limit. + FeeLimit lnwire.MilliSatoshi // PaymentHash is the r-hash value to use within the HTLC extended to // the first hop. From ddf8f2cb01e2d0d842da84e6e3d82d58dce26548 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 19 Apr 2018 10:32:24 -0400 Subject: [PATCH 4/8] routing: allow specifying a fee limit during route construction --- routing/errors.go | 6 ++-- routing/missioncontrol.go | 3 +- routing/pathfind.go | 15 ++++---- routing/pathfind_test.go | 70 +++++++++++++++++++++++++++++++----- routing/router.go | 10 +++--- routing/router_test.go | 75 +++++++++++++++++++++++++++++++++------ 6 files changed, 143 insertions(+), 36 deletions(-) diff --git a/routing/errors.go b/routing/errors.go index a879cfe7..58a92b90 100644 --- a/routing/errors.go +++ b/routing/errors.go @@ -43,9 +43,9 @@ const ( // attempt timed out before we were able to successfully route an HTLC. ErrPaymentAttemptTimeout - // ErrFeeCutoffExceeded is returned when the total fees of a route - // exceed the user-specified maximum payment for the fee. - ErrFeeCutoffExceeded + // ErrFeeLimitExceeded is returned when the total fees of a route exceed + // the user-specified fee limit. + ErrFeeLimitExceeded ) // routerError is a structure that represent the error inside the routing package, diff --git a/routing/missioncontrol.go b/routing/missioncontrol.go index c6eaad9a..9e0fa908 100644 --- a/routing/missioncontrol.go +++ b/routing/missioncontrol.go @@ -384,7 +384,8 @@ func (p *paymentSession) RequestRoute(payment *LightningPayment, // a route by applying the time-lock and fee requirements. sourceVertex := Vertex(p.mc.selfNode.PubKeyBytes) route, err := newRoute( - payment.Amount, sourceVertex, path, height, finalCltvDelta, + payment.Amount, payment.FeeLimit, sourceVertex, path, height, + finalCltvDelta, ) if err != nil { // TODO(roasbeef): return which edge/vertex didn't work diff --git a/routing/pathfind.go b/routing/pathfind.go index 18a6cce8..b85b149f 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -248,9 +248,9 @@ func (r *Route) ToHopPayloads() []sphinx.HopData { // // NOTE: The passed slice of ChannelHops MUST be sorted in forward order: from // the source to the target node of the path finding attempt. -func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex, +func newRoute(amtToSend, feeLimit lnwire.MilliSatoshi, sourceVertex Vertex, pathEdges []*ChannelHop, currentHeight uint32, - finalCLTVDelta uint16, feeLimit btcutil.Amount) (*Route, error) { + finalCLTVDelta uint16) (*Route, error) { // First, we'll create a new empty route with enough hops to match the // amount of path edges. We set the TotalTimeLock to the current block @@ -339,12 +339,11 @@ func newRoute(amtToSend lnwire.MilliSatoshi, sourceVertex Vertex, route.TotalFees += nextHop.Fee - // If the total fees exceed the fee limit established for this - // payment, stop hopping the route and return - if route.TotalFees.ToSatoshis() > feeLimit { - err := fmt.Sprintf("Route fee exceeded fee limit of %v", - feeLimit) - return nil, newErrf(ErrFeeCutoffExceeded, err) + // Invalidate this route if its total fees exceed our fee limit. + if route.TotalFees > feeLimit { + err := fmt.Sprintf("total route fees exceeded fee "+ + "limit of %v", feeLimit) + return nil, newErrf(ErrFeeLimitExceeded, err) } // As a sanity check, we ensure that the selected channel has diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index f3a4d006..7a7be0da 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "io/ioutil" + "math" "math/big" "net" "os" @@ -40,6 +41,11 @@ const ( // implementations will use in order to ensure that they're calculating // the payload for each hop in path properly. specExampleFilePath = "testdata/spec_example.json" + + // noFeeLimit is the maximum value of a payment through Lightning. We + // can use this value to signal there is no fee limit since payments + // should never be larger than this. + noFeeLimit = lnwire.MilliSatoshi(math.MaxUint32) ) var ( @@ -310,7 +316,6 @@ func TestBasicGraphPathFinding(t *testing.T) { ) paymentAmt := lnwire.NewMSatFromSatoshis(100) - feeLimit := paymentAmt.ToSatoshis() target := aliases["sophon"] path, err := findPath( nil, graph, nil, sourceNode, target, ignoredVertexes, @@ -320,8 +325,10 @@ func TestBasicGraphPathFinding(t *testing.T) { t.Fatalf("unable to find path: %v", err) } - route, err := newRoute(paymentAmt, sourceVertex, path, startingHeight, - finalHopCLTV, feeLimit) + route, err := newRoute( + paymentAmt, noFeeLimit, sourceVertex, path, startingHeight, + finalHopCLTV, + ) if err != nil { t.Fatalf("unable to create path: %v", err) } @@ -463,8 +470,10 @@ func TestBasicGraphPathFinding(t *testing.T) { t.Fatalf("unable to find route: %v", err) } - route, err = newRoute(paymentAmt, sourceVertex, path, startingHeight, - finalHopCLTV, feeLimit) + route, err = newRoute( + paymentAmt, noFeeLimit, sourceVertex, path, startingHeight, + finalHopCLTV, + ) if err != nil { t.Fatalf("unable to create path: %v", err) } @@ -732,6 +741,8 @@ func TestPathInsufficientCapacity(t *testing.T) { // TestRouteFailMinHTLC tests that if we attempt to route an HTLC which is // smaller than the advertised minHTLC of an edge, then path finding fails. func TestRouteFailMinHTLC(t *testing.T) { + t.Parallel() + graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) defer cleanUp() if err != nil { @@ -763,6 +774,8 @@ func TestRouteFailMinHTLC(t *testing.T) { // that's disabled, then that edge is disqualified, and the routing attempt // will fail. func TestRouteFailDisabledEdge(t *testing.T) { + t.Parallel() + graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) defer cleanUp() if err != nil { @@ -810,6 +823,48 @@ func TestRouteFailDisabledEdge(t *testing.T) { } } +// TestRouteExceededFeeLimit tests that routes respect the fee limit imposed. +func TestRouteExceededFeeLimit(t *testing.T) { + t.Parallel() + + graph, cleanUp, aliases, err := parseTestGraph(basicGraphFilePath) + defer cleanUp() + if err != nil { + t.Fatalf("unable to create graph: %v", err) + } + + sourceNode, err := graph.SourceNode() + if err != nil { + t.Fatalf("unable to fetch source node: %v", err) + } + sourceVertex := Vertex(sourceNode.PubKeyBytes) + + ignoredVertices := make(map[Vertex]struct{}) + ignoredEdges := make(map[uint64]struct{}) + + // Find a path to send 100 satoshis from roasbeef to sophon. + target := aliases["sophon"] + amt := lnwire.NewMSatFromSatoshis(100) + path, err := findPath( + nil, graph, nil, sourceNode, target, ignoredVertices, + ignoredEdges, amt, nil, + ) + if err != nil { + t.Fatalf("unable to find path from roasbeef to phamnuwen for "+ + "100 satoshis: %v", err) + } + + // We'll now purposefully set a fee limit of 0 to trigger the exceeded + // fee limit error. This should work since the path retrieved spans + // multiple hops incurring a fee. + feeLimit := lnwire.NewMSatFromSatoshis(0) + + _, err = newRoute(amt, feeLimit, sourceVertex, path, 100, 1) + if !IsError(err, ErrFeeLimitExceeded) { + t.Fatalf("route should've exceeded fee limit: %v", err) + } +} + func TestPathInsufficientCapacityWithFee(t *testing.T) { t.Parallel() @@ -855,8 +910,7 @@ func TestPathFindSpecExample(t *testing.T) { // Query for a route of 4,999,999 mSAT to carol. carol := ctx.aliases["C"] const amt lnwire.MilliSatoshi = 4999999 - feeLimit := amt.ToSatoshis() - routes, err := ctx.router.FindRoutes(carol, amt, feeLimit, 100) + routes, err := ctx.router.FindRoutes(carol, amt, noFeeLimit, 100) if err != nil { t.Fatalf("unable to find route: %v", err) } @@ -916,7 +970,7 @@ func TestPathFindSpecExample(t *testing.T) { // We'll now request a route from A -> B -> C. ctx.router.routeCache = make(map[routeTuple][]*Route) - routes, err = ctx.router.FindRoutes(carol, amt, feeLimit, 100) + routes, err = ctx.router.FindRoutes(carol, amt, noFeeLimit, 100) if err != nil { t.Fatalf("unable to find routes: %v", err) } diff --git a/routing/router.go b/routing/router.go index eef768b6..4f3a5bfb 100644 --- a/routing/router.go +++ b/routing/router.go @@ -1258,8 +1258,8 @@ func pruneChannelFromRoutes(routes []*Route, skipChan uint64) []*Route { // fee information attached. The set of routes returned may be less than 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. -func pathsToFeeSortedRoutes(source Vertex, paths [][]*ChannelHop, finalCLTVDelta uint16, - amt lnwire.MilliSatoshi, feeLimit btcutil.Amount, +func pathsToFeeSortedRoutes(source Vertex, paths [][]*ChannelHop, + finalCLTVDelta uint16, amt, feeLimit lnwire.MilliSatoshi, currentHeight uint32) ([]*Route, error) { validRoutes := make([]*Route, 0, len(paths)) @@ -1268,8 +1268,8 @@ func pathsToFeeSortedRoutes(source Vertex, paths [][]*ChannelHop, finalCLTVDelta // hop in the path as it contains a "self-hop" that is inserted // by our KSP algorithm. route, err := newRoute( - amt, source, path[1:], currentHeight, finalCLTVDelta, - feeLimit, + amt, feeLimit, source, path[1:], currentHeight, + finalCLTVDelta, ) if err != nil { // TODO(roasbeef): report straw breaking edge? @@ -1318,7 +1318,7 @@ func pathsToFeeSortedRoutes(source Vertex, paths [][]*ChannelHop, finalCLTVDelta // route that will be ranked the highest is the one with the lowest cumulative // fee along the route. func (r *ChannelRouter) FindRoutes(target *btcec.PublicKey, - amt lnwire.MilliSatoshi, feeLimit btcutil.Amount, numPaths uint32, + amt, feeLimit lnwire.MilliSatoshi, numPaths uint32, finalExpiry ...uint16) ([]*Route, error) { var finalCLTVDelta uint16 diff --git a/routing/router_test.go b/routing/router_test.go index 511842eb..97944064 100644 --- a/routing/router_test.go +++ b/routing/router_test.go @@ -174,10 +174,9 @@ func TestFindRoutesFeeSorting(t *testing.T) { // Execute a query for all possible routes between roasbeef and luo ji. paymentAmt := lnwire.NewMSatFromSatoshis(100) - feeLimit := paymentAmt.ToSatoshis() target := ctx.aliases["luoji"] routes, err := ctx.router.FindRoutes( - target, paymentAmt, feeLimit, defaultNumRoutes, + target, paymentAmt, noFeeLimit, defaultNumRoutes, DefaultFinalCLTVDelta, ) if err != nil { @@ -209,6 +208,59 @@ func TestFindRoutesFeeSorting(t *testing.T) { } } +// TestFindRoutesWithFeeLimit asserts that routes found by the FindRoutes method +// within the channel router contain a total fee less than or equal to the fee +// limit. +func TestFindRoutesWithFeeLimit(t *testing.T) { + t.Parallel() + + const startingBlockHeight = 101 + ctx, cleanUp, err := createTestCtx( + startingBlockHeight, basicGraphFilePath, + ) + defer cleanUp() + if err != nil { + t.Fatalf("unable to create router: %v", err) + } + + // This test will attempt to find routes from roasbeef to sophon for 100 + // satoshis with a fee limit of 10 satoshis. There are two routes from + // roasbeef to sophon: + // 1. roasbeef -> songoku -> sophon + // 2. roasbeef -> phamnuwen -> sophon + // The second route violates our fee limit, so we should only expect to + // see the first route. + target := ctx.aliases["sophon"] + paymentAmt := lnwire.NewMSatFromSatoshis(100) + feeLimit := lnwire.NewMSatFromSatoshis(10) + + routes, err := ctx.router.FindRoutes( + target, paymentAmt, feeLimit, defaultNumRoutes, + DefaultFinalCLTVDelta, + ) + if err != nil { + t.Fatalf("unable to find any routes: %v", err) + } + + if len(routes) != 1 { + t.Fatalf("expected 1 route, got %d", len(routes)) + } + + if routes[0].TotalFees > feeLimit { + t.Fatalf("route exceeded fee limit: %v", spew.Sdump(routes[0])) + } + + hops := routes[0].Hops + if len(hops) != 2 { + t.Fatalf("expected 2 hops, got %d", len(hops)) + } + + if hops[0].Channel.Node.Alias != "songoku" { + t.Fatalf("expected first hop through songoku, got %s", + hops[0].Channel.Node.Alias) + } +} + // TestSendPaymentRouteFailureFallback tests that when sending a payment, if // one of the target routes is seen as unavailable, then the next route in the // queue is used instead. This process should continue until either a payment @@ -227,12 +279,11 @@ func TestSendPaymentRouteFailureFallback(t *testing.T) { // to luo ji for 1000 satoshis, with a maximum of 1000 satoshis in fees. var payHash [32]byte paymentAmt := lnwire.NewMSatFromSatoshis(1000) - feeLimit := paymentAmt.ToSatoshis() payment := LightningPayment{ Target: ctx.aliases["luoji"], Amount: paymentAmt, + FeeLimit: noFeeLimit, PaymentHash: payHash, - FeeLimit: feeLimit, } var preImage [32]byte @@ -305,9 +356,11 @@ func TestSendPaymentErrorRepeatedFeeInsufficient(t *testing.T) { // Craft a LightningPayment struct that'll send a payment from roasbeef // to luo ji for 100 satoshis. var payHash [32]byte + amt := lnwire.NewMSatFromSatoshis(1000) payment := LightningPayment{ Target: ctx.aliases["sophon"], - Amount: lnwire.NewMSatFromSatoshis(1000), + Amount: amt, + FeeLimit: noFeeLimit, PaymentHash: payHash, } @@ -403,9 +456,11 @@ func TestSendPaymentErrorNonFinalTimeLockErrors(t *testing.T) { // Craft a LightningPayment struct that'll send a payment from roasbeef // to sophon for 1k satoshis. var payHash [32]byte + amt := lnwire.NewMSatFromSatoshis(1000) payment := LightningPayment{ Target: ctx.aliases["sophon"], - Amount: lnwire.NewMSatFromSatoshis(1000), + Amount: amt, + FeeLimit: noFeeLimit, PaymentHash: payHash, } @@ -533,12 +588,11 @@ func TestSendPaymentErrorPathPruning(t *testing.T) { // to luo ji for 1000 satoshis, with a maximum of 1000 satoshis in fees. var payHash [32]byte paymentAmt := lnwire.NewMSatFromSatoshis(1000) - feeLimit := paymentAmt.ToSatoshis() payment := LightningPayment{ Target: ctx.aliases["luoji"], Amount: paymentAmt, + FeeLimit: noFeeLimit, PaymentHash: payHash, - FeeLimit: feeLimit, } var preImage [32]byte @@ -974,10 +1028,9 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { // We should now be able to find two routes to node 2. paymentAmt := lnwire.NewMSatFromSatoshis(100) - feeLimit := paymentAmt.ToSatoshis() targetNode := priv2.PubKey() routes, err := ctx.router.FindRoutes( - targetNode, paymentAmt, feeLimit, defaultNumRoutes, + targetNode, paymentAmt, noFeeLimit, defaultNumRoutes, DefaultFinalCLTVDelta, ) if err != nil { @@ -1022,7 +1075,7 @@ func TestAddEdgeUnknownVertexes(t *testing.T) { // Should still be able to find the routes, and the info should be // updated. routes, err = ctx.router.FindRoutes( - targetNode, paymentAmt, feeLimit, defaultNumRoutes, + targetNode, paymentAmt, noFeeLimit, defaultNumRoutes, DefaultFinalCLTVDelta, ) if err != nil { From 63f079d1a43f9ae13858175eee4a9fe2e97c71ae Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 19 Apr 2018 10:27:37 -0400 Subject: [PATCH 5/8] rpcserver: add fee limit support for routing related RPCs --- rpcserver.go | 132 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 51 deletions(-) diff --git a/rpcserver.go b/rpcserver.go index 549a91b2..591d08e6 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -1765,6 +1765,27 @@ type rpcPaymentRequest struct { routes []*routing.Route } +// 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 + } +} + // SendPayment dispatches a bi-directional streaming RPC for sending payments // through the Lightning Network. A single RPC invocation creates a persistent // bi-directional stream allowing clients to rapidly send payments through the @@ -1831,6 +1852,7 @@ func (r *rpcServer) SendToRoute(stream lnrpc.Lightning_SendToRouteServer) error // directly to the channel router for dispatching. type rpcPaymentIntent struct { msat lnwire.MilliSatoshi + feeLimit lnwire.MilliSatoshi dest *btcec.PublicKey rHash [32]byte cltvDelta uint16 @@ -1897,57 +1919,68 @@ func extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPaymentIntent, error payIntent.msat = *payReq.MilliSat } + // Calculate the fee limit that should be used for this payment. + payIntent.feeLimit = calculateFeeLimit( + rpcPayReq.FeeLimit, payIntent.msat, + ) + copy(payIntent.rHash[:], payReq.PaymentHash[:]) payIntent.dest = payReq.Destination payIntent.cltvDelta = uint16(payReq.MinFinalCLTVExpiry()) payIntent.routeHints = payReq.RouteHints return payIntent, nil - } else { - // At this point, a destination MUST be specified, so we'll convert it - // into the proper representation now. The destination will either be - // encoded as raw bytes, or via a hex string. - if len(rpcPayReq.Dest) != 0 { - payIntent.dest, err = btcec.ParsePubKey( - rpcPayReq.Dest, btcec.S256(), - ) - if err != nil { - return payIntent, err - } + } - } else { - pubBytes, err := hex.DecodeString(rpcPayReq.DestString) - if err != nil { - return payIntent, err - } - payIntent.dest, err = btcec.ParsePubKey(pubBytes, btcec.S256()) - if err != nil { - return payIntent, err - } - } - - // Otherwise, If the payment request field was not specified - // (and a custom route wasn't specified), construct the payment - // from the other fields. - payIntent.msat = lnwire.NewMSatFromSatoshis( - btcutil.Amount(rpcPayReq.Amt), + // At this point, a destination MUST be specified, so we'll convert it + // into the proper representation now. The destination will either be + // encoded as raw bytes, or via a hex string. + if len(rpcPayReq.Dest) != 0 { + payIntent.dest, err = btcec.ParsePubKey( + rpcPayReq.Dest, btcec.S256(), ) - payIntent.cltvDelta = uint16(rpcPayReq.FinalCltvDelta) - - // If the user is manually specifying payment details, then the - // payment hash may be encoded as a string. - if rpcPayReq.PaymentHashString != "" { - paymentHash, err := hex.DecodeString( - rpcPayReq.PaymentHashString, - ) - if err != nil { - return payIntent, err - } - - copy(payIntent.rHash[:], paymentHash) - } else { - copy(payIntent.rHash[:], rpcPayReq.PaymentHash) + if err != nil { + return payIntent, err } + + } else { + pubBytes, err := hex.DecodeString(rpcPayReq.DestString) + if err != nil { + return payIntent, err + } + payIntent.dest, err = btcec.ParsePubKey(pubBytes, btcec.S256()) + if err != nil { + return payIntent, err + } + } + + // Otherwise, If the payment request field was not specified + // (and a custom route wasn't specified), construct the payment + // from the other fields. + payIntent.msat = lnwire.NewMSatFromSatoshis( + btcutil.Amount(rpcPayReq.Amt), + ) + + // Calculate the fee limit that should be used for this payment. + payIntent.feeLimit = calculateFeeLimit( + rpcPayReq.FeeLimit, payIntent.msat, + ) + + payIntent.cltvDelta = uint16(rpcPayReq.FinalCltvDelta) + + // If the user is manually specifying payment details, then the + // payment hash may be encoded as a string. + if rpcPayReq.PaymentHashString != "" { + paymentHash, err := hex.DecodeString( + rpcPayReq.PaymentHashString, + ) + if err != nil { + return payIntent, err + } + + copy(payIntent.rHash[:], paymentHash) + } else { + copy(payIntent.rHash[:], rpcPayReq.PaymentHash) } // If we're in debug HTLC mode, then all outgoing HTLCs will pay to the @@ -1993,6 +2026,7 @@ func (r *rpcServer) dispatchPaymentIntent(payIntent *rpcPaymentIntent) (*routing payment := &routing.LightningPayment{ Target: payIntent.dest, Amount: payIntent.msat, + FeeLimit: payIntent.feeLimit, PaymentHash: payIntent.rHash, RouteHints: payIntent.routeHints, } @@ -2052,9 +2086,6 @@ func (r *rpcServer) sendPayment(stream *paymentStream) error { payChan := make(chan *rpcPaymentIntent) errChan := make(chan error, 1) - // TODO(roasbeef): enforce fee limits, pass into router, ditch if exceed limit - // * limit either a %, or absolute, or iff more than sending - // We don't allow payments to be sent while the daemon itself is still // syncing as we may be trying to sent a payment over a "stale" // channel. @@ -2241,9 +2272,6 @@ func (r *rpcServer) SendToRouteSync(ctx context.Context, func (r *rpcServer) sendPaymentSync(ctx context.Context, nextPayment *rpcPaymentRequest) (*lnrpc.SendResponse, error) { - // TODO(roasbeef): enforce fee limits, pass into router, ditch if exceed limit - // * limit either a %, or absolute, or iff more than sending - // We don't allow payments to be sent while the daemon itself is still // syncing as we may be trying to sent a payment over a "stale" // channel. @@ -3047,13 +3075,14 @@ func (r *rpcServer) QueryRoutes(ctx context.Context, // largest payment size allotted to (2^32) - 1 mSAT or 4.29 million // satoshis. amt := btcutil.Amount(in.Amt) - feeLimit := btcutil.Amount(in.FeeLimit) 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) + // 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. @@ -3063,11 +3092,12 @@ func (r *rpcServer) QueryRoutes(ctx context.Context, ) if in.FinalCltvDelta == 0 { routes, findErr = r.server.chanRouter.FindRoutes( - pubKey, amtMSat, uint32(in.NumRoutes), + pubKey, amtMSat, feeLimit, uint32(in.NumRoutes), ) } else { routes, findErr = r.server.chanRouter.FindRoutes( - pubKey, amtMSat, uint32(in.NumRoutes), uint16(in.FinalCltvDelta), + pubKey, amtMSat, feeLimit, uint32(in.NumRoutes), + uint16(in.FinalCltvDelta), ) } if findErr != nil { From a9d873d2481daf8521e4aff89ee8a9882b5f2c10 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 19 Apr 2018 10:28:13 -0400 Subject: [PATCH 6/8] cmd/lncli: add fee limit flags to routing related commands --- cmd/lncli/commands.go | 262 ++++++++++++++++++++++-------------------- 1 file changed, 136 insertions(+), 126 deletions(-) diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index a00ec192..50bfad40 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -103,37 +103,6 @@ func actionDecorator(f func(*cli.Context) error) func(*cli.Context) error { } } -// calculateFeeLimit takes ctx and the amount for the payment in satoshis. -// It checks the fee_limit and fee_limit_percent flags and determines the -// the feeLimit based on those values. If both flags are set, calculateFeeLimit -// sets feeLimit to the Minumum value between them. If neither flag is set, -// feeLimit is set to the maximum int64 value as to avoid enforcing a limit. -func calculateFeeLimit(ctx *cli.Context, amount int64) int64 { - var ( - feeLimit int64 - feeLimitPercent int64 - ) - - const MaxInt64Value int64 = 1<<63 - 1 // 9223372036854775807 - feeLimit = MaxInt64Value - - if ctx.IsSet("fee_limit_percent") { - feeRatio := float64(ctx.Int64("fee_limit_percent")) / 100 - feeLimitPercent = int64(float64(amount) * feeRatio) - feeLimit = feeLimitPercent - } - - if ctx.IsSet("fee_limit") { - feeLimit = ctx.Int64("fee_limit") - } - - // If both fee_limit and fee_limit_percent are set, pick the minimum - if ctx.IsSet("fee_limit") && ctx.IsSet("fee_limit_percent") { - feeLimit = int64(math.Min(float64(feeLimit), float64(feeLimitPercent))) - } - return feeLimit -} - var newAddressCommand = cli.Command{ Name: "newaddress", Category: "Wallet", @@ -1648,6 +1617,16 @@ var sendPaymentCommand = cli.Command{ Name: "amt, a", Usage: "number of satoshis to send", }, + cli.Int64Flag{ + Name: "fee_limit", + Usage: "maximum fee allowed in satoshis when sending" + + "the payment", + }, + cli.Int64Flag{ + Name: "fee_limit_percent", + Usage: "percentage of the payment's amount used as the" + + "maximum fee allowed when sending the payment", + }, cli.StringFlag{ Name: "payment_hash, r", Usage: "the hash to use within the payment's HTLC", @@ -1664,18 +1643,36 @@ var sendPaymentCommand = cli.Command{ Name: "final_cltv_delta", Usage: "the number of blocks the last hop has to reveal the preimage", }, - cli.Int64Flag{ - Name: "fee_limit", - Usage: "maximum total fees for the payment in satoshis", - }, - cli.Int64Flag{ - Name: "fee_limit_percent", - Usage: "maximum total fees as a percentage of amt", - }, }, Action: sendPayment, } +// retrieveFeeLimit retrieves the fee limit based on the different fee limit +// flags passed. +func retrieveFeeLimit(ctx *cli.Context) (*lnrpc.FeeLimit, error) { + switch { + case ctx.IsSet("fee_limit") && ctx.IsSet("fee_limit_percent"): + return nil, fmt.Errorf("either fee_limit or fee_limit_percent " + + "can be set, but not both") + case ctx.IsSet("fee_limit"): + return &lnrpc.FeeLimit{ + Limit: &lnrpc.FeeLimit_Fixed{ + Fixed: ctx.Int64("fee_limit"), + }, + }, nil + case ctx.IsSet("fee_limit_percent"): + return &lnrpc.FeeLimit{ + Limit: &lnrpc.FeeLimit_Percent{ + Percent: ctx.Int64("fee_limit_percent"), + }, + }, nil + } + + // Since the fee limit flags aren't required, we don't return an error + // if they're not set. + return nil, nil +} + func sendPayment(ctx *cli.Context) error { // Show command help if no arguments provided if ctx.NArg() == 0 && ctx.NumFlags() == 0 { @@ -1683,91 +1680,99 @@ func sendPayment(ctx *cli.Context) error { return nil } - var req *lnrpc.SendRequest + // First, we'll retrieve the fee limit value passed since it can apply + // to both ways of sending payments (with the payment request or + // providing the details manually). + feeLimit, err := retrieveFeeLimit(ctx) + if err != nil { + return err + } + + // If a payment request was provided, we can exit early since all of the + // details of the payment are encoded within the request. if ctx.IsSet("pay_req") { - req = &lnrpc.SendRequest{ + req := &lnrpc.SendRequest{ PaymentRequest: ctx.String("pay_req"), Amt: ctx.Int64("amt"), + FeeLimit: feeLimit, } - } else { - args := ctx.Args() - var ( - destNode []byte - err error - amount int64 - feeLimit int64 - ) + return sendPaymentRequest(ctx, req) + } + + var ( + destNode []byte + amount int64 + ) + + args := ctx.Args() + + switch { + case ctx.IsSet("dest"): + destNode, err = hex.DecodeString(ctx.String("dest")) + case args.Present(): + destNode, err = hex.DecodeString(args.First()) + args = args.Tail() + default: + return fmt.Errorf("destination txid argument missing") + } + if err != nil { + return err + } + + if len(destNode) != 33 { + return fmt.Errorf("dest node pubkey must be exactly 33 bytes, is "+ + "instead: %v", len(destNode)) + } + + if ctx.IsSet("amt") { + amount = ctx.Int64("amt") + } else if args.Present() { + amount, err = strconv.ParseInt(args.First(), 10, 64) + args = args.Tail() + if err != nil { + return fmt.Errorf("unable to decode payment amount: %v", err) + } + } + + req := &lnrpc.SendRequest{ + Dest: destNode, + Amt: amount, + FeeLimit: feeLimit, + } + + if ctx.Bool("debug_send") && (ctx.IsSet("payment_hash") || args.Present()) { + return fmt.Errorf("do not provide a payment hash with debug send") + } else if !ctx.Bool("debug_send") { + var rHash []byte switch { - case ctx.IsSet("dest"): - destNode, err = hex.DecodeString(ctx.String("dest")) + case ctx.IsSet("payment_hash"): + rHash, err = hex.DecodeString(ctx.String("payment_hash")) case args.Present(): - destNode, err = hex.DecodeString(args.First()) - args = args.Tail() + rHash, err = hex.DecodeString(args.First()) default: - return fmt.Errorf("destination txid argument missing") + return fmt.Errorf("payment hash argument missing") } + if err != nil { return err } - - if len(destNode) != 33 { - return fmt.Errorf("dest node pubkey must be exactly 33 bytes, is "+ - "instead: %v", len(destNode)) + if len(rHash) != 32 { + return fmt.Errorf("payment hash must be exactly 32 "+ + "bytes, is instead %v", len(rHash)) } + req.PaymentHash = rHash - if ctx.IsSet("amt") { - amount = ctx.Int64("amt") - } else if args.Present() { - amount, err = strconv.ParseInt(args.First(), 10, 64) - args = args.Tail() - if err != nil { - return fmt.Errorf("unable to decode payment amount: %v", err) - } - } - - feeLimit = calculateFeeLimit(ctx, amount) - - req = &lnrpc.SendRequest{ - Dest: destNode, - Amt: amount, - FeeLimit: feeLimit, - } - - if ctx.Bool("debug_send") && (ctx.IsSet("payment_hash") || args.Present()) { - return fmt.Errorf("do not provide a payment hash with debug send") - } else if !ctx.Bool("debug_send") { - var rHash []byte - - switch { - case ctx.IsSet("payment_hash"): - rHash, err = hex.DecodeString(ctx.String("payment_hash")) - case args.Present(): - rHash, err = hex.DecodeString(args.First()) - default: - return fmt.Errorf("payment hash argument missing") - } - + switch { + case ctx.IsSet("final_cltv_delta"): + req.FinalCltvDelta = int32(ctx.Int64("final_cltv_delta")) + case args.Present(): + delta, err := strconv.ParseInt(args.First(), 10, 64) if err != nil { return err } - if len(rHash) != 32 { - return fmt.Errorf("payment hash must be exactly 32 "+ - "bytes, is instead %v", len(rHash)) - } - req.PaymentHash = rHash - - switch { - case ctx.IsSet("final_cltv_delta"): - req.FinalCltvDelta = int32(ctx.Int64("final_cltv_delta")) - case args.Present(): - delta, err := strconv.ParseInt(args.First(), 10, 64) - if err != nil { - return err - } - req.FinalCltvDelta = int32(delta) - } + req.FinalCltvDelta = int32(delta) } } @@ -1823,12 +1828,14 @@ var payInvoiceCommand = cli.Command{ "invoice", }, cli.Int64Flag{ - Name: "fee_limit", - Usage: "maximum total fees for the payment in satoshis", + Name: "fee_limit", + Usage: "maximum fee allowed in satoshis when sending" + + "the payment", }, cli.Int64Flag{ - Name: "fee_limit_percent", - Usage: "maximum total fees as a percentage of amt", + Name: "fee_limit_percent", + Usage: "percentage of the payment's amount used as the" + + "maximum fee allowed when sending the payment", }, }, Action: actionDecorator(payInvoice), @@ -1838,9 +1845,6 @@ func payInvoice(ctx *cli.Context) error { args := ctx.Args() var payReq string - var feeLimit int64 - var amt int64 - switch { case ctx.IsSet("pay_req"): payReq = ctx.String("pay_req") @@ -1850,13 +1854,14 @@ func payInvoice(ctx *cli.Context) error { return fmt.Errorf("pay_req argument missing") } - amt = ctx.Int64("amt") - - feeLimit = calculateFeeLimit(ctx, amt) + feeLimit, err := retrieveFeeLimit(ctx) + if err != nil { + return err + } req := &lnrpc.SendRequest{ PaymentRequest: payReq, - Amt: amt, + Amt: ctx.Int64("amt"), FeeLimit: feeLimit, } @@ -2558,12 +2563,14 @@ var queryRoutesCommand = cli.Command{ Usage: "the amount to send expressed in satoshis", }, cli.Int64Flag{ - Name: "fee_limit", - Usage: "maximum total fees for the payment in satoshis", + Name: "fee_limit", + Usage: "maximum fee allowed in satoshis when sending" + + "the payment", }, cli.Int64Flag{ - Name: "fee_limit_percent", - Usage: "maximum total fees as a percentage of amt", + Name: "fee_limit_percent", + Usage: "percentage of the payment's amount used as the" + + "maximum fee allowed when sending the payment", }, cli.Int64Flag{ Name: "num_max_routes", @@ -2585,10 +2592,9 @@ func queryRoutes(ctx *cli.Context) error { defer cleanUp() var ( - dest string - amt int64 - err error - feeLimit int64 + dest string + amt int64 + err error ) args := ctx.Args() @@ -2615,11 +2621,15 @@ func queryRoutes(ctx *cli.Context) error { return fmt.Errorf("amt argument missing") } - feeLimit = calculateFeeLimit(ctx, amt) + feeLimit, err := retrieveFeeLimit(ctx) + if err != nil { + return err + } req := &lnrpc.QueryRoutesRequest{ PubKey: dest, Amt: amt, + FeeLimit: feeLimit, NumRoutes: int32(ctx.Int("num_max_routes")), FinalCltvDelta: int32(ctx.Int("final_cltv_delta")), } From b2585f33adfe36a98fcd0d80c0099130a57f740a Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 30 Apr 2018 16:55:31 -0400 Subject: [PATCH 7/8] lnd_test: refactor out waitForChannelUpdate and assertChannelPolicy --- lnd_test.go | 333 ++++++++++++++++++++++++++++------------------------ 1 file changed, 179 insertions(+), 154 deletions(-) diff --git a/lnd_test.go b/lnd_test.go index d9e4f2a2..0b3f1c1b 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -674,6 +674,135 @@ func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false) } +// txStr returns the string representation of the channel's funding transaction. +func txStr(chanPoint *lnrpc.ChannelPoint) string { + txidHash, err := getChanPointFundingTxid(chanPoint) + if err != nil { + return "" + } + fundingTxID, err := chainhash.NewHash(txidHash) + if err != nil { + return "" + } + cp := wire.OutPoint{ + Hash: *fundingTxID, + Index: chanPoint.OutputIndex, + } + return cp.String() +} + +// waitForChannelUpdate waits for a node to receive updates from the advertising +// node for the specified channels. +func waitForChannelUpdate(t *harnessTest, graphUpdates chan *lnrpc.GraphTopologyUpdate, + advertisingNode string, expectedPolicy *lnrpc.RoutingPolicy, + chanPoints ...*lnrpc.ChannelPoint) { + + // Create a set containing all the channel points we are awaiting + // updates for. + cps := make(map[string]struct{}) + for _, chanPoint := range chanPoints { + cps[txStr(chanPoint)] = struct{}{} + } +out: + for { + select { + case graphUpdate := <-graphUpdates: + for _, update := range graphUpdate.ChannelUpdates { + fundingTxStr := txStr(update.ChanPoint) + if _, ok := cps[fundingTxStr]; !ok { + continue + } + + if update.AdvertisingNode != advertisingNode { + continue + } + + err := checkChannelPolicy( + update.RoutingPolicy, expectedPolicy, + ) + if err != nil { + continue + } + + // We got a policy update that matched the + // values and channel point of what we + // expected, delete it from the map. + delete(cps, fundingTxStr) + + // If we have no more channel points we are + // waiting for, break out of the loop. + if len(cps) == 0 { + break out + } + } + case <-time.After(20 * time.Second): + t.Fatalf("did not receive channel update") + } + } +} + +// assertChannelPolicy asserts that the passed node's known channel policy for +// the passed chanPoint is consistent with the expected policy values. +func assertChannelPolicy(t *harnessTest, node *lntest.HarnessNode, + advertisingNode string, expectedPolicy *lnrpc.RoutingPolicy, + chanPoints ...*lnrpc.ChannelPoint) { + + descReq := &lnrpc.ChannelGraphRequest{} + chanGraph, err := node.DescribeGraph(context.Background(), descReq) + if err != nil { + t.Fatalf("unable to query for alice's graph: %v", err) + } + +out: + for _, chanPoint := range chanPoints { + for _, e := range chanGraph.Edges { + if e.ChanPoint != txStr(chanPoint) { + continue + } + + var err error + if e.Node1Pub == advertisingNode { + err = checkChannelPolicy( + e.Node1Policy, expectedPolicy, + ) + } else { + err = checkChannelPolicy( + e.Node2Policy, expectedPolicy, + ) + } + if err != nil { + t.Fatalf(err.Error()) + } + + continue out + } + + // If we've iterated over all the known edges and we weren't + // able to find this specific one, then we'll fail. + t.Fatalf("did not find edge %v", txStr(chanPoint)) + } +} + +// checkChannelPolicy checks that the policy matches the expected one. +func checkChannelPolicy(policy, expectedPolicy *lnrpc.RoutingPolicy) error { + if policy.FeeBaseMsat != expectedPolicy.FeeBaseMsat { + return fmt.Errorf("expected base fee %v, got %v", + expectedPolicy.FeeBaseMsat, policy.FeeBaseMsat) + } + if policy.FeeRateMilliMsat != expectedPolicy.FeeRateMilliMsat { + return fmt.Errorf("expected fee rate %v, got %v", + expectedPolicy.FeeRateMilliMsat, + policy.FeeRateMilliMsat) + } + if policy.TimeLockDelta != expectedPolicy.TimeLockDelta { + return fmt.Errorf("expected time lock delta %v, got %v", + expectedPolicy.TimeLockDelta, + policy.TimeLockDelta) + } + + return nil +} + // testUpdateChannelPolicy tests that policy updates made to a channel // gets propagated to other nodes in the network. func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { @@ -746,162 +875,46 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { feeRate := int64(12) timeLockDelta := uint32(66) + expectedPolicy := &lnrpc.RoutingPolicy{ + FeeBaseMsat: baseFee, + FeeRateMilliMsat: feeBase * feeRate, + TimeLockDelta: timeLockDelta, + } + req := &lnrpc.PolicyUpdateRequest{ BaseFeeMsat: baseFee, FeeRate: float64(feeRate), TimeLockDelta: timeLockDelta, - } - req.Scope = &lnrpc.PolicyUpdateRequest_ChanPoint{ - ChanPoint: chanPoint, + Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ + ChanPoint: chanPoint, + }, } - _, err = net.Bob.UpdateChannelPolicy(ctxb, req) - if err != nil { + if _, err := net.Bob.UpdateChannelPolicy(ctxb, req); err != nil { t.Fatalf("unable to get alice's balance: %v", err) } - // txStr returns the string representation of the channel's - // funding tx. - txStr := func(chanPoint *lnrpc.ChannelPoint) string { - txidHash, err := getChanPointFundingTxid(chanPoint) - if err != nil { - return "" - } - fundingTxID, err := chainhash.NewHash(txidHash) - if err != nil { - return "" - } - cp := wire.OutPoint{ - Hash: *fundingTxID, - Index: chanPoint.OutputIndex, - } - return cp.String() - } - - // A closure that is used to wait for a channel updates that matches - // the channel policy update done by Alice. - waitForChannelUpdate := func(graphUpdates chan *lnrpc.GraphTopologyUpdate, - advertisingNode string, chanPoints ...*lnrpc.ChannelPoint) { - - // Create a map containing all the channel points we are - // waiting for updates for. - cps := make(map[string]bool) - for _, chanPoint := range chanPoints { - cps[txStr(chanPoint)] = true - } - Loop: - for { - select { - case graphUpdate := <-graphUpdates: - for _, update := range graphUpdate.ChannelUpdates { - fundingTxStr := txStr(update.ChanPoint) - if _, ok := cps[fundingTxStr]; !ok { - continue - } - - if update.AdvertisingNode != advertisingNode { - continue - } - - policy := update.RoutingPolicy - if policy.FeeBaseMsat != baseFee { - continue - } - if policy.FeeRateMilliMsat != feeRate*feeBase { - continue - } - if policy.TimeLockDelta != timeLockDelta { - continue - } - - // We got a policy update that matched the - // values and channel point of what we - // expected, delete it from the map. - delete(cps, fundingTxStr) - - // If we have no more channel points we are - // waiting for, break out of the loop. - if len(cps) == 0 { - break Loop - } - } - case <-time.After(20 * time.Second): - t.Fatalf("did not receive channel update") - } - } - } - // Wait for all nodes to have seen the policy update done by Bob. - waitForChannelUpdate(aliceUpdates, net.Bob.PubKeyStr, chanPoint) - waitForChannelUpdate(bobUpdates, net.Bob.PubKeyStr, chanPoint) - waitForChannelUpdate(carolUpdates, net.Bob.PubKeyStr, chanPoint) - - // assertChannelPolicy asserts that the passed node's known channel - // policy for the passed chanPoint is consistent with Bob's current - // expected policy values. - assertChannelPolicy := func(node *lntest.HarnessNode, - advertisingNode string, chanPoint *lnrpc.ChannelPoint) { - - // Get a DescribeGraph from the node. - descReq := &lnrpc.ChannelGraphRequest{} - chanGraph, err := node.DescribeGraph(ctxb, descReq) - if err != nil { - t.Fatalf("unable to query for alice's routing table: %v", - err) - } - - edgeFound := false - for _, e := range chanGraph.Edges { - if e.ChanPoint == txStr(chanPoint) { - edgeFound = true - if e.Node1Pub == advertisingNode { - if e.Node1Policy.FeeBaseMsat != baseFee { - t.Fatalf("expected base fee "+ - "%v, got %v", baseFee, - e.Node1Policy.FeeBaseMsat) - } - if e.Node1Policy.FeeRateMilliMsat != feeRate*feeBase { - t.Fatalf("expected fee rate "+ - "%v, got %v", feeRate*feeBase, - e.Node1Policy.FeeRateMilliMsat) - } - if e.Node1Policy.TimeLockDelta != timeLockDelta { - t.Fatalf("expected time lock "+ - "delta %v, got %v", - timeLockDelta, - e.Node1Policy.TimeLockDelta) - } - } else { - if e.Node2Policy.FeeBaseMsat != baseFee { - t.Fatalf("expected base fee "+ - "%v, got %v", baseFee, - e.Node2Policy.FeeBaseMsat) - } - if e.Node2Policy.FeeRateMilliMsat != feeRate*feeBase { - t.Fatalf("expected fee rate "+ - "%v, got %v", feeRate*feeBase, - e.Node2Policy.FeeRateMilliMsat) - } - if e.Node2Policy.TimeLockDelta != timeLockDelta { - t.Fatalf("expected time lock "+ - "delta %v, got %v", - timeLockDelta, - e.Node2Policy.TimeLockDelta) - } - } - } - } - - if !edgeFound { - t.Fatalf("did not find edge") - } - - } + waitForChannelUpdate( + t, aliceUpdates, net.Bob.PubKeyStr, expectedPolicy, chanPoint, + ) + waitForChannelUpdate( + t, bobUpdates, net.Bob.PubKeyStr, expectedPolicy, chanPoint, + ) + waitForChannelUpdate( + t, carolUpdates, net.Bob.PubKeyStr, expectedPolicy, chanPoint, + ) // Check that all nodes now know about Bob's updated policy. - assertChannelPolicy(net.Alice, net.Bob.PubKeyStr, chanPoint) - assertChannelPolicy(net.Bob, net.Bob.PubKeyStr, chanPoint) - assertChannelPolicy(carol, net.Bob.PubKeyStr, chanPoint) + assertChannelPolicy( + t, net.Alice, net.Bob.PubKeyStr, expectedPolicy, chanPoint, + ) + assertChannelPolicy( + t, net.Bob, net.Bob.PubKeyStr, expectedPolicy, chanPoint, + ) + assertChannelPolicy( + t, carol, net.Bob.PubKeyStr, expectedPolicy, chanPoint, + ) // Now that all nodes have received the new channel update, we'll try // to send a payment from Alice to Carol to ensure that Alice has @@ -951,6 +964,10 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { feeRate = int64(123) timeLockDelta = uint32(22) + expectedPolicy.FeeBaseMsat = baseFee + expectedPolicy.FeeRateMilliMsat = feeBase * feeRate + expectedPolicy.TimeLockDelta = timeLockDelta + req = &lnrpc.PolicyUpdateRequest{ BaseFeeMsat: baseFee, FeeRate: float64(feeRate), @@ -966,24 +983,32 @@ func testUpdateChannelPolicy(net *lntest.NetworkHarness, t *harnessTest) { // Wait for all nodes to have seen the policy updates for both of // Alice's channels. waitForChannelUpdate( - aliceUpdates, net.Alice.PubKeyStr, chanPoint, chanPoint3, + t, aliceUpdates, net.Alice.PubKeyStr, expectedPolicy, chanPoint, + chanPoint3, ) waitForChannelUpdate( - bobUpdates, net.Alice.PubKeyStr, chanPoint, chanPoint3, + t, bobUpdates, net.Alice.PubKeyStr, expectedPolicy, chanPoint, + chanPoint3, ) waitForChannelUpdate( - carolUpdates, net.Alice.PubKeyStr, chanPoint, chanPoint3, + t, carolUpdates, net.Alice.PubKeyStr, expectedPolicy, chanPoint, + chanPoint3, ) // And finally check that all nodes remembers the policy update they // received. - assertChannelPolicy(net.Alice, net.Alice.PubKeyStr, chanPoint) - assertChannelPolicy(net.Bob, net.Alice.PubKeyStr, chanPoint) - assertChannelPolicy(carol, net.Alice.PubKeyStr, chanPoint) - - assertChannelPolicy(net.Alice, net.Alice.PubKeyStr, chanPoint3) - assertChannelPolicy(net.Bob, net.Alice.PubKeyStr, chanPoint3) - assertChannelPolicy(carol, net.Alice.PubKeyStr, chanPoint3) + assertChannelPolicy( + t, net.Alice, net.Alice.PubKeyStr, expectedPolicy, chanPoint, + chanPoint3, + ) + assertChannelPolicy( + t, net.Bob, net.Alice.PubKeyStr, expectedPolicy, chanPoint, + chanPoint3, + ) + assertChannelPolicy( + t, carol, net.Alice.PubKeyStr, expectedPolicy, chanPoint, + chanPoint3, + ) // Close the channels. ctxt, _ = context.WithTimeout(ctxb, timeout) From 70a52c9eae142662db5f46896ef2e15b0639bebc Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Mon, 30 Apr 2018 16:56:02 -0400 Subject: [PATCH 8/8] lnd_test: add route fee cutoff test --- lnd_test.go | 276 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) diff --git a/lnd_test.go b/lnd_test.go index 0b3f1c1b..54e6756d 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -9761,6 +9761,278 @@ func testQueryRoutes(net *lntest.NetworkHarness, t *harnessTest) { } } +// testRouteFeeCutoff tests that we are able to prevent querying routes and +// sending payments that incur a fee higher than the fee limit. +func testRouteFeeCutoff(net *lntest.NetworkHarness, t *harnessTest) { + // For this test, we'll create the following topology: + // + // --- Bob --- + // / \ + // Alice ---- ---- Dave + // \ / + // -- Carol -- + // + // Alice will attempt to send payments to Dave that should not incur a + // fee greater than the fee limit expressed as a percentage of the + // amount and as a fixed amount of satoshis. + + ctxb := context.Background() + timeout := time.Duration(time.Second * 15) + + const chanAmt = btcutil.Amount(100000) + + // Open a channel between Alice and Bob. + ctxt, _ := context.WithTimeout(ctxb, timeout) + chanPointAliceBob := openChannelAndAssert( + ctxt, t, net, net.Alice, net.Bob, chanAmt, 0, false, + ) + + // Create Carol's node and open a channel between her and Alice with + // Alice being the funder. + carol, err := net.NewNode("Carol", nil) + if err != nil { + t.Fatalf("unable to create carol's node: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + if err := net.ConnectNodes(ctxt, carol, net.Alice); err != nil { + t.Fatalf("unable to connect carol to alice: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = net.SendCoins(ctxt, btcutil.SatoshiPerBitcoin, carol) + if err != nil { + t.Fatalf("unable to send coins to carol: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + chanPointAliceCarol := openChannelAndAssert( + ctxt, t, net, net.Alice, carol, chanAmt, 0, false, + ) + + // Create Dave's node and open a channel between him and Bob with Bob + // being the funder. + dave, err := net.NewNode("Dave", nil) + if err != nil { + t.Fatalf("unable to create dave's node: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + if err := net.ConnectNodes(ctxt, dave, net.Bob); err != nil { + t.Fatalf("unable to connect dave to bob: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + chanPointBobDave := openChannelAndAssert( + ctxt, t, net, net.Bob, dave, chanAmt, 0, false, + ) + + // Open a channel between Carol and Dave. + ctxt, _ = context.WithTimeout(ctxb, timeout) + if err := net.ConnectNodes(ctxt, carol, dave); err != nil { + t.Fatalf("unable to connect carol to dave: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + chanPointCarolDave := openChannelAndAssert( + ctxt, t, net, carol, dave, chanAmt, 0, false, + ) + + // Now that all the channels were set up, we'll wait for all the nodes + // to have seen all the channels. + nodes := []*lntest.HarnessNode{net.Alice, net.Bob, carol, dave} + nodeNames := []string{"alice", "bob", "carol", "dave"} + networkChans := []*lnrpc.ChannelPoint{ + chanPointAliceBob, chanPointAliceCarol, chanPointBobDave, + chanPointCarolDave, + } + for _, chanPoint := range networkChans { + for i, node := range nodes { + txidHash, err := getChanPointFundingTxid(chanPoint) + if err != nil { + t.Fatalf("unable to get txid: %v", err) + } + txid, e := chainhash.NewHash(txidHash) + if e != nil { + t.Fatalf("unable to create sha hash: %v", e) + } + outpoint := wire.OutPoint{ + Hash: *txid, + Index: chanPoint.OutputIndex, + } + + ctxt, _ := context.WithTimeout(ctxb, timeout) + err = node.WaitForNetworkChannelOpen(ctxt, chanPoint) + if err != nil { + t.Fatalf("%s(%d) timed out waiting for "+ + "channel(%s) open: %v", nodeNames[i], + node.NodeID, outpoint, err) + } + } + } + + // The payments should only be succesful across the route: + // Alice -> Bob -> Dave + // Therefore, we'll update the fee policy on Carol's side for the + // channel between her and Dave to invalidate the route: + // Alice -> Carol -> Dave + const feeBase = 1e+6 + baseFee := int64(10000) + feeRate := int64(5) + timeLockDelta := uint32(144) + + expectedPolicy := &lnrpc.RoutingPolicy{ + FeeBaseMsat: baseFee, + FeeRateMilliMsat: feeBase * feeRate, + TimeLockDelta: timeLockDelta, + } + + updateFeeReq := &lnrpc.PolicyUpdateRequest{ + BaseFeeMsat: baseFee, + FeeRate: float64(feeRate), + TimeLockDelta: timeLockDelta, + Scope: &lnrpc.PolicyUpdateRequest_ChanPoint{ + ChanPoint: chanPointCarolDave, + }, + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + if _, err := carol.UpdateChannelPolicy(ctxt, updateFeeReq); err != nil { + t.Fatalf("unable to update chan policy: %v", err) + } + + // Wait for Alice to receive the channel update from Carol. + ctxt, _ = context.WithTimeout(ctxb, timeout) + aliceUpdates, aQuit := subscribeGraphNotifications(t, ctxt, net.Alice) + defer close(aQuit) + waitForChannelUpdate( + t, aliceUpdates, carol.PubKeyStr, expectedPolicy, + chanPointCarolDave, + ) + + // We'll also need the channel IDs for Bob's channels in order to + // confirm the route of the payments. + listReq := &lnrpc.ListChannelsRequest{} + ctxt, _ = context.WithTimeout(ctxb, timeout) + listResp, err := net.Bob.ListChannels(ctxt, listReq) + if err != nil { + t.Fatalf("unable to retrieve bob's channels: %v", err) + } + + var aliceBobChanID, bobDaveChanID uint64 + for _, channel := range listResp.Channels { + switch channel.RemotePubkey { + case net.Alice.PubKeyStr: + aliceBobChanID = channel.ChanId + case dave.PubKeyStr: + bobDaveChanID = channel.ChanId + } + } + + if aliceBobChanID == 0 { + t.Fatalf("channel between alice and bob not found") + } + if bobDaveChanID == 0 { + t.Fatalf("channel between bob and dave not found") + } + hopChanIDs := []uint64{aliceBobChanID, bobDaveChanID} + + // checkRoute is a helper closure to ensure the route contains the + // correct intermediate hops. + checkRoute := func(route *lnrpc.Route) { + if len(route.Hops) != 2 { + t.Fatalf("expected two hops, got %d", len(route.Hops)) + } + + for i, hop := range route.Hops { + if hop.ChanId != hopChanIDs[i] { + t.Fatalf("expected chan id %d, got %d", + hop.ChanId) + } + } + } + + // We'll be attempting to send two payments from Alice to Dave. One will + // have a fee cutoff expressed as a percentage of the amount and the + // other will have it expressed as a fixed amount of satoshis. + const paymentAmt = 100 + carolFee := computeFee(lnwire.MilliSatoshi(baseFee), 1, paymentAmt) + + // testFeeCutoff is a helper closure that will ensure the different + // types of fee limits work as intended when querying routes and sending + // payments. + testFeeCutoff := func(feeLimit *lnrpc.FeeLimit) { + queryRoutesReq := &lnrpc.QueryRoutesRequest{ + PubKey: dave.PubKeyStr, + Amt: paymentAmt, + FeeLimit: feeLimit, + NumRoutes: 2, + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + routesResp, err := net.Alice.QueryRoutes(ctxt, queryRoutesReq) + if err != nil { + t.Fatalf("unable to get routes: %v", err) + } + + if len(routesResp.Routes) != 1 { + t.Fatalf("expected one route, got %d", + len(routesResp.Routes)) + } + + checkRoute(routesResp.Routes[0]) + + invoice := &lnrpc.Invoice{Value: paymentAmt} + ctxt, _ = context.WithTimeout(ctxb, timeout) + invoiceResp, err := dave.AddInvoice(ctxt, invoice) + if err != nil { + t.Fatalf("unable to create invoice: %v", err) + } + + sendReq := &lnrpc.SendRequest{ + PaymentRequest: invoiceResp.PaymentRequest, + FeeLimit: feeLimit, + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + paymentResp, err := net.Alice.SendPaymentSync(ctxt, sendReq) + if err != nil { + t.Fatalf("unable to send payment: %v", err) + } + if paymentResp.PaymentError != "" { + t.Fatalf("unable to send payment: %v", + paymentResp.PaymentError) + } + + checkRoute(paymentResp.PaymentRoute) + } + + // We'll start off using percentages first. Since the fee along the + // route using Carol as an intermediate hop is 10% of the payment's + // amount, we'll use a lower percentage in order to invalid that route. + feeLimitPercent := &lnrpc.FeeLimit{ + &lnrpc.FeeLimit_Percent{baseFee/1000 - 1}, + } + testFeeCutoff(feeLimitPercent) + + // Now we'll test using fixed fee limit amounts. Since we computed the + // fee for the route using Carol as an intermediate hop earlier, we can + // use a smaller value in order to invalidate that route. + feeLimitFixed := &lnrpc.FeeLimit{ + &lnrpc.FeeLimit_Fixed{int64(carolFee.ToSatoshis()) - 1}, + } + testFeeCutoff(feeLimitFixed) + + // Once we're done, close the channels and shut down the nodes created + // throughout this test. + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAliceBob, false) + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(ctxt, t, net, net.Alice, chanPointAliceCarol, false) + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(ctxt, t, net, net.Bob, chanPointBobDave, false) + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(ctxt, t, net, carol, chanPointCarolDave, false) + + if err := net.ShutdownNode(carol); err != nil { + t.Fatalf("unable to shut down carol: %v", err) + } + if err := net.ShutdownNode(dave); err != nil { + t.Fatalf("unable to shut down dave: %v", err) + } +} + type testCase struct { name string test func(net *lntest.NetworkHarness, t *harnessTest) @@ -9952,6 +10224,10 @@ var testsCases = []*testCase{ name: "query routes", test: testQueryRoutes, }, + { + name: "route fee cutoff", + test: testRouteFeeCutoff, + }, } // TestLightningNetworkDaemon performs a series of integration tests amongst a