diff --git a/autopilot/agent.go b/autopilot/agent.go index da69a935..6e521ba6 100644 --- a/autopilot/agent.go +++ b/autopilot/agent.go @@ -186,13 +186,18 @@ type balanceUpdate struct { balanceDelta btcutil.Amount } -// chanOpenUpdate is a type of external state update the indicates a new +// chanOpenUpdate is a type of external state update that indicates a new // channel has been opened, either by the Agent itself (within the main // controller loop), or by an external user to the system. type chanOpenUpdate struct { newChan Channel } +// chanPendingOpenUpdate is a type of external state update that indicates a new +// channel has been opened, either by the agent itself or an external subsystem, +// but is still pending. +type chanPendingOpenUpdate struct{} + // chanOpenFailureUpdate is a type of external state update that indicates // a previous channel open failed, and that it might be possible to try again. type chanOpenFailureUpdate struct{} @@ -206,9 +211,13 @@ type chanCloseUpdate struct { // OnBalanceChange is a callback that should be executed each time the balance of // the backing wallet changes. func (a *Agent) OnBalanceChange(delta btcutil.Amount) { + a.wg.Add(1) go func() { - a.stateUpdates <- &balanceUpdate{ - balanceDelta: delta, + defer a.wg.Done() + + select { + case a.stateUpdates <- &balanceUpdate{balanceDelta: delta}: + case <-a.quit: } }() } @@ -216,9 +225,25 @@ func (a *Agent) OnBalanceChange(delta btcutil.Amount) { // OnChannelOpen is a callback that should be executed each time a new channel // is manually opened by the user or any system outside the autopilot agent. func (a *Agent) OnChannelOpen(c Channel) { + a.wg.Add(1) go func() { - a.stateUpdates <- &chanOpenUpdate{ - newChan: c, + defer a.wg.Done() + + select { + case a.stateUpdates <- &chanOpenUpdate{newChan: c}: + case <-a.quit: + } + }() +} + +// OnChannelPendingOpen is a callback that should be executed each time a new +// channel is opened, either by the agent or an external subsystems, but is +// still pending. +func (a *Agent) OnChannelPendingOpen() { + go func() { + select { + case a.stateUpdates <- &chanPendingOpenUpdate{}: + case <-a.quit: } }() } @@ -227,8 +252,14 @@ func (a *Agent) OnChannelOpen(c Channel) { // autopilot has attempted to open a channel, but failed. In this case we can // retry channel creation with a different node. func (a *Agent) OnChannelOpenFailure() { + a.wg.Add(1) go func() { - a.stateUpdates <- &chanOpenFailureUpdate{} + defer a.wg.Done() + + select { + case a.stateUpdates <- &chanOpenFailureUpdate{}: + case <-a.quit: + } }() } @@ -236,9 +267,13 @@ func (a *Agent) OnChannelOpenFailure() { // channel has been closed for any reason. This includes regular // closes, force closes, and channel breaches. func (a *Agent) OnChannelClose(closedChans ...lnwire.ShortChannelID) { + a.wg.Add(1) go func() { - a.stateUpdates <- &chanCloseUpdate{ - closedChans: closedChans, + defer a.wg.Done() + + select { + case a.stateUpdates <- &chanCloseUpdate{closedChans: closedChans}: + case <-a.quit: } }() } @@ -364,6 +399,12 @@ func (a *Agent) controller(startingBalance btcutil.Amount) { updateBalance() + // A new channel has been opened by the agent or an + // external subsystem, but is still pending + // confirmation. + case *chanPendingOpenUpdate: + updateBalance() + // A channel has been closed, this may free up an // available slot, triggering a new channel update. case *chanCloseUpdate: @@ -580,6 +621,12 @@ func (a *Agent) controller(startingBalance btcutil.Amount) { err) } } + + // Since the channel open was successful + // and is currently pending, we'll + // trigger the autopilot agent to query + // for more peers. + a.OnChannelPendingOpen() }(chanCandidate) } pendingMtx.Unlock() diff --git a/autopilot/agent_test.go b/autopilot/agent_test.go index 9baf96eb..d89913bf 100644 --- a/autopilot/agent_test.go +++ b/autopilot/agent_test.go @@ -2,13 +2,12 @@ package autopilot import ( "bytes" + "errors" "net" "sync" "testing" "time" - "errors" - "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcutil" @@ -31,21 +30,32 @@ type mockHeuristic struct { directiveResps chan []AttachmentDirective directiveArgs chan directiveArg + + quit chan struct{} } func (m *mockHeuristic) NeedMoreChans(chans []Channel, balance btcutil.Amount) (btcutil.Amount, uint32, bool) { if m.moreChanArgs != nil { - m.moreChanArgs <- moreChanArg{ + moreChan := moreChanArg{ chans: chans, balance: balance, } + select { + case m.moreChanArgs <- moreChan: + case <-m.quit: + return 0, 0, false + } } - resp := <-m.moreChansResps - return resp.amt, resp.numMore, resp.needMore + select { + case resp := <-m.moreChansResps: + return resp.amt, resp.numMore, resp.needMore + case <-m.quit: + return 0, 0, false + } } type directiveArg struct { @@ -60,16 +70,26 @@ func (m *mockHeuristic) Select(self *btcec.PublicKey, graph ChannelGraph, skipChans map[NodeID]struct{}) ([]AttachmentDirective, error) { if m.directiveArgs != nil { - m.directiveArgs <- directiveArg{ + directive := directiveArg{ self: self, graph: graph, amt: amtToUse, skip: skipChans, } + + select { + case m.directiveArgs <- directive: + case <-m.quit: + return nil, errors.New("exiting") + } } - resp := <-m.directiveResps - return resp, nil + select { + case resp := <-m.directiveResps: + return resp, nil + case <-m.quit: + return nil, errors.New("exiting") + } } var _ AttachmentHeuristic = (*mockHeuristic)(nil) @@ -155,6 +175,10 @@ func TestAgentChannelOpenSignal(t *testing.T) { t.Fatalf("unable to create agent: %v", err) } + // To ensure the heuristic doesn't block on quitting the agent, we'll + // use the agent's quit chan to signal when it should also stop. + heuristic.quit = agent.quit + // With the autopilot agent and all its dependencies we'll star the // primary controller goroutine. if err := agent.Start(); err != nil { @@ -296,6 +320,10 @@ func TestAgentChannelFailureSignal(t *testing.T) { t.Fatalf("unable to create agent: %v", err) } + // To ensure the heuristic doesn't block on quitting the agent, we'll + // use the agent's quit chan to signal when it should also stop. + heuristic.quit = agent.quit + // With the autopilot agent and all its dependencies we'll start the // primary controller goroutine. if err := agent.Start(); err != nil { @@ -402,6 +430,10 @@ func TestAgentChannelCloseSignal(t *testing.T) { t.Fatalf("unable to create agent: %v", err) } + // To ensure the heuristic doesn't block on quitting the agent, we'll + // use the agent's quit chan to signal when it should also stop. + heuristic.quit = agent.quit + // With the autopilot agent and all its dependencies we'll star the // primary controller goroutine. if err := agent.Start(); err != nil { @@ -521,6 +553,10 @@ func TestAgentBalanceUpdate(t *testing.T) { t.Fatalf("unable to create agent: %v", err) } + // To ensure the heuristic doesn't block on quitting the agent, we'll + // use the agent's quit chan to signal when it should also stop. + heuristic.quit = agent.quit + // With the autopilot agent and all its dependencies we'll star the // primary controller goroutine. if err := agent.Start(); err != nil { @@ -643,6 +679,10 @@ func TestAgentImmediateAttach(t *testing.T) { t.Fatalf("unable to create agent: %v", err) } + // To ensure the heuristic doesn't block on quitting the agent, we'll + // use the agent's quit chan to signal when it should also stop. + heuristic.quit = agent.quit + // With the autopilot agent and all its dependencies we'll star the // primary controller goroutine. if err := agent.Start(); err != nil { @@ -781,6 +821,10 @@ func TestAgentPrivateChannels(t *testing.T) { t.Fatalf("unable to create agent: %v", err) } + // To ensure the heuristic doesn't block on quitting the agent, we'll + // use the agent's quit chan to signal when it should also stop. + heuristic.quit = agent.quit + // With the autopilot agent and all its dependencies we'll star the // primary controller goroutine. if err := agent.Start(); err != nil { @@ -914,6 +958,10 @@ func TestAgentPendingChannelState(t *testing.T) { t.Fatalf("unable to create agent: %v", err) } + // To ensure the heuristic doesn't block on quitting the agent, we'll + // use the agent's quit chan to signal when it should also stop. + heuristic.quit = agent.quit + // With the autopilot agent and all its dependencies we'll start the // primary controller goroutine. if err := agent.Start(); err != nil { @@ -966,7 +1014,6 @@ func TestAgentPendingChannelState(t *testing.T) { } select { case heuristic.directiveResps <- []AttachmentDirective{nodeDirective}: - return case <-time.After(time.Second * 10): t.Fatalf("heuristic wasn't queried in time") } @@ -994,8 +1041,6 @@ func TestAgentPendingChannelState(t *testing.T) { // heuristic. agent.OnBalanceChange(0.4 * btcutil.SatoshiPerBitcoin) - wg = sync.WaitGroup{} - // The heuristic should be queried, and the argument for the set of // channels passed in should include the pending channels that // should've been created above. @@ -1044,3 +1089,97 @@ func TestAgentPendingChannelState(t *testing.T) { t.Fatalf("select wasn't queried in time") } } + +// TestAgentPendingOpenChannel ensures that the agent queries its heuristic once +// it detects a channel is pending open. This allows the agent to use its own +// change outputs that have yet to confirm for funding transactions. +func TestAgentPendingOpenChannel(t *testing.T) { + t.Parallel() + + // First, we'll create all the dependencies that we'll need in order to + // create the autopilot agent. + self, err := randKey() + if err != nil { + t.Fatalf("unable to generate key: %v", err) + } + heuristic := &mockHeuristic{ + moreChansResps: make(chan moreChansResp), + directiveResps: make(chan []AttachmentDirective), + } + chanController := &mockChanController{ + openChanSignals: make(chan openChanIntent), + } + memGraph, _, _ := newMemChanGraph() + + // The wallet will start with 6 BTC available. + const walletBalance = btcutil.SatoshiPerBitcoin * 6 + + // With the dependencies we created, we can now create the initial + // agent itself. + cfg := Config{ + Self: self, + Heuristic: heuristic, + ChanController: chanController, + WalletBalance: func() (btcutil.Amount, error) { + return walletBalance, nil + }, + Graph: memGraph, + MaxPendingOpens: 10, + } + agent, err := New(cfg, nil) + if err != nil { + t.Fatalf("unable to create agent: %v", err) + } + + // To ensure the heuristic doesn't block on quitting the agent, we'll + // use the agent's quit chan to signal when it should also stop. + heuristic.quit = agent.quit + + // With the autopilot agent and all its dependencies we'll start the + // primary controller goroutine. + if err := agent.Start(); err != nil { + t.Fatalf("unable to start agent: %v", err) + } + defer agent.Stop() + + // We'll send an initial "no" response to advance the agent past its + // initial check. + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + select { + case heuristic.moreChansResps <- moreChansResp{false, 0, 0}: + case <-time.After(time.Second * 10): + t.Fatalf("heuristic wasn't queried in time") + } + }() + + // Next, we'll signal that a new channel has been opened, but it is + // still pending. + agent.OnChannelPendingOpen() + + // The agent should now query the heuristic in order to determine its + // next action as its local state has now been modified. + wg.Add(1) + go func() { + defer wg.Done() + select { + case heuristic.moreChansResps <- moreChansResp{false, 0, 0}: + case <-time.After(time.Second * 10): + t.Fatalf("heuristic wasn't queried in time") + } + }() + + // We'll wait here for either the agent to query the heuristic to be + // queried, or for the timeout above to tick. + wg.Wait() + + // There shouldn't be a call to the Select method as we've returned + // "false" for NeedMoreChans above. + select { + case heuristic.directiveResps <- []AttachmentDirective{}: + t.Fatalf("Select was called but shouldn't have been") + default: + } +} diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 47d90327..7956af5e 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -469,6 +469,12 @@ var openChannelCommand = cli.Command{ "not set, we will scale the value according to the " + "channel size", }, + cli.Uint64Flag{ + Name: "min_confs", + Usage: "(optional) the minimum number of confirmations " + + "each one of your outputs used for the funding " + + "transaction must satisfy", + }, }, Action: actionDecorator(openChannel), } @@ -493,6 +499,7 @@ func openChannel(ctx *cli.Context) error { SatPerByte: ctx.Int64("sat_per_byte"), MinHtlcMsat: ctx.Int64("min_htlc_msat"), RemoteCsvDelay: uint32(ctx.Uint64("remote_csv_delay")), + MinConfs: int32(ctx.Uint64("min_confs")), } switch { diff --git a/config.go b/config.go index 6e65afb7..f70785de 100644 --- a/config.go +++ b/config.go @@ -146,6 +146,7 @@ type autoPilotConfig struct { MinChannelSize int64 `long:"minchansize" description:"The smallest channel that the autopilot agent should create"` MaxChannelSize int64 `long:"maxchansize" description:"The largest channel that the autopilot agent should create"` Private bool `long:"private" description:"Whether the channels created by the autopilot agent should be private or not. Private channels won't be announced to the network."` + MinConfs int32 `long:"minconfs" description:"The minimum number of confirmations each of your inputs in funding transactions created by the autopilot agent must have."` } type torConfig struct { @@ -424,6 +425,12 @@ func loadConfig() (*config, error) { fmt.Fprintln(os.Stderr, err) return nil, err } + if cfg.Autopilot.MinConfs < 0 { + str := "%s: autopilot.minconfs must be non-negative" + err := fmt.Errorf(str, funcName) + fmt.Fprintln(os.Stderr, err) + return nil, err + } // Ensure that the specified values for the min and max channel size // don't are within the bounds of the normal chan size constraints. diff --git a/fundingmanager.go b/fundingmanager.go index 4a4e14f2..f1163fea 100644 --- a/fundingmanager.go +++ b/fundingmanager.go @@ -1042,12 +1042,20 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) { // responding side of a single funder workflow, we don't commit any // funds to the channel ourselves. chainHash := chainhash.Hash(msg.ChainHash) - reservation, err := f.cfg.Wallet.InitChannelReservation( - amt, 0, msg.PushAmount, - lnwallet.SatPerKWeight(msg.FeePerKiloWeight), 0, - fmsg.peer.IdentityKey(), fmsg.peer.Address(), &chainHash, - msg.ChannelFlags, - ) + req := &lnwallet.InitFundingReserveMsg{ + ChainHash: &chainHash, + NodeID: fmsg.peer.IdentityKey(), + NodeAddr: fmsg.peer.Address(), + FundingAmount: 0, + Capacity: amt, + CommitFeePerKw: lnwallet.SatPerKWeight(msg.FeePerKiloWeight), + FundingFeePerKw: 0, + PushMSat: msg.PushAmount, + Flags: msg.ChannelFlags, + MinConfs: 1, + } + + reservation, err := f.cfg.Wallet.InitChannelReservation(req) if err != nil { fndgLog.Errorf("Unable to initialize reservation: %v", err) f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err) @@ -2598,11 +2606,20 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) { // Initialize a funding reservation with the local wallet. If the // wallet doesn't have enough funds to commit to this channel, then the // request will fail, and be aborted. - reservation, err := f.cfg.Wallet.InitChannelReservation( - capacity, localAmt, msg.pushAmt, commitFeePerKw, - msg.fundingFeePerKw, peerKey, msg.peer.Address(), - &msg.chainHash, channelFlags, - ) + req := &lnwallet.InitFundingReserveMsg{ + ChainHash: &msg.chainHash, + NodeID: peerKey, + NodeAddr: msg.peer.Address(), + FundingAmount: localAmt, + Capacity: capacity, + CommitFeePerKw: commitFeePerKw, + FundingFeePerKw: msg.fundingFeePerKw, + PushMSat: msg.pushAmt, + Flags: channelFlags, + MinConfs: msg.minConfs, + } + + reservation, err := f.cfg.Wallet.InitChannelReservation(req) if err != nil { msg.err <- err return diff --git a/lnd_test.go b/lnd_test.go index 03c60722..959abf7b 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -153,7 +153,7 @@ func openChannelAndAssert(ctx context.Context, t *harnessTest, private bool) *lnrpc.ChannelPoint { chanOpenUpdate, err := net.OpenChannel( - ctx, alice, bob, fundingAmt, pushAmt, private, + ctx, alice, bob, fundingAmt, pushAmt, private, true, ) if err != nil { t.Fatalf("unable to open channel: %v", err) @@ -677,6 +677,82 @@ func testBasicChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { closeChannelAndAssert(ctxt, t, net, net.Alice, chanPoint, false) } +// testUnconfirmedChannelFunding tests that unconfirmed outputs that pay to us +// can be used to fund channels. +func testUnconfirmedChannelFunding(net *lntest.NetworkHarness, t *harnessTest) { + const ( + timeout = time.Duration(15 * time.Second) + chanAmt = maxBtcFundingAmount + pushAmt = btcutil.Amount(100000) + ) + + ctxb := context.Background() + + // We'll start off by creating a node for Carol. + carol, err := net.NewNode("Carol", nil) + if err != nil { + t.Fatalf("unable to create carol's node: %v", err) + } + defer shutdownAndAssert(net, t, carol) + + // We'll send her some funds that should not confirm. + ctxt, _ := context.WithTimeout(ctxb, timeout) + err = net.SendCoinsUnconfirmed(ctxt, 2*chanAmt, carol) + if err != nil { + t.Fatalf("unable to send coins to carol: %v", err) + } + + // Now, we'll connect her to Alice so that they can open a channel + // together. The funding flow should select Carol's unconfirmed output + // as she doesn't have any other funds since it's a new node. + ctxt, _ = context.WithTimeout(ctxb, timeout) + if err := net.ConnectNodes(ctxt, carol, net.Alice); err != nil { + t.Fatalf("unable to connect dave to alice: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + chanOpenUpdate, err := net.OpenChannel( + ctxt, carol, net.Alice, chanAmt, pushAmt, false, false, + ) + if err != nil { + t.Fatalf("unable to open channel between carol and alice: %v", + err) + } + + // Confirm the channel and wait for it to be recognized by both parties. + mineBlocks(t, net, 6) + ctxt, _ = context.WithTimeout(ctxb, timeout) + chanPoint, err := net.WaitForChannelOpen(ctxt, chanOpenUpdate) + if err != nil { + t.Fatalf("error while waiting for channel open: %v", err) + } + + // With the channel open, we'll check the balances on each side of the + // channel as a sanity check to ensure things worked out as intended. + balReq := &lnrpc.ChannelBalanceRequest{} + ctxt, _ = context.WithTimeout(ctxb, timeout) + carolBal, err := carol.ChannelBalance(ctxt, balReq) + if err != nil { + t.Fatalf("unable to get carol's balance: %v", err) + } + ctxt, _ = context.WithTimeout(ctxb, timeout) + aliceBal, err := net.Alice.ChannelBalance(ctxt, balReq) + if err != nil { + t.Fatalf("unable to get alice's balance: %v", err) + } + if carolBal.Balance != int64(chanAmt-pushAmt-calcStaticFee(0)) { + t.Fatalf("carol's balance is incorrect: expected %v got %v", + chanAmt-pushAmt-calcStaticFee(0), carolBal) + } + if aliceBal.Balance != int64(pushAmt) { + t.Fatalf("alice's balance is incorrect: expected %v got %v", + pushAmt, aliceBal.Balance) + } + + // Now that we're done with the test, the channel can be closed. + ctxt, _ = context.WithTimeout(ctxb, timeout) + closeChannelAndAssert(ctxt, t, net, carol, chanPoint, false) +} + // txStr returns the string representation of the channel's funding transaction. func txStr(chanPoint *lnrpc.ChannelPoint) string { txidHash, err := getChanPointFundingTxid(chanPoint) @@ -3699,8 +3775,9 @@ func testPrivateChannels(net *lntest.NetworkHarness, t *harnessTest) { if err := net.ConnectNodes(ctxb, carol, net.Alice); err != nil { t.Fatalf("unable to connect dave to alice: %v", err) } - chanOpenUpdate, err := net.OpenChannel(ctxb, carol, net.Alice, chanAmt, - 0, true) + chanOpenUpdate, err := net.OpenChannel( + ctxb, carol, net.Alice, chanAmt, 0, true, true, + ) if err != nil { t.Fatalf("unable to open channel: %v", err) } @@ -4581,8 +4658,9 @@ func testMaxPendingChannels(net *lntest.NetworkHarness, t *harnessTest) { openStreams := make([]lnrpc.Lightning_OpenChannelClient, maxPendingChannels) for i := 0; i < maxPendingChannels; i++ { ctx, _ = context.WithTimeout(context.Background(), timeout) - stream, err := net.OpenChannel(ctx, net.Alice, carol, amount, - 0, false) + stream, err := net.OpenChannel( + ctx, net.Alice, carol, amount, 0, false, true, + ) if err != nil { t.Fatalf("unable to open channel: %v", err) } @@ -4592,7 +4670,9 @@ func testMaxPendingChannels(net *lntest.NetworkHarness, t *harnessTest) { // Carol exhausted available amount of pending channels, next open // channel request should cause ErrorGeneric to be sent back to Alice. ctx, _ = context.WithTimeout(context.Background(), timeout) - _, err = net.OpenChannel(ctx, net.Alice, carol, amount, 0, false) + _, err = net.OpenChannel( + ctx, net.Alice, carol, amount, 0, false, true, + ) if err == nil { t.Fatalf("error wasn't received") } else if grpc.Code(err) != lnwire.ErrMaxPendingChannels.ToGrpcCode() { @@ -11060,6 +11140,10 @@ var testsCases = []*testCase{ name: "basic funding flow", test: testBasicChannelFunding, }, + { + name: "unconfirmed channel funding", + test: testUnconfirmedChannelFunding, + }, { name: "update channel policy", test: testUpdateChannelPolicy, diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index 58df3965..bf94f027 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -2214,6 +2214,8 @@ type OpenChannelRequest struct { MinHtlcMsat int64 `protobuf:"varint,9,opt,name=min_htlc_msat" json:"min_htlc_msat,omitempty"` // / The delay we require on the remote's commitment transaction. If this is not set, it will be scaled automatically with the channel size. RemoteCsvDelay uint32 `protobuf:"varint,10,opt,name=remote_csv_delay" json:"remote_csv_delay,omitempty"` + // / The minimum number of confirmations each one of your outputs used for the funding transaction must satisfy. + MinConfs int32 `protobuf:"varint,11,opt,name=min_confs" json:"min_confs,omitempty"` } func (m *OpenChannelRequest) Reset() { *m = OpenChannelRequest{} } @@ -2284,6 +2286,13 @@ func (m *OpenChannelRequest) GetRemoteCsvDelay() uint32 { return 0 } +func (m *OpenChannelRequest) GetMinConfs() int32 { + if m != nil { + return m.MinConfs + } + return 0 +} + type OpenStatusUpdate struct { // Types that are valid to be assigned to Update: // *OpenStatusUpdate_ChanPending @@ -7093,395 +7102,395 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 6227 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5c, 0xcd, 0x6f, 0x1c, 0xc9, - 0x75, 0x57, 0x0f, 0x87, 0x1f, 0xf3, 0x66, 0x48, 0x0e, 0x8b, 0x14, 0x35, 0x9a, 0xdd, 0xd5, 0x6a, - 0xdb, 0xc2, 0x4a, 0x66, 0x36, 0x92, 0x96, 0xb6, 0x37, 0xeb, 0xdd, 0xc4, 0x8e, 0x44, 0x52, 0xa2, - 0x6c, 0xae, 0x44, 0x37, 0x25, 0x2b, 0xb1, 0x13, 0x8c, 0x9b, 0x33, 0xc5, 0x61, 0x5b, 0x33, 0xdd, - 0xed, 0xee, 0x1e, 0x52, 0xe3, 0x8d, 0x00, 0xe7, 0x03, 0x39, 0xc5, 0x08, 0x82, 0xe4, 0xe2, 0x00, - 0x41, 0x00, 0x07, 0x08, 0x9c, 0x3f, 0x20, 0xb9, 0x38, 0x01, 0x72, 0xc8, 0xc5, 0x01, 0x82, 0x1c, - 0x7c, 0x32, 0x72, 0x4c, 0x72, 0x48, 0x82, 0x5c, 0x02, 0xe4, 0x1a, 0x04, 0xef, 0xd5, 0x47, 0x57, - 0x75, 0x37, 0x45, 0xf9, 0x23, 0xb9, 0x4d, 0xfd, 0xea, 0x75, 0x7d, 0xbe, 0xaf, 0x7a, 0xf5, 0x6a, - 0xa0, 0x91, 0xc4, 0xfd, 0x9b, 0x71, 0x12, 0x65, 0x11, 0x9b, 0x1d, 0x85, 0x49, 0xdc, 0xef, 0xbe, - 0x3e, 0x8c, 0xa2, 0xe1, 0x88, 0xdf, 0xf2, 0xe3, 0xe0, 0x96, 0x1f, 0x86, 0x51, 0xe6, 0x67, 0x41, - 0x14, 0xa6, 0x82, 0xc8, 0xfd, 0x1a, 0x2c, 0xdd, 0xe7, 0xe1, 0x01, 0xe7, 0x03, 0x8f, 0x7f, 0x63, - 0xc2, 0xd3, 0x8c, 0xfd, 0x1c, 0xac, 0xf8, 0xfc, 0x9b, 0x9c, 0x0f, 0x7a, 0xb1, 0x9f, 0xa6, 0xf1, - 0x71, 0xe2, 0xa7, 0xbc, 0xe3, 0x5c, 0x75, 0x6e, 0xb4, 0xbc, 0xb6, 0xa8, 0xd8, 0xd7, 0x38, 0x7b, - 0x0b, 0x5a, 0x29, 0x92, 0xf2, 0x30, 0x4b, 0xa2, 0x78, 0xda, 0xa9, 0x11, 0x5d, 0x13, 0xb1, 0x1d, - 0x01, 0xb9, 0x23, 0x58, 0xd6, 0x3d, 0xa4, 0x71, 0x14, 0xa6, 0x9c, 0xdd, 0x86, 0xb5, 0x7e, 0x10, - 0x1f, 0xf3, 0xa4, 0x47, 0x1f, 0x8f, 0x43, 0x3e, 0x8e, 0xc2, 0xa0, 0xdf, 0x71, 0xae, 0xce, 0xdc, - 0x68, 0x78, 0x4c, 0xd4, 0xe1, 0x17, 0x1f, 0xc9, 0x1a, 0x76, 0x1d, 0x96, 0x79, 0x28, 0x70, 0x3e, - 0xa0, 0xaf, 0x64, 0x57, 0x4b, 0x39, 0x8c, 0x1f, 0xb8, 0x7f, 0xe7, 0xc0, 0xca, 0x83, 0x30, 0xc8, - 0x9e, 0xfa, 0xa3, 0x11, 0xcf, 0xd4, 0x9c, 0xae, 0xc3, 0xf2, 0x29, 0x01, 0x34, 0xa7, 0xd3, 0x28, - 0x19, 0xc8, 0x19, 0x2d, 0x09, 0x78, 0x5f, 0xa2, 0x67, 0x8e, 0xac, 0x76, 0xe6, 0xc8, 0x2a, 0x97, - 0x6b, 0xe6, 0x8c, 0xe5, 0xba, 0x0e, 0xcb, 0x09, 0xef, 0x47, 0x27, 0x3c, 0x99, 0xf6, 0x4e, 0x83, - 0x70, 0x10, 0x9d, 0x76, 0xea, 0x57, 0x9d, 0x1b, 0xb3, 0xde, 0x92, 0x82, 0x9f, 0x12, 0xea, 0xae, - 0x01, 0x33, 0x67, 0x21, 0xd6, 0xcd, 0x1d, 0xc2, 0xea, 0x93, 0x70, 0x14, 0xf5, 0x9f, 0xfd, 0x84, - 0xb3, 0xab, 0xe8, 0xbe, 0x56, 0xd9, 0xfd, 0x3a, 0xac, 0xd9, 0x1d, 0xc9, 0x01, 0x70, 0xb8, 0xb8, - 0x75, 0xec, 0x87, 0x43, 0xae, 0x9a, 0x54, 0x43, 0xf8, 0x24, 0xb4, 0xfb, 0x93, 0x24, 0xe1, 0x61, - 0x69, 0x0c, 0xcb, 0x12, 0xd7, 0x83, 0x78, 0x0b, 0x5a, 0x21, 0x3f, 0xcd, 0xc9, 0x24, 0xcb, 0x84, - 0xfc, 0x54, 0x91, 0xb8, 0x1d, 0x58, 0x2f, 0x76, 0x23, 0x07, 0xf0, 0x9d, 0x1a, 0x34, 0x1f, 0x27, - 0x7e, 0x98, 0xfa, 0x7d, 0xe4, 0x62, 0xd6, 0x81, 0xf9, 0xec, 0x79, 0xef, 0xd8, 0x4f, 0x8f, 0xa9, - 0xbb, 0x86, 0xa7, 0x8a, 0x6c, 0x1d, 0xe6, 0xfc, 0x71, 0x34, 0x09, 0x33, 0xea, 0x60, 0xc6, 0x93, - 0x25, 0xf6, 0x0e, 0xac, 0x84, 0x93, 0x71, 0xaf, 0x1f, 0x85, 0x47, 0x41, 0x32, 0x16, 0xb2, 0x40, - 0xfb, 0x35, 0xeb, 0x95, 0x2b, 0xd8, 0x15, 0x80, 0x43, 0x5c, 0x07, 0xd1, 0x45, 0x9d, 0xba, 0x30, - 0x10, 0xe6, 0x42, 0x4b, 0x96, 0x78, 0x30, 0x3c, 0xce, 0x3a, 0xb3, 0xd4, 0x90, 0x85, 0x61, 0x1b, - 0x59, 0x30, 0xe6, 0xbd, 0x34, 0xf3, 0xc7, 0x71, 0x67, 0x8e, 0x46, 0x63, 0x20, 0x54, 0x1f, 0x65, - 0xfe, 0xa8, 0x77, 0xc4, 0x79, 0xda, 0x99, 0x97, 0xf5, 0x1a, 0x61, 0x6f, 0xc3, 0xd2, 0x80, 0xa7, - 0x59, 0xcf, 0x1f, 0x0c, 0x12, 0x9e, 0xa6, 0x3c, 0xed, 0x2c, 0x10, 0x37, 0x16, 0x50, 0x5c, 0xb5, - 0xfb, 0x3c, 0x33, 0x56, 0x27, 0x95, 0xbb, 0xe3, 0xee, 0x01, 0x33, 0xe0, 0x6d, 0x9e, 0xf9, 0xc1, - 0x28, 0x65, 0xef, 0x41, 0x2b, 0x33, 0x88, 0x49, 0xfa, 0x9a, 0x9b, 0xec, 0x26, 0xa9, 0x8d, 0x9b, - 0xc6, 0x07, 0x9e, 0x45, 0xe7, 0xde, 0x87, 0x85, 0x7b, 0x9c, 0xef, 0x05, 0xe3, 0x20, 0x63, 0xeb, - 0x30, 0x7b, 0x14, 0x3c, 0xe7, 0x62, 0xb3, 0x67, 0x76, 0x2f, 0x78, 0xa2, 0xc8, 0xba, 0x30, 0x1f, - 0xf3, 0xa4, 0xcf, 0xd5, 0xf2, 0xef, 0x5e, 0xf0, 0x14, 0x70, 0x77, 0x1e, 0x66, 0x47, 0xf8, 0xb1, - 0xfb, 0xbd, 0x1a, 0x34, 0x0f, 0x78, 0xa8, 0x99, 0x88, 0x41, 0x1d, 0xa7, 0x24, 0x19, 0x87, 0x7e, - 0xb3, 0x37, 0xa1, 0x49, 0xd3, 0x4c, 0xb3, 0x24, 0x08, 0x87, 0xd4, 0x58, 0xc3, 0x03, 0x84, 0x0e, - 0x08, 0x61, 0x6d, 0x98, 0xf1, 0xc7, 0x19, 0xed, 0xe0, 0x8c, 0x87, 0x3f, 0x91, 0xc1, 0x62, 0x7f, - 0x3a, 0x46, 0x5e, 0xd4, 0xbb, 0xd6, 0xf2, 0x9a, 0x12, 0xdb, 0xc5, 0x6d, 0xbb, 0x09, 0xab, 0x26, - 0x89, 0x6a, 0x7d, 0x96, 0x5a, 0x5f, 0x31, 0x28, 0x65, 0x27, 0xd7, 0x61, 0x59, 0xd1, 0x27, 0x62, - 0xb0, 0xb4, 0x8f, 0x0d, 0x6f, 0x49, 0xc2, 0x6a, 0x0a, 0x37, 0xa0, 0x7d, 0x14, 0x84, 0xfe, 0xa8, - 0xd7, 0x1f, 0x65, 0x27, 0xbd, 0x01, 0x1f, 0x65, 0x3e, 0xed, 0xe8, 0xac, 0xb7, 0x44, 0xf8, 0xd6, - 0x28, 0x3b, 0xd9, 0x46, 0x94, 0xbd, 0x03, 0x8d, 0x23, 0xce, 0x7b, 0xb4, 0x12, 0x9d, 0x85, 0xab, - 0xce, 0x8d, 0xe6, 0xe6, 0xb2, 0x5c, 0x7a, 0xb5, 0xba, 0xde, 0xc2, 0x91, 0xfc, 0xe5, 0xfe, 0x91, - 0x03, 0x2d, 0xb1, 0x54, 0x52, 0x85, 0x5e, 0x83, 0x45, 0x35, 0x22, 0x9e, 0x24, 0x51, 0x22, 0xd9, - 0xdf, 0x06, 0xd9, 0x06, 0xb4, 0x15, 0x10, 0x27, 0x3c, 0x18, 0xfb, 0x43, 0x2e, 0xe5, 0xad, 0x84, - 0xb3, 0xcd, 0xbc, 0xc5, 0x24, 0x9a, 0x64, 0x42, 0x89, 0x35, 0x37, 0x5b, 0x72, 0x50, 0x1e, 0x62, - 0x9e, 0x4d, 0xe2, 0x7e, 0xdb, 0x01, 0x86, 0xc3, 0x7a, 0x1c, 0x89, 0x6a, 0xb9, 0x0a, 0xc5, 0x1d, - 0x70, 0x5e, 0x79, 0x07, 0x6a, 0x67, 0xed, 0xc0, 0x35, 0x98, 0xa3, 0x2e, 0x51, 0x56, 0x67, 0x4a, - 0xc3, 0x92, 0x75, 0xee, 0x77, 0x1d, 0x68, 0xa1, 0xe6, 0x08, 0xf9, 0x68, 0x3f, 0x0a, 0xc2, 0x8c, - 0xdd, 0x06, 0x76, 0x34, 0x09, 0x07, 0x41, 0x38, 0xec, 0x65, 0xcf, 0x83, 0x41, 0xef, 0x70, 0x8a, - 0x4d, 0xd0, 0x78, 0x76, 0x2f, 0x78, 0x15, 0x75, 0xec, 0x1d, 0x68, 0x5b, 0x68, 0x9a, 0x25, 0x62, - 0x54, 0xbb, 0x17, 0xbc, 0x52, 0x0d, 0xca, 0x7f, 0x34, 0xc9, 0xe2, 0x49, 0xd6, 0x0b, 0xc2, 0x01, - 0x7f, 0x4e, 0x6b, 0xb6, 0xe8, 0x59, 0xd8, 0xdd, 0x25, 0x68, 0x99, 0xdf, 0xb9, 0x9f, 0x83, 0xf6, - 0x1e, 0x2a, 0x86, 0x30, 0x08, 0x87, 0x77, 0x84, 0xf4, 0xa2, 0xb6, 0x8a, 0x27, 0x87, 0xcf, 0xf8, - 0x54, 0xee, 0xa3, 0x2c, 0xa1, 0x48, 0x1c, 0x47, 0x69, 0x26, 0xd7, 0x85, 0x7e, 0xbb, 0xff, 0xec, - 0xc0, 0x32, 0x2e, 0xfa, 0x47, 0x7e, 0x38, 0x55, 0x2b, 0xbe, 0x07, 0x2d, 0x6c, 0xea, 0x71, 0x74, - 0x47, 0xe8, 0x3c, 0x21, 0xcb, 0x37, 0xe4, 0x22, 0x15, 0xa8, 0x6f, 0x9a, 0xa4, 0x68, 0xa6, 0xa7, - 0x9e, 0xf5, 0x35, 0x0a, 0x5d, 0xe6, 0x27, 0x43, 0x9e, 0x91, 0x36, 0x94, 0xda, 0x11, 0x04, 0xb4, - 0x15, 0x85, 0x47, 0xec, 0x2a, 0xb4, 0x52, 0x3f, 0xeb, 0xc5, 0x3c, 0xa1, 0x55, 0x23, 0xc1, 0x99, - 0xf1, 0x20, 0xf5, 0xb3, 0x7d, 0x9e, 0xdc, 0x9d, 0x66, 0xbc, 0xfb, 0x79, 0x58, 0x29, 0xf5, 0x82, - 0xb2, 0x9a, 0x4f, 0x11, 0x7f, 0xb2, 0x35, 0x98, 0x3d, 0xf1, 0x47, 0x13, 0x2e, 0x95, 0xb4, 0x28, - 0x7c, 0x50, 0x7b, 0xdf, 0x71, 0xdf, 0x86, 0x76, 0x3e, 0x6c, 0xc9, 0xf4, 0x0c, 0xea, 0xb8, 0x82, - 0xb2, 0x01, 0xfa, 0xed, 0xfe, 0xa6, 0x23, 0x08, 0xb7, 0xa2, 0x40, 0x2b, 0x3c, 0x24, 0x44, 0xbd, - 0xa8, 0x08, 0xf1, 0xf7, 0x99, 0x06, 0xe1, 0xa7, 0x9f, 0xac, 0x7b, 0x1d, 0x56, 0x8c, 0x21, 0xbc, - 0x64, 0xb0, 0xdf, 0x76, 0x60, 0xe5, 0x21, 0x3f, 0x95, 0xbb, 0xae, 0x46, 0xfb, 0x3e, 0xd4, 0xb3, - 0x69, 0x2c, 0x9c, 0xac, 0xa5, 0xcd, 0x6b, 0x72, 0xd3, 0x4a, 0x74, 0x37, 0x65, 0xf1, 0xf1, 0x34, - 0xe6, 0x1e, 0x7d, 0xe1, 0x7e, 0x0e, 0x9a, 0x06, 0xc8, 0x2e, 0xc1, 0xea, 0xd3, 0x07, 0x8f, 0x1f, - 0xee, 0x1c, 0x1c, 0xf4, 0xf6, 0x9f, 0xdc, 0xfd, 0xe2, 0xce, 0xaf, 0xf6, 0x76, 0xef, 0x1c, 0xec, - 0xb6, 0x2f, 0xb0, 0x75, 0x60, 0x0f, 0x77, 0x0e, 0x1e, 0xef, 0x6c, 0x5b, 0xb8, 0xe3, 0x76, 0xa1, - 0xf3, 0x90, 0x9f, 0x3e, 0x0d, 0xb2, 0x90, 0xa7, 0xa9, 0xdd, 0x9b, 0x7b, 0x13, 0x98, 0x39, 0x04, - 0x39, 0xab, 0x0e, 0xcc, 0x4b, 0x8b, 0xa3, 0x0c, 0xae, 0x2c, 0xba, 0x6f, 0x03, 0x3b, 0x08, 0x86, - 0xe1, 0x47, 0x3c, 0x4d, 0xfd, 0xa1, 0x56, 0x05, 0x6d, 0x98, 0x19, 0xa7, 0x43, 0xa9, 0x01, 0xf0, - 0xa7, 0xfb, 0x29, 0x58, 0xb5, 0xe8, 0x64, 0xc3, 0xaf, 0x43, 0x23, 0x0d, 0x86, 0xa1, 0x9f, 0x4d, - 0x12, 0x2e, 0x9b, 0xce, 0x01, 0xf7, 0x1e, 0xac, 0x7d, 0x99, 0x27, 0xc1, 0xd1, 0xf4, 0xbc, 0xe6, - 0xed, 0x76, 0x6a, 0xc5, 0x76, 0x76, 0xe0, 0x62, 0xa1, 0x1d, 0xd9, 0xbd, 0x60, 0x44, 0xb9, 0x5d, - 0x0b, 0x9e, 0x28, 0x18, 0x62, 0x59, 0x33, 0xc5, 0xd2, 0x7d, 0x02, 0x6c, 0x2b, 0x0a, 0x43, 0xde, - 0xcf, 0xf6, 0x39, 0x4f, 0x72, 0xcf, 0x39, 0xe7, 0xba, 0xe6, 0xe6, 0x25, 0xb9, 0x8f, 0x45, 0x59, - 0x97, 0xec, 0xc8, 0xa0, 0x1e, 0xf3, 0x64, 0x4c, 0x0d, 0x2f, 0x78, 0xf4, 0xdb, 0xbd, 0x08, 0xab, - 0x56, 0xb3, 0xd2, 0xe9, 0x79, 0x17, 0x2e, 0x6e, 0x07, 0x69, 0xbf, 0xdc, 0x61, 0x07, 0xe6, 0xe3, - 0xc9, 0x61, 0x2f, 0x97, 0x29, 0x55, 0x44, 0x5f, 0xa0, 0xf8, 0x89, 0x6c, 0xec, 0x77, 0x1d, 0xa8, - 0xef, 0x3e, 0xde, 0xdb, 0x62, 0x5d, 0x58, 0x08, 0xc2, 0x7e, 0x34, 0x46, 0xb5, 0x2b, 0x26, 0xad, - 0xcb, 0x67, 0xca, 0xca, 0xeb, 0xd0, 0x20, 0x6d, 0x8d, 0xee, 0x8d, 0x74, 0x72, 0x73, 0x00, 0x5d, - 0x2b, 0xfe, 0x3c, 0x0e, 0x12, 0xf2, 0x9d, 0x94, 0x47, 0x54, 0x27, 0x8d, 0x58, 0xae, 0x70, 0xff, - 0xa7, 0x0e, 0xf3, 0x52, 0x57, 0x53, 0x7f, 0xfd, 0x2c, 0x38, 0xe1, 0x72, 0x24, 0xb2, 0x84, 0x56, - 0x2e, 0xe1, 0xe3, 0x28, 0xe3, 0x3d, 0x6b, 0x1b, 0x6c, 0x10, 0xa9, 0xfa, 0xa2, 0xa1, 0x5e, 0x8c, - 0x5a, 0x9f, 0x46, 0xd6, 0xf0, 0x6c, 0x10, 0x17, 0x0b, 0x81, 0x5e, 0x30, 0xa0, 0x31, 0xd5, 0x3d, - 0x55, 0xc4, 0x95, 0xe8, 0xfb, 0xb1, 0xdf, 0x0f, 0xb2, 0xa9, 0x14, 0x6e, 0x5d, 0xc6, 0xb6, 0x47, - 0x51, 0xdf, 0x1f, 0xf5, 0x0e, 0xfd, 0x91, 0x1f, 0xf6, 0xb9, 0xf4, 0xdf, 0x6c, 0x10, 0x5d, 0x34, - 0x39, 0x24, 0x45, 0x26, 0xdc, 0xb8, 0x02, 0x8a, 0xae, 0x5e, 0x3f, 0x1a, 0x8f, 0x83, 0x0c, 0x3d, - 0x3b, 0xb2, 0xfa, 0x33, 0x9e, 0x81, 0xd0, 0x4c, 0x44, 0xe9, 0x54, 0xac, 0x5e, 0x43, 0xf4, 0x66, - 0x81, 0xd8, 0x0a, 0xba, 0x0e, 0xa8, 0x90, 0x9e, 0x9d, 0x76, 0x40, 0xb4, 0x92, 0x23, 0xb8, 0x0f, - 0x93, 0x30, 0xe5, 0x59, 0x36, 0xe2, 0x03, 0x3d, 0xa0, 0x26, 0x91, 0x95, 0x2b, 0xd8, 0x6d, 0x58, - 0x15, 0xce, 0x66, 0xea, 0x67, 0x51, 0x7a, 0x1c, 0xa4, 0xbd, 0x14, 0xdd, 0xb6, 0x16, 0xd1, 0x57, - 0x55, 0xb1, 0xf7, 0xe1, 0x52, 0x01, 0x4e, 0x78, 0x9f, 0x07, 0x27, 0x7c, 0xd0, 0x59, 0xa4, 0xaf, - 0xce, 0xaa, 0x66, 0x57, 0xa1, 0x89, 0x3e, 0xf6, 0x24, 0x1e, 0xf8, 0x68, 0x87, 0x97, 0x68, 0x1f, - 0x4c, 0x88, 0xbd, 0x0b, 0x8b, 0x31, 0x17, 0xc6, 0xf2, 0x38, 0x1b, 0xf5, 0xd3, 0xce, 0x32, 0x59, - 0xb2, 0xa6, 0x14, 0x26, 0xe4, 0x5c, 0xcf, 0xa6, 0x40, 0xa6, 0xec, 0xa7, 0xe4, 0x6c, 0xf9, 0xd3, - 0x4e, 0x9b, 0xd8, 0x2d, 0x07, 0x48, 0x46, 0x92, 0xe0, 0xc4, 0xcf, 0x78, 0x67, 0x85, 0x78, 0x4b, - 0x15, 0xdd, 0x3f, 0x75, 0x60, 0x75, 0x2f, 0x48, 0x33, 0xc9, 0x84, 0x5a, 0x1d, 0xbf, 0x09, 0x4d, - 0xc1, 0x7e, 0xbd, 0x28, 0x1c, 0x4d, 0x25, 0x47, 0x82, 0x80, 0x1e, 0x85, 0xa3, 0x29, 0xfb, 0x04, - 0x2c, 0x06, 0xa1, 0x49, 0x22, 0x64, 0xb8, 0xa5, 0x40, 0x22, 0x7a, 0x13, 0x9a, 0xf1, 0xe4, 0x70, - 0x14, 0xf4, 0x05, 0xc9, 0x8c, 0x68, 0x45, 0x40, 0x44, 0x80, 0x4e, 0x92, 0x18, 0x89, 0xa0, 0xa8, - 0x13, 0x45, 0x53, 0x62, 0x48, 0xe2, 0xde, 0x85, 0x35, 0x7b, 0x80, 0x52, 0x59, 0x6d, 0xc0, 0x82, - 0xe4, 0xed, 0xb4, 0xd3, 0xa4, 0xf5, 0x59, 0x92, 0xeb, 0x23, 0x49, 0x3d, 0x5d, 0xef, 0xfe, 0x79, - 0x1d, 0x56, 0x25, 0xba, 0x35, 0x8a, 0x52, 0x7e, 0x30, 0x19, 0x8f, 0xfd, 0xa4, 0x42, 0x68, 0x9c, - 0x73, 0x84, 0xa6, 0x66, 0x0b, 0x0d, 0xb2, 0xf2, 0xb1, 0x1f, 0x84, 0xc2, 0xc3, 0x13, 0x12, 0x67, - 0x20, 0xec, 0x06, 0x2c, 0xf7, 0x47, 0x51, 0x2a, 0xbc, 0x1e, 0xf3, 0xf8, 0x54, 0x84, 0xcb, 0x42, - 0x3e, 0x5b, 0x25, 0xe4, 0xa6, 0x90, 0xce, 0x15, 0x84, 0xd4, 0x85, 0x16, 0x36, 0xca, 0x95, 0xce, - 0x99, 0x17, 0x5e, 0x98, 0x89, 0xe1, 0x78, 0x8a, 0x22, 0x21, 0xe4, 0x6f, 0xb9, 0x4a, 0x20, 0xf0, - 0x74, 0x86, 0x3a, 0xcd, 0xa0, 0x6e, 0x48, 0x81, 0x28, 0x57, 0xb1, 0x7b, 0x00, 0xa2, 0x2f, 0x32, - 0xe3, 0x40, 0x66, 0xfc, 0x6d, 0x7b, 0x47, 0xcc, 0xb5, 0xbf, 0x89, 0x85, 0x49, 0xc2, 0xc9, 0x90, - 0x1b, 0x5f, 0xba, 0x1f, 0x43, 0xd3, 0xa8, 0x62, 0x17, 0x61, 0x65, 0xeb, 0xd1, 0xa3, 0xfd, 0x1d, - 0xef, 0xce, 0xe3, 0x07, 0x5f, 0xde, 0xe9, 0x6d, 0xed, 0x3d, 0x3a, 0xd8, 0x69, 0x5f, 0x40, 0x78, - 0xef, 0xd1, 0xd6, 0x9d, 0xbd, 0xde, 0xbd, 0x47, 0xde, 0x96, 0x82, 0x1d, 0xb4, 0xf1, 0xde, 0xce, - 0x47, 0x8f, 0x1e, 0xef, 0x58, 0x78, 0x8d, 0xb5, 0xa1, 0x75, 0xd7, 0xdb, 0xb9, 0xb3, 0xb5, 0x2b, - 0x91, 0x19, 0xb6, 0x06, 0xed, 0x7b, 0x4f, 0x1e, 0x6e, 0x3f, 0x78, 0x78, 0xbf, 0xb7, 0x75, 0xe7, - 0xe1, 0xd6, 0xce, 0xde, 0xce, 0x76, 0xbb, 0xee, 0xfe, 0xad, 0x03, 0x17, 0x69, 0x94, 0x83, 0xa2, - 0x40, 0x5c, 0x85, 0x66, 0x3f, 0x8a, 0x62, 0x8e, 0xfa, 0x5b, 0xab, 0x68, 0x13, 0x42, 0x66, 0x17, - 0x0a, 0xf1, 0x28, 0x4a, 0xfa, 0x5c, 0xca, 0x03, 0x10, 0x74, 0x0f, 0x11, 0x64, 0x76, 0xb9, 0x9d, - 0x82, 0x42, 0x88, 0x43, 0x53, 0x60, 0x82, 0x64, 0x1d, 0xe6, 0x0e, 0x13, 0xee, 0xf7, 0x8f, 0xa5, - 0x24, 0xc8, 0x12, 0xfb, 0x64, 0xee, 0x90, 0xf7, 0x71, 0xb5, 0x47, 0x7c, 0x40, 0x1c, 0xb2, 0xe0, - 0x2d, 0x4b, 0x7c, 0x4b, 0xc2, 0xee, 0x3e, 0xac, 0x17, 0x67, 0x20, 0x25, 0xe6, 0x3d, 0x43, 0x62, - 0x84, 0x6f, 0xdc, 0x3d, 0x7b, 0x7f, 0x0c, 0xe9, 0xf9, 0x77, 0x07, 0xea, 0x68, 0x3e, 0xcf, 0x36, - 0xb5, 0xa6, 0x47, 0x34, 0x63, 0x79, 0x44, 0x14, 0x3c, 0xc0, 0x33, 0x85, 0x50, 0xa8, 0xc2, 0xe8, - 0x18, 0x48, 0x5e, 0x9f, 0xf0, 0xfe, 0x09, 0xcd, 0x49, 0xd7, 0x23, 0x82, 0x2c, 0x8f, 0x8e, 0x27, - 0x7d, 0x2d, 0x59, 0x5e, 0x95, 0x55, 0x1d, 0x7d, 0x39, 0x9f, 0xd7, 0xd1, 0x77, 0x1d, 0x98, 0x0f, - 0xc2, 0xc3, 0x68, 0x12, 0x0e, 0x88, 0xc5, 0x17, 0x3c, 0x55, 0x44, 0x55, 0x19, 0x93, 0xe8, 0x05, - 0x63, 0xc5, 0xd0, 0x39, 0xe0, 0x32, 0x3c, 0x98, 0xa4, 0xe4, 0x2e, 0x68, 0x2f, 0xf0, 0x3d, 0x58, - 0x31, 0x30, 0xb9, 0x9a, 0x6f, 0xc1, 0x6c, 0x8c, 0x80, 0x5c, 0x4a, 0xa5, 0x9c, 0xc9, 0xcf, 0x10, - 0x35, 0x6e, 0x1b, 0x96, 0xee, 0xf3, 0xec, 0x41, 0x78, 0x14, 0xa9, 0x96, 0x7e, 0x34, 0x03, 0xcb, - 0x1a, 0x92, 0x0d, 0xdd, 0x80, 0xe5, 0x60, 0xc0, 0xc3, 0x2c, 0xc8, 0xa6, 0x3d, 0xeb, 0xfc, 0x53, - 0x84, 0xd1, 0x3f, 0xf3, 0x47, 0x81, 0x9f, 0x4a, 0x0f, 0x40, 0x14, 0xd8, 0x26, 0xac, 0xa1, 0xf1, - 0x50, 0xf6, 0x40, 0x6f, 0xb1, 0x38, 0x86, 0x55, 0xd6, 0xa1, 0x78, 0x23, 0x2e, 0xf5, 0xb7, 0xfe, - 0x44, 0xf8, 0x29, 0x55, 0x55, 0xb8, 0x6a, 0xa2, 0x25, 0x9c, 0xf2, 0xac, 0x30, 0x30, 0x1a, 0x28, - 0x85, 0x80, 0xe6, 0x84, 0xf2, 0x29, 0x86, 0x80, 0x8c, 0x30, 0xd2, 0x42, 0x29, 0x8c, 0x84, 0xca, - 0x69, 0x1a, 0xf6, 0xf9, 0xa0, 0x97, 0x45, 0x3d, 0x52, 0xa2, 0xb4, 0x3b, 0x0b, 0x5e, 0x11, 0xa6, - 0x80, 0x17, 0x4f, 0xb3, 0x90, 0x67, 0xa4, 0x67, 0x16, 0x3c, 0x55, 0x44, 0xf9, 0x21, 0x12, 0x61, - 0x12, 0x1a, 0x9e, 0x2c, 0xa1, 0xa3, 0x39, 0x49, 0x82, 0xb4, 0xd3, 0x22, 0x94, 0x7e, 0xb3, 0x4f, - 0xc3, 0xc5, 0x43, 0x9e, 0x66, 0xbd, 0x63, 0xee, 0x0f, 0x78, 0x42, 0xbb, 0x2f, 0xa2, 0x53, 0xc2, - 0x7e, 0x57, 0x57, 0x62, 0xdf, 0x27, 0x3c, 0x49, 0x83, 0x28, 0x24, 0xcb, 0xdd, 0xf0, 0x54, 0xd1, - 0xfd, 0x26, 0xf9, 0xc3, 0x3a, 0x6e, 0xf6, 0x84, 0x8c, 0x39, 0x7b, 0x0d, 0x1a, 0x62, 0x8e, 0xe9, - 0xb1, 0x2f, 0x5d, 0xf4, 0x05, 0x02, 0x0e, 0x8e, 0x7d, 0xd4, 0x08, 0xd6, 0xb2, 0x89, 0x40, 0x64, - 0x93, 0xb0, 0x5d, 0xb1, 0x6a, 0xd7, 0x60, 0x49, 0x45, 0xe4, 0xd2, 0xde, 0x88, 0x1f, 0x65, 0xea, - 0x78, 0x1d, 0x4e, 0xc6, 0xd8, 0x5d, 0xba, 0xc7, 0x8f, 0x32, 0xf7, 0x21, 0xac, 0x48, 0x19, 0x7e, - 0x14, 0x73, 0xd5, 0xf5, 0x67, 0xab, 0xac, 0x5b, 0x73, 0x73, 0xd5, 0x16, 0x7a, 0x8a, 0x11, 0x14, - 0x4c, 0x9e, 0xeb, 0x01, 0x33, 0x75, 0x82, 0x6c, 0x50, 0x9a, 0x18, 0x75, 0x88, 0x97, 0xd3, 0xb1, - 0x30, 0x5c, 0x9f, 0x74, 0xd2, 0xef, 0xa3, 0x26, 0x10, 0x1a, 0x50, 0x15, 0xdd, 0xef, 0x39, 0xb0, - 0x4a, 0xad, 0x29, 0xfb, 0xac, 0x4f, 0x7e, 0xaf, 0x3e, 0xcc, 0x56, 0xdf, 0x0c, 0x6c, 0xac, 0xc1, - 0xac, 0xa9, 0x6b, 0x45, 0xe1, 0xc7, 0x3f, 0xcb, 0xd6, 0x4b, 0x67, 0xd9, 0x1f, 0x39, 0xb0, 0x22, - 0x94, 0x61, 0xe6, 0x67, 0x93, 0x54, 0x4e, 0xff, 0x17, 0x61, 0x51, 0xd8, 0x29, 0x29, 0x4e, 0x72, - 0xa0, 0x6b, 0x5a, 0xf2, 0x09, 0x15, 0xc4, 0xbb, 0x17, 0x3c, 0x9b, 0x98, 0x7d, 0x1e, 0x5a, 0x66, - 0x58, 0x95, 0xc6, 0xdc, 0xdc, 0xbc, 0xac, 0x66, 0x59, 0xe2, 0x9c, 0xdd, 0x0b, 0x9e, 0xf5, 0x01, - 0xfb, 0x90, 0x9c, 0x8d, 0xb0, 0x47, 0xcd, 0xca, 0xc0, 0xd4, 0xe5, 0x0a, 0x05, 0xae, 0x3f, 0x37, - 0xc8, 0xef, 0x2e, 0xc0, 0x9c, 0xf0, 0x2e, 0xdd, 0xfb, 0xb0, 0x68, 0x8d, 0xd4, 0x3a, 0xa3, 0xb7, - 0xc4, 0x19, 0xbd, 0x14, 0xd2, 0xa9, 0x95, 0x43, 0x3a, 0xee, 0xbf, 0xd6, 0x80, 0x21, 0xb7, 0x15, - 0xb6, 0x13, 0xdd, 0xdb, 0x68, 0x60, 0x1d, 0x56, 0x5a, 0x9e, 0x09, 0xb1, 0x9b, 0xc0, 0x8c, 0xa2, - 0x8a, 0x7a, 0x09, 0xbb, 0x51, 0x51, 0x83, 0x0a, 0x4e, 0x1a, 0x56, 0x69, 0x02, 0xe5, 0xb1, 0x4c, - 0xec, 0x5b, 0x65, 0x1d, 0x9a, 0x86, 0x78, 0x92, 0x1e, 0xa3, 0xfb, 0xad, 0x8e, 0x33, 0xaa, 0x5c, - 0x64, 0x90, 0xb9, 0x73, 0x19, 0x64, 0xbe, 0xc8, 0x20, 0xa6, 0x43, 0xbd, 0x60, 0x39, 0xd4, 0xe8, - 0xc8, 0x8d, 0xd1, 0xfd, 0xcb, 0x46, 0xfd, 0xde, 0x18, 0x7b, 0x97, 0xa7, 0x17, 0x0b, 0x64, 0x1b, - 0xd0, 0x96, 0xae, 0x40, 0xee, 0xb5, 0x03, 0xad, 0x71, 0x09, 0x77, 0x7f, 0xe8, 0x40, 0x1b, 0xd7, - 0xd9, 0xe2, 0xc5, 0x0f, 0x80, 0x44, 0xe1, 0x15, 0x59, 0xd1, 0xa2, 0xfd, 0xe9, 0x39, 0xf1, 0x7d, - 0x68, 0x50, 0x83, 0x51, 0xcc, 0x43, 0xc9, 0x88, 0x1d, 0x9b, 0x11, 0x73, 0x2d, 0xb4, 0x7b, 0xc1, - 0xcb, 0x89, 0x0d, 0x36, 0xfc, 0x47, 0x07, 0x9a, 0x72, 0x98, 0x3f, 0xf1, 0x49, 0xbc, 0x0b, 0x0b, - 0xc8, 0x91, 0xc6, 0x71, 0x57, 0x97, 0xd1, 0x9a, 0x8c, 0xfd, 0x6c, 0x92, 0xa0, 0xf9, 0xb4, 0x4e, - 0xe1, 0x45, 0x18, 0x6d, 0x21, 0x29, 0xdc, 0xb4, 0x97, 0x05, 0xa3, 0x9e, 0xaa, 0x95, 0xb7, 0x18, - 0x55, 0x55, 0xa8, 0x77, 0xd2, 0xcc, 0x1f, 0x72, 0x69, 0xe6, 0x44, 0xc1, 0xed, 0xc0, 0xba, 0x9c, - 0x50, 0xc1, 0x77, 0x74, 0xff, 0xa6, 0x05, 0x97, 0x4a, 0x55, 0xfa, 0x1a, 0x50, 0x1e, 0x2f, 0x47, - 0xc1, 0xf8, 0x30, 0xd2, 0x8e, 0xb6, 0x63, 0x9e, 0x3c, 0xad, 0x2a, 0x36, 0x84, 0x8b, 0xca, 0x9e, - 0xe3, 0x9a, 0xe6, 0xd6, 0xbb, 0x46, 0x8e, 0xc8, 0xbb, 0x36, 0x0f, 0x14, 0x3b, 0x54, 0xb8, 0x29, - 0xb9, 0xd5, 0xed, 0xb1, 0x63, 0xe8, 0x68, 0xc7, 0x41, 0xaa, 0x78, 0xc3, 0xb9, 0xc0, 0xbe, 0xde, - 0x39, 0xa7, 0x2f, 0xcb, 0x11, 0xf5, 0xce, 0x6c, 0x8d, 0x4d, 0xe1, 0x8a, 0xaa, 0x23, 0x1d, 0x5e, - 0xee, 0xaf, 0xfe, 0x4a, 0x73, 0x23, 0x27, 0xda, 0xee, 0xf4, 0x9c, 0x86, 0xd9, 0xd7, 0x61, 0xfd, - 0xd4, 0x0f, 0x32, 0x35, 0x2c, 0xc3, 0x19, 0x9a, 0xa5, 0x2e, 0x37, 0xcf, 0xe9, 0xf2, 0xa9, 0xf8, - 0xd8, 0x32, 0x6c, 0x67, 0xb4, 0xd8, 0xfd, 0x7b, 0x07, 0x96, 0xec, 0x76, 0x90, 0x4d, 0xa5, 0xc0, - 0x2b, 0xc5, 0xa7, 0x9c, 0xbf, 0x02, 0x5c, 0x3e, 0xab, 0xd6, 0xaa, 0xce, 0xaa, 0xe6, 0x09, 0x71, - 0xe6, 0xbc, 0x30, 0x4e, 0xfd, 0xd5, 0xc2, 0x38, 0xb3, 0x55, 0x61, 0x9c, 0xee, 0x7f, 0x3b, 0xc0, - 0xca, 0xbc, 0xc4, 0xee, 0x8b, 0xc3, 0x72, 0xc8, 0x47, 0x52, 0x27, 0xfd, 0xfc, 0xab, 0xf1, 0xa3, - 0x5a, 0x3b, 0xf5, 0x35, 0x0a, 0x86, 0xa9, 0x74, 0x4c, 0x17, 0x69, 0xd1, 0xab, 0xaa, 0x2a, 0x04, - 0x96, 0xea, 0xe7, 0x07, 0x96, 0x66, 0xcf, 0x0f, 0x2c, 0xcd, 0x15, 0x03, 0x4b, 0xdd, 0xdf, 0x71, - 0x60, 0xb5, 0x62, 0xd3, 0x7f, 0x76, 0x13, 0xc7, 0x6d, 0xb2, 0x74, 0x41, 0x4d, 0x6e, 0x93, 0x09, - 0x76, 0x7f, 0x03, 0x16, 0x2d, 0x46, 0xff, 0xd9, 0xf5, 0x5f, 0xf4, 0xf2, 0x04, 0x9f, 0x59, 0x58, - 0xf7, 0x3f, 0x6a, 0xc0, 0xca, 0xc2, 0xf6, 0xff, 0x3a, 0x86, 0xf2, 0x3a, 0xcd, 0x54, 0xac, 0xd3, - 0xff, 0xa9, 0x1d, 0x78, 0x07, 0x56, 0x64, 0xce, 0x80, 0x11, 0x22, 0x11, 0x1c, 0x53, 0xae, 0x40, - 0x3f, 0xd7, 0x8e, 0xea, 0x2d, 0x58, 0x77, 0xcd, 0x86, 0x31, 0x2c, 0x04, 0xf7, 0xdc, 0x75, 0x58, - 0x13, 0x39, 0x08, 0x77, 0x45, 0x53, 0xca, 0xae, 0xfc, 0x89, 0x03, 0x17, 0x0b, 0x15, 0xf9, 0xcd, - 0xa8, 0x30, 0x1d, 0xb6, 0x3d, 0xb1, 0x41, 0x1c, 0xbf, 0x94, 0x23, 0x63, 0xfc, 0x82, 0xdb, 0xca, - 0x15, 0xb8, 0x3e, 0x93, 0xb0, 0x4c, 0x2f, 0x56, 0xbd, 0xaa, 0xca, 0xbd, 0x24, 0x32, 0x25, 0x42, - 0x3e, 0x2a, 0x0c, 0xfc, 0x48, 0xe4, 0x36, 0x98, 0x15, 0xf9, 0xd5, 0x8a, 0x3d, 0x64, 0x55, 0x44, - 0x2f, 0xd0, 0x32, 0x53, 0xf6, 0x78, 0x2b, 0xeb, 0xdc, 0xbf, 0x72, 0x80, 0x7d, 0x69, 0xc2, 0x93, - 0x29, 0xdd, 0x90, 0xea, 0x58, 0xce, 0xa5, 0x62, 0x1c, 0x63, 0x2e, 0x9e, 0x1c, 0x7e, 0x91, 0x4f, - 0xd5, 0x3d, 0x7a, 0x2d, 0xbf, 0x47, 0x7f, 0x03, 0x00, 0x8f, 0x5f, 0xfa, 0xda, 0x15, 0x79, 0x01, - 0xcf, 0xbd, 0xa2, 0xc1, 0xca, 0xab, 0xee, 0xfa, 0xf9, 0x57, 0xdd, 0xb3, 0xe7, 0x5d, 0x75, 0x7f, - 0x08, 0xab, 0xd6, 0xb8, 0xf5, 0xb6, 0xaa, 0x0b, 0x60, 0xe7, 0x25, 0x17, 0xc0, 0xff, 0xe9, 0xc0, - 0xcc, 0x6e, 0x14, 0x9b, 0x71, 0x4b, 0xc7, 0x8e, 0x5b, 0x4a, 0x5b, 0xd2, 0xd3, 0xa6, 0x42, 0xaa, - 0x18, 0x0b, 0x64, 0x1b, 0xb0, 0xe4, 0x8f, 0x33, 0x3c, 0x76, 0x1f, 0x45, 0xc9, 0xa9, 0x9f, 0x0c, - 0xc4, 0x5e, 0xdf, 0xad, 0x75, 0x1c, 0xaf, 0x50, 0xc3, 0xd6, 0x60, 0x46, 0x2b, 0x5d, 0x22, 0xc0, - 0x22, 0x3a, 0x6e, 0x74, 0xe7, 0x31, 0x95, 0x11, 0x03, 0x59, 0x42, 0x56, 0xb2, 0xbf, 0x17, 0xae, - 0xb2, 0x10, 0x9d, 0xaa, 0x2a, 0xb4, 0x6b, 0xb8, 0x7c, 0x44, 0x26, 0x43, 0x3d, 0xaa, 0xec, 0xfe, - 0x9b, 0x03, 0xb3, 0xb4, 0x02, 0x28, 0xec, 0x82, 0xc3, 0x75, 0x80, 0x92, 0x66, 0xbe, 0xe8, 0x15, - 0x61, 0xe6, 0x5a, 0xf9, 0x26, 0x35, 0x3d, 0x6c, 0x33, 0xe7, 0xe4, 0x2a, 0x34, 0x44, 0x49, 0xe7, - 0x56, 0x10, 0x49, 0x0e, 0xb2, 0x2b, 0x50, 0x3f, 0x8e, 0x62, 0xe5, 0x9d, 0x80, 0x8a, 0xcf, 0x47, - 0xb1, 0x47, 0x78, 0x3e, 0x1e, 0x6c, 0x4f, 0x0c, 0x5e, 0xd8, 0x9c, 0x22, 0x8c, 0x56, 0x57, 0x37, - 0x6b, 0x2e, 0x46, 0x01, 0x75, 0x37, 0x60, 0xf9, 0x61, 0x34, 0xe0, 0x46, 0x4c, 0xe9, 0x4c, 0x6e, - 0x76, 0xbf, 0xe5, 0xc0, 0x82, 0x22, 0x66, 0x37, 0xa0, 0x8e, 0xae, 0x44, 0xe1, 0xa0, 0xa0, 0xef, - 0xe5, 0x90, 0xce, 0x23, 0x0a, 0xd4, 0xbd, 0x14, 0x71, 0xc8, 0xdd, 0x4a, 0x15, 0x6f, 0xc8, 0xbd, - 0x26, 0x3d, 0xdc, 0x82, 0xb3, 0x51, 0x40, 0xdd, 0xbf, 0x70, 0x60, 0xd1, 0xea, 0x03, 0x8f, 0x87, - 0x23, 0x3f, 0xcd, 0xe4, 0x5d, 0x87, 0xdc, 0x1e, 0x13, 0x32, 0xa3, 0x8c, 0x35, 0x3b, 0xca, 0xa8, - 0xe3, 0x5f, 0x33, 0x66, 0xfc, 0xeb, 0x36, 0x34, 0xf2, 0xac, 0xa0, 0xba, 0xa5, 0x53, 0xb1, 0x47, - 0x75, 0xe3, 0x98, 0x13, 0x61, 0x3b, 0xfd, 0x68, 0x14, 0x25, 0x32, 0xc8, 0x2e, 0x0a, 0xee, 0x87, - 0xd0, 0x34, 0xe8, 0x71, 0x18, 0x21, 0xcf, 0x4e, 0xa3, 0xe4, 0x99, 0x0a, 0x76, 0xca, 0xa2, 0xbe, - 0x58, 0xaf, 0xe5, 0x17, 0xeb, 0xee, 0x0f, 0x1c, 0x58, 0x44, 0x1e, 0x0c, 0xc2, 0xe1, 0x7e, 0x34, - 0x0a, 0xfa, 0x53, 0xda, 0x7b, 0xc5, 0x6e, 0x52, 0x33, 0x28, 0x5e, 0xb4, 0x61, 0xe4, 0x6d, 0x75, - 0x3a, 0x94, 0x82, 0xa8, 0xcb, 0x28, 0xa9, 0xc8, 0xe7, 0x87, 0x7e, 0x2a, 0x99, 0x5f, 0x1a, 0x39, - 0x0b, 0x44, 0x79, 0x42, 0x20, 0xf1, 0x33, 0xde, 0x1b, 0x07, 0xa3, 0x51, 0x20, 0x68, 0x85, 0x0b, - 0x54, 0x55, 0x85, 0x7d, 0x0e, 0x82, 0xd4, 0x3f, 0xcc, 0x03, 0xc9, 0xba, 0xec, 0x7e, 0xbf, 0x06, - 0x4d, 0xa9, 0x9e, 0x77, 0x06, 0x43, 0x2e, 0x6f, 0x39, 0xc8, 0xc9, 0xd4, 0xaa, 0xc4, 0x40, 0x54, - 0xbd, 0xe5, 0x96, 0x1a, 0x48, 0x71, 0xcb, 0x67, 0xca, 0x5b, 0xfe, 0x3a, 0x34, 0x90, 0xf5, 0xde, - 0x25, 0xff, 0x57, 0xdc, 0x90, 0xe4, 0x80, 0xaa, 0xdd, 0xa4, 0xda, 0xd9, 0xbc, 0x96, 0x80, 0x97, - 0xde, 0x89, 0xbc, 0x0f, 0x2d, 0xd9, 0x0c, 0xed, 0x09, 0x69, 0x8e, 0x9c, 0xf9, 0xad, 0xfd, 0xf2, - 0x2c, 0x4a, 0xf5, 0xe5, 0xa6, 0xfa, 0x72, 0xe1, 0xbc, 0x2f, 0x15, 0x25, 0xdd, 0x5f, 0x8b, 0xb5, - 0xb9, 0x9f, 0xf8, 0xf1, 0xb1, 0x32, 0x79, 0x03, 0x9d, 0x94, 0x43, 0x30, 0xdb, 0x80, 0x59, 0xfc, - 0x4c, 0x69, 0xf2, 0x6a, 0x81, 0x14, 0x24, 0xec, 0x06, 0xcc, 0xf2, 0xc1, 0x90, 0xab, 0x13, 0x1e, - 0xb3, 0xcf, 0xda, 0xb8, 0x47, 0x9e, 0x20, 0x40, 0xf5, 0x80, 0x68, 0x41, 0x3d, 0xd8, 0x56, 0x60, - 0x0e, 0x8b, 0x0f, 0x06, 0xee, 0x1a, 0xb0, 0x87, 0x82, 0xa3, 0xcd, 0x08, 0xf5, 0x6f, 0xcf, 0x40, - 0xd3, 0x80, 0x51, 0xd2, 0x87, 0x38, 0xe0, 0xde, 0x20, 0xf0, 0xc7, 0x3c, 0xe3, 0x89, 0xe4, 0xe2, - 0x02, 0x8a, 0x74, 0xfe, 0xc9, 0xb0, 0x17, 0x4d, 0xb2, 0xde, 0x80, 0x0f, 0x13, 0x2e, 0x0c, 0x33, - 0x1a, 0x0a, 0x0b, 0x45, 0xba, 0xb1, 0xff, 0xdc, 0xa4, 0x13, 0xfc, 0x50, 0x40, 0x55, 0xbc, 0x59, - 0xac, 0x51, 0x3d, 0x8f, 0x37, 0x8b, 0x15, 0x29, 0xea, 0xa8, 0xd9, 0x0a, 0x1d, 0xf5, 0x1e, 0xac, - 0x0b, 0x6d, 0x24, 0xe5, 0xb6, 0x57, 0x60, 0x93, 0x33, 0x6a, 0xd9, 0x06, 0xb4, 0x71, 0xcc, 0x8a, - 0xc1, 0xd3, 0xe0, 0x9b, 0x22, 0x02, 0xe4, 0x78, 0x25, 0x1c, 0x69, 0x51, 0x54, 0x2d, 0x5a, 0x71, - 0xa3, 0x56, 0xc2, 0x89, 0xd6, 0x7f, 0x6e, 0xd3, 0x36, 0x24, 0x6d, 0x01, 0x77, 0x17, 0xa1, 0x79, - 0x90, 0x45, 0xb1, 0xda, 0x94, 0x25, 0x68, 0x89, 0xa2, 0xcc, 0x5f, 0x78, 0x0d, 0x2e, 0x13, 0x17, - 0x3d, 0x8e, 0xe2, 0x68, 0x14, 0x0d, 0xa7, 0x07, 0x93, 0xc3, 0xb4, 0x9f, 0x04, 0x31, 0x9e, 0x86, - 0xdc, 0x7f, 0x70, 0x60, 0xd5, 0xaa, 0x95, 0x21, 0xa3, 0x4f, 0x0b, 0x96, 0xd6, 0x17, 0xcf, 0x82, - 0xf1, 0x56, 0x0c, 0x55, 0x29, 0x08, 0x45, 0xb0, 0xee, 0x89, 0xbc, 0x8b, 0xbe, 0x03, 0xcb, 0x6a, - 0x64, 0xea, 0x43, 0xc1, 0x85, 0x9d, 0x32, 0x17, 0xca, 0xef, 0x97, 0xe4, 0x07, 0xaa, 0x89, 0x5f, - 0x92, 0x37, 0x93, 0x03, 0x9a, 0xa3, 0x8a, 0x1d, 0xe8, 0xbb, 0x27, 0xf3, 0x04, 0xa1, 0x46, 0xd0, - 0xd7, 0x60, 0xea, 0xfe, 0x9e, 0x03, 0x90, 0x8f, 0x0e, 0x19, 0x23, 0x57, 0xf7, 0x22, 0x59, 0xda, - 0x50, 0xed, 0x6f, 0x41, 0x4b, 0xdf, 0x9a, 0xe4, 0x16, 0xa4, 0xa9, 0x30, 0x74, 0xf2, 0xae, 0xc3, - 0xf2, 0x70, 0x14, 0x1d, 0x92, 0xf9, 0xa5, 0x84, 0x98, 0x54, 0x66, 0x71, 0x2c, 0x09, 0xf8, 0x9e, - 0x44, 0x73, 0x73, 0x53, 0x37, 0xcc, 0x8d, 0xfb, 0xed, 0x9a, 0x8e, 0xb5, 0xe7, 0x73, 0x3e, 0x53, - 0xca, 0xd8, 0x66, 0x49, 0x39, 0x9e, 0x11, 0xda, 0xa6, 0x28, 0xd9, 0xfe, 0xb9, 0x87, 0xf8, 0x0f, - 0x61, 0x29, 0x11, 0xda, 0x47, 0xa9, 0xa6, 0xfa, 0x4b, 0x54, 0xd3, 0x62, 0x62, 0xd9, 0xa4, 0x4f, - 0x42, 0xdb, 0x1f, 0x9c, 0xf0, 0x24, 0x0b, 0xe8, 0x18, 0x45, 0x0e, 0x81, 0x50, 0xa8, 0xcb, 0x06, - 0x4e, 0x76, 0xfa, 0x3a, 0x2c, 0xcb, 0xcc, 0x19, 0x4d, 0x29, 0xb3, 0x3d, 0x73, 0x18, 0x09, 0xdd, - 0x3f, 0x53, 0x61, 0x7d, 0x7b, 0x0f, 0xcf, 0x5e, 0x11, 0x73, 0x76, 0xb5, 0xc2, 0xec, 0x3e, 0x21, - 0x43, 0xec, 0x03, 0x75, 0x56, 0x9b, 0x31, 0x6e, 0xb1, 0x07, 0xf2, 0x4a, 0xc4, 0x5e, 0xd2, 0xfa, - 0xab, 0x2c, 0xa9, 0xfb, 0x43, 0x07, 0xe6, 0x77, 0xa3, 0x78, 0x57, 0xde, 0xe7, 0x93, 0x20, 0xe8, - 0xbc, 0x34, 0x55, 0x7c, 0xc9, 0x4d, 0x7f, 0xa5, 0x1d, 0x5e, 0x2c, 0xda, 0xe1, 0x5f, 0x86, 0xd7, - 0x28, 0x52, 0x90, 0x44, 0x71, 0x94, 0xa0, 0x30, 0xfa, 0x23, 0x61, 0x74, 0xa3, 0x30, 0x3b, 0x56, - 0x6a, 0xec, 0x65, 0x24, 0x74, 0x24, 0xc3, 0xa3, 0x84, 0x70, 0x94, 0xa5, 0xdf, 0x20, 0xb4, 0x5b, - 0xb9, 0xc2, 0xfd, 0x2c, 0x34, 0xc8, 0xf1, 0xa5, 0x69, 0xbd, 0x03, 0x8d, 0xe3, 0x28, 0xee, 0x1d, - 0x07, 0x61, 0xa6, 0x84, 0x7b, 0x29, 0xf7, 0x48, 0x77, 0x69, 0x41, 0x34, 0x81, 0xfb, 0x83, 0x3a, - 0xcc, 0x3f, 0x08, 0x4f, 0xa2, 0xa0, 0x4f, 0x37, 0x00, 0x63, 0x3e, 0x8e, 0x54, 0x96, 0x1e, 0xfe, - 0xc6, 0xa5, 0xa0, 0x8c, 0x95, 0x38, 0x93, 0x21, 0x7c, 0x55, 0x44, 0x73, 0x9f, 0xe4, 0x99, 0xb4, - 0x42, 0x74, 0x0c, 0x04, 0x9d, 0xfe, 0xc4, 0x4c, 0x3a, 0x96, 0xa5, 0x3c, 0xcd, 0x71, 0xd6, 0x48, - 0x73, 0xa4, 0xfb, 0x22, 0x91, 0x7b, 0x40, 0xfc, 0xb5, 0xe0, 0xa9, 0x22, 0x1d, 0x52, 0x12, 0x2e, - 0x22, 0x3c, 0xe4, 0x38, 0xcc, 0xcb, 0x43, 0x8a, 0x09, 0xa2, 0x73, 0x21, 0x3e, 0x10, 0x34, 0x42, - 0xf9, 0x9a, 0x10, 0x3a, 0x62, 0xc5, 0xbc, 0xe5, 0x86, 0xe0, 0xf9, 0x02, 0x8c, 0x1a, 0x7a, 0xc0, - 0xb5, 0x22, 0x15, 0x73, 0x00, 0x91, 0x29, 0x5c, 0xc4, 0x8d, 0xa3, 0x8d, 0x48, 0x2a, 0x52, 0x47, - 0x1b, 0x64, 0x14, 0x7f, 0x34, 0x3a, 0xf4, 0xfb, 0xcf, 0x28, 0x2d, 0x9d, 0x72, 0x88, 0x1a, 0x9e, - 0x0d, 0x52, 0x36, 0x41, 0xbe, 0x9b, 0x74, 0xe3, 0x58, 0xf7, 0x4c, 0x88, 0x6d, 0x42, 0x93, 0x8e, - 0x73, 0x72, 0x3f, 0x97, 0x68, 0x3f, 0xdb, 0xe6, 0x79, 0x8f, 0x76, 0xd4, 0x24, 0x32, 0x6f, 0x25, - 0x96, 0xed, 0x5b, 0x09, 0xa1, 0x34, 0xe5, 0x65, 0x4e, 0x9b, 0x7a, 0xcb, 0x01, 0xb4, 0xa6, 0x72, - 0xc1, 0x04, 0xc1, 0x0a, 0x11, 0x58, 0x18, 0x4a, 0x2d, 0x1e, 0x42, 0x62, 0x3f, 0x18, 0x74, 0x98, - 0x90, 0x5a, 0x55, 0x76, 0x33, 0x60, 0x77, 0x06, 0x03, 0xc9, 0x4d, 0xfa, 0xb0, 0x9a, 0xf3, 0x81, - 0x63, 0xf1, 0x41, 0xc5, 0x7e, 0xd4, 0xaa, 0xf7, 0xe3, 0xa5, 0xa3, 0x76, 0x77, 0xa0, 0xb9, 0x6f, - 0x24, 0x53, 0x13, 0x5b, 0xaa, 0x34, 0x6a, 0xc9, 0xca, 0x06, 0x62, 0x0c, 0xa7, 0x66, 0x0e, 0xc7, - 0xfd, 0x05, 0x60, 0x7b, 0x41, 0x9a, 0xe9, 0xd1, 0xe7, 0xd9, 0xdb, 0x2a, 0xa2, 0x90, 0x27, 0x40, - 0x35, 0x25, 0x46, 0x89, 0x49, 0x77, 0x44, 0xe6, 0x54, 0x71, 0xda, 0x1b, 0xb0, 0x10, 0x08, 0xa8, - 0x28, 0x85, 0x8a, 0x52, 0xd7, 0xbb, 0x4f, 0x61, 0x55, 0x82, 0xa6, 0x05, 0xb7, 0xe7, 0xed, 0x9c, - 0xb7, 0x5b, 0xb5, 0xf2, 0x6e, 0xb9, 0xdf, 0x77, 0x60, 0x5e, 0x2e, 0x0e, 0xd2, 0x97, 0x12, 0xd1, - 0x1b, 0x9e, 0x85, 0x55, 0xa7, 0x20, 0x97, 0x25, 0x70, 0xa6, 0x4a, 0x02, 0x19, 0xd4, 0x63, 0x3f, - 0x3b, 0xa6, 0xa3, 0x57, 0xc3, 0xa3, 0xdf, 0xac, 0x2d, 0xc2, 0x01, 0x42, 0xd2, 0x29, 0x14, 0x50, - 0x95, 0x85, 0x2f, 0x0c, 0x4a, 0x09, 0x47, 0x17, 0x9a, 0xf2, 0x2d, 0x04, 0xae, 0xaf, 0x51, 0x64, - 0x26, 0x58, 0x0e, 0xe7, 0x2b, 0x2e, 0x9b, 0x28, 0xae, 0xb8, 0x24, 0xf5, 0x74, 0xbd, 0xdb, 0x85, - 0xce, 0x36, 0x1f, 0xf1, 0x8c, 0xdf, 0x19, 0x8d, 0x8a, 0xed, 0xbf, 0x06, 0x97, 0x2b, 0xea, 0xa4, - 0xcb, 0x75, 0x0f, 0x56, 0xb6, 0xf9, 0xe1, 0x64, 0xb8, 0xc7, 0x4f, 0xf2, 0xbb, 0x4e, 0x06, 0xf5, - 0xf4, 0x38, 0x3a, 0x95, 0xdc, 0x41, 0xbf, 0xd9, 0x1b, 0x00, 0x23, 0xa4, 0xe9, 0xa5, 0x31, 0xef, - 0xab, 0xe4, 0x5b, 0x42, 0x0e, 0x62, 0xde, 0x77, 0xdf, 0x03, 0x66, 0xb6, 0x23, 0xa7, 0x80, 0x5a, - 0x6c, 0x72, 0xd8, 0x4b, 0xa7, 0x69, 0xc6, 0xc7, 0x2a, 0xab, 0xd8, 0x84, 0xdc, 0xeb, 0xd0, 0xda, - 0xf7, 0xa7, 0x1e, 0xff, 0x86, 0x7c, 0x0b, 0x80, 0xa7, 0x7e, 0x7f, 0x8a, 0xa2, 0xa2, 0x4f, 0xfd, - 0x54, 0xed, 0xfe, 0x57, 0x0d, 0xe6, 0x04, 0x25, 0xb6, 0x3a, 0xe0, 0x69, 0x16, 0x84, 0xe2, 0x9e, - 0x4f, 0xb6, 0x6a, 0x40, 0x25, 0xde, 0xa8, 0x55, 0xf0, 0x86, 0xf4, 0xb5, 0x55, 0x22, 0xa3, 0x64, - 0x02, 0x0b, 0x43, 0x8e, 0xcd, 0xf3, 0x27, 0xc4, 0xb1, 0x33, 0x07, 0x0a, 0x61, 0xa0, 0x5c, 0x57, - 0x8a, 0xf1, 0x29, 0xb6, 0x97, 0xec, 0x60, 0x42, 0x95, 0x1a, 0x79, 0x5e, 0x70, 0x4d, 0x49, 0x23, - 0x97, 0x34, 0xef, 0xc2, 0x2b, 0x68, 0x5e, 0xe1, 0x80, 0xbf, 0x4c, 0xf3, 0xc2, 0x2b, 0x68, 0x5e, - 0x97, 0x41, 0xfb, 0x1e, 0xe7, 0x1e, 0x47, 0x9b, 0xae, 0xd8, 0xe9, 0x3b, 0x0e, 0xb4, 0xa5, 0x3b, - 0xa2, 0xeb, 0xd8, 0x5b, 0x96, 0xef, 0x52, 0x99, 0x6e, 0x78, 0x0d, 0x16, 0xc9, 0xa3, 0xd0, 0xf1, - 0x2e, 0x19, 0x9c, 0xb3, 0x40, 0x9c, 0x87, 0xba, 0x94, 0x18, 0x07, 0x23, 0xb9, 0x29, 0x26, 0xa4, - 0x42, 0x66, 0x78, 0xf2, 0xa7, 0x2d, 0x71, 0x3c, 0x5d, 0x76, 0xff, 0xda, 0x81, 0x15, 0x63, 0xc0, - 0x92, 0x0b, 0x3f, 0x04, 0x95, 0x5f, 0x21, 0xc2, 0x62, 0x42, 0x98, 0x2e, 0xd9, 0xae, 0x55, 0xfe, - 0x99, 0x45, 0x4c, 0x9b, 0xe9, 0x4f, 0x69, 0x80, 0xe9, 0x64, 0x2c, 0xb5, 0x92, 0x09, 0x21, 0x23, - 0x9d, 0x72, 0xfe, 0x4c, 0x93, 0xcc, 0x08, 0xc5, 0x65, 0x62, 0x74, 0x7d, 0x8e, 0x9e, 0x90, 0x26, - 0x12, 0x19, 0x63, 0x36, 0xe8, 0xfe, 0x93, 0x03, 0xab, 0xc2, 0xa5, 0x95, 0x07, 0x06, 0x9d, 0x0b, - 0x3e, 0x27, 0x7c, 0x78, 0x21, 0x91, 0xbb, 0x17, 0x3c, 0x59, 0x66, 0x9f, 0x79, 0x45, 0x37, 0x5c, - 0xa7, 0x4d, 0x9c, 0xb1, 0x17, 0x33, 0x55, 0x7b, 0xf1, 0x92, 0x95, 0xae, 0x0a, 0x03, 0xcd, 0x56, - 0x86, 0x81, 0xee, 0xce, 0xc3, 0x6c, 0xda, 0x8f, 0x62, 0xee, 0xae, 0xc3, 0x9a, 0x3d, 0x39, 0xa9, - 0x82, 0xbe, 0xeb, 0x40, 0xe7, 0x9e, 0x08, 0x8a, 0x06, 0xe1, 0x70, 0x37, 0x48, 0xb3, 0x28, 0xd1, - 0x8f, 0x5f, 0xae, 0x00, 0xa4, 0x99, 0x9f, 0x64, 0x22, 0xad, 0x4d, 0x06, 0x69, 0x72, 0x04, 0xc7, - 0xc8, 0xc3, 0x81, 0xa8, 0x15, 0x7b, 0xa3, 0xcb, 0xb8, 0x31, 0x64, 0x36, 0x7a, 0xd1, 0xd1, 0x51, - 0xca, 0xb5, 0xd3, 0x6d, 0x62, 0x78, 0x6e, 0x47, 0x89, 0xc7, 0x93, 0x2a, 0x3f, 0x21, 0x55, 0x2b, - 0xbc, 0xd9, 0x02, 0xea, 0xfe, 0xa5, 0x03, 0xcb, 0xf9, 0x20, 0x77, 0x10, 0xb4, 0xb5, 0x83, 0xb4, - 0x67, 0xb9, 0x76, 0x50, 0xe1, 0xa3, 0x00, 0x0d, 0x9c, 0x1c, 0x9b, 0x81, 0x90, 0xc4, 0xca, 0x52, - 0x34, 0x51, 0x29, 0x84, 0x26, 0x24, 0xf2, 0x03, 0x32, 0xfc, 0x5a, 0xe4, 0x0f, 0xca, 0x12, 0x65, - 0x25, 0x8e, 0x33, 0xfa, 0x6a, 0x4e, 0xb8, 0xf3, 0xb2, 0xa8, 0xec, 0xd3, 0x3c, 0xa1, 0xf8, 0xd3, - 0xfd, 0x7d, 0x07, 0x2e, 0x57, 0x2c, 0xae, 0x94, 0x8c, 0x6d, 0x58, 0x39, 0xd2, 0x95, 0x6a, 0x01, - 0x84, 0x78, 0xac, 0xab, 0x28, 0xbe, 0x3d, 0x69, 0xaf, 0xfc, 0x01, 0x3a, 0xf7, 0x14, 0xf5, 0x12, - 0x4b, 0x6a, 0xa5, 0xd6, 0x94, 0x2b, 0x36, 0xff, 0x60, 0x06, 0x96, 0xc4, 0xed, 0x8e, 0x78, 0x86, - 0xca, 0x13, 0xf6, 0x11, 0xcc, 0xcb, 0x67, 0xc4, 0xec, 0xa2, 0xec, 0xd6, 0x7e, 0xb8, 0xdc, 0x5d, - 0x2f, 0xc2, 0x92, 0x77, 0x56, 0x7f, 0xeb, 0x87, 0xff, 0xf2, 0x87, 0xb5, 0x45, 0xd6, 0xbc, 0x75, - 0xf2, 0xee, 0xad, 0x21, 0x0f, 0x53, 0x6c, 0xe3, 0xd7, 0x00, 0xf2, 0x07, 0xb6, 0xac, 0xa3, 0xdd, - 0x94, 0xc2, 0xcb, 0xe1, 0xee, 0xe5, 0x8a, 0x1a, 0xd9, 0xee, 0x65, 0x6a, 0x77, 0xd5, 0x5d, 0xc2, - 0x76, 0x83, 0x30, 0xc8, 0xc4, 0x6b, 0xdb, 0x0f, 0x9c, 0x0d, 0x36, 0x80, 0x96, 0xf9, 0x7e, 0x96, - 0xa9, 0x03, 0x7f, 0xc5, 0xeb, 0xdd, 0xee, 0x6b, 0x95, 0x75, 0x2a, 0xda, 0x41, 0x7d, 0x5c, 0x74, - 0xdb, 0xd8, 0xc7, 0x84, 0x28, 0xf2, 0x5e, 0x46, 0xb0, 0x64, 0x3f, 0x93, 0x65, 0xaf, 0x1b, 0x62, - 0x5d, 0x7a, 0xa4, 0xdb, 0x7d, 0xe3, 0x8c, 0x5a, 0xd9, 0xd7, 0x1b, 0xd4, 0xd7, 0x25, 0x97, 0x61, - 0x5f, 0x7d, 0xa2, 0x51, 0x8f, 0x74, 0x3f, 0x70, 0x36, 0x36, 0xbf, 0x75, 0x05, 0x1a, 0x3a, 0x44, - 0xc7, 0xbe, 0x0e, 0x8b, 0xd6, 0xf5, 0x1b, 0x53, 0xd3, 0xa8, 0xba, 0xad, 0xeb, 0xbe, 0x5e, 0x5d, - 0x29, 0x3b, 0xbe, 0x42, 0x1d, 0x77, 0xd8, 0x3a, 0x76, 0x2c, 0xef, 0xaf, 0x6e, 0xd1, 0xa5, 0xa3, - 0xc8, 0x79, 0x7c, 0x26, 0xe6, 0x99, 0x5f, 0x99, 0x59, 0xf3, 0x2c, 0x5d, 0xb1, 0x59, 0xf3, 0x2c, - 0xdf, 0xb3, 0xb9, 0xaf, 0x53, 0x77, 0xeb, 0x6c, 0xcd, 0xec, 0x4e, 0x87, 0xce, 0x38, 0x65, 0xa9, - 0x9a, 0xaf, 0x68, 0xd9, 0x1b, 0x9a, 0xb1, 0xaa, 0x5e, 0xd7, 0x6a, 0x16, 0x29, 0x3f, 0xb1, 0x75, - 0x3b, 0xd4, 0x15, 0x63, 0xb4, 0x7d, 0xe6, 0x23, 0x5a, 0xf6, 0x55, 0x68, 0xe8, 0x27, 0x63, 0xec, - 0x92, 0xf1, 0x4e, 0xcf, 0x7c, 0xc7, 0xd6, 0xed, 0x94, 0x2b, 0xaa, 0x18, 0xc3, 0x6c, 0x19, 0x19, - 0x63, 0x0f, 0x2e, 0x4a, 0xa7, 0xfa, 0x90, 0xff, 0x38, 0x33, 0xa9, 0x78, 0xfb, 0x7b, 0xdb, 0x61, - 0x1f, 0xc2, 0x82, 0x7a, 0x89, 0xc7, 0xd6, 0xab, 0x5f, 0x14, 0x76, 0x2f, 0x95, 0x70, 0xa9, 0x3d, - 0xee, 0x00, 0xe4, 0xaf, 0xc8, 0xb4, 0x9c, 0x95, 0xde, 0xb6, 0xe9, 0x45, 0xac, 0x78, 0x72, 0x36, - 0xa4, 0x37, 0x73, 0xf6, 0x23, 0x35, 0xf6, 0x66, 0x4e, 0x5f, 0xf9, 0x7c, 0xed, 0x25, 0x0d, 0xba, - 0xeb, 0xb4, 0x76, 0x6d, 0x46, 0x82, 0x1b, 0xf2, 0x53, 0x95, 0xaf, 0xbd, 0x0d, 0x4d, 0xe3, 0x65, - 0x1a, 0x53, 0x2d, 0x94, 0x5f, 0xb5, 0x75, 0xbb, 0x55, 0x55, 0x72, 0xb8, 0x5f, 0x80, 0x45, 0xeb, - 0x89, 0x99, 0x96, 0x8c, 0xaa, 0x07, 0x6c, 0x5a, 0x32, 0xaa, 0x5f, 0xa5, 0x7d, 0x05, 0x9a, 0xc6, - 0x83, 0x30, 0x66, 0xe4, 0xa9, 0x15, 0x9e, 0x82, 0xe9, 0x11, 0x55, 0xbd, 0x1f, 0x5b, 0xa3, 0xf9, - 0x2e, 0xb9, 0x0d, 0x9c, 0x2f, 0x25, 0x2d, 0x23, 0x93, 0x7c, 0x1d, 0x96, 0xec, 0x27, 0x62, 0x5a, - 0xaa, 0x2a, 0x1f, 0x9b, 0x69, 0xa9, 0x3a, 0xe3, 0x5d, 0x99, 0x64, 0xc8, 0x8d, 0x55, 0xdd, 0xc9, - 0xad, 0x8f, 0xe5, 0xe5, 0xd5, 0x0b, 0xf6, 0x25, 0x54, 0x1d, 0x32, 0x8b, 0x9c, 0xe5, 0x0f, 0xe3, - 0xec, 0x5c, 0x73, 0xcd, 0xed, 0xa5, 0x84, 0x73, 0x77, 0x85, 0x1a, 0x6f, 0xb2, 0x7c, 0x06, 0xc2, - 0x1e, 0x50, 0x36, 0xb9, 0x61, 0x0f, 0xcc, 0x84, 0x73, 0xc3, 0x1e, 0x58, 0x49, 0xe7, 0x45, 0x7b, - 0x90, 0x05, 0xd8, 0x46, 0x08, 0xcb, 0x85, 0x44, 0x0d, 0x2d, 0x2c, 0xd5, 0x99, 0x6d, 0xdd, 0x2b, - 0x2f, 0xcf, 0xef, 0xb0, 0xd5, 0x8c, 0x52, 0x2f, 0xb7, 0x54, 0x22, 0xe2, 0xaf, 0x43, 0xcb, 0x7c, - 0xda, 0xa3, 0x2d, 0x44, 0xc5, 0x83, 0x24, 0x6d, 0x21, 0xaa, 0xde, 0x02, 0xa9, 0xcd, 0x65, 0x2d, - 0xb3, 0x1b, 0xdc, 0x5c, 0xfb, 0x25, 0x44, 0xae, 0x32, 0xab, 0x9e, 0x78, 0xe4, 0x2a, 0xb3, 0xf2, - 0xf9, 0x84, 0xda, 0x5c, 0xb6, 0x6a, 0xcd, 0x45, 0x44, 0x26, 0xd9, 0x57, 0x60, 0xd9, 0xc8, 0x82, - 0x3a, 0x98, 0x86, 0x7d, 0xcd, 0xa8, 0xe5, 0x1c, 0xd9, 0x6e, 0x95, 0xe7, 0xe9, 0x5e, 0xa2, 0xf6, - 0x57, 0x5c, 0x6b, 0x12, 0xc8, 0xa4, 0x5b, 0xd0, 0x34, 0x33, 0xac, 0x5e, 0xd2, 0xee, 0x25, 0xa3, - 0xca, 0x4c, 0x17, 0xbd, 0xed, 0xb0, 0x3f, 0x76, 0xa0, 0x65, 0xe5, 0x2b, 0x59, 0xf1, 0xf7, 0x42, - 0x3b, 0x1d, 0xb3, 0xce, 0x6c, 0xc8, 0xf5, 0x68, 0x90, 0x7b, 0x1b, 0x5f, 0xb0, 0x16, 0xe1, 0x63, - 0xeb, 0x04, 0x73, 0xb3, 0xf8, 0x42, 0xfc, 0x45, 0x91, 0xc0, 0xcc, 0x23, 0x7e, 0x71, 0xdb, 0x61, - 0x1f, 0x88, 0xff, 0x40, 0x50, 0x11, 0x0b, 0x66, 0x28, 0xd2, 0xe2, 0x92, 0x99, 0x7f, 0x00, 0x70, - 0xc3, 0xb9, 0xed, 0xb0, 0xaf, 0x89, 0x87, 0xe0, 0xf2, 0x5b, 0x5a, 0xf9, 0x57, 0xfd, 0xde, 0xbd, - 0x46, 0xb3, 0xb9, 0xe2, 0x5e, 0xb6, 0x66, 0x53, 0xb4, 0x24, 0x77, 0xc4, 0xe8, 0xe4, 0xfb, 0xfe, - 0x5c, 0x25, 0x96, 0xde, 0xfc, 0x9f, 0x3d, 0xc8, 0xb1, 0x18, 0xa4, 0x24, 0xb7, 0xd8, 0xe3, 0x15, - 0x9b, 0x71, 0x37, 0x68, 0xac, 0xd7, 0xdc, 0x37, 0xcf, 0x1c, 0xeb, 0x2d, 0x3a, 0x91, 0xe2, 0x88, - 0xf7, 0x01, 0xf2, 0x80, 0x1c, 0x2b, 0xc4, 0x9f, 0xb4, 0x55, 0x28, 0xc7, 0xec, 0x6c, 0x1e, 0x54, - 0x61, 0x2a, 0x6c, 0xf1, 0xab, 0x42, 0x54, 0x25, 0x7d, 0xaa, 0x47, 0x5f, 0x0e, 0x9d, 0x75, 0xbb, - 0x55, 0x55, 0x55, 0x82, 0xaa, 0xda, 0x67, 0x4f, 0x60, 0x71, 0x2f, 0x8a, 0x9e, 0x4d, 0x62, 0x1d, - 0x90, 0xb6, 0xe3, 0x37, 0xbb, 0x7e, 0x7a, 0xdc, 0x2d, 0xcc, 0xc2, 0xbd, 0x4a, 0x4d, 0x75, 0x59, - 0xc7, 0x68, 0xea, 0xd6, 0xc7, 0x79, 0xc0, 0xef, 0x05, 0xf3, 0x61, 0x45, 0x7b, 0x00, 0x7a, 0xe0, - 0x5d, 0xbb, 0x19, 0x33, 0xee, 0x56, 0xea, 0xc2, 0xf2, 0xc9, 0xd4, 0x68, 0x6f, 0xa5, 0xaa, 0xcd, - 0xdb, 0x0e, 0xdb, 0x87, 0xd6, 0x36, 0xef, 0x47, 0x03, 0x2e, 0x23, 0x2e, 0xab, 0xf9, 0xc0, 0x75, - 0xa8, 0xa6, 0xbb, 0x68, 0x81, 0xb6, 0x4e, 0x8c, 0xfd, 0x69, 0xc2, 0xbf, 0x71, 0xeb, 0x63, 0x19, - 0xcb, 0x79, 0xa1, 0x74, 0xa2, 0x8a, 0x3f, 0x59, 0x3a, 0xb1, 0x10, 0xb0, 0xb2, 0x74, 0x62, 0x29, - 0x60, 0x65, 0x2d, 0xb5, 0x8a, 0x7f, 0xb1, 0x11, 0xac, 0x94, 0x62, 0x5c, 0xda, 0x8f, 0x38, 0x2b, - 0x32, 0xd6, 0xbd, 0x7a, 0x36, 0x81, 0xdd, 0xdb, 0x86, 0xdd, 0xdb, 0x01, 0x2c, 0x6e, 0x73, 0xb1, - 0x58, 0xe2, 0xd6, 0xbb, 0xf0, 0xe0, 0xcc, 0xbc, 0x21, 0x2f, 0x2a, 0x45, 0xaa, 0xb3, 0x8d, 0x1e, - 0x5d, 0x39, 0xb3, 0xaf, 0x42, 0xf3, 0x3e, 0xcf, 0xd4, 0x35, 0xb7, 0xf6, 0xc6, 0x0a, 0xf7, 0xde, - 0xdd, 0x8a, 0x5b, 0x72, 0x9b, 0x67, 0xa8, 0xb5, 0x5b, 0x7c, 0x30, 0xe4, 0x42, 0x3d, 0xf5, 0x82, - 0xc1, 0x0b, 0xf6, 0x2b, 0xd4, 0xb8, 0xce, 0x9a, 0x59, 0x37, 0x6e, 0x47, 0xcd, 0xc6, 0x97, 0x0b, - 0x78, 0x55, 0xcb, 0x61, 0x34, 0xe0, 0x86, 0xf9, 0x0f, 0xa1, 0x69, 0xa4, 0x74, 0x69, 0x01, 0x2a, - 0xa7, 0xa7, 0x69, 0x01, 0xaa, 0xc8, 0x00, 0x73, 0x6f, 0x50, 0x3f, 0x2e, 0xbb, 0x9a, 0xf7, 0x23, - 0xb2, 0xbe, 0xf2, 0x9e, 0x6e, 0x7d, 0xec, 0x8f, 0xb3, 0x17, 0xec, 0x29, 0x3d, 0x3e, 0x33, 0xaf, - 0xf2, 0x73, 0x6f, 0xb0, 0x78, 0xeb, 0xaf, 0x17, 0xcb, 0xa8, 0xb2, 0x3d, 0x44, 0xd1, 0x15, 0x79, - 0x09, 0x9f, 0x01, 0x38, 0xc8, 0xa2, 0x78, 0xdb, 0xe7, 0xe3, 0x28, 0xcc, 0x75, 0x6d, 0x7e, 0x5d, - 0x9d, 0xeb, 0x2f, 0xe3, 0xce, 0x9a, 0x3d, 0x35, 0xfc, 0x71, 0x2b, 0x13, 0x42, 0x31, 0xd7, 0x99, - 0x37, 0xda, 0x7a, 0x41, 0x2a, 0x6e, 0xb5, 0x6f, 0x3b, 0xe8, 0x5d, 0xe7, 0x11, 0x55, 0xed, 0x5d, - 0x97, 0x82, 0xb5, 0x5a, 0xed, 0x55, 0x84, 0x5f, 0xf7, 0xa1, 0x91, 0x87, 0xe8, 0x2e, 0xe5, 0x69, - 0x79, 0x56, 0x40, 0x4f, 0x5b, 0xc5, 0x52, 0xe0, 0xcc, 0x6d, 0xd3, 0x52, 0x01, 0x5b, 0xc0, 0xa5, - 0xa2, 0x68, 0x58, 0x00, 0xab, 0x62, 0x80, 0xda, 0xc4, 0xd3, 0x05, 0xac, 0x9a, 0x49, 0x45, 0xf0, - 0x4a, 0x4b, 0x73, 0x65, 0xec, 0xc7, 0x3a, 0x67, 0x23, 0xb7, 0x8a, 0xcb, 0x5f, 0x54, 0xcd, 0x63, - 0x58, 0x29, 0x05, 0x2e, 0xb4, 0x48, 0x9f, 0x15, 0x2f, 0xd2, 0x22, 0x7d, 0x66, 0xcc, 0xc3, 0xbd, - 0x48, 0x5d, 0x2e, 0xbb, 0x80, 0x5d, 0xa6, 0xa7, 0x41, 0xd6, 0x3f, 0xfe, 0xc0, 0xd9, 0x38, 0x9c, - 0xa3, 0xff, 0x4c, 0xfb, 0xd4, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x2e, 0xa2, 0xa7, 0xf7, 0x65, - 0x4d, 0x00, 0x00, + // 6239 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x5c, 0xdd, 0x8f, 0x1c, 0xd9, + 0x55, 0x77, 0x75, 0xf7, 0x7c, 0xf4, 0xe9, 0x9e, 0x99, 0x9e, 0x3b, 0xe3, 0x71, 0xbb, 0x77, 0xd7, + 0xeb, 0xad, 0x58, 0x6b, 0x67, 0x58, 0x6c, 0xef, 0x24, 0x59, 0x36, 0xbb, 0x90, 0x60, 0xcf, 0x8c, + 0x3d, 0x4e, 0x66, 0xed, 0x49, 0x8d, 0x1d, 0x43, 0x02, 0xea, 0xd4, 0x74, 0xdf, 0xe9, 0xa9, 0xb8, + 0xbb, 0xaa, 0x53, 0x55, 0x3d, 0xe3, 0xce, 0x62, 0x29, 0x10, 0xc4, 0x13, 0x11, 0x42, 0xf0, 0x12, + 0x24, 0x84, 0x14, 0x24, 0x14, 0xfe, 0x00, 0x78, 0x09, 0x48, 0x3c, 0xf0, 0x12, 0x24, 0xc4, 0x43, + 0x9e, 0x22, 0x1e, 0xe1, 0x05, 0x10, 0x2f, 0x48, 0xbc, 0x22, 0x74, 0xce, 0xfd, 0xa8, 0x7b, 0xab, + 0xaa, 0x3d, 0xce, 0x07, 0xbc, 0xf5, 0xfd, 0xdd, 0x53, 0xf7, 0xf3, 0x7c, 0xdd, 0x73, 0xcf, 0x6d, + 0xa8, 0xc7, 0xe3, 0xde, 0xcd, 0x71, 0x1c, 0xa5, 0x11, 0x9b, 0x1b, 0x86, 0xf1, 0xb8, 0xd7, 0x79, + 0x7d, 0x10, 0x45, 0x83, 0x21, 0xbf, 0xe5, 0x8f, 0x83, 0x5b, 0x7e, 0x18, 0x46, 0xa9, 0x9f, 0x06, + 0x51, 0x98, 0x08, 0x22, 0xf7, 0x6b, 0xb0, 0x7c, 0x9f, 0x87, 0x87, 0x9c, 0xf7, 0x3d, 0xfe, 0x8d, + 0x09, 0x4f, 0x52, 0xf6, 0x0b, 0xb0, 0xea, 0xf3, 0x6f, 0x72, 0xde, 0xef, 0x8e, 0xfd, 0x24, 0x19, + 0x9f, 0xc4, 0x7e, 0xc2, 0xdb, 0xce, 0x55, 0xe7, 0x46, 0xd3, 0x6b, 0x89, 0x8a, 0x03, 0x8d, 0xb3, + 0xb7, 0xa0, 0x99, 0x20, 0x29, 0x0f, 0xd3, 0x38, 0x1a, 0x4f, 0xdb, 0x15, 0xa2, 0x6b, 0x20, 0xb6, + 0x2b, 0x20, 0x77, 0x08, 0x2b, 0xba, 0x87, 0x64, 0x1c, 0x85, 0x09, 0x67, 0xb7, 0x61, 0xbd, 0x17, + 0x8c, 0x4f, 0x78, 0xdc, 0xa5, 0x8f, 0x47, 0x21, 0x1f, 0x45, 0x61, 0xd0, 0x6b, 0x3b, 0x57, 0xab, + 0x37, 0xea, 0x1e, 0x13, 0x75, 0xf8, 0xc5, 0x47, 0xb2, 0x86, 0x5d, 0x87, 0x15, 0x1e, 0x0a, 0x9c, + 0xf7, 0xe9, 0x2b, 0xd9, 0xd5, 0x72, 0x06, 0xe3, 0x07, 0xee, 0xdf, 0x3b, 0xb0, 0xfa, 0x20, 0x0c, + 0xd2, 0xa7, 0xfe, 0x70, 0xc8, 0x53, 0x35, 0xa7, 0xeb, 0xb0, 0x72, 0x46, 0x00, 0xcd, 0xe9, 0x2c, + 0x8a, 0xfb, 0x72, 0x46, 0xcb, 0x02, 0x3e, 0x90, 0xe8, 0xcc, 0x91, 0x55, 0x66, 0x8e, 0xac, 0x74, + 0xb9, 0xaa, 0x33, 0x96, 0xeb, 0x3a, 0xac, 0xc4, 0xbc, 0x17, 0x9d, 0xf2, 0x78, 0xda, 0x3d, 0x0b, + 0xc2, 0x7e, 0x74, 0xd6, 0xae, 0x5d, 0x75, 0x6e, 0xcc, 0x79, 0xcb, 0x0a, 0x7e, 0x4a, 0xa8, 0xbb, + 0x0e, 0xcc, 0x9c, 0x85, 0x58, 0x37, 0x77, 0x00, 0x6b, 0x4f, 0xc2, 0x61, 0xd4, 0x7b, 0xf6, 0x53, + 0xce, 0xae, 0xa4, 0xfb, 0x4a, 0x69, 0xf7, 0x1b, 0xb0, 0x6e, 0x77, 0x24, 0x07, 0xc0, 0xe1, 0xe2, + 0xf6, 0x89, 0x1f, 0x0e, 0xb8, 0x6a, 0x52, 0x0d, 0xe1, 0x93, 0xd0, 0xea, 0x4d, 0xe2, 0x98, 0x87, + 0x85, 0x31, 0xac, 0x48, 0x5c, 0x0f, 0xe2, 0x2d, 0x68, 0x86, 0xfc, 0x2c, 0x23, 0x93, 0x2c, 0x13, + 0xf2, 0x33, 0x45, 0xe2, 0xb6, 0x61, 0x23, 0xdf, 0x8d, 0x1c, 0xc0, 0x77, 0x2b, 0xd0, 0x78, 0x1c, + 0xfb, 0x61, 0xe2, 0xf7, 0x90, 0x8b, 0x59, 0x1b, 0x16, 0xd2, 0xe7, 0xdd, 0x13, 0x3f, 0x39, 0xa1, + 0xee, 0xea, 0x9e, 0x2a, 0xb2, 0x0d, 0x98, 0xf7, 0x47, 0xd1, 0x24, 0x4c, 0xa9, 0x83, 0xaa, 0x27, + 0x4b, 0xec, 0x1d, 0x58, 0x0d, 0x27, 0xa3, 0x6e, 0x2f, 0x0a, 0x8f, 0x83, 0x78, 0x24, 0x64, 0x81, + 0xf6, 0x6b, 0xce, 0x2b, 0x56, 0xb0, 0x2b, 0x00, 0x47, 0xb8, 0x0e, 0xa2, 0x8b, 0x1a, 0x75, 0x61, + 0x20, 0xcc, 0x85, 0xa6, 0x2c, 0xf1, 0x60, 0x70, 0x92, 0xb6, 0xe7, 0xa8, 0x21, 0x0b, 0xc3, 0x36, + 0xd2, 0x60, 0xc4, 0xbb, 0x49, 0xea, 0x8f, 0xc6, 0xed, 0x79, 0x1a, 0x8d, 0x81, 0x50, 0x7d, 0x94, + 0xfa, 0xc3, 0xee, 0x31, 0xe7, 0x49, 0x7b, 0x41, 0xd6, 0x6b, 0x84, 0xbd, 0x0d, 0xcb, 0x7d, 0x9e, + 0xa4, 0x5d, 0xbf, 0xdf, 0x8f, 0x79, 0x92, 0xf0, 0xa4, 0xbd, 0x48, 0xdc, 0x98, 0x43, 0x71, 0xd5, + 0xee, 0xf3, 0xd4, 0x58, 0x9d, 0x44, 0xee, 0x8e, 0xbb, 0x0f, 0xcc, 0x80, 0x77, 0x78, 0xea, 0x07, + 0xc3, 0x84, 0xbd, 0x07, 0xcd, 0xd4, 0x20, 0x26, 0xe9, 0x6b, 0x6c, 0xb1, 0x9b, 0xa4, 0x36, 0x6e, + 0x1a, 0x1f, 0x78, 0x16, 0x9d, 0x7b, 0x1f, 0x16, 0xef, 0x71, 0xbe, 0x1f, 0x8c, 0x82, 0x94, 0x6d, + 0xc0, 0xdc, 0x71, 0xf0, 0x9c, 0x8b, 0xcd, 0xae, 0xee, 0x5d, 0xf0, 0x44, 0x91, 0x75, 0x60, 0x61, + 0xcc, 0xe3, 0x1e, 0x57, 0xcb, 0xbf, 0x77, 0xc1, 0x53, 0xc0, 0xdd, 0x05, 0x98, 0x1b, 0xe2, 0xc7, + 0xee, 0xf7, 0x2b, 0xd0, 0x38, 0xe4, 0xa1, 0x66, 0x22, 0x06, 0x35, 0x9c, 0x92, 0x64, 0x1c, 0xfa, + 0xcd, 0xde, 0x84, 0x06, 0x4d, 0x33, 0x49, 0xe3, 0x20, 0x1c, 0x50, 0x63, 0x75, 0x0f, 0x10, 0x3a, + 0x24, 0x84, 0xb5, 0xa0, 0xea, 0x8f, 0x52, 0xda, 0xc1, 0xaa, 0x87, 0x3f, 0x91, 0xc1, 0xc6, 0xfe, + 0x74, 0x84, 0xbc, 0xa8, 0x77, 0xad, 0xe9, 0x35, 0x24, 0xb6, 0x87, 0xdb, 0x76, 0x13, 0xd6, 0x4c, + 0x12, 0xd5, 0xfa, 0x1c, 0xb5, 0xbe, 0x6a, 0x50, 0xca, 0x4e, 0xae, 0xc3, 0x8a, 0xa2, 0x8f, 0xc5, + 0x60, 0x69, 0x1f, 0xeb, 0xde, 0xb2, 0x84, 0xd5, 0x14, 0x6e, 0x40, 0xeb, 0x38, 0x08, 0xfd, 0x61, + 0xb7, 0x37, 0x4c, 0x4f, 0xbb, 0x7d, 0x3e, 0x4c, 0x7d, 0xda, 0xd1, 0x39, 0x6f, 0x99, 0xf0, 0xed, + 0x61, 0x7a, 0xba, 0x83, 0x28, 0x7b, 0x07, 0xea, 0xc7, 0x9c, 0x77, 0x69, 0x25, 0xda, 0x8b, 0x57, + 0x9d, 0x1b, 0x8d, 0xad, 0x15, 0xb9, 0xf4, 0x6a, 0x75, 0xbd, 0xc5, 0x63, 0xf9, 0xcb, 0xfd, 0x63, + 0x07, 0x9a, 0x62, 0xa9, 0xa4, 0x0a, 0xbd, 0x06, 0x4b, 0x6a, 0x44, 0x3c, 0x8e, 0xa3, 0x58, 0xb2, + 0xbf, 0x0d, 0xb2, 0x4d, 0x68, 0x29, 0x60, 0x1c, 0xf3, 0x60, 0xe4, 0x0f, 0xb8, 0x94, 0xb7, 0x02, + 0xce, 0xb6, 0xb2, 0x16, 0xe3, 0x68, 0x92, 0x0a, 0x25, 0xd6, 0xd8, 0x6a, 0xca, 0x41, 0x79, 0x88, + 0x79, 0x36, 0x89, 0xfb, 0x1d, 0x07, 0x18, 0x0e, 0xeb, 0x71, 0x24, 0xaa, 0xe5, 0x2a, 0xe4, 0x77, + 0xc0, 0x79, 0xe5, 0x1d, 0xa8, 0xcc, 0xda, 0x81, 0x6b, 0x30, 0x4f, 0x5d, 0xa2, 0xac, 0x56, 0x0b, + 0xc3, 0x92, 0x75, 0xee, 0xf7, 0x1c, 0x68, 0xa2, 0xe6, 0x08, 0xf9, 0xf0, 0x20, 0x0a, 0xc2, 0x94, + 0xdd, 0x06, 0x76, 0x3c, 0x09, 0xfb, 0x41, 0x38, 0xe8, 0xa6, 0xcf, 0x83, 0x7e, 0xf7, 0x68, 0x8a, + 0x4d, 0xd0, 0x78, 0xf6, 0x2e, 0x78, 0x25, 0x75, 0xec, 0x1d, 0x68, 0x59, 0x68, 0x92, 0xc6, 0x62, + 0x54, 0x7b, 0x17, 0xbc, 0x42, 0x0d, 0xca, 0x7f, 0x34, 0x49, 0xc7, 0x93, 0xb4, 0x1b, 0x84, 0x7d, + 0xfe, 0x9c, 0xd6, 0x6c, 0xc9, 0xb3, 0xb0, 0xbb, 0xcb, 0xd0, 0x34, 0xbf, 0x73, 0x3f, 0x07, 0xad, + 0x7d, 0x54, 0x0c, 0x61, 0x10, 0x0e, 0xee, 0x08, 0xe9, 0x45, 0x6d, 0x35, 0x9e, 0x1c, 0x3d, 0xe3, + 0x53, 0xb9, 0x8f, 0xb2, 0x84, 0x22, 0x71, 0x12, 0x25, 0xa9, 0x5c, 0x17, 0xfa, 0xed, 0xfe, 0x8b, + 0x03, 0x2b, 0xb8, 0xe8, 0x1f, 0xf9, 0xe1, 0x54, 0xad, 0xf8, 0x3e, 0x34, 0xb1, 0xa9, 0xc7, 0xd1, + 0x1d, 0xa1, 0xf3, 0x84, 0x2c, 0xdf, 0x90, 0x8b, 0x94, 0xa3, 0xbe, 0x69, 0x92, 0xa2, 0x99, 0x9e, + 0x7a, 0xd6, 0xd7, 0x28, 0x74, 0xa9, 0x1f, 0x0f, 0x78, 0x4a, 0xda, 0x50, 0x6a, 0x47, 0x10, 0xd0, + 0x76, 0x14, 0x1e, 0xb3, 0xab, 0xd0, 0x4c, 0xfc, 0xb4, 0x3b, 0xe6, 0x31, 0xad, 0x1a, 0x09, 0x4e, + 0xd5, 0x83, 0xc4, 0x4f, 0x0f, 0x78, 0x7c, 0x77, 0x9a, 0xf2, 0xce, 0xe7, 0x61, 0xb5, 0xd0, 0x0b, + 0xca, 0x6a, 0x36, 0x45, 0xfc, 0xc9, 0xd6, 0x61, 0xee, 0xd4, 0x1f, 0x4e, 0xb8, 0x54, 0xd2, 0xa2, + 0xf0, 0x41, 0xe5, 0x7d, 0xc7, 0x7d, 0x1b, 0x5a, 0xd9, 0xb0, 0x25, 0xd3, 0x33, 0xa8, 0xe1, 0x0a, + 0xca, 0x06, 0xe8, 0xb7, 0xfb, 0xdb, 0x8e, 0x20, 0xdc, 0x8e, 0x02, 0xad, 0xf0, 0x90, 0x10, 0xf5, + 0xa2, 0x22, 0xc4, 0xdf, 0x33, 0x0d, 0xc2, 0xcf, 0x3e, 0x59, 0xf7, 0x3a, 0xac, 0x1a, 0x43, 0x78, + 0xc9, 0x60, 0xbf, 0xe3, 0xc0, 0xea, 0x43, 0x7e, 0x26, 0x77, 0x5d, 0x8d, 0xf6, 0x7d, 0xa8, 0xa5, + 0xd3, 0xb1, 0x70, 0xb2, 0x96, 0xb7, 0xae, 0xc9, 0x4d, 0x2b, 0xd0, 0xdd, 0x94, 0xc5, 0xc7, 0xd3, + 0x31, 0xf7, 0xe8, 0x0b, 0xf7, 0x73, 0xd0, 0x30, 0x40, 0x76, 0x09, 0xd6, 0x9e, 0x3e, 0x78, 0xfc, + 0x70, 0xf7, 0xf0, 0xb0, 0x7b, 0xf0, 0xe4, 0xee, 0x17, 0x77, 0x7f, 0xbd, 0xbb, 0x77, 0xe7, 0x70, + 0xaf, 0x75, 0x81, 0x6d, 0x00, 0x7b, 0xb8, 0x7b, 0xf8, 0x78, 0x77, 0xc7, 0xc2, 0x1d, 0xb7, 0x03, + 0xed, 0x87, 0xfc, 0xec, 0x69, 0x90, 0x86, 0x3c, 0x49, 0xec, 0xde, 0xdc, 0x9b, 0xc0, 0xcc, 0x21, + 0xc8, 0x59, 0xb5, 0x61, 0x41, 0x5a, 0x1c, 0x65, 0x70, 0x65, 0xd1, 0x7d, 0x1b, 0xd8, 0x61, 0x30, + 0x08, 0x3f, 0xe2, 0x49, 0xe2, 0x0f, 0xb4, 0x2a, 0x68, 0x41, 0x75, 0x94, 0x0c, 0xa4, 0x06, 0xc0, + 0x9f, 0xee, 0xa7, 0x60, 0xcd, 0xa2, 0x93, 0x0d, 0xbf, 0x0e, 0xf5, 0x24, 0x18, 0x84, 0x7e, 0x3a, + 0x89, 0xb9, 0x6c, 0x3a, 0x03, 0xdc, 0x7b, 0xb0, 0xfe, 0x65, 0x1e, 0x07, 0xc7, 0xd3, 0xf3, 0x9a, + 0xb7, 0xdb, 0xa9, 0xe4, 0xdb, 0xd9, 0x85, 0x8b, 0xb9, 0x76, 0x64, 0xf7, 0x82, 0x11, 0xe5, 0x76, + 0x2d, 0x7a, 0xa2, 0x60, 0x88, 0x65, 0xc5, 0x14, 0x4b, 0xf7, 0x09, 0xb0, 0xed, 0x28, 0x0c, 0x79, + 0x2f, 0x3d, 0xe0, 0x3c, 0xce, 0x3c, 0xe7, 0x8c, 0xeb, 0x1a, 0x5b, 0x97, 0xe4, 0x3e, 0xe6, 0x65, + 0x5d, 0xb2, 0x23, 0x83, 0xda, 0x98, 0xc7, 0x23, 0x6a, 0x78, 0xd1, 0xa3, 0xdf, 0xee, 0x45, 0x58, + 0xb3, 0x9a, 0x95, 0x4e, 0xcf, 0xbb, 0x70, 0x71, 0x27, 0x48, 0x7a, 0xc5, 0x0e, 0xdb, 0xb0, 0x30, + 0x9e, 0x1c, 0x75, 0x33, 0x99, 0x52, 0x45, 0xf4, 0x05, 0xf2, 0x9f, 0xc8, 0xc6, 0x7e, 0xcf, 0x81, + 0xda, 0xde, 0xe3, 0xfd, 0x6d, 0xd6, 0x81, 0xc5, 0x20, 0xec, 0x45, 0x23, 0x54, 0xbb, 0x62, 0xd2, + 0xba, 0x3c, 0x53, 0x56, 0x5e, 0x87, 0x3a, 0x69, 0x6b, 0x74, 0x6f, 0xa4, 0x93, 0x9b, 0x01, 0xe8, + 0x5a, 0xf1, 0xe7, 0xe3, 0x20, 0x26, 0xdf, 0x49, 0x79, 0x44, 0x35, 0xd2, 0x88, 0xc5, 0x0a, 0xf7, + 0x7f, 0x6a, 0xb0, 0x20, 0x75, 0x35, 0xf5, 0xd7, 0x4b, 0x83, 0x53, 0x2e, 0x47, 0x22, 0x4b, 0x68, + 0xe5, 0x62, 0x3e, 0x8a, 0x52, 0xde, 0xb5, 0xb6, 0xc1, 0x06, 0x91, 0xaa, 0x27, 0x1a, 0xea, 0x8e, + 0x51, 0xeb, 0xd3, 0xc8, 0xea, 0x9e, 0x0d, 0xe2, 0x62, 0x21, 0xd0, 0x0d, 0xfa, 0x34, 0xa6, 0x9a, + 0xa7, 0x8a, 0xb8, 0x12, 0x3d, 0x7f, 0xec, 0xf7, 0x82, 0x74, 0x2a, 0x85, 0x5b, 0x97, 0xb1, 0xed, + 0x61, 0xd4, 0xf3, 0x87, 0xdd, 0x23, 0x7f, 0xe8, 0x87, 0x3d, 0x2e, 0xfd, 0x37, 0x1b, 0x44, 0x17, + 0x4d, 0x0e, 0x49, 0x91, 0x09, 0x37, 0x2e, 0x87, 0xa2, 0xab, 0xd7, 0x8b, 0x46, 0xa3, 0x20, 0x45, + 0xcf, 0x8e, 0xac, 0x7e, 0xd5, 0x33, 0x10, 0x9a, 0x89, 0x28, 0x9d, 0x89, 0xd5, 0xab, 0x8b, 0xde, + 0x2c, 0x10, 0x5b, 0x41, 0xd7, 0x01, 0x15, 0xd2, 0xb3, 0xb3, 0x36, 0x88, 0x56, 0x32, 0x04, 0xf7, + 0x61, 0x12, 0x26, 0x3c, 0x4d, 0x87, 0xbc, 0xaf, 0x07, 0xd4, 0x20, 0xb2, 0x62, 0x05, 0xbb, 0x0d, + 0x6b, 0xc2, 0xd9, 0x4c, 0xfc, 0x34, 0x4a, 0x4e, 0x82, 0xa4, 0x9b, 0xa0, 0xdb, 0xd6, 0x24, 0xfa, + 0xb2, 0x2a, 0xf6, 0x3e, 0x5c, 0xca, 0xc1, 0x31, 0xef, 0xf1, 0xe0, 0x94, 0xf7, 0xdb, 0x4b, 0xf4, + 0xd5, 0xac, 0x6a, 0x76, 0x15, 0x1a, 0xe8, 0x63, 0x4f, 0xc6, 0x7d, 0x1f, 0xed, 0xf0, 0x32, 0xed, + 0x83, 0x09, 0xb1, 0x77, 0x61, 0x69, 0xcc, 0x85, 0xb1, 0x3c, 0x49, 0x87, 0xbd, 0xa4, 0xbd, 0x42, + 0x96, 0xac, 0x21, 0x85, 0x09, 0x39, 0xd7, 0xb3, 0x29, 0x90, 0x29, 0x7b, 0x09, 0x39, 0x5b, 0xfe, + 0xb4, 0xdd, 0x22, 0x76, 0xcb, 0x00, 0x92, 0x91, 0x38, 0x38, 0xf5, 0x53, 0xde, 0x5e, 0x25, 0xde, + 0x52, 0x45, 0xf7, 0xcf, 0x1c, 0x58, 0xdb, 0x0f, 0x92, 0x54, 0x32, 0xa1, 0x56, 0xc7, 0x6f, 0x42, + 0x43, 0xb0, 0x5f, 0x37, 0x0a, 0x87, 0x53, 0xc9, 0x91, 0x20, 0xa0, 0x47, 0xe1, 0x70, 0xca, 0x3e, + 0x01, 0x4b, 0x41, 0x68, 0x92, 0x08, 0x19, 0x6e, 0x2a, 0x90, 0x88, 0xde, 0x84, 0xc6, 0x78, 0x72, + 0x34, 0x0c, 0x7a, 0x82, 0xa4, 0x2a, 0x5a, 0x11, 0x10, 0x11, 0xa0, 0x93, 0x24, 0x46, 0x22, 0x28, + 0x6a, 0x44, 0xd1, 0x90, 0x18, 0x92, 0xb8, 0x77, 0x61, 0xdd, 0x1e, 0xa0, 0x54, 0x56, 0x9b, 0xb0, + 0x28, 0x79, 0x3b, 0x69, 0x37, 0x68, 0x7d, 0x96, 0xe5, 0xfa, 0x48, 0x52, 0x4f, 0xd7, 0xbb, 0x7f, + 0x51, 0x83, 0x35, 0x89, 0x6e, 0x0f, 0xa3, 0x84, 0x1f, 0x4e, 0x46, 0x23, 0x3f, 0x2e, 0x11, 0x1a, + 0xe7, 0x1c, 0xa1, 0xa9, 0xd8, 0x42, 0x83, 0xac, 0x7c, 0xe2, 0x07, 0xa1, 0xf0, 0xf0, 0x84, 0xc4, + 0x19, 0x08, 0xbb, 0x01, 0x2b, 0xbd, 0x61, 0x94, 0x08, 0xaf, 0xc7, 0x3c, 0x3e, 0xe5, 0xe1, 0xa2, + 0x90, 0xcf, 0x95, 0x09, 0xb9, 0x29, 0xa4, 0xf3, 0x39, 0x21, 0x75, 0xa1, 0x89, 0x8d, 0x72, 0xa5, + 0x73, 0x16, 0x84, 0x17, 0x66, 0x62, 0x38, 0x9e, 0xbc, 0x48, 0x08, 0xf9, 0x5b, 0x29, 0x13, 0x08, + 0x3c, 0x9d, 0xa1, 0x4e, 0x33, 0xa8, 0xeb, 0x52, 0x20, 0x8a, 0x55, 0xec, 0x1e, 0x80, 0xe8, 0x8b, + 0xcc, 0x38, 0x90, 0x19, 0x7f, 0xdb, 0xde, 0x11, 0x73, 0xed, 0x6f, 0x62, 0x61, 0x12, 0x73, 0x32, + 0xe4, 0xc6, 0x97, 0xee, 0xc7, 0xd0, 0x30, 0xaa, 0xd8, 0x45, 0x58, 0xdd, 0x7e, 0xf4, 0xe8, 0x60, + 0xd7, 0xbb, 0xf3, 0xf8, 0xc1, 0x97, 0x77, 0xbb, 0xdb, 0xfb, 0x8f, 0x0e, 0x77, 0x5b, 0x17, 0x10, + 0xde, 0x7f, 0xb4, 0x7d, 0x67, 0xbf, 0x7b, 0xef, 0x91, 0xb7, 0xad, 0x60, 0x07, 0x6d, 0xbc, 0xb7, + 0xfb, 0xd1, 0xa3, 0xc7, 0xbb, 0x16, 0x5e, 0x61, 0x2d, 0x68, 0xde, 0xf5, 0x76, 0xef, 0x6c, 0xef, + 0x49, 0xa4, 0xca, 0xd6, 0xa1, 0x75, 0xef, 0xc9, 0xc3, 0x9d, 0x07, 0x0f, 0xef, 0x77, 0xb7, 0xef, + 0x3c, 0xdc, 0xde, 0xdd, 0xdf, 0xdd, 0x69, 0xd5, 0xdc, 0xbf, 0x73, 0xe0, 0x22, 0x8d, 0xb2, 0x9f, + 0x17, 0x88, 0xab, 0xd0, 0xe8, 0x45, 0xd1, 0x98, 0xa3, 0xfe, 0xd6, 0x2a, 0xda, 0x84, 0x90, 0xd9, + 0x85, 0x42, 0x3c, 0x8e, 0xe2, 0x1e, 0x97, 0xf2, 0x00, 0x04, 0xdd, 0x43, 0x04, 0x99, 0x5d, 0x6e, + 0xa7, 0xa0, 0x10, 0xe2, 0xd0, 0x10, 0x98, 0x20, 0xd9, 0x80, 0xf9, 0xa3, 0x98, 0xfb, 0xbd, 0x13, + 0x29, 0x09, 0xb2, 0xc4, 0x3e, 0x99, 0x39, 0xe4, 0x3d, 0x5c, 0xed, 0x21, 0xef, 0x13, 0x87, 0x2c, + 0x7a, 0x2b, 0x12, 0xdf, 0x96, 0xb0, 0x7b, 0x00, 0x1b, 0xf9, 0x19, 0x48, 0x89, 0x79, 0xcf, 0x90, + 0x18, 0xe1, 0x1b, 0x77, 0x66, 0xef, 0x8f, 0x21, 0x3d, 0xff, 0xee, 0x40, 0x0d, 0xcd, 0xe7, 0x6c, + 0x53, 0x6b, 0x7a, 0x44, 0x55, 0xcb, 0x23, 0xa2, 0xe0, 0x01, 0x9e, 0x29, 0x84, 0x42, 0x15, 0x46, + 0xc7, 0x40, 0xb2, 0xfa, 0x98, 0xf7, 0x4e, 0x69, 0x4e, 0xba, 0x1e, 0x11, 0x64, 0x79, 0x74, 0x3c, + 0xe9, 0x6b, 0xc9, 0xf2, 0xaa, 0xac, 0xea, 0xe8, 0xcb, 0x85, 0xac, 0x8e, 0xbe, 0x6b, 0xc3, 0x42, + 0x10, 0x1e, 0x45, 0x93, 0xb0, 0x4f, 0x2c, 0xbe, 0xe8, 0xa9, 0x22, 0xaa, 0xca, 0x31, 0x89, 0x5e, + 0x30, 0x52, 0x0c, 0x9d, 0x01, 0x2e, 0xc3, 0x83, 0x49, 0x42, 0xee, 0x82, 0xf6, 0x02, 0xdf, 0x83, + 0x55, 0x03, 0x93, 0xab, 0xf9, 0x16, 0xcc, 0x8d, 0x11, 0x90, 0x4b, 0xa9, 0x94, 0x33, 0xf9, 0x19, + 0xa2, 0xc6, 0x6d, 0xc1, 0xf2, 0x7d, 0x9e, 0x3e, 0x08, 0x8f, 0x23, 0xd5, 0xd2, 0x8f, 0xab, 0xb0, + 0xa2, 0x21, 0xd9, 0xd0, 0x0d, 0x58, 0x09, 0xfa, 0x3c, 0x4c, 0x83, 0x74, 0xda, 0xb5, 0xce, 0x3f, + 0x79, 0x18, 0xfd, 0x33, 0x7f, 0x18, 0xf8, 0x89, 0xf4, 0x00, 0x44, 0x81, 0x6d, 0xc1, 0x3a, 0x1a, + 0x0f, 0x65, 0x0f, 0xf4, 0x16, 0x8b, 0x63, 0x58, 0x69, 0x1d, 0x8a, 0x37, 0xe2, 0x52, 0x7f, 0xeb, + 0x4f, 0x84, 0x9f, 0x52, 0x56, 0x85, 0xab, 0x26, 0x5a, 0xc2, 0x29, 0xcf, 0x09, 0x03, 0xa3, 0x81, + 0x42, 0x08, 0x68, 0x5e, 0x28, 0x9f, 0x7c, 0x08, 0xc8, 0x08, 0x23, 0x2d, 0x16, 0xc2, 0x48, 0xa8, + 0x9c, 0xa6, 0x61, 0x8f, 0xf7, 0xbb, 0x69, 0xd4, 0x25, 0x25, 0x4a, 0xbb, 0xb3, 0xe8, 0xe5, 0x61, + 0x0a, 0x78, 0xf1, 0x24, 0x0d, 0x79, 0x4a, 0x7a, 0x66, 0xd1, 0x53, 0x45, 0x94, 0x1f, 0x22, 0x11, + 0x26, 0xa1, 0xee, 0xc9, 0x12, 0x3a, 0x9a, 0x93, 0x38, 0x48, 0xda, 0x4d, 0x42, 0xe9, 0x37, 0xfb, + 0x34, 0x5c, 0x3c, 0xe2, 0x49, 0xda, 0x3d, 0xe1, 0x7e, 0x9f, 0xc7, 0xb4, 0xfb, 0x22, 0x3a, 0x25, + 0xec, 0x77, 0x79, 0x25, 0xf6, 0x7d, 0xca, 0xe3, 0x24, 0x88, 0x42, 0xb2, 0xdc, 0x75, 0x4f, 0x15, + 0xdd, 0x6f, 0x92, 0x3f, 0xac, 0xe3, 0x66, 0x4f, 0xc8, 0x98, 0xb3, 0xd7, 0xa0, 0x2e, 0xe6, 0x98, + 0x9c, 0xf8, 0xd2, 0x45, 0x5f, 0x24, 0xe0, 0xf0, 0xc4, 0x47, 0x8d, 0x60, 0x2d, 0x9b, 0x08, 0x44, + 0x36, 0x08, 0xdb, 0x13, 0xab, 0x76, 0x0d, 0x96, 0x55, 0x44, 0x2e, 0xe9, 0x0e, 0xf9, 0x71, 0xaa, + 0x8e, 0xd7, 0xe1, 0x64, 0x84, 0xdd, 0x25, 0xfb, 0xfc, 0x38, 0x75, 0x1f, 0xc2, 0xaa, 0x94, 0xe1, + 0x47, 0x63, 0xae, 0xba, 0xfe, 0x6c, 0x99, 0x75, 0x6b, 0x6c, 0xad, 0xd9, 0x42, 0x4f, 0x31, 0x82, + 0x9c, 0xc9, 0x73, 0x3d, 0x60, 0xa6, 0x4e, 0x90, 0x0d, 0x4a, 0x13, 0xa3, 0x0e, 0xf1, 0x72, 0x3a, + 0x16, 0x86, 0xeb, 0x93, 0x4c, 0x7a, 0x3d, 0xd4, 0x04, 0x42, 0x03, 0xaa, 0xa2, 0xfb, 0x7d, 0x07, + 0xd6, 0xa8, 0x35, 0x65, 0x9f, 0xf5, 0xc9, 0xef, 0xd5, 0x87, 0xd9, 0xec, 0x99, 0x81, 0x8d, 0x75, + 0x98, 0x33, 0x75, 0xad, 0x28, 0xfc, 0xe4, 0x67, 0xd9, 0x5a, 0xe1, 0x2c, 0xfb, 0x63, 0x07, 0x56, + 0x85, 0x32, 0x4c, 0xfd, 0x74, 0x92, 0xc8, 0xe9, 0xff, 0x32, 0x2c, 0x09, 0x3b, 0x25, 0xc5, 0x49, + 0x0e, 0x74, 0x5d, 0x4b, 0x3e, 0xa1, 0x82, 0x78, 0xef, 0x82, 0x67, 0x13, 0xb3, 0xcf, 0x43, 0xd3, + 0x0c, 0xab, 0xd2, 0x98, 0x1b, 0x5b, 0x97, 0xd5, 0x2c, 0x0b, 0x9c, 0xb3, 0x77, 0xc1, 0xb3, 0x3e, + 0x60, 0x1f, 0x92, 0xb3, 0x11, 0x76, 0xa9, 0x59, 0x19, 0x98, 0xba, 0x5c, 0xa2, 0xc0, 0xf5, 0xe7, + 0x06, 0xf9, 0xdd, 0x45, 0x98, 0x17, 0xde, 0xa5, 0x7b, 0x1f, 0x96, 0xac, 0x91, 0x5a, 0x67, 0xf4, + 0xa6, 0x38, 0xa3, 0x17, 0x42, 0x3a, 0x95, 0x62, 0x48, 0xc7, 0xfd, 0x76, 0x15, 0x18, 0x72, 0x5b, + 0x6e, 0x3b, 0xd1, 0xbd, 0x8d, 0xfa, 0xd6, 0x61, 0xa5, 0xe9, 0x99, 0x10, 0xbb, 0x09, 0xcc, 0x28, + 0xaa, 0xa8, 0x97, 0xb0, 0x1b, 0x25, 0x35, 0xa8, 0xe0, 0xa4, 0x61, 0x95, 0x26, 0x50, 0x1e, 0xcb, + 0xc4, 0xbe, 0x95, 0xd6, 0xa1, 0x69, 0x18, 0x4f, 0x92, 0x13, 0x74, 0xbf, 0xd5, 0x71, 0x46, 0x95, + 0xf3, 0x0c, 0x32, 0x7f, 0x2e, 0x83, 0x2c, 0xe4, 0x19, 0xc4, 0x74, 0xa8, 0x17, 0x2d, 0x87, 0x1a, + 0x1d, 0xb9, 0x11, 0xba, 0x7f, 0xe9, 0xb0, 0xd7, 0x1d, 0x61, 0xef, 0xf2, 0xf4, 0x62, 0x81, 0x6c, + 0x13, 0x5a, 0xd2, 0x15, 0xc8, 0xbc, 0x76, 0xa0, 0x35, 0x2e, 0xe0, 0xa8, 0x79, 0xf1, 0x63, 0xd2, + 0x00, 0x74, 0x82, 0x99, 0xf3, 0x32, 0xc0, 0xfd, 0x91, 0x03, 0x2d, 0xdc, 0x05, 0x8b, 0x53, 0x3f, + 0x00, 0x12, 0x94, 0x57, 0x64, 0x54, 0x8b, 0xf6, 0x67, 0xe7, 0xd3, 0xf7, 0xa1, 0x4e, 0x0d, 0x46, + 0x63, 0x1e, 0x4a, 0x36, 0x6d, 0xdb, 0x6c, 0x9a, 0xe9, 0xa8, 0xbd, 0x0b, 0x5e, 0x46, 0x6c, 0x30, + 0xe9, 0x3f, 0x39, 0xd0, 0x90, 0xc3, 0xfc, 0xa9, 0xcf, 0xe9, 0x1d, 0x58, 0x44, 0x7e, 0x35, 0x0e, + 0xc3, 0xba, 0x8c, 0xb6, 0x66, 0xe4, 0xa7, 0x93, 0x18, 0x8d, 0xab, 0x75, 0x46, 0xcf, 0xc3, 0x68, + 0x29, 0x49, 0x1d, 0x27, 0xdd, 0x34, 0x18, 0x76, 0x55, 0xad, 0xbc, 0xe3, 0x28, 0xab, 0x42, 0xad, + 0x94, 0xa4, 0xfe, 0x80, 0x4b, 0x23, 0x28, 0x0a, 0x6e, 0x1b, 0x36, 0xe4, 0x84, 0x72, 0x9e, 0xa5, + 0xfb, 0xb7, 0x4d, 0xb8, 0x54, 0xa8, 0xd2, 0x97, 0x84, 0xf2, 0xf0, 0x39, 0x0c, 0x46, 0x47, 0x91, + 0x76, 0xc3, 0x1d, 0xf3, 0x5c, 0x6a, 0x55, 0xb1, 0x01, 0x5c, 0x54, 0xd6, 0x1e, 0xd7, 0x34, 0xb3, + 0xed, 0x15, 0x72, 0x53, 0xde, 0xb5, 0x79, 0x20, 0xdf, 0xa1, 0xc2, 0x4d, 0xb9, 0x2e, 0x6f, 0x8f, + 0x9d, 0x40, 0x5b, 0xbb, 0x15, 0xd2, 0x00, 0x18, 0xae, 0x07, 0xf6, 0xf5, 0xce, 0x39, 0x7d, 0x59, + 0x6e, 0xaa, 0x37, 0xb3, 0x35, 0x36, 0x85, 0x2b, 0xaa, 0x8e, 0x34, 0x7c, 0xb1, 0xbf, 0xda, 0x2b, + 0xcd, 0x8d, 0x5c, 0x6c, 0xbb, 0xd3, 0x73, 0x1a, 0x66, 0x5f, 0x87, 0x8d, 0x33, 0x3f, 0x48, 0xd5, + 0xb0, 0x0c, 0x57, 0x69, 0x8e, 0xba, 0xdc, 0x3a, 0xa7, 0xcb, 0xa7, 0xe2, 0x63, 0xcb, 0xec, 0xcd, + 0x68, 0xb1, 0xf3, 0x0f, 0x0e, 0x2c, 0xdb, 0xed, 0x20, 0x9b, 0x4a, 0x75, 0xa0, 0xd4, 0xa2, 0x72, + 0x0d, 0x73, 0x70, 0xf1, 0x24, 0x5b, 0x29, 0x3b, 0xc9, 0x9a, 0xe7, 0xc7, 0xea, 0x79, 0x41, 0x9e, + 0xda, 0xab, 0x05, 0x79, 0xe6, 0xca, 0x82, 0x3c, 0x9d, 0xff, 0x76, 0x80, 0x15, 0x79, 0x89, 0xdd, + 0x17, 0x47, 0xe9, 0x90, 0x0f, 0xa5, 0x4e, 0xfa, 0xc5, 0x57, 0xe3, 0x47, 0xb5, 0x76, 0xea, 0x6b, + 0x14, 0x0c, 0x53, 0xe9, 0x98, 0x0e, 0xd4, 0x92, 0x57, 0x56, 0x95, 0x0b, 0x3b, 0xd5, 0xce, 0x0f, + 0x3b, 0xcd, 0x9d, 0x1f, 0x76, 0x9a, 0xcf, 0x87, 0x9d, 0x3a, 0xbf, 0xeb, 0xc0, 0x5a, 0xc9, 0xa6, + 0xff, 0xfc, 0x26, 0x8e, 0xdb, 0x64, 0xe9, 0x82, 0x8a, 0xdc, 0x26, 0x13, 0xec, 0xfc, 0x16, 0x2c, + 0x59, 0x8c, 0xfe, 0xf3, 0xeb, 0x3f, 0xef, 0x03, 0x0a, 0x3e, 0xb3, 0xb0, 0xce, 0x7f, 0x54, 0x80, + 0x15, 0x85, 0xed, 0xff, 0x75, 0x0c, 0xc5, 0x75, 0xaa, 0x96, 0xac, 0xd3, 0xff, 0xa9, 0x1d, 0x78, + 0x07, 0x56, 0x65, 0x46, 0x81, 0x11, 0x40, 0x11, 0x1c, 0x53, 0xac, 0x40, 0x2f, 0xd8, 0x8e, 0xf9, + 0x2d, 0x5a, 0x37, 0xd1, 0x86, 0x31, 0xcc, 0x85, 0xfe, 0xdc, 0x0d, 0x58, 0x17, 0x19, 0x0a, 0x77, + 0x45, 0x53, 0xca, 0xae, 0xfc, 0xa9, 0x03, 0x17, 0x73, 0x15, 0xd9, 0xbd, 0xa9, 0x30, 0x1d, 0xb6, + 0x3d, 0xb1, 0x41, 0x1c, 0xbf, 0x94, 0x23, 0x63, 0xfc, 0x82, 0xdb, 0x8a, 0x15, 0xb8, 0x3e, 0x93, + 0xb0, 0x48, 0x2f, 0x56, 0xbd, 0xac, 0xca, 0xbd, 0x24, 0xf2, 0x28, 0x42, 0x3e, 0xcc, 0x0d, 0xfc, + 0x58, 0x64, 0x3e, 0x98, 0x15, 0xd9, 0xc5, 0x8b, 0x3d, 0x64, 0x55, 0x44, 0x1f, 0xd1, 0x32, 0x53, + 0xf6, 0x78, 0x4b, 0xeb, 0xdc, 0xbf, 0x76, 0x80, 0x7d, 0x69, 0xc2, 0xe3, 0x29, 0xdd, 0x9f, 0xea, + 0x48, 0xcf, 0xa5, 0x7c, 0x94, 0x63, 0x7e, 0x3c, 0x39, 0xfa, 0x22, 0x9f, 0xaa, 0x5b, 0xf6, 0x4a, + 0x76, 0xcb, 0xfe, 0x06, 0x00, 0x1e, 0xce, 0xf4, 0xa5, 0x2c, 0xf9, 0x66, 0xe1, 0x64, 0x24, 0x1a, + 0x2c, 0xbd, 0x08, 0xaf, 0x9d, 0x7f, 0x11, 0x3e, 0x77, 0xde, 0x45, 0xf8, 0x87, 0xb0, 0x66, 0x8d, + 0x5b, 0x6f, 0xab, 0xba, 0x1e, 0x76, 0x5e, 0x72, 0x3d, 0xfc, 0x9f, 0x0e, 0x54, 0xf7, 0xa2, 0xb1, + 0x19, 0xd5, 0x74, 0xec, 0xa8, 0xa6, 0xb4, 0x25, 0x5d, 0x6d, 0x2a, 0xa4, 0x8a, 0xb1, 0x40, 0xb6, + 0x09, 0xcb, 0xfe, 0x28, 0xc5, 0x43, 0xf9, 0x71, 0x14, 0x9f, 0xf9, 0x71, 0x5f, 0xec, 0xf5, 0xdd, + 0x4a, 0xdb, 0xf1, 0x72, 0x35, 0x6c, 0x1d, 0xaa, 0x5a, 0xe9, 0x12, 0x01, 0x16, 0xd1, 0x71, 0xa3, + 0x1b, 0x91, 0xa9, 0x8c, 0x27, 0xc8, 0x12, 0xb2, 0x92, 0xfd, 0xbd, 0x70, 0xa4, 0x85, 0xe8, 0x94, + 0x55, 0xa1, 0x5d, 0xc3, 0xe5, 0x23, 0x32, 0x19, 0x08, 0x52, 0x65, 0xf7, 0xdf, 0x1c, 0x98, 0xa3, + 0x15, 0x40, 0x61, 0x17, 0x1c, 0xae, 0xc3, 0x97, 0x34, 0xf3, 0x25, 0x2f, 0x0f, 0x33, 0xd7, 0xca, + 0x46, 0xa9, 0xe8, 0x61, 0x9b, 0x19, 0x29, 0x57, 0xa1, 0x2e, 0x4a, 0x3a, 0xf3, 0x82, 0x48, 0x32, + 0x90, 0x5d, 0x81, 0xda, 0x49, 0x34, 0x56, 0xde, 0x09, 0xa8, 0xe8, 0x7d, 0x34, 0xf6, 0x08, 0xcf, + 0xc6, 0x83, 0xed, 0x89, 0xc1, 0x0b, 0x9b, 0x93, 0x87, 0xd1, 0xea, 0xea, 0x66, 0xcd, 0xc5, 0xc8, + 0xa1, 0xee, 0x26, 0xac, 0x3c, 0x8c, 0xfa, 0xdc, 0x88, 0x38, 0xcd, 0xe4, 0x66, 0xf7, 0x5b, 0x0e, + 0x2c, 0x2a, 0x62, 0x76, 0x03, 0x6a, 0xe8, 0x4a, 0xe4, 0x0e, 0x0a, 0xfa, 0xd6, 0x0e, 0xe9, 0x3c, + 0xa2, 0x40, 0xdd, 0x4b, 0xf1, 0x88, 0xcc, 0xad, 0x54, 0xd1, 0x88, 0xcc, 0x6b, 0xd2, 0xc3, 0xcd, + 0x39, 0x1b, 0x39, 0xd4, 0xfd, 0x4b, 0x07, 0x96, 0xac, 0x3e, 0xf0, 0xf0, 0x38, 0xf4, 0x93, 0x54, + 0xde, 0x84, 0xc8, 0xed, 0x31, 0x21, 0x33, 0x06, 0x59, 0xb1, 0x63, 0x90, 0x3a, 0x3a, 0x56, 0x35, + 0xa3, 0x63, 0xb7, 0xa1, 0x9e, 0xe5, 0x0c, 0xd5, 0x2c, 0x9d, 0x8a, 0x3d, 0xaa, 0xfb, 0xc8, 0x8c, + 0x08, 0xdb, 0xe9, 0x45, 0xc3, 0x28, 0x96, 0x21, 0x78, 0x51, 0x70, 0x3f, 0x84, 0x86, 0x41, 0x8f, + 0xc3, 0x08, 0x79, 0x7a, 0x16, 0xc5, 0xcf, 0x54, 0x28, 0x54, 0x16, 0xf5, 0xb5, 0x7b, 0x25, 0xbb, + 0x76, 0x77, 0x7f, 0xe8, 0xc0, 0x12, 0xf2, 0x60, 0x10, 0x0e, 0x0e, 0xa2, 0x61, 0xd0, 0x9b, 0xd2, + 0xde, 0x2b, 0x76, 0x93, 0x9a, 0x41, 0xf1, 0xa2, 0x0d, 0x23, 0x6f, 0xab, 0xb3, 0xa3, 0x14, 0x44, + 0x5d, 0x46, 0x49, 0x45, 0x3e, 0x3f, 0xf2, 0x13, 0xc9, 0xfc, 0xd2, 0xc8, 0x59, 0x20, 0xca, 0x13, + 0x02, 0xb1, 0x9f, 0xf2, 0xee, 0x28, 0x18, 0x0e, 0x03, 0x41, 0x2b, 0x5c, 0xa0, 0xb2, 0x2a, 0xec, + 0xb3, 0x1f, 0x24, 0xfe, 0x51, 0x16, 0x66, 0xd6, 0x65, 0xf7, 0x07, 0x15, 0x68, 0x48, 0xf5, 0xbc, + 0xdb, 0x1f, 0x70, 0x79, 0x07, 0x42, 0x4e, 0xa6, 0x56, 0x25, 0x06, 0xa2, 0xea, 0x2d, 0xb7, 0xd4, + 0x40, 0xf2, 0x5b, 0x5e, 0x2d, 0x6e, 0xf9, 0xeb, 0x50, 0x47, 0xd6, 0x7b, 0x97, 0xfc, 0x5f, 0x71, + 0x7f, 0x92, 0x01, 0xaa, 0x76, 0x8b, 0x6a, 0xe7, 0xb2, 0x5a, 0x02, 0x5e, 0x7a, 0x63, 0xf2, 0x3e, + 0x34, 0x65, 0x33, 0xb4, 0x27, 0xa4, 0x39, 0x32, 0xe6, 0xb7, 0xf6, 0xcb, 0xb3, 0x28, 0xd5, 0x97, + 0x5b, 0xea, 0xcb, 0xc5, 0xf3, 0xbe, 0x54, 0x94, 0x74, 0xbb, 0x2d, 0xd6, 0xe6, 0x7e, 0xec, 0x8f, + 0x4f, 0x94, 0xc9, 0xeb, 0xeb, 0x94, 0x1d, 0x82, 0xd9, 0x26, 0xcc, 0xe1, 0x67, 0x4a, 0x93, 0x97, + 0x0b, 0xa4, 0x20, 0x61, 0x37, 0x60, 0x8e, 0xf7, 0x07, 0x5c, 0x9d, 0xf0, 0x98, 0x7d, 0xd6, 0xc6, + 0x3d, 0xf2, 0x04, 0x01, 0xaa, 0x07, 0x44, 0x73, 0xea, 0xc1, 0xb6, 0x02, 0xf3, 0x58, 0x7c, 0xd0, + 0x77, 0xd7, 0x81, 0x3d, 0x14, 0x1c, 0x6d, 0xc6, 0xaf, 0xbf, 0x5d, 0x85, 0x86, 0x01, 0xa3, 0xa4, + 0x0f, 0x70, 0xc0, 0xdd, 0x7e, 0xe0, 0x8f, 0x78, 0xca, 0x63, 0xc9, 0xc5, 0x39, 0x14, 0xe9, 0xfc, + 0xd3, 0x41, 0x37, 0x9a, 0xa4, 0xdd, 0x3e, 0x1f, 0xc4, 0x5c, 0x18, 0x66, 0x34, 0x14, 0x16, 0x8a, + 0x74, 0x23, 0xff, 0xb9, 0x49, 0x27, 0xf8, 0x21, 0x87, 0xaa, 0x68, 0xb4, 0x58, 0xa3, 0x5a, 0x16, + 0x8d, 0x16, 0x2b, 0x92, 0xd7, 0x51, 0x73, 0x25, 0x3a, 0xea, 0x3d, 0xd8, 0x10, 0xda, 0x48, 0xca, + 0x6d, 0x37, 0xc7, 0x26, 0x33, 0x6a, 0xd9, 0x26, 0xb4, 0x70, 0xcc, 0x8a, 0xc1, 0x93, 0xe0, 0x9b, + 0x22, 0x3e, 0xe4, 0x78, 0x05, 0x1c, 0x69, 0x29, 0x50, 0x63, 0xd2, 0x8a, 0xfb, 0xb6, 0x02, 0x4e, + 0xb4, 0xfe, 0x73, 0x9b, 0xb6, 0x2e, 0x69, 0x73, 0xb8, 0xbb, 0x04, 0x8d, 0xc3, 0x34, 0x1a, 0xab, + 0x4d, 0x59, 0x86, 0xa6, 0x28, 0xca, 0xec, 0x86, 0xd7, 0xe0, 0x32, 0x71, 0xd1, 0xe3, 0x68, 0x1c, + 0x0d, 0xa3, 0xc1, 0xf4, 0x70, 0x72, 0x94, 0xf4, 0xe2, 0x60, 0x8c, 0xa7, 0x21, 0xf7, 0x1f, 0x1d, + 0x58, 0xb3, 0x6a, 0x65, 0xc8, 0xe8, 0xd3, 0x82, 0xa5, 0xf5, 0xb5, 0xb4, 0x60, 0xbc, 0x55, 0x43, + 0x55, 0x0a, 0x42, 0x11, 0xca, 0x7b, 0x22, 0x6f, 0xaa, 0xef, 0xc0, 0x8a, 0x1a, 0x99, 0xfa, 0x50, + 0x70, 0x61, 0xbb, 0xc8, 0x85, 0xf2, 0xfb, 0x65, 0xf9, 0x81, 0x6a, 0xe2, 0x57, 0xe4, 0xbd, 0x65, + 0x9f, 0xe6, 0xa8, 0x62, 0x07, 0xfa, 0x66, 0xca, 0x3c, 0x41, 0xa8, 0x11, 0xf4, 0x34, 0x98, 0xb8, + 0xbf, 0xef, 0x00, 0x64, 0xa3, 0x43, 0xc6, 0xc8, 0xd4, 0xbd, 0x48, 0xa5, 0x36, 0x54, 0xfb, 0x5b, + 0xd0, 0xd4, 0x77, 0x2a, 0x99, 0x05, 0x69, 0x28, 0x0c, 0x9d, 0xbc, 0xeb, 0xb0, 0x32, 0x18, 0x46, + 0x47, 0x64, 0x7e, 0x29, 0x5d, 0x26, 0x91, 0x39, 0x1e, 0xcb, 0x02, 0xbe, 0x27, 0xd1, 0xcc, 0xdc, + 0xd4, 0x0c, 0x73, 0xe3, 0x7e, 0xa7, 0xa2, 0x23, 0xf1, 0xd9, 0x9c, 0x67, 0x4a, 0x19, 0xdb, 0x2a, + 0x28, 0xc7, 0x19, 0x81, 0x6f, 0x8a, 0x92, 0x1d, 0x9c, 0x7b, 0x88, 0xff, 0x10, 0x96, 0x63, 0xa1, + 0x7d, 0x94, 0x6a, 0xaa, 0xbd, 0x44, 0x35, 0x2d, 0xc5, 0x96, 0x4d, 0xfa, 0x24, 0xb4, 0xfc, 0xfe, + 0x29, 0x8f, 0xd3, 0x80, 0x8e, 0x51, 0xe4, 0x10, 0x08, 0x85, 0xba, 0x62, 0xe0, 0x64, 0xa7, 0xaf, + 0xc3, 0x8a, 0xcc, 0xab, 0xd1, 0x94, 0x32, 0x17, 0x34, 0x83, 0x91, 0xd0, 0xfd, 0x73, 0x15, 0xf4, + 0xb7, 0xf7, 0x70, 0xf6, 0x8a, 0x98, 0xb3, 0xab, 0xe4, 0x66, 0xf7, 0x09, 0x19, 0x80, 0xef, 0xab, + 0xb3, 0x5a, 0xd5, 0xb8, 0xe3, 0xee, 0xcb, 0x0b, 0x13, 0x7b, 0x49, 0x6b, 0xaf, 0xb2, 0xa4, 0xee, + 0x8f, 0x1c, 0x58, 0xd8, 0x8b, 0xc6, 0x7b, 0xf2, 0xb6, 0x9f, 0x04, 0x41, 0x67, 0xad, 0xa9, 0xe2, + 0x4b, 0xf2, 0x00, 0x4a, 0xed, 0xf0, 0x52, 0xde, 0x0e, 0xff, 0x2a, 0xbc, 0x46, 0x91, 0x82, 0x38, + 0x1a, 0x47, 0x31, 0x0a, 0xa3, 0x3f, 0x14, 0x46, 0x37, 0x0a, 0xd3, 0x13, 0xa5, 0xc6, 0x5e, 0x46, + 0x42, 0x47, 0x32, 0x3c, 0x4a, 0x08, 0x47, 0x59, 0xfa, 0x0d, 0x42, 0xbb, 0x15, 0x2b, 0xdc, 0xcf, + 0x42, 0x9d, 0x1c, 0x5f, 0x9a, 0xd6, 0x3b, 0x50, 0x3f, 0x89, 0xc6, 0xdd, 0x93, 0x20, 0x4c, 0x95, + 0x70, 0x2f, 0x67, 0x1e, 0xe9, 0x1e, 0x2d, 0x88, 0x26, 0x70, 0x7f, 0x58, 0x83, 0x85, 0x07, 0xe1, + 0x69, 0x14, 0xf4, 0xe8, 0x7e, 0x60, 0xc4, 0x47, 0x91, 0xca, 0xe1, 0xc3, 0xdf, 0xb8, 0x14, 0x94, + 0xcf, 0x32, 0x4e, 0x65, 0x80, 0x5f, 0x15, 0xd1, 0xdc, 0xc7, 0x59, 0x9e, 0xad, 0x10, 0x1d, 0x03, + 0x41, 0xa7, 0x3f, 0x36, 0x53, 0x92, 0x65, 0x29, 0x4b, 0x82, 0x9c, 0x33, 0x92, 0x20, 0xe9, 0x36, + 0x49, 0x64, 0x26, 0x10, 0x7f, 0x2d, 0x7a, 0xaa, 0x48, 0x87, 0x94, 0x98, 0x8b, 0x08, 0x0f, 0x39, + 0x0e, 0x0b, 0xf2, 0x90, 0x62, 0x82, 0xe8, 0x5c, 0x88, 0x0f, 0x04, 0x8d, 0x50, 0xbe, 0x26, 0x84, + 0x8e, 0x58, 0x3e, 0xab, 0xb9, 0x2e, 0x78, 0x3e, 0x07, 0xa3, 0x86, 0xee, 0x73, 0xad, 0x48, 0xc5, + 0x1c, 0x40, 0xe4, 0x11, 0xe7, 0x71, 0xe3, 0x68, 0x23, 0x52, 0x8e, 0xd4, 0xd1, 0x06, 0x19, 0xc5, + 0x1f, 0x0e, 0x8f, 0xfc, 0xde, 0x33, 0x4a, 0x5a, 0xa7, 0x0c, 0xa3, 0xba, 0x67, 0x83, 0x94, 0x6b, + 0x90, 0xed, 0x26, 0xdd, 0x47, 0xd6, 0x3c, 0x13, 0x62, 0x5b, 0xd0, 0xa0, 0xe3, 0x9c, 0xdc, 0xcf, + 0x65, 0xda, 0xcf, 0x96, 0x79, 0xde, 0xa3, 0x1d, 0x35, 0x89, 0xcc, 0x3b, 0x8b, 0x15, 0xfb, 0xce, + 0x42, 0x28, 0x4d, 0x79, 0xd5, 0xd3, 0xa2, 0xde, 0x32, 0x00, 0xad, 0xa9, 0x5c, 0x30, 0x41, 0xb0, + 0x4a, 0x04, 0x16, 0x86, 0x52, 0x8b, 0x87, 0x90, 0xb1, 0x1f, 0xf4, 0xdb, 0x4c, 0x48, 0xad, 0x2a, + 0xbb, 0x29, 0xb0, 0x3b, 0xfd, 0xbe, 0xe4, 0x26, 0x7d, 0x58, 0xcd, 0xf8, 0xc0, 0xb1, 0xf8, 0xa0, + 0x64, 0x3f, 0x2a, 0xe5, 0xfb, 0xf1, 0xd2, 0x51, 0xbb, 0xbb, 0xd0, 0x38, 0x30, 0x52, 0xad, 0x89, + 0x2d, 0x55, 0x92, 0xb5, 0x64, 0x65, 0x03, 0x31, 0x86, 0x53, 0x31, 0x87, 0xe3, 0xfe, 0x12, 0xb0, + 0xfd, 0x20, 0x49, 0xf5, 0xe8, 0xb3, 0xdc, 0x6e, 0x15, 0x51, 0xc8, 0xd2, 0xa3, 0x1a, 0x12, 0xa3, + 0xb4, 0xa5, 0x3b, 0x22, 0xaf, 0x2a, 0x3f, 0xed, 0x4d, 0x58, 0x0c, 0x04, 0x94, 0x97, 0x42, 0x45, + 0xa9, 0xeb, 0xdd, 0xa7, 0xb0, 0x26, 0x41, 0xd3, 0x82, 0xdb, 0xf3, 0x76, 0xce, 0xdb, 0xad, 0x4a, + 0x71, 0xb7, 0xdc, 0x1f, 0x38, 0xb0, 0x20, 0x17, 0x07, 0xe9, 0x0b, 0x69, 0xea, 0x75, 0xcf, 0xc2, + 0xca, 0x13, 0x94, 0x8b, 0x12, 0x58, 0x2d, 0x93, 0x40, 0x06, 0xb5, 0xb1, 0x9f, 0x9e, 0xd0, 0xd1, + 0xab, 0xee, 0xd1, 0x6f, 0xd6, 0x12, 0xe1, 0x00, 0x21, 0xe9, 0x14, 0x0a, 0x28, 0xcb, 0xd1, 0x17, + 0x06, 0xa5, 0x80, 0xa3, 0x0b, 0x4d, 0xd9, 0x18, 0x02, 0xd7, 0xd7, 0x28, 0x32, 0x4f, 0x2c, 0x83, + 0xb3, 0x15, 0x97, 0x4d, 0xe4, 0x57, 0x5c, 0x92, 0x7a, 0xba, 0xde, 0xed, 0x40, 0x7b, 0x87, 0x0f, + 0x79, 0xca, 0xef, 0x0c, 0x87, 0xf9, 0xf6, 0x5f, 0x83, 0xcb, 0x25, 0x75, 0xd2, 0xe5, 0xba, 0x07, + 0xab, 0x3b, 0xfc, 0x68, 0x32, 0xd8, 0xe7, 0xa7, 0xd9, 0x4d, 0x28, 0x83, 0x5a, 0x72, 0x12, 0x9d, + 0x49, 0xee, 0xa0, 0xdf, 0xec, 0x0d, 0x80, 0x21, 0xd2, 0x74, 0x93, 0x31, 0xef, 0xa9, 0xd4, 0x5c, + 0x42, 0x0e, 0xc7, 0xbc, 0xe7, 0xbe, 0x07, 0xcc, 0x6c, 0x47, 0x4e, 0x01, 0xb5, 0xd8, 0xe4, 0xa8, + 0x9b, 0x4c, 0x93, 0x94, 0x8f, 0x54, 0xce, 0xb1, 0x09, 0xb9, 0xd7, 0xa1, 0x79, 0xe0, 0x4f, 0x3d, + 0xfe, 0x0d, 0xf9, 0x52, 0x00, 0x4f, 0xfd, 0xfe, 0x14, 0x45, 0x45, 0x9f, 0xfa, 0xa9, 0xda, 0xfd, + 0xaf, 0x0a, 0xcc, 0x0b, 0x4a, 0x6c, 0xb5, 0xcf, 0x93, 0x34, 0x08, 0xc5, 0x3d, 0x9f, 0x6c, 0xd5, + 0x80, 0x0a, 0xbc, 0x51, 0x29, 0xe1, 0x0d, 0xe9, 0x6b, 0xab, 0x34, 0x47, 0xc9, 0x04, 0x16, 0x86, + 0x1c, 0x9b, 0x65, 0x57, 0x88, 0x63, 0x67, 0x06, 0xe4, 0xc2, 0x40, 0x99, 0xae, 0x14, 0xe3, 0x53, + 0x6c, 0x2f, 0xd9, 0xc1, 0x84, 0x4a, 0x35, 0xf2, 0x82, 0xe0, 0x9a, 0x82, 0x46, 0x2e, 0x68, 0xde, + 0xc5, 0x57, 0xd0, 0xbc, 0xc2, 0x01, 0x7f, 0x99, 0xe6, 0x85, 0x57, 0xd0, 0xbc, 0x2e, 0x83, 0xd6, + 0x3d, 0xce, 0x3d, 0x8e, 0x36, 0x5d, 0xb1, 0xd3, 0x77, 0x1d, 0x68, 0x49, 0x77, 0x44, 0xd7, 0xb1, + 0xb7, 0x2c, 0xdf, 0xa5, 0x34, 0x19, 0xf1, 0x1a, 0x2c, 0x91, 0x47, 0xa1, 0xe3, 0x5d, 0x32, 0x38, + 0x67, 0x81, 0x38, 0x0f, 0x75, 0x29, 0x31, 0x0a, 0x86, 0x72, 0x53, 0x4c, 0x48, 0x85, 0xcc, 0xf0, + 0xe4, 0x4f, 0x5b, 0xe2, 0x78, 0xba, 0xec, 0xfe, 0x8d, 0x03, 0xab, 0xc6, 0x80, 0x25, 0x17, 0x7e, + 0x08, 0x2a, 0xfb, 0x42, 0x84, 0xc5, 0x84, 0x30, 0x5d, 0xb2, 0x5d, 0xab, 0xec, 0x33, 0x8b, 0x98, + 0x36, 0xd3, 0x9f, 0xd2, 0x00, 0x93, 0xc9, 0x48, 0x6a, 0x25, 0x13, 0x42, 0x46, 0x3a, 0xe3, 0xfc, + 0x99, 0x26, 0xa9, 0x0a, 0xc5, 0x65, 0x62, 0x74, 0xb9, 0x8e, 0x9e, 0x90, 0x26, 0x12, 0xf9, 0x64, + 0x36, 0xe8, 0xfe, 0xb3, 0x03, 0x6b, 0xc2, 0xa5, 0x95, 0x07, 0x06, 0x9d, 0x29, 0x3e, 0x2f, 0x7c, + 0x78, 0x21, 0x91, 0x7b, 0x17, 0x3c, 0x59, 0x66, 0x9f, 0x79, 0x45, 0x37, 0x5c, 0x27, 0x55, 0xcc, + 0xd8, 0x8b, 0x6a, 0xd9, 0x5e, 0xbc, 0x64, 0xa5, 0xcb, 0xc2, 0x40, 0x73, 0xa5, 0x61, 0xa0, 0xbb, + 0x0b, 0x30, 0x97, 0xf4, 0xa2, 0x31, 0x77, 0x37, 0x60, 0xdd, 0x9e, 0x9c, 0x54, 0x41, 0xdf, 0x73, + 0xa0, 0x7d, 0x4f, 0x04, 0x45, 0x83, 0x70, 0xb0, 0x17, 0x24, 0x69, 0x14, 0xeb, 0xa7, 0x31, 0x57, + 0x00, 0x92, 0xd4, 0x8f, 0x53, 0x91, 0xf4, 0x26, 0x83, 0x34, 0x19, 0x82, 0x63, 0xe4, 0x61, 0x5f, + 0xd4, 0x8a, 0xbd, 0xd1, 0x65, 0xdc, 0x18, 0x32, 0x1b, 0xdd, 0xe8, 0xf8, 0x38, 0xe1, 0xda, 0xe9, + 0x36, 0x31, 0x3c, 0xb7, 0xa3, 0xc4, 0xe3, 0x49, 0x95, 0x9f, 0x92, 0xaa, 0x15, 0xde, 0x6c, 0x0e, + 0x75, 0xff, 0xca, 0x81, 0x95, 0x6c, 0x90, 0xbb, 0x08, 0xda, 0xda, 0x41, 0xda, 0xb3, 0x4c, 0x3b, + 0xa8, 0xf0, 0x51, 0x80, 0x06, 0x4e, 0x8e, 0xcd, 0x40, 0x48, 0x62, 0x65, 0x29, 0x9a, 0xa8, 0x04, + 0x43, 0x13, 0x12, 0xf9, 0x01, 0x29, 0x7e, 0x2d, 0xb2, 0x0b, 0x65, 0x89, 0x72, 0x16, 0x47, 0x29, + 0x7d, 0x35, 0x2f, 0xdc, 0x79, 0x59, 0x54, 0xf6, 0x69, 0x81, 0x50, 0xfc, 0xe9, 0xfe, 0x81, 0x03, + 0x97, 0x4b, 0x16, 0x57, 0x4a, 0xc6, 0x0e, 0xac, 0x1e, 0xeb, 0x4a, 0xb5, 0x00, 0x42, 0x3c, 0x36, + 0x54, 0x14, 0xdf, 0x9e, 0xb4, 0x57, 0xfc, 0x00, 0x9d, 0x7b, 0x8a, 0x7a, 0x89, 0x25, 0xb5, 0x12, + 0x6f, 0x8a, 0x15, 0x5b, 0x7f, 0x58, 0x85, 0x65, 0x71, 0xbb, 0x23, 0x1e, 0xa9, 0xf2, 0x98, 0x7d, + 0x04, 0x0b, 0xf2, 0x91, 0x31, 0xbb, 0x28, 0xbb, 0xb5, 0x9f, 0x35, 0x77, 0x36, 0xf2, 0xb0, 0xe4, + 0x9d, 0xb5, 0xdf, 0xf9, 0xd1, 0xbf, 0xfe, 0x51, 0x65, 0x89, 0x35, 0x6e, 0x9d, 0xbe, 0x7b, 0x6b, + 0xc0, 0xc3, 0x04, 0xdb, 0xf8, 0x0d, 0x80, 0xec, 0xf9, 0x2d, 0x6b, 0x6b, 0x37, 0x25, 0xf7, 0xae, + 0xb8, 0x73, 0xb9, 0xa4, 0x46, 0xb6, 0x7b, 0x99, 0xda, 0x5d, 0x73, 0x97, 0xb1, 0xdd, 0x20, 0x0c, + 0x52, 0xf1, 0x16, 0xf7, 0x03, 0x67, 0x93, 0xf5, 0xa1, 0x69, 0xbe, 0xae, 0x65, 0xea, 0xc0, 0x5f, + 0xf2, 0xb6, 0xb7, 0xf3, 0x5a, 0x69, 0x9d, 0x8a, 0x76, 0x50, 0x1f, 0x17, 0xdd, 0x16, 0xf6, 0x31, + 0x21, 0x8a, 0xac, 0x97, 0x21, 0x2c, 0xdb, 0x8f, 0x68, 0xd9, 0xeb, 0x86, 0x58, 0x17, 0x9e, 0xf0, + 0x76, 0xde, 0x98, 0x51, 0x2b, 0xfb, 0x7a, 0x83, 0xfa, 0xba, 0xe4, 0x32, 0xec, 0xab, 0x47, 0x34, + 0xea, 0x09, 0xef, 0x07, 0xce, 0xe6, 0xd6, 0xb7, 0xae, 0x40, 0x5d, 0x87, 0xe8, 0xd8, 0xd7, 0x61, + 0xc9, 0xba, 0x7e, 0x63, 0x6a, 0x1a, 0x65, 0xb7, 0x75, 0x9d, 0xd7, 0xcb, 0x2b, 0x65, 0xc7, 0x57, + 0xa8, 0xe3, 0x36, 0xdb, 0xc0, 0x8e, 0xe5, 0xfd, 0xd5, 0x2d, 0xba, 0x74, 0x14, 0x19, 0x91, 0xcf, + 0xc4, 0x3c, 0xb3, 0x2b, 0x33, 0x6b, 0x9e, 0x85, 0x2b, 0x36, 0x6b, 0x9e, 0xc5, 0x7b, 0x36, 0xf7, + 0x75, 0xea, 0x6e, 0x83, 0xad, 0x9b, 0xdd, 0xe9, 0xd0, 0x19, 0xa7, 0x1c, 0x56, 0xf3, 0x8d, 0x2d, + 0x7b, 0x43, 0x33, 0x56, 0xd9, 0xdb, 0x5b, 0xcd, 0x22, 0xc5, 0x07, 0xb8, 0x6e, 0x9b, 0xba, 0x62, + 0x8c, 0xb6, 0xcf, 0x7c, 0x62, 0xcb, 0xbe, 0x0a, 0x75, 0xfd, 0xa0, 0x8c, 0x5d, 0x32, 0x5e, 0xf1, + 0x99, 0xaf, 0xdc, 0x3a, 0xed, 0x62, 0x45, 0x19, 0x63, 0x98, 0x2d, 0x23, 0x63, 0xec, 0xc3, 0x45, + 0xe9, 0x54, 0x1f, 0xf1, 0x9f, 0x64, 0x26, 0x25, 0x2f, 0x83, 0x6f, 0x3b, 0xec, 0x43, 0x58, 0x54, + 0xef, 0xf4, 0xd8, 0x46, 0xf9, 0x7b, 0xc3, 0xce, 0xa5, 0x02, 0x2e, 0xb5, 0xc7, 0x1d, 0x80, 0xec, + 0x8d, 0x99, 0x96, 0xb3, 0xc2, 0xcb, 0x37, 0xbd, 0x88, 0x25, 0x0f, 0xd2, 0x06, 0xf4, 0xa2, 0xce, + 0x7e, 0xc2, 0xc6, 0xde, 0xcc, 0xe8, 0x4b, 0x1f, 0xb7, 0xbd, 0xa4, 0x41, 0x77, 0x83, 0xd6, 0xae, + 0xc5, 0x48, 0x70, 0x43, 0x7e, 0xa6, 0xb2, 0xb9, 0x77, 0xa0, 0x61, 0xbc, 0x5b, 0x63, 0xaa, 0x85, + 0xe2, 0x9b, 0xb7, 0x4e, 0xa7, 0xac, 0x4a, 0x0e, 0xf7, 0x0b, 0xb0, 0x64, 0x3d, 0x40, 0xd3, 0x92, + 0x51, 0xf6, 0xbc, 0x4d, 0x4b, 0x46, 0xf9, 0x9b, 0xb5, 0xaf, 0x40, 0xc3, 0x78, 0x2e, 0xc6, 0x8c, + 0x3c, 0xb5, 0xdc, 0x43, 0x31, 0x3d, 0xa2, 0xb2, 0xd7, 0x65, 0xeb, 0x34, 0xdf, 0x65, 0xb7, 0x8e, + 0xf3, 0xa5, 0x94, 0x66, 0x64, 0x92, 0xaf, 0xc3, 0xb2, 0xfd, 0x80, 0x4c, 0x4b, 0x55, 0xe9, 0x53, + 0x34, 0x2d, 0x55, 0x33, 0x5e, 0x9d, 0x49, 0x86, 0xdc, 0x5c, 0xd3, 0x9d, 0xdc, 0xfa, 0x58, 0x5e, + 0x5e, 0xbd, 0x60, 0x5f, 0x42, 0xd5, 0x21, 0x73, 0xcc, 0x59, 0xf6, 0x6c, 0xce, 0xce, 0x44, 0xd7, + 0xdc, 0x5e, 0x48, 0x47, 0x77, 0x57, 0xa9, 0xf1, 0x06, 0xcb, 0x66, 0x20, 0xec, 0x01, 0xe5, 0x9a, + 0x1b, 0xf6, 0xc0, 0x4c, 0x47, 0x37, 0xec, 0x81, 0x95, 0x92, 0x9e, 0xb7, 0x07, 0x69, 0x80, 0x6d, + 0x84, 0xb0, 0x92, 0x4b, 0xd4, 0xd0, 0xc2, 0x52, 0x9e, 0xd9, 0xd6, 0xb9, 0xf2, 0xf2, 0xfc, 0x0e, + 0x5b, 0xcd, 0x28, 0xf5, 0x72, 0x4b, 0x25, 0x22, 0xfe, 0x26, 0x34, 0xcd, 0x87, 0x3f, 0xda, 0x42, + 0x94, 0x3c, 0x57, 0xd2, 0x16, 0xa2, 0xec, 0xa5, 0x90, 0xda, 0x5c, 0xd6, 0x34, 0xbb, 0xc1, 0xcd, + 0xb5, 0xdf, 0x49, 0x64, 0x2a, 0xb3, 0xec, 0x01, 0x48, 0xa6, 0x32, 0x4b, 0x1f, 0x57, 0xa8, 0xcd, + 0x65, 0x6b, 0xd6, 0x5c, 0x44, 0x64, 0x92, 0x7d, 0x05, 0x56, 0x8c, 0x2c, 0xa8, 0xc3, 0x69, 0xd8, + 0xd3, 0x8c, 0x5a, 0xcc, 0xa0, 0xed, 0x94, 0x79, 0x9e, 0xee, 0x25, 0x6a, 0x7f, 0xd5, 0xb5, 0x26, + 0x81, 0x4c, 0xba, 0x0d, 0x0d, 0x33, 0xc3, 0xea, 0x25, 0xed, 0x5e, 0x32, 0xaa, 0xcc, 0x74, 0xd1, + 0xdb, 0x0e, 0xfb, 0x13, 0x07, 0x9a, 0x56, 0xbe, 0x92, 0x15, 0x7f, 0xcf, 0xb5, 0xd3, 0x36, 0xeb, + 0xcc, 0x86, 0x5c, 0x8f, 0x06, 0xb9, 0xbf, 0xf9, 0x05, 0x6b, 0x11, 0x3e, 0xb6, 0x4e, 0x30, 0x37, + 0xf3, 0xef, 0xc7, 0x5f, 0xe4, 0x09, 0xcc, 0x2c, 0xe3, 0x17, 0xb7, 0x1d, 0xf6, 0x81, 0xf8, 0x87, + 0x04, 0x15, 0xb1, 0x60, 0x86, 0x22, 0xcd, 0x2f, 0x99, 0xf9, 0xf7, 0x00, 0x37, 0x9c, 0xdb, 0x0e, + 0xfb, 0x9a, 0x78, 0x26, 0x2e, 0xbf, 0xa5, 0x95, 0x7f, 0xd5, 0xef, 0xdd, 0x6b, 0x34, 0x9b, 0x2b, + 0xee, 0x65, 0x6b, 0x36, 0x79, 0x4b, 0x72, 0x47, 0x8c, 0x4e, 0xbe, 0xfe, 0xcf, 0x54, 0x62, 0xe1, + 0x1f, 0x01, 0x66, 0x0f, 0x72, 0x24, 0x06, 0x29, 0xc9, 0x2d, 0xf6, 0x78, 0xc5, 0x66, 0xdc, 0x4d, + 0x1a, 0xeb, 0x35, 0xf7, 0xcd, 0x99, 0x63, 0xbd, 0x45, 0x27, 0x52, 0x1c, 0xf1, 0x01, 0x40, 0x16, + 0x90, 0x63, 0xb9, 0xf8, 0x93, 0xb6, 0x0a, 0xc5, 0x98, 0x9d, 0xcd, 0x83, 0x2a, 0x4c, 0x85, 0x2d, + 0x7e, 0x55, 0x88, 0xaa, 0xa4, 0x4f, 0xf4, 0xe8, 0x8b, 0xa1, 0xb3, 0x4e, 0xa7, 0xac, 0xaa, 0x4c, + 0x50, 0x55, 0xfb, 0xec, 0x09, 0x2c, 0xed, 0x47, 0xd1, 0xb3, 0xc9, 0x58, 0x07, 0xa4, 0xed, 0xf8, + 0xcd, 0x9e, 0x9f, 0x9c, 0x74, 0x72, 0xb3, 0x70, 0xaf, 0x52, 0x53, 0x1d, 0xd6, 0x36, 0x9a, 0xba, + 0xf5, 0x71, 0x16, 0xf0, 0x7b, 0xc1, 0x7c, 0x58, 0xd5, 0x1e, 0x80, 0x1e, 0x78, 0xc7, 0x6e, 0xc6, + 0x8c, 0xbb, 0x15, 0xba, 0xb0, 0x7c, 0x32, 0x35, 0xda, 0x5b, 0x89, 0x6a, 0xf3, 0xb6, 0xc3, 0x0e, + 0xa0, 0xb9, 0xc3, 0x7b, 0x51, 0x9f, 0xcb, 0x88, 0xcb, 0x5a, 0x36, 0x70, 0x1d, 0xaa, 0xe9, 0x2c, + 0x59, 0xa0, 0xad, 0x13, 0xc7, 0xfe, 0x34, 0xe6, 0xdf, 0xb8, 0xf5, 0xb1, 0x8c, 0xe5, 0xbc, 0x50, + 0x3a, 0x51, 0xc5, 0x9f, 0x2c, 0x9d, 0x98, 0x0b, 0x58, 0x59, 0x3a, 0xb1, 0x10, 0xb0, 0xb2, 0x96, + 0x5a, 0xc5, 0xbf, 0xd8, 0x10, 0x56, 0x0b, 0x31, 0x2e, 0xed, 0x47, 0xcc, 0x8a, 0x8c, 0x75, 0xae, + 0xce, 0x26, 0xb0, 0x7b, 0xdb, 0xb4, 0x7b, 0x3b, 0x84, 0xa5, 0x1d, 0x2e, 0x16, 0x4b, 0xdc, 0x7a, + 0xe7, 0x9e, 0xa3, 0x99, 0x37, 0xe4, 0x79, 0xa5, 0x48, 0x75, 0xb6, 0xd1, 0xa3, 0x2b, 0x67, 0xf6, + 0x55, 0x68, 0xdc, 0xe7, 0xa9, 0xba, 0xe6, 0xd6, 0xde, 0x58, 0xee, 0xde, 0xbb, 0x53, 0x72, 0x4b, + 0x6e, 0xf3, 0x0c, 0xb5, 0x76, 0x8b, 0xf7, 0x07, 0x5c, 0xa8, 0xa7, 0x6e, 0xd0, 0x7f, 0xc1, 0x7e, + 0x8d, 0x1a, 0xd7, 0x59, 0x33, 0x1b, 0xc6, 0xed, 0xa8, 0xd9, 0xf8, 0x4a, 0x0e, 0x2f, 0x6b, 0x39, + 0x8c, 0xfa, 0xdc, 0x30, 0xff, 0x21, 0x34, 0x8c, 0x94, 0x2e, 0x2d, 0x40, 0xc5, 0xf4, 0x34, 0x2d, + 0x40, 0x25, 0x19, 0x60, 0xee, 0x0d, 0xea, 0xc7, 0x65, 0x57, 0xb3, 0x7e, 0x44, 0xd6, 0x57, 0xd6, + 0xd3, 0xad, 0x8f, 0xfd, 0x51, 0xfa, 0x82, 0x3d, 0xa5, 0xa7, 0x69, 0xe6, 0x55, 0x7e, 0xe6, 0x0d, + 0xe6, 0x6f, 0xfd, 0xf5, 0x62, 0x19, 0x55, 0xb6, 0x87, 0x28, 0xba, 0x22, 0x2f, 0xe1, 0x33, 0x00, + 0x87, 0x69, 0x34, 0xde, 0xf1, 0xf9, 0x28, 0x0a, 0x33, 0x5d, 0x9b, 0x5d, 0x57, 0x67, 0xfa, 0xcb, + 0xb8, 0xb3, 0x66, 0x4f, 0x0d, 0x7f, 0xdc, 0xca, 0x84, 0x50, 0xcc, 0x35, 0xf3, 0x46, 0x5b, 0x2f, + 0x48, 0xc9, 0xad, 0xf6, 0x6d, 0x07, 0xbd, 0xeb, 0x2c, 0xa2, 0xaa, 0xbd, 0xeb, 0x42, 0xb0, 0x56, + 0xab, 0xbd, 0x92, 0xf0, 0xeb, 0x01, 0xd4, 0xb3, 0x10, 0xdd, 0xa5, 0x2c, 0x2d, 0xcf, 0x0a, 0xe8, + 0x69, 0xab, 0x58, 0x08, 0x9c, 0xb9, 0x2d, 0x5a, 0x2a, 0x60, 0x8b, 0xb8, 0x54, 0x14, 0x0d, 0x0b, + 0x60, 0x4d, 0x0c, 0x50, 0x9b, 0x78, 0xba, 0x80, 0x55, 0x33, 0x29, 0x09, 0x5e, 0x69, 0x69, 0x2e, + 0x8d, 0xfd, 0x58, 0xe7, 0x6c, 0xe4, 0x56, 0x71, 0xf9, 0x8b, 0xaa, 0x79, 0x04, 0xab, 0x85, 0xc0, + 0x85, 0x16, 0xe9, 0x59, 0xf1, 0x22, 0x2d, 0xd2, 0x33, 0x63, 0x1e, 0xee, 0x45, 0xea, 0x72, 0xc5, + 0x05, 0xec, 0x32, 0x39, 0x0b, 0xd2, 0xde, 0xc9, 0x07, 0xce, 0xe6, 0xd1, 0x3c, 0xfd, 0xa3, 0xda, + 0xa7, 0xfe, 0x37, 0x00, 0x00, 0xff, 0xff, 0x2f, 0xeb, 0x5e, 0xe3, 0x83, 0x4d, 0x00, 0x00, } diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index cc42faba..769b3fb9 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -1129,11 +1129,10 @@ message PendingUpdate { } message OpenChannelRequest { - /// The pubkey of the node to open a channel with bytes node_pubkey = 2 [json_name = "node_pubkey"]; - /// The hex encoded pubkey of the node to open a channel with + /// The hex encoded pubkey of the node to open a channel with string node_pubkey_string = 3 [json_name = "node_pubkey_string"]; /// The number of satoshis the wallet should commit to the channel @@ -1156,6 +1155,9 @@ message OpenChannelRequest { /// The delay we require on the remote's commitment transaction. If this is not set, it will be scaled automatically with the channel size. uint32 remote_csv_delay = 10 [json_name = "remote_csv_delay"]; + + /// The minimum number of confirmations each one of your outputs used for the funding transaction must satisfy. + int32 min_confs = 11 [json_name = "min_confs"]; } message OpenStatusUpdate { oneof update { diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index 117ca38c..bbaec3e5 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -2164,6 +2164,11 @@ "type": "integer", "format": "int64", "description": "/ The delay we require on the remote's commitment transaction. If this is not set, it will be scaled automatically with the channel size." + }, + "min_confs": { + "type": "integer", + "format": "int32", + "description": "/ The minimum number of confirmations each one of your outputs used for the funding transaction must satisfy." } } }, diff --git a/lntest/harness.go b/lntest/harness.go index 60c0f4ef..fd0b4078 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -676,10 +676,12 @@ func (n *NetworkHarness) WaitForTxBroadcast(ctx context.Context, txid chainhash. // OpenChannel attempts to open a channel between srcNode and destNode with the // passed channel funding parameters. If the passed context has a timeout, then // if the timeout is reached before the channel pending notification is -// received, an error is returned. +// received, an error is returned. The confirmed boolean determines whether we +// should fund the channel with confirmed outputs or not. func (n *NetworkHarness) OpenChannel(ctx context.Context, srcNode, destNode *HarnessNode, amt btcutil.Amount, - pushAmt btcutil.Amount, private bool) (lnrpc.Lightning_OpenChannelClient, error) { + pushAmt btcutil.Amount, + private, confirmed bool) (lnrpc.Lightning_OpenChannelClient, error) { // Wait until srcNode and destNode have the latest chain synced. // Otherwise, we may run into a check within the funding manager that @@ -692,11 +694,17 @@ func (n *NetworkHarness) OpenChannel(ctx context.Context, return nil, fmt.Errorf("Unable to sync destNode chain: %v", err) } + minConfs := int32(0) + if confirmed { + minConfs = 1 + } + openReq := &lnrpc.OpenChannelRequest{ NodePubkey: destNode.PubKey[:], LocalFundingAmount: int64(amt), PushSat: int64(pushAmt), Private: private, + MinConfs: minConfs, } respStream, err := srcNode.OpenChannel(ctx, openReq) @@ -1104,12 +1112,26 @@ func (n *NetworkHarness) DumpLogs(node *HarnessNode) (string, error) { } // SendCoins attempts to send amt satoshis from the internal mining node to the -// targeted lightning node using a P2WKH address. +// targeted lightning node using a P2WKH address. 6 blocks are mined after in +// order to confirm the transaction. func (n *NetworkHarness) SendCoins(ctx context.Context, amt btcutil.Amount, target *HarnessNode) error { return n.sendCoins( ctx, amt, target, lnrpc.NewAddressRequest_WITNESS_PUBKEY_HASH, + true, + ) +} + +// SendCoinsUnconfirmed sends coins from the internal mining node to the target +// lightning node using a P2WPKH address. No blocks are mined after, so the +// transaction remains unconfirmed. +func (n *NetworkHarness) SendCoinsUnconfirmed(ctx context.Context, + amt btcutil.Amount, target *HarnessNode) error { + + return n.sendCoins( + ctx, amt, target, lnrpc.NewAddressRequest_WITNESS_PUBKEY_HASH, + false, ) } @@ -1120,14 +1142,16 @@ func (n *NetworkHarness) SendCoinsNP2WKH(ctx context.Context, return n.sendCoins( ctx, amt, target, lnrpc.NewAddressRequest_NESTED_PUBKEY_HASH, + true, ) } // sendCoins attempts to send amt satoshis from the internal mining node to the -// targeted lightning node. +// targeted lightning node. The confirmed boolean indicates whether the +// transaction that pays to the target should confirm. func (n *NetworkHarness) sendCoins(ctx context.Context, amt btcutil.Amount, - target *HarnessNode, - addrType lnrpc.NewAddressRequest_AddressType) error { + target *HarnessNode, addrType lnrpc.NewAddressRequest_AddressType, + confirmed bool) error { balReq := &lnrpc.WalletBalanceRequest{} initialBalance, err := target.WalletBalance(ctx, balReq) @@ -1165,30 +1189,21 @@ func (n *NetworkHarness) sendCoins(ctx context.Context, amt btcutil.Amount, return err } - // Finally, generate 6 new blocks to ensure the output gains a - // sufficient number of confirmations. + // If the transaction should remain unconfirmed, then we'll wait until + // the target node's unconfirmed balance reflects the expected balance + // and exit. + if !confirmed { + expectedBalance := initialBalance.UnconfirmedBalance + int64(amt) + return target.WaitForBalance(expectedBalance, false) + } + + // Otherwise, we'll generate 6 new blocks to ensure the output gains a + // sufficient number of confirmations and wait for the balance to + // reflect what's expected. if _, err := n.Miner.Node.Generate(6); err != nil { return err } - // Pause until the nodes current wallet balances reflects the amount - // sent to it above. - // TODO(roasbeef): factor out into helper func - balanceTicker := time.Tick(time.Millisecond * 50) - balanceTimeout := time.After(time.Second * 30) - for { - select { - case <-balanceTicker: - currentBal, err := target.WalletBalance(ctx, balReq) - if err != nil { - return err - } - - if currentBal.ConfirmedBalance == initialBalance.ConfirmedBalance+int64(amt) { - return nil - } - case <-balanceTimeout: - return fmt.Errorf("balances not synced after deadline") - } - } + expectedBalance := initialBalance.ConfirmedBalance + int64(amt) + return target.WaitForBalance(expectedBalance, true) } diff --git a/lntest/node.go b/lntest/node.go index c3c44590..aa965568 100644 --- a/lntest/node.go +++ b/lntest/node.go @@ -895,6 +895,33 @@ func (hn *HarnessNode) WaitForBlockchainSync(ctx context.Context) error { } } +// WaitForBalance waits until the node sees the expected confirmed/unconfirmed +// balance within their wallet. +func (hn *HarnessNode) WaitForBalance(expectedBalance int64, confirmed bool) error { + ctx := context.Background() + req := &lnrpc.WalletBalanceRequest{} + + doesBalanceMatch := func() bool { + balance, err := hn.WalletBalance(ctx, req) + if err != nil { + return false + } + + if confirmed { + return balance.ConfirmedBalance == expectedBalance + } + + return balance.UnconfirmedBalance == expectedBalance + } + + err := WaitPredicate(doesBalanceMatch, 30*time.Second) + if err != nil { + return errors.New("balances not synced after deadline") + } + + return nil +} + // fileExists reports whether the named file or directory exists. // This function is taken from https://github.com/btcsuite/btcd func fileExists(name string) bool { diff --git a/lnwallet/interface_test.go b/lnwallet/interface_test.go index d19b59ee..d2ded0f3 100644 --- a/lnwallet/interface_test.go +++ b/lnwallet/interface_test.go @@ -294,10 +294,18 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, if err != nil { t.Fatalf("unable to query fee estimator: %v", err) } - aliceChanReservation, err := alice.InitChannelReservation( - fundingAmount*2, fundingAmount, 0, feePerKw, feePerKw, bobPub, - bobAddr, chainHash, lnwire.FFAnnounceChannel, - ) + aliceReq := &lnwallet.InitFundingReserveMsg{ + ChainHash: chainHash, + NodeID: bobPub, + NodeAddr: bobAddr, + FundingAmount: fundingAmount, + Capacity: fundingAmount * 2, + CommitFeePerKw: feePerKw, + FundingFeePerKw: feePerKw, + PushMSat: 0, + Flags: lnwire.FFAnnounceChannel, + } + aliceChanReservation, err := alice.InitChannelReservation(aliceReq) if err != nil { t.Fatalf("unable to initialize funding reservation: %v", err) } @@ -325,10 +333,18 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness, // Bob does the same, generating his own contribution. He then also // receives' Alice's contribution, and consumes that so we can continue // the funding process. - bobChanReservation, err := bob.InitChannelReservation( - fundingAmount*2, fundingAmount, 0, feePerKw, feePerKw, alicePub, - aliceAddr, chainHash, lnwire.FFAnnounceChannel, - ) + bobReq := &lnwallet.InitFundingReserveMsg{ + ChainHash: chainHash, + NodeID: alicePub, + NodeAddr: aliceAddr, + FundingAmount: fundingAmount, + Capacity: fundingAmount * 2, + CommitFeePerKw: feePerKw, + FundingFeePerKw: feePerKw, + PushMSat: 0, + Flags: lnwire.FFAnnounceChannel, + } + bobChanReservation, err := bob.InitChannelReservation(bobReq) if err != nil { t.Fatalf("bob unable to init channel reservation: %v", err) } @@ -481,11 +497,18 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness, if err != nil { t.Fatalf("unable to query fee estimator: %v", err) } - _, err = alice.InitChannelReservation( - fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub, - bobAddr, chainHash, lnwire.FFAnnounceChannel, - ) - if err != nil { + req := &lnwallet.InitFundingReserveMsg{ + ChainHash: chainHash, + NodeID: bobPub, + NodeAddr: bobAddr, + FundingAmount: fundingAmount, + Capacity: fundingAmount, + CommitFeePerKw: feePerKw, + FundingFeePerKw: feePerKw, + PushMSat: 0, + Flags: lnwire.FFAnnounceChannel, + } + if _, err := alice.InitChannelReservation(req); err != nil { t.Fatalf("unable to initialize funding reservation 1: %v", err) } @@ -496,10 +519,18 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness, if err != nil { t.Fatalf("unable to create amt: %v", err) } - failedReservation, err := alice.InitChannelReservation( - amt, amt, 0, feePerKw, feePerKw, bobPub, bobAddr, chainHash, - lnwire.FFAnnounceChannel, - ) + failedReq := &lnwallet.InitFundingReserveMsg{ + ChainHash: chainHash, + NodeID: bobPub, + NodeAddr: bobAddr, + FundingAmount: amt, + Capacity: amt, + CommitFeePerKw: feePerKw, + FundingFeePerKw: feePerKw, + PushMSat: 0, + Flags: lnwire.FFAnnounceChannel, + } + failedReservation, err := alice.InitChannelReservation(failedReq) if err == nil { t.Fatalf("not error returned, should fail on coin selection") } @@ -524,19 +555,24 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness, if err != nil { t.Fatalf("unable to create amt: %v", err) } - chanReservation, err := alice.InitChannelReservation( - fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub, - bobAddr, chainHash, lnwire.FFAnnounceChannel, - ) + req := &lnwallet.InitFundingReserveMsg{ + ChainHash: chainHash, + NodeID: bobPub, + NodeAddr: bobAddr, + FundingAmount: fundingAmount, + Capacity: fundingAmount, + CommitFeePerKw: feePerKw, + FundingFeePerKw: feePerKw, + PushMSat: 0, + Flags: lnwire.FFAnnounceChannel, + } + chanReservation, err := alice.InitChannelReservation(req) if err != nil { t.Fatalf("unable to initialize funding reservation: %v", err) } // Attempt to create another channel with 44 BTC, this should fail. - _, err = alice.InitChannelReservation( - fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub, - bobAddr, chainHash, lnwire.FFAnnounceChannel, - ) + _, err = alice.InitChannelReservation(req) if _, ok := err.(*lnwallet.ErrInsufficientFunds); !ok { t.Fatalf("coin selection succeeded should have insufficient funds: %v", err) @@ -565,10 +601,7 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness, // attempting coin selection. // Request to fund a new channel should now succeed. - _, err = alice.InitChannelReservation(fundingAmount, fundingAmount, - 0, feePerKw, feePerKw, bobPub, bobAddr, chainHash, - lnwire.FFAnnounceChannel) - if err != nil { + if _, err := alice.InitChannelReservation(req); err != nil { t.Fatalf("unable to initialize funding reservation: %v", err) } } @@ -612,10 +645,18 @@ func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness, feePerKw := lnwallet.SatPerKWeight( numBTC * numBTC * btcutil.SatoshiPerBitcoin, ) - _, err = alice.InitChannelReservation( - fundingAmount, fundingAmount, 0, feePerKw, feePerKw, bobPub, - bobAddr, chainHash, lnwire.FFAnnounceChannel, - ) + req := &lnwallet.InitFundingReserveMsg{ + ChainHash: chainHash, + NodeID: bobPub, + NodeAddr: bobAddr, + FundingAmount: fundingAmount, + Capacity: fundingAmount, + CommitFeePerKw: feePerKw, + FundingFeePerKw: feePerKw, + PushMSat: 0, + Flags: lnwire.FFAnnounceChannel, + } + _, err = alice.InitChannelReservation(req) switch { case err == nil: t.Fatalf("initialization should have failed due to " + @@ -685,10 +726,18 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, if err != nil { t.Fatalf("unable to query fee estimator: %v", err) } - aliceChanReservation, err := alice.InitChannelReservation( - fundingAmt, fundingAmt, pushAmt, feePerKw, feePerKw, bobPub, - bobAddr, chainHash, lnwire.FFAnnounceChannel, - ) + aliceReq := &lnwallet.InitFundingReserveMsg{ + ChainHash: chainHash, + NodeID: bobPub, + NodeAddr: bobAddr, + FundingAmount: fundingAmt, + Capacity: fundingAmt, + CommitFeePerKw: feePerKw, + FundingFeePerKw: feePerKw, + PushMSat: pushAmt, + Flags: lnwire.FFAnnounceChannel, + } + aliceChanReservation, err := alice.InitChannelReservation(aliceReq) if err != nil { t.Fatalf("unable to init channel reservation: %v", err) } @@ -716,10 +765,18 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness, // Next, Bob receives the initial request, generates a corresponding // reservation initiation, then consume Alice's contribution. - bobChanReservation, err := bob.InitChannelReservation( - fundingAmt, 0, pushAmt, feePerKw, feePerKw, alicePub, aliceAddr, - chainHash, lnwire.FFAnnounceChannel, - ) + bobReq := &lnwallet.InitFundingReserveMsg{ + ChainHash: chainHash, + NodeID: alicePub, + NodeAddr: aliceAddr, + FundingAmount: 0, + Capacity: fundingAmt, + CommitFeePerKw: feePerKw, + FundingFeePerKw: feePerKw, + PushMSat: pushAmt, + Flags: lnwire.FFAnnounceChannel, + } + bobChanReservation, err := bob.InitChannelReservation(bobReq) if err != nil { t.Fatalf("unable to create bob reservation: %v", err) } diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index b86b200a..c0218957 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -3,24 +3,24 @@ package lnwallet import ( "bytes" "crypto/sha256" + "errors" "fmt" "net" "sync" "sync/atomic" "github.com/btcsuite/btcd/blockchain" + "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" + "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil/hdkeychain" + "github.com/btcsuite/btcutil/txsort" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" - - "github.com/btcsuite/btcd/btcec" - "github.com/btcsuite/btcd/txscript" - "github.com/btcsuite/btcd/wire" - "github.com/btcsuite/btcutil" - "github.com/btcsuite/btcutil/txsort" "github.com/lightningnetwork/lnd/shachain" ) @@ -44,7 +44,7 @@ func (e *ErrInsufficientFunds) Error() string { e.amountSelected) } -// initFundingReserveReq is the first message sent to initiate the workflow +// InitFundingReserveMsg is the first message sent to initiate the workflow // required to open a payment channel with a remote peer. The initial required // parameters are configurable across channels. These parameters are to be // chosen depending on the fee climate within the network, and time value of @@ -54,44 +54,48 @@ func (e *ErrInsufficientFunds) Error() string { // pending reservations. Therefore, all channels in reservation limbo will be // periodically timed out after an idle period in order to avoid "exhaustion" // attacks. -type initFundingReserveMsg struct { - // chainHash denotes that chain to be used to ultimately open the +type InitFundingReserveMsg struct { + // ChainHash denotes that chain to be used to ultimately open the // target channel. - chainHash *chainhash.Hash + ChainHash *chainhash.Hash - // nodeId is the ID of the remote node we would like to open a channel + // NodeID is the ID of the remote node we would like to open a channel // with. - nodeID *btcec.PublicKey + NodeID *btcec.PublicKey - // nodeAddr is the address port that we used to either establish or + // NodeAddr is the address port that we used to either establish or // accept the connection which led to the negotiation of this funding // workflow. - nodeAddr net.Addr + NodeAddr net.Addr - // fundingAmount is the amount of funds requested for this channel. - fundingAmount btcutil.Amount + // FundingAmount is the amount of funds requested for this channel. + FundingAmount btcutil.Amount - // capacity is the total capacity of the channel which includes the + // Capacity is the total capacity of the channel which includes the // amount of funds the remote party contributes (if any). - capacity btcutil.Amount + Capacity btcutil.Amount - // commitFeePerKw is the starting accepted satoshis/Kw fee for the set + // CommitFeePerKw is the starting accepted satoshis/Kw fee for the set // of initial commitment transactions. In order to ensure timely // confirmation, it is recommended that this fee should be generous, // paying some multiple of the accepted base fee rate of the network. - commitFeePerKw SatPerKWeight + CommitFeePerKw SatPerKWeight - // fundingFeePerKw is the fee rate in sat/kw to use for the initial + // FundingFeePerKw is the fee rate in sat/kw to use for the initial // funding transaction. - fundingFeePerKw SatPerKWeight + FundingFeePerKw SatPerKWeight - // pushMSat is the number of milli-satoshis that should be pushed over + // PushMSat is the number of milli-satoshis that should be pushed over // the responder as part of the initial channel creation. - pushMSat lnwire.MilliSatoshi + PushMSat lnwire.MilliSatoshi - // flags are the channel flags specified by the initiator in the + // Flags are the channel flags specified by the initiator in the // open_channel message. - flags lnwire.FundingFlag + Flags lnwire.FundingFlag + + // MinConfs indicates the minimum number of confirmations that each + // output selected to fund the channel should satisfy. + MinConfs int32 // err is a channel in which all errors will be sent across. Will be // nil if this initial set is successful. @@ -372,7 +376,7 @@ out: select { case m := <-l.msgChan: switch msg := m.(type) { - case *initFundingReserveMsg: + case *InitFundingReserveMsg: l.handleFundingReserveRequest(msg) case *fundingReserveCancelMsg: l.handleFundingCancelRequest(msg) @@ -412,36 +416,25 @@ out: // transaction, and that the signature we record for our version of the // commitment transaction is valid. func (l *LightningWallet) InitChannelReservation( - capacity, ourFundAmt btcutil.Amount, pushMSat lnwire.MilliSatoshi, - commitFeePerKw SatPerKWeight, fundingFeePerKw SatPerKWeight, - theirID *btcec.PublicKey, theirAddr net.Addr, - chainHash *chainhash.Hash, flags lnwire.FundingFlag) (*ChannelReservation, error) { + req *InitFundingReserveMsg) (*ChannelReservation, error) { - errChan := make(chan error, 1) - respChan := make(chan *ChannelReservation, 1) + req.resp = make(chan *ChannelReservation, 1) + req.err = make(chan error, 1) - l.msgChan <- &initFundingReserveMsg{ - chainHash: chainHash, - nodeID: theirID, - nodeAddr: theirAddr, - fundingAmount: ourFundAmt, - capacity: capacity, - commitFeePerKw: commitFeePerKw, - fundingFeePerKw: fundingFeePerKw, - pushMSat: pushMSat, - flags: flags, - err: errChan, - resp: respChan, + select { + case l.msgChan <- req: + case <-l.quit: + return nil, errors.New("wallet shutting down") } - return <-respChan, <-errChan + return <-req.resp, <-req.err } // handleFundingReserveRequest processes a message intending to create, and // validate a funding reservation request. -func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg) { +func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg) { // It isn't possible to create a channel with zero funds committed. - if req.fundingAmount+req.capacity == 0 { + if req.FundingAmount+req.Capacity == 0 { err := ErrZeroCapacity() req.err <- err req.resp <- nil @@ -450,18 +443,20 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg // If the funding request is for a different chain than the one the // wallet is aware of, then we'll reject the request. - if !bytes.Equal(l.Cfg.NetParams.GenesisHash[:], req.chainHash[:]) { - err := ErrChainMismatch(l.Cfg.NetParams.GenesisHash, - req.chainHash) + if !bytes.Equal(l.Cfg.NetParams.GenesisHash[:], req.ChainHash[:]) { + err := ErrChainMismatch( + l.Cfg.NetParams.GenesisHash, req.ChainHash, + ) req.err <- err req.resp <- nil return } id := atomic.AddUint64(&l.nextFundingID, 1) - reservation, err := NewChannelReservation(req.capacity, req.fundingAmount, - req.commitFeePerKw, l, id, req.pushMSat, - l.Cfg.NetParams.GenesisHash, req.flags) + reservation, err := NewChannelReservation( + req.Capacity, req.FundingAmount, req.CommitFeePerKw, l, id, + req.PushMSat, l.Cfg.NetParams.GenesisHash, req.Flags, + ) if err != nil { req.err <- err req.resp <- nil @@ -472,17 +467,17 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg reservation.Lock() defer reservation.Unlock() - reservation.nodeAddr = req.nodeAddr - reservation.partialState.IdentityPub = req.nodeID + reservation.nodeAddr = req.NodeAddr + reservation.partialState.IdentityPub = req.NodeID // If we're on the receiving end of a single funder channel then we // don't need to perform any coin selection. Otherwise, attempt to // obtain enough coins to meet the required funding amount. - if req.fundingAmount != 0 { + if req.FundingAmount != 0 { // Coin selection is done on the basis of sat/kw, so we'll use // the fee rate passed in to perform coin selection. err := l.selectCoinsAndChange( - req.fundingFeePerKw, req.fundingAmount, + req.FundingFeePerKw, req.FundingAmount, req.MinConfs, reservation.ourContribution, ) if err != nil { @@ -1265,9 +1260,10 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { // selection is successful/possible, then the selected coins are available // within the passed contribution's inputs. If necessary, a change address will // also be generated. -// TODO(roasbeef): remove hardcoded fees and req'd confs for outputs. +// TODO(roasbeef): remove hardcoded fees. func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight, - amt btcutil.Amount, contribution *ChannelContribution) error { + amt btcutil.Amount, minConfs int32, + contribution *ChannelContribution) error { // We hold the coin select mutex while querying for outputs, and // performing coin selection in order to avoid inadvertent double @@ -1278,10 +1274,9 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight, walletLog.Infof("Performing funding tx coin selection using %v "+ "sat/kw as fee rate", int64(feeRate)) - // Find all unlocked unspent witness outputs with greater than 1 - // confirmation. - // TODO(roasbeef): make num confs a configuration parameter - coins, err := l.ListUnspentWitness(1) + // Find all unlocked unspent witness outputs that satisfy the minimum + // number of confirmations required. + coins, err := l.ListUnspentWitness(minConfs) if err != nil { return err } diff --git a/pilot.go b/pilot.go index c77237a8..d9a1a200 100644 --- a/pilot.go +++ b/pilot.go @@ -17,8 +17,9 @@ import ( // chanController is an implementation of the autopilot.ChannelController // interface that's backed by a running lnd instance. type chanController struct { - server *server - private bool + server *server + private bool + minConfs int32 } // OpenChannel opens a channel to a target peer, with a capacity of the @@ -37,10 +38,21 @@ func (c *chanController) OpenChannel(target *btcec.PublicKey, // TODO(halseth): make configurable? minHtlc := lnwire.NewMSatFromSatoshis(1) - updateStream, errChan := c.server.OpenChannel( - target, amt, 0, minHtlc, feePerKw, c.private, 0, - ) + // Construct the open channel request and send it to the server to begin + // the funding workflow. + req := &openChanReq{ + targetPubkey: target, + chainHash: *activeNetParams.GenesisHash, + localFundingAmt: amt, + pushAmt: 0, + minHtlc: minHtlc, + fundingFeePerKw: feePerKw, + private: c.private, + remoteCsvDelay: 0, + minConfs: c.minConfs, + } + updateStream, errChan := c.server.OpenChannel(req) select { case err := <-errChan: // If we were not able to actually open a channel to the peer @@ -100,11 +112,12 @@ func initAutoPilot(svr *server, cfg *autoPilotConfig) (*autopilot.Agent, error) Self: self, Heuristic: prefAttachment, ChanController: &chanController{ - server: svr, - private: cfg.Private, + server: svr, + private: cfg.Private, + minConfs: cfg.MinConfs, }, WalletBalance: func() (btcutil.Amount, error) { - return svr.cc.wallet.ConfirmedBalance(1) + return svr.cc.wallet.ConfirmedBalance(cfg.MinConfs) }, Graph: autopilot.ChannelGraphFromDatabase(svr.chanDB.ChannelGraph()), MaxPendingOpens: 10, diff --git a/rpcserver.go b/rpcserver.go index 87d78bb3..bcee345a 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -770,6 +770,12 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest, "size is: %v SAT", int64(minChanFundingSize)) } + // Ensure that the MinConfs parameter is non-negative. + if in.MinConfs < 0 { + return errors.New("minimum number of confirmations must be a " + + "non-negative number") + } + var ( nodePubKey *btcec.PublicKey nodePubKeyBytes []byte @@ -813,11 +819,19 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest, // Instruct the server to trigger the necessary events to attempt to // open a new channel. A stream is returned in place, this stream will // be used to consume updates of the state of the pending channel. - updateChan, errChan := r.server.OpenChannel( - nodePubKey, localFundingAmt, - lnwire.NewMSatFromSatoshis(remoteInitialBalance), - minHtlc, feeRate, in.Private, remoteCsvDelay, - ) + req := &openChanReq{ + targetPubkey: nodePubKey, + chainHash: *activeNetParams.GenesisHash, + localFundingAmt: localFundingAmt, + pushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance), + minHtlc: minHtlc, + fundingFeePerKw: feeRate, + private: in.Private, + remoteCsvDelay: remoteCsvDelay, + minConfs: in.MinConfs, + } + + updateChan, errChan := r.server.OpenChannel(req) var outpoint wire.OutPoint out: @@ -929,6 +943,12 @@ func (r *rpcServer) OpenChannelSync(ctx context.Context, "size is: %v SAT", int64(minChanFundingSize)) } + // Ensure that the MinConfs parameter is non-negative. + if in.MinConfs < 0 { + return nil, errors.New("minimum number of confirmations must " + + "be a non-negative number") + } + // Based on the passed fee related parameters, we'll determine an // appropriate fee rate for the funding transaction. feeRate, err := determineFeePerKw( @@ -941,12 +961,19 @@ func (r *rpcServer) OpenChannelSync(ctx context.Context, rpcsLog.Tracef("[openchannel] target sat/kw for funding tx: %v", int64(feeRate)) - updateChan, errChan := r.server.OpenChannel( - nodepubKey, localFundingAmt, - lnwire.NewMSatFromSatoshis(remoteInitialBalance), - minHtlc, feeRate, in.Private, remoteCsvDelay, - ) + req := &openChanReq{ + targetPubkey: nodepubKey, + chainHash: *activeNetParams.GenesisHash, + localFundingAmt: localFundingAmt, + pushAmt: lnwire.NewMSatFromSatoshis(remoteInitialBalance), + minHtlc: minHtlc, + fundingFeePerKw: feeRate, + private: in.Private, + remoteCsvDelay: remoteCsvDelay, + minConfs: in.MinConfs, + } + updateChan, errChan := r.server.OpenChannel(req) select { // If an error occurs them immediately return the error to the client. case err := <-errChan: diff --git a/server.go b/server.go index bf770092..5b1e704b 100644 --- a/server.go +++ b/server.go @@ -2597,6 +2597,10 @@ type openChanReq struct { remoteCsvDelay uint16 + // minConfs indicates the minimum number of confirmations that each + // output selected to fund the channel should satisfy. + minConfs int32 + // TODO(roasbeef): add ability to specify channel constraints as well updates chan *lnrpc.OpenStatusUpdate @@ -2735,77 +2739,45 @@ func (s *server) DisconnectPeer(pubKey *btcec.PublicKey) error { // peer identified by nodeKey with the passed channel funding parameters. // // NOTE: This function is safe for concurrent access. -func (s *server) OpenChannel(nodeKey *btcec.PublicKey, - localAmt btcutil.Amount, pushAmt, minHtlc lnwire.MilliSatoshi, - fundingFeePerKw lnwallet.SatPerKWeight, private bool, - remoteCsvDelay uint16) (chan *lnrpc.OpenStatusUpdate, chan error) { +func (s *server) OpenChannel( + req *openChanReq) (chan *lnrpc.OpenStatusUpdate, chan error) { - // The updateChan will have a buffer of 2, since we expect a - // ChanPending + a ChanOpen update, and we want to make sure the - // funding process is not blocked if the caller is not reading the - // updates. - updateChan := make(chan *lnrpc.OpenStatusUpdate, 2) - errChan := make(chan error, 1) - - var ( - targetPeer *peer - pubKeyBytes []byte - err error - ) - - // If the user is targeting the peer by public key, then we'll need to - // convert that into a string for our map. Otherwise, we expect them to - // target by peer ID instead. - if nodeKey != nil { - pubKeyBytes = nodeKey.SerializeCompressed() - } + // The updateChan will have a buffer of 2, since we expect a ChanPending + // + a ChanOpen update, and we want to make sure the funding process is + // not blocked if the caller is not reading the updates. + req.updates = make(chan *lnrpc.OpenStatusUpdate, 2) + req.err = make(chan error, 1) // First attempt to locate the target peer to open a channel with, if // we're unable to locate the peer then this request will fail. + pubKeyBytes := req.targetPubkey.SerializeCompressed() s.mu.RLock() - if peer, ok := s.peersByPub[string(pubKeyBytes)]; ok { - targetPeer = peer + peer, ok := s.peersByPub[string(pubKeyBytes)] + if !ok { + req.err <- fmt.Errorf("peer %x is not online", pubKeyBytes) + return req.updates, req.err } s.mu.RUnlock() - if targetPeer == nil { - errChan <- fmt.Errorf("peer is not connected NodeKey(%x)", pubKeyBytes) - return updateChan, errChan - } - // If the fee rate wasn't specified, then we'll use a default // confirmation target. - if fundingFeePerKw == 0 { + if req.fundingFeePerKw == 0 { estimator := s.cc.feeEstimator - fundingFeePerKw, err = estimator.EstimateFeePerKW(6) + feeRate, err := estimator.EstimateFeePerKW(6) if err != nil { - errChan <- err - return updateChan, errChan + req.err <- err + return req.updates, req.err } + req.fundingFeePerKw = feeRate } - // Spawn a goroutine to send the funding workflow request to the - // funding manager. This allows the server to continue handling queries - // instead of blocking on this request which is exported as a - // synchronous request to the outside world. - req := &openChanReq{ - targetPubkey: nodeKey, - chainHash: *activeNetParams.GenesisHash, - localFundingAmt: localAmt, - fundingFeePerKw: fundingFeePerKw, - pushAmt: pushAmt, - private: private, - minHtlc: minHtlc, - remoteCsvDelay: remoteCsvDelay, - updates: updateChan, - err: errChan, - } + // Spawn a goroutine to send the funding workflow request to the funding + // manager. This allows the server to continue handling queries instead + // of blocking on this request which is exported as a synchronous + // request to the outside world. + go s.fundingMgr.initFundingWorkflow(peer, req) - // TODO(roasbeef): pass in chan that's closed if/when funding succeeds - // so can track as persistent peer? - go s.fundingMgr.initFundingWorkflow(targetPeer, req) - - return updateChan, errChan + return req.updates, req.err } // Peers returns a slice of all active peers.