Merge pull request #4079 from guggero/psbt-chanfunding

wallet: PSBT channel funding
This commit is contained in:
Wilmer Paulino 2020-03-31 10:03:46 -07:00 committed by GitHub
commit f996203883
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 4200 additions and 1130 deletions

@ -0,0 +1,661 @@
package main
import (
"context"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"strconv"
"strings"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
"github.com/lightningnetwork/lnd/signal"
"github.com/urfave/cli"
)
const (
defaultUtxoMinConf = 1
userMsgFund = `PSBT funding initiated with peer %x.
Please create a PSBT that sends %v (%d satoshi) to the funding address %s.
Note: The whole process should be completed within 10 minutes, otherwise there
is a risk of the remote node timing out and canceling the funding process.
Example with bitcoind:
bitcoin-cli walletcreatefundedpsbt [] '[{"%s":%.8f}]'
If you are using a wallet that can fund a PSBT directly (currently not possible
with bitcoind), you can use this PSBT that contains the same address and amount:
%s
Paste the funded PSBT here to continue the funding flow.
Base64 encoded PSBT: `
userMsgSign = `
PSBT verified by lnd, please continue the funding flow by signing the PSBT by
all required parties/devices. Once the transaction is fully signed, paste it
again here.
Base64 encoded signed PSBT: `
)
// TODO(roasbeef): change default number of confirmations
var openChannelCommand = cli.Command{
Name: "openchannel",
Category: "Channels",
Usage: "Open a channel to a node or an existing peer.",
Description: `
Attempt to open a new channel to an existing peer with the key node-key
optionally blocking until the channel is 'open'.
One can also connect to a node before opening a new channel to it by
setting its host:port via the --connect argument. For this to work,
the node_key must be provided, rather than the peer_id. This is optional.
The channel will be initialized with local-amt satoshis local and push-amt
satoshis for the remote node. Note that specifying push-amt means you give that
amount to the remote node as part of the channel opening. Once the channel is open,
a channelPoint (txid:vout) of the funding output is returned.
If the remote peer supports the option upfront shutdown feature bit (query
listpeers to see their supported feature bits), an address to enforce
payout of funds on cooperative close can optionally be provided. Note that
if you set this value, you will not be able to cooperatively close out to
another address.
One can manually set the fee to be used for the funding transaction via either
the --conf_target or --sat_per_byte arguments. This is optional.`,
ArgsUsage: "node-key local-amt push-amt",
Flags: []cli.Flag{
cli.StringFlag{
Name: "node_key",
Usage: "the identity public key of the target node/peer " +
"serialized in compressed format",
},
cli.StringFlag{
Name: "connect",
Usage: "(optional) the host:port of the target node",
},
cli.IntFlag{
Name: "local_amt",
Usage: "the number of satoshis the wallet should commit to the channel",
},
cli.IntFlag{
Name: "push_amt",
Usage: "the number of satoshis to give the remote side " +
"as part of the initial commitment state, " +
"this is equivalent to first opening a " +
"channel and sending the remote party funds, " +
"but done all in one step",
},
cli.BoolFlag{
Name: "block",
Usage: "block and wait until the channel is fully open",
},
cli.Int64Flag{
Name: "conf_target",
Usage: "(optional) the number of blocks that the " +
"transaction *should* confirm in, will be " +
"used for fee estimation",
},
cli.Int64Flag{
Name: "sat_per_byte",
Usage: "(optional) a manual fee expressed in " +
"sat/byte that should be used when crafting " +
"the transaction",
},
cli.BoolFlag{
Name: "private",
Usage: "make the channel private, such that it won't " +
"be announced to the greater network, and " +
"nodes other than the two channel endpoints " +
"must be explicitly told about it to be able " +
"to route through it",
},
cli.Int64Flag{
Name: "min_htlc_msat",
Usage: "(optional) the minimum value we will require " +
"for incoming HTLCs on the channel",
},
cli.Uint64Flag{
Name: "remote_csv_delay",
Usage: "(optional) the number of blocks we will require " +
"our channel counterparty to wait before accessing " +
"its funds in case of unilateral close. If this is " +
"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",
Value: defaultUtxoMinConf,
},
cli.StringFlag{
Name: "close_address",
Usage: "(optional) an address to enforce payout of our " +
"funds to on cooperative close. Note that if this " +
"value is set on channel open, you will *not* be " +
"able to cooperatively close to a different address.",
},
cli.BoolFlag{
Name: "psbt",
Usage: "start an interactive mode that initiates " +
"funding through a partially signed bitcoin " +
"transaction (PSBT), allowing the channel " +
"funds to be added and signed from a hardware " +
"or other offline device.",
},
cli.StringFlag{
Name: "base_psbt",
Usage: "when using the interactive PSBT mode to open " +
"a new channel, use this base64 encoded PSBT " +
"as a base and add the new channel output to " +
"it instead of creating a new, empty one.",
},
},
Action: actionDecorator(openChannel),
}
func openChannel(ctx *cli.Context) error {
// TODO(roasbeef): add deadline to context
ctxb := context.Background()
client, cleanUp := getClient(ctx)
defer cleanUp()
args := ctx.Args()
var err error
// Show command help if no arguments provided
if ctx.NArg() == 0 && ctx.NumFlags() == 0 {
_ = cli.ShowCommandHelp(ctx, "openchannel")
return nil
}
minConfs := int32(ctx.Uint64("min_confs"))
req := &lnrpc.OpenChannelRequest{
TargetConf: int32(ctx.Int64("conf_target")),
SatPerByte: ctx.Int64("sat_per_byte"),
MinHtlcMsat: ctx.Int64("min_htlc_msat"),
RemoteCsvDelay: uint32(ctx.Uint64("remote_csv_delay")),
MinConfs: minConfs,
SpendUnconfirmed: minConfs == 0,
CloseAddress: ctx.String("close_address"),
}
switch {
case ctx.IsSet("node_key"):
nodePubHex, err := hex.DecodeString(ctx.String("node_key"))
if err != nil {
return fmt.Errorf("unable to decode node public key: %v", err)
}
req.NodePubkey = nodePubHex
case args.Present():
nodePubHex, err := hex.DecodeString(args.First())
if err != nil {
return fmt.Errorf("unable to decode node public key: %v", err)
}
args = args.Tail()
req.NodePubkey = nodePubHex
default:
return fmt.Errorf("node id argument missing")
}
// As soon as we can confirm that the node's node_key was set, rather
// than the peer_id, we can check if the host:port was also set to
// connect to it before opening the channel.
if req.NodePubkey != nil && ctx.IsSet("connect") {
addr := &lnrpc.LightningAddress{
Pubkey: hex.EncodeToString(req.NodePubkey),
Host: ctx.String("connect"),
}
req := &lnrpc.ConnectPeerRequest{
Addr: addr,
Perm: false,
}
// Check if connecting to the node was successful.
// We discard the peer id returned as it is not needed.
_, err := client.ConnectPeer(ctxb, req)
if err != nil &&
!strings.Contains(err.Error(), "already connected") {
return err
}
}
switch {
case ctx.IsSet("local_amt"):
req.LocalFundingAmount = int64(ctx.Int("local_amt"))
case args.Present():
req.LocalFundingAmount, err = strconv.ParseInt(args.First(), 10, 64)
if err != nil {
return fmt.Errorf("unable to decode local amt: %v", err)
}
args = args.Tail()
default:
return fmt.Errorf("local amt argument missing")
}
if ctx.IsSet("push_amt") {
req.PushSat = int64(ctx.Int("push_amt"))
} else if args.Present() {
req.PushSat, err = strconv.ParseInt(args.First(), 10, 64)
if err != nil {
return fmt.Errorf("unable to decode push amt: %v", err)
}
}
req.Private = ctx.Bool("private")
// PSBT funding is a more involved, interactive process that is too
// large to also fit into this already long function.
if ctx.Bool("psbt") {
return openChannelPsbt(ctx, client, req)
}
stream, err := client.OpenChannel(ctxb, req)
if err != nil {
return err
}
for {
resp, err := stream.Recv()
if err == io.EOF {
return nil
} else if err != nil {
return err
}
switch update := resp.Update.(type) {
case *lnrpc.OpenStatusUpdate_ChanPending:
err := printChanPending(update)
if err != nil {
return err
}
if !ctx.Bool("block") {
return nil
}
case *lnrpc.OpenStatusUpdate_ChanOpen:
return printChanOpen(update)
}
}
}
// openChannelPsbt starts an interactive channel open protocol that uses a
// partially signed bitcoin transaction (PSBT) to fund the channel output. The
// protocol involves several steps between the RPC server and the CLI client:
//
// RPC server CLI client
// | |
// | |<------open channel (stream)-----|
// | |-------ready for funding----->| |
// | |<------PSBT verify------------| |
// | |-------ready for signing----->| |
// | |<------PSBT finalize----------| |
// | |-------channel pending------->| |
// | |-------channel open------------->|
// | |
func openChannelPsbt(ctx *cli.Context, client lnrpc.LightningClient,
req *lnrpc.OpenChannelRequest) error {
var (
pendingChanID [32]byte
shimPending = true
basePsbtBytes []byte
quit = make(chan struct{})
srvMsg = make(chan *lnrpc.OpenStatusUpdate, 1)
srvErr = make(chan error, 1)
ctxc, cancel = context.WithCancel(context.Background())
)
defer cancel()
// Make sure the user didn't supply any command line flags that are
// incompatible with PSBT funding.
err := checkPsbtFlags(req)
if err != nil {
return err
}
// If the user supplied a base PSBT, only make sure it's valid base64.
// The RPC server will make sure it's also a valid PSBT.
basePsbt := ctx.String("base_psbt")
if basePsbt != "" {
basePsbtBytes, err = base64.StdEncoding.DecodeString(basePsbt)
if err != nil {
return fmt.Errorf("error parsing base PSBT: %v", err)
}
}
// Generate a new, random pending channel ID that we'll use as the main
// identifier when sending update messages to the RPC server.
if _, err := rand.Read(pendingChanID[:]); err != nil {
return fmt.Errorf("unable to generate random chan ID: %v", err)
}
fmt.Printf("Starting PSBT funding flow with pending channel ID %x.\n",
pendingChanID)
// maybeCancelShim is a helper function that cancels the funding shim
// with the RPC server in case we end up aborting early.
maybeCancelShim := func() {
// If the user canceled while there was still a shim registered
// with the wallet, release the resources now.
if shimPending {
fmt.Printf("Canceling PSBT funding flow for pending "+
"channel ID %x.\n", pendingChanID)
cancelMsg := &lnrpc.FundingTransitionMsg{
Trigger: &lnrpc.FundingTransitionMsg_ShimCancel{
ShimCancel: &lnrpc.FundingShimCancel{
PendingChanId: pendingChanID[:],
},
},
}
err := sendFundingState(ctxc, ctx, cancelMsg)
if err != nil {
fmt.Printf("Error canceling shim: %v\n", err)
}
shimPending = false
}
// Abort the stream connection to the server.
cancel()
}
defer maybeCancelShim()
// Create the PSBT funding shim that will tell the funding manager we
// want to use a PSBT.
req.FundingShim = &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{
PsbtShim: &lnrpc.PsbtShim{
PendingChanId: pendingChanID[:],
BasePsbt: basePsbtBytes,
},
},
}
// Start the interactive process by opening the stream connection to the
// daemon. If the user cancels by pressing <Ctrl+C> we need to cancel
// the shim. To not just kill the process on interrupt, we need to
// explicitly capture the signal.
stream, err := client.OpenChannel(ctxc, req)
if err != nil {
return fmt.Errorf("opening stream to server failed: %v", err)
}
signal.Intercept()
// We also need to spawn a goroutine that reads from the server. This
// will copy the messages to the channel as long as they come in or add
// exactly one error to the error stream and then bail out.
go func() {
for {
// Recv blocks until a message or error arrives.
resp, err := stream.Recv()
if err == io.EOF {
srvErr <- fmt.Errorf("lnd shutting down: %v",
err)
return
} else if err != nil {
srvErr <- fmt.Errorf("got error from server: "+
"%v", err)
return
}
// Don't block on sending in case of shutting down.
select {
case srvMsg <- resp:
case <-quit:
return
}
}
}()
// Spawn another goroutine that only handles abort from user or errors
// from the server. Both will trigger an attempt to cancel the shim with
// the server.
go func() {
select {
case <-signal.ShutdownChannel():
fmt.Printf("\nInterrupt signal received.\n")
close(quit)
case err := <-srvErr:
fmt.Printf("\nError received: %v\n", err)
// If the remote peer canceled on us, the reservation
// has already been deleted. We don't need to try to
// remove it again, this would just produce another
// error.
cancelErr := chanfunding.ErrRemoteCanceled.Error()
if err != nil && strings.Contains(err.Error(), cancelErr) {
shimPending = false
}
close(quit)
case <-quit:
}
}()
// Our main event loop where we wait for triggers
for {
var srvResponse *lnrpc.OpenStatusUpdate
select {
case srvResponse = <-srvMsg:
case <-quit:
return nil
}
switch update := srvResponse.Update.(type) {
case *lnrpc.OpenStatusUpdate_PsbtFund:
// First tell the user how to create the PSBT with the
// address and amount we now know.
amt := btcutil.Amount(update.PsbtFund.FundingAmount)
addr := update.PsbtFund.FundingAddress
fmt.Printf(
userMsgFund, req.NodePubkey, amt, amt, addr,
addr, amt.ToBTC(),
base64.StdEncoding.EncodeToString(
update.PsbtFund.Psbt,
),
)
// Read the user's response and send it to the server to
// verify everything's correct before anything is
// signed.
psbtBase64, err := readLine(quit)
if err == io.EOF {
return nil
}
if err != nil {
return fmt.Errorf("reading from console "+
"failed: %v", err)
}
psbt, err := base64.StdEncoding.DecodeString(
strings.TrimSpace(psbtBase64),
)
if err != nil {
return fmt.Errorf("base64 decode failed: %v",
err)
}
verifyMsg := &lnrpc.FundingTransitionMsg{
Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{
PsbtVerify: &lnrpc.FundingPsbtVerify{
FundedPsbt: psbt,
PendingChanId: pendingChanID[:],
},
},
}
err = sendFundingState(ctxc, ctx, verifyMsg)
if err != nil {
return fmt.Errorf("verifying PSBT by lnd "+
"failed: %v", err)
}
// Now that we know the PSBT looks good, we can let it
// be signed by the user.
fmt.Print(userMsgSign)
// Read the signed PSBT and send it to lnd.
psbtBase64, err = readLine(quit)
if err == io.EOF {
return nil
}
if err != nil {
return fmt.Errorf("reading from console "+
"failed: %v", err)
}
psbt, err = base64.StdEncoding.DecodeString(
strings.TrimSpace(psbtBase64),
)
if err != nil {
return fmt.Errorf("base64 decode failed: %v",
err)
}
finalizeMsg := &lnrpc.FundingTransitionMsg{
Trigger: &lnrpc.FundingTransitionMsg_PsbtFinalize{
PsbtFinalize: &lnrpc.FundingPsbtFinalize{
SignedPsbt: psbt,
PendingChanId: pendingChanID[:],
},
},
}
err = sendFundingState(ctxc, ctx, finalizeMsg)
if err != nil {
return fmt.Errorf("finalizing PSBT funding "+
"flow failed: %v", err)
}
case *lnrpc.OpenStatusUpdate_ChanPending:
// As soon as the channel is pending, there is no more
// shim that needs to be canceled. If the user
// interrupts now, we don't need to clean up anything.
shimPending = false
err := printChanPending(update)
if err != nil {
return err
}
if !ctx.Bool("block") {
return nil
}
case *lnrpc.OpenStatusUpdate_ChanOpen:
return printChanOpen(update)
}
}
}
// printChanOpen prints the channel point of the channel open message.
func printChanOpen(update *lnrpc.OpenStatusUpdate_ChanOpen) error {
channelPoint := update.ChanOpen.ChannelPoint
// A channel point's funding txid can be get/set as a
// byte slice or a string. In the case it is a string,
// decode it.
var txidHash []byte
switch channelPoint.GetFundingTxid().(type) {
case *lnrpc.ChannelPoint_FundingTxidBytes:
txidHash = channelPoint.GetFundingTxidBytes()
case *lnrpc.ChannelPoint_FundingTxidStr:
s := channelPoint.GetFundingTxidStr()
h, err := chainhash.NewHashFromStr(s)
if err != nil {
return err
}
txidHash = h[:]
}
txid, err := chainhash.NewHash(txidHash)
if err != nil {
return err
}
index := channelPoint.OutputIndex
printJSON(struct {
ChannelPoint string `json:"channel_point"`
}{
ChannelPoint: fmt.Sprintf("%v:%v", txid, index),
})
return nil
}
// printChanPending prints the funding transaction ID of the channel pending
// message.
func printChanPending(update *lnrpc.OpenStatusUpdate_ChanPending) error {
txid, err := chainhash.NewHash(update.ChanPending.Txid)
if err != nil {
return err
}
printJSON(struct {
FundingTxid string `json:"funding_txid"`
}{
FundingTxid: txid.String(),
})
return nil
}
// readLine reads a line from standard in but does not block in case of a
// system interrupt like syscall.SIGINT (Ctrl+C).
func readLine(quit chan struct{}) (string, error) {
msg := make(chan string, 1)
// In a normal console, reading from stdin won't signal EOF when the
// user presses Ctrl+C. That's why we need to put this in a separate
// goroutine so it doesn't block.
go func() {
for {
var str string
_, _ = fmt.Scan(&str)
msg <- str
return
}
}()
for {
select {
case <-quit:
return "", io.EOF
case str := <-msg:
return str, nil
}
}
}
// checkPsbtFlags make sure a request to open a channel doesn't set any
// parameters that are incompatible with the PSBT funding flow.
func checkPsbtFlags(req *lnrpc.OpenChannelRequest) error {
if req.MinConfs != defaultUtxoMinConf || req.SpendUnconfirmed {
return fmt.Errorf("specifying minimum confirmations for PSBT " +
"funding is not supported")
}
if req.TargetConf != 0 || req.SatPerByte != 0 {
return fmt.Errorf("setting fee estimation parameters not " +
"supported for PSBT funding")
}
return nil
}
// sendFundingState sends a single funding state step message by using a new
// client connection. This is necessary if the whole funding flow takes longer
// than the default macaroon timeout, then we cannot use a single client
// connection.
func sendFundingState(cancelCtx context.Context, cliCtx *cli.Context,
msg *lnrpc.FundingTransitionMsg) error {
client, cleanUp := getClient(cliCtx)
defer cleanUp()
_, err := client.FundingStateStep(cancelCtx, msg)
return err
}

@ -577,269 +577,6 @@ func disconnectPeer(ctx *cli.Context) error {
return nil
}
// TODO(roasbeef): change default number of confirmations
var openChannelCommand = cli.Command{
Name: "openchannel",
Category: "Channels",
Usage: "Open a channel to a node or an existing peer.",
Description: `
Attempt to open a new channel to an existing peer with the key node-key
optionally blocking until the channel is 'open'.
One can also connect to a node before opening a new channel to it by
setting its host:port via the --connect argument. For this to work,
the node_key must be provided, rather than the peer_id. This is optional.
The channel will be initialized with local-amt satoshis local and push-amt
satoshis for the remote node. Note that specifying push-amt means you give that
amount to the remote node as part of the channel opening. Once the channel is open,
a channelPoint (txid:vout) of the funding output is returned.
If the remote peer supports the option upfront shutdown feature bit (query
listpeers to see their supported feature bits), an address to enforce
payout of funds on cooperative close can optionally be provided. Note that
if you set this value, you will not be able to cooperatively close out to
another address.
One can manually set the fee to be used for the funding transaction via either
the --conf_target or --sat_per_byte arguments. This is optional.`,
ArgsUsage: "node-key local-amt push-amt",
Flags: []cli.Flag{
cli.StringFlag{
Name: "node_key",
Usage: "the identity public key of the target node/peer " +
"serialized in compressed format",
},
cli.StringFlag{
Name: "connect",
Usage: "(optional) the host:port of the target node",
},
cli.IntFlag{
Name: "local_amt",
Usage: "the number of satoshis the wallet should commit to the channel",
},
cli.IntFlag{
Name: "push_amt",
Usage: "the number of satoshis to give the remote side " +
"as part of the initial commitment state, " +
"this is equivalent to first opening a " +
"channel and sending the remote party funds, " +
"but done all in one step",
},
cli.BoolFlag{
Name: "block",
Usage: "block and wait until the channel is fully open",
},
cli.Int64Flag{
Name: "conf_target",
Usage: "(optional) the number of blocks that the " +
"transaction *should* confirm in, will be " +
"used for fee estimation",
},
cli.Int64Flag{
Name: "sat_per_byte",
Usage: "(optional) a manual fee expressed in " +
"sat/byte that should be used when crafting " +
"the transaction",
},
cli.BoolFlag{
Name: "private",
Usage: "make the channel private, such that it won't " +
"be announced to the greater network, and " +
"nodes other than the two channel endpoints " +
"must be explicitly told about it to be able " +
"to route through it",
},
cli.Int64Flag{
Name: "min_htlc_msat",
Usage: "(optional) the minimum value we will require " +
"for incoming HTLCs on the channel",
},
cli.Uint64Flag{
Name: "remote_csv_delay",
Usage: "(optional) the number of blocks we will require " +
"our channel counterparty to wait before accessing " +
"its funds in case of unilateral close. If this is " +
"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",
Value: 1,
},
cli.StringFlag{
Name: "close_address",
Usage: "(optional) an address to enforce payout of our " +
"funds to on cooperative close. Note that if this " +
"value is set on channel open, you will *not* be " +
"able to cooperatively close to a different address.",
},
},
Action: actionDecorator(openChannel),
}
func openChannel(ctx *cli.Context) error {
// TODO(roasbeef): add deadline to context
ctxb := context.Background()
client, cleanUp := getClient(ctx)
defer cleanUp()
args := ctx.Args()
var err error
// Show command help if no arguments provided
if ctx.NArg() == 0 && ctx.NumFlags() == 0 {
cli.ShowCommandHelp(ctx, "openchannel")
return nil
}
minConfs := int32(ctx.Uint64("min_confs"))
req := &lnrpc.OpenChannelRequest{
TargetConf: int32(ctx.Int64("conf_target")),
SatPerByte: ctx.Int64("sat_per_byte"),
MinHtlcMsat: ctx.Int64("min_htlc_msat"),
RemoteCsvDelay: uint32(ctx.Uint64("remote_csv_delay")),
MinConfs: minConfs,
SpendUnconfirmed: minConfs == 0,
CloseAddress: ctx.String("close_address"),
}
switch {
case ctx.IsSet("node_key"):
nodePubHex, err := hex.DecodeString(ctx.String("node_key"))
if err != nil {
return fmt.Errorf("unable to decode node public key: %v", err)
}
req.NodePubkey = nodePubHex
case args.Present():
nodePubHex, err := hex.DecodeString(args.First())
if err != nil {
return fmt.Errorf("unable to decode node public key: %v", err)
}
args = args.Tail()
req.NodePubkey = nodePubHex
default:
return fmt.Errorf("node id argument missing")
}
// As soon as we can confirm that the node's node_key was set, rather
// than the peer_id, we can check if the host:port was also set to
// connect to it before opening the channel.
if req.NodePubkey != nil && ctx.IsSet("connect") {
addr := &lnrpc.LightningAddress{
Pubkey: hex.EncodeToString(req.NodePubkey),
Host: ctx.String("connect"),
}
req := &lnrpc.ConnectPeerRequest{
Addr: addr,
Perm: false,
}
// Check if connecting to the node was successful.
// We discard the peer id returned as it is not needed.
_, err := client.ConnectPeer(ctxb, req)
if err != nil &&
!strings.Contains(err.Error(), "already connected") {
return err
}
}
switch {
case ctx.IsSet("local_amt"):
req.LocalFundingAmount = int64(ctx.Int("local_amt"))
case args.Present():
req.LocalFundingAmount, err = strconv.ParseInt(args.First(), 10, 64)
if err != nil {
return fmt.Errorf("unable to decode local amt: %v", err)
}
args = args.Tail()
default:
return fmt.Errorf("local amt argument missing")
}
if ctx.IsSet("push_amt") {
req.PushSat = int64(ctx.Int("push_amt"))
} else if args.Present() {
req.PushSat, err = strconv.ParseInt(args.First(), 10, 64)
if err != nil {
return fmt.Errorf("unable to decode push amt: %v", err)
}
}
req.Private = ctx.Bool("private")
stream, err := client.OpenChannel(ctxb, req)
if err != nil {
return err
}
for {
resp, err := stream.Recv()
if err == io.EOF {
return nil
} else if err != nil {
return err
}
switch update := resp.Update.(type) {
case *lnrpc.OpenStatusUpdate_ChanPending:
txid, err := chainhash.NewHash(update.ChanPending.Txid)
if err != nil {
return err
}
printJSON(struct {
FundingTxid string `json:"funding_txid"`
}{
FundingTxid: txid.String(),
},
)
if !ctx.Bool("block") {
return nil
}
case *lnrpc.OpenStatusUpdate_ChanOpen:
channelPoint := update.ChanOpen.ChannelPoint
// A channel point's funding txid can be get/set as a
// byte slice or a string. In the case it is a string,
// decode it.
var txidHash []byte
switch channelPoint.GetFundingTxid().(type) {
case *lnrpc.ChannelPoint_FundingTxidBytes:
txidHash = channelPoint.GetFundingTxidBytes()
case *lnrpc.ChannelPoint_FundingTxidStr:
s := channelPoint.GetFundingTxidStr()
h, err := chainhash.NewHashFromStr(s)
if err != nil {
return err
}
txidHash = h[:]
}
txid, err := chainhash.NewHash(txidHash)
if err != nil {
return err
}
index := channelPoint.OutputIndex
printJSON(struct {
ChannelPoint string `json:"channel_point"`
}{
ChannelPoint: fmt.Sprintf("%v:%v", txid, index),
},
)
}
}
}
// TODO(roasbeef): also allow short relative channel ID.
var closeChannelCommand = cli.Command{

216
docs/psbt.md Normal file

@ -0,0 +1,216 @@
# PSBT
This document describes various use cases around the topic of Partially Signed
Bitcoin Transactions (PSBTs). Currently only channel funding is possible with
PSBTs but more features are planned.
See [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) for
a full description of the PSBT format and the different _roles_ that a
participant in a PSBT can have.
## Opening a channel by using a PSBT
This is a step-by-step guide on how to open a channel with `lnd` by using a PSBT
as the funding transaction.
We will use `bitcoind` to create and sign the transaction just to keep the
example simple. Of course any other PSBT compatible wallet could be used and the
process would likely be spread out over multiple signing steps. The goal of this
example is not to cover each and every possible edge case but to help users of
`lnd` understand what inputs the `lncli` utility expects.
The goal is to open a channel of 1'234'567 satoshis to the node
`03db1e56e5f76bc4018cf6f03d1bb98a7ae96e3f18535e929034f85e7f1ca2b8ac` by using
a PSBT. That means, `lnd` can have a wallet balance of `0` and is still able to
open a channel. We'll jump into an example right away.
The new funding flow has a small caveat: _Time matters_.
When opening a channel using the PSBT flow, we start the negotiation
with the remote peer immediately so we can obtain their multisig key they are
going to use for the channel. Then we pause the whole process until we get a
fully signed transaction back from the user. Unfortunately there is no reliable
way to know after how much time the remote node starts to clean up and "forgets"
about the pending channel. If the remote node is an `lnd` node, we know it's
after 10 minutes. **So as long as the whole process takes less than 10 minutes,
everything should work fine.**
### 1. Use the new `--psbt` flag in `lncli openchannel`
The new `--psbt` flag in the `openchannel` command starts an interactive dialog
between `lncli` and the user. Below the command you see an example output from
a regtest setup. Of course all values will be different.
```bash
$ lncli openchannel --node_key 03db1e56e5f76bc4018cf6f03d1bb98a7ae96e3f18535e929034f85e7f1ca2b8ac --local_amt 1234567 --psbt
Starting PSBT funding flow with pending channel ID fc7853889a04d33b8115bd79ebc99c5eea80d894a0bead40fae5a06bcbdccd3d.
PSBT funding initiated with peer 03db1e56e5f76bc4018cf6f03d1bb98a7ae96e3f18535e929034f85e7f1ca2b8ac.
Please create a PSBT that sends 0.01234567 BTC (1234567 satoshi) to the funding address bcrt1qh33ghvgjj3ef625nl9jxz6nnrz2z9e65vsdey7w5msrklgr6rc0sv0s08q.
Example with bitcoind:
bitcoin-cli walletcreatefundedpsbt [] '[{"bcrt1qh33ghvgjj3ef625nl9jxz6nnrz2z9e65vsdey7w5msrklgr6rc0sv0s08q":0.01234567}]'
Or if you are using a wallet that can fund a PSBT directly (currently not
possible with bitcoind), you can use this PSBT that contains the same address
and amount: cHNidP8BADUCAAAAAAGH1hIAAAAAACIAILxii7ESlHKdKpP5ZGFqcxiUIudUZBuSedTcB2+geh4fAAAAAAAA
Paste the funded PSBT here to continue the funding flow.
Base64 encoded PSBT:
```
The command line now waits until a PSBT is entered. We'll create one in the next
step. Make sure to use a new shell window/tab for the next commands and leave
the prompt from the `openchannel` running as is.
### 2. Use `bitcoind` to create a funding transaction
The output of the last command already gave us an example command to use with
`bitcoind`. We'll go ahead and execute it now. The meaning of this command is
something like "bitcoind, give me a PSBT that sends the given amount to the
given address, choose any input you see fit":
```bash
$ bitcoin-cli walletcreatefundedpsbt [] '[{"bcrt1qh33ghvgjj3ef625nl9jxz6nnrz2z9e65vsdey7w5msrklgr6rc0sv0s08q":0.01234567}]'
{
"psbt": "cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAAAA",
"fee": 0.00003060,
"changepos": 1
}
```
We see that `bitcoind` has given us a transaction that would pay `3060` satoshi
in fees. Fee estimation/calculation can be changed with parameters of the
`walletcreatefundedpsbt` command. To see all options, use
`bitcoin-cli help walletcreatefundedpsbt`.
If we want to know what exactly is in this PSBT, we can look at it with the
`decodepsbt` command:
```bash
$ bitcoin-cli decodepsbt cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAAAA
{
"tx": {
"txid": "374504e4246a93a45b4a2c2bc31d8adc8525aa101c7b9065db6dc01c4bdfce0a",
"hash": "374504e4246a93a45b4a2c2bc31d8adc8525aa101c7b9065db6dc01c4bdfce0a",
"version": 2,
"size": 125,
"vsize": 125,
"weight": 500,
"locktime": 0,
"vin": [
{
"txid": "3ff673717cfb451658e260ecacc6e9cb39112e0440bd5e7cea87017eff2d4bbc",
"vout": 0,
"scriptSig": {
"asm": "",
"hex": ""
},
"sequence": 4294967294
}
],
"vout": [
{
"value": 0.01234567,
"n": 0,
"scriptPubKey": {
"asm": "0 bc628bb11294729d2a93f964616a73189422e754641b9279d4dc076fa07a1e1f",
"hex": "0020bc628bb11294729d2a93f964616a73189422e754641b9279d4dc076fa07a1e1f",
"reqSigs": 1,
"type": "witness_v0_scripthash",
"addresses": [
"bcrt1qh33ghvgjj3ef625nl9jxz6nnrz2z9e65vsdey7w5msrklgr6rc0sv0s08q"
]
}
},
{
"value": 48.98759093,
"n": 1,
"scriptPubKey": {
"asm": "0 bfba4c71068726c99ce9051924456ed09c3ce1bc",
"hex": "0014bfba4c71068726c99ce9051924456ed09c3ce1bc",
"reqSigs": 1,
"type": "witness_v0_keyhash",
"addresses": [
"bcrt1qh7aycugxsunvn88fq5vjg3tw6zwrecduvvgre5"
]
}
}
]
},
"unknown": {
},
"inputs": [
{
"witness_utxo": {
"amount": 48.99996720,
"scriptPubKey": {
"asm": "0 77a6275d5717b094ed65c12092c3fea645fba8eb",
"hex": "001477a6275d5717b094ed65c12092c3fea645fba8eb",
"type": "witness_v0_keyhash",
"address": "bcrt1qw7nzwh2hz7cffmt9cysf9sl75ezlh28tzl4n4e"
}
}
}
],
"outputs": [
{
},
{
}
],
"fee": 0.00003060
}
```
This tells us that we got a PSBT with a big input, the channel output and a
change output for the rest. Everything is there but the signatures/witness data,
which is exactly what we need.
### 3. Verify and sign the PSBT
Now that we have a valid PSBT that has everything but the final
signatures/witness data, we can paste it into the prompt in `lncli` that is
still waiting for our input.
```bash
...
Base64 encoded PSBT: cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAAAA
PSBT verified by lnd, please continue the funding flow by signing the PSBT by
all required parties/devices. Once the transaction is fully signed, paste it
again here.
Base64 encoded PSBT:
```
We can now go ahead and sign the transaction. We are going to use `bitcoind` for
this again, but in practice this would now happen on a hardware wallet and
perhaps `bitcoind` would only know the public keys and couldn't sign for the
transaction itself. Again, this is only an example and can't reflect all
real-world use cases.
```bash
$ bitcoin-cli walletprocesspsbt cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAAAA
{
"psbt": "cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAQhrAkcwRAIgHKQbenZYvgADRd9TKGVO36NnaIgW3S12OUg8XGtSrE8CICmeaYoJ/U7Ecm+/GneY8i2hu2QCaQnuomJgzn+JAnrDASEDUBmCLcsybA5qXSRBBdZ0Uk/FQiay9NgOpv4D26yeJpAAAAA=",
"complete": true
}
```
Interpreting the output, we now have a complete, final, and signed transaction
inside the PSBT. Let's give it to `lncli` to continue:
```bash
...
Base64 encoded PSBT: cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAQhrAkcwRAIgHKQbenZYvgADRd9TKGVO36NnaIgW3S12OUg8XGtSrE8CICmeaYoJ/U7Ecm+/GneY8i2hu2QCaQnuomJgzn+JAnrDASEDUBmCLcsybA5qXSRBBdZ0Uk/FQiay9NgOpv4D26yeJpAAAAA=
{
"funding_txid": "374504e4246a93a45b4a2c2bc31d8adc8525aa101c7b9065db6dc01c4bdfce0a"
}
```
Success! We now have the final transaction ID of the published funding
transaction. Now we only have to wait for some confirmations, then we can start
using the freshly created channel.

@ -26,6 +26,7 @@ import (
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwallet/chanfunding"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing"
"golang.org/x/crypto/salsa20"
@ -698,7 +699,7 @@ func (f *fundingManager) failFundingFlow(peer lnpeer.Peer, tempChanID [32]byte,
fndgLog.Debugf("Failing funding flow for pending_id=%x: %v",
tempChanID, fundingErr)
ctx, err := f.cancelReservationCtx(peer.IdentityKey(), tempChanID)
ctx, err := f.cancelReservationCtx(peer.IdentityKey(), tempChanID, false)
if err != nil {
fndgLog.Errorf("unable to cancel reservation: %v", err)
}
@ -1547,7 +1548,42 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
UpfrontShutdown: msg.UpfrontShutdownScript,
}
err = resCtx.reservation.ProcessContribution(remoteContribution)
if err != nil {
// The wallet has detected that a PSBT funding process was requested by
// the user and has halted the funding process after negotiating the
// multisig keys. We now have everything that is needed for the user to
// start constructing a PSBT that sends to the multisig funding address.
var psbtIntent *chanfunding.PsbtIntent
if psbtErr, ok := err.(*lnwallet.PsbtFundingRequired); ok {
// Return the information that is needed by the user to
// construct the PSBT back to the caller.
addr, amt, packet, err := psbtErr.Intent.FundingParams()
if err != nil {
fndgLog.Errorf("Unable to process PSBT funding params "+
"for contribution from %v: %v", peerKey, err)
f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
return
}
var buf bytes.Buffer
err = packet.Serialize(&buf)
if err != nil {
fndgLog.Errorf("Unable to serialize PSBT for "+
"contribution from %v: %v", peerKey, err)
f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
return
}
resCtx.updates <- &lnrpc.OpenStatusUpdate{
PendingChanId: pendingChanID[:],
Update: &lnrpc.OpenStatusUpdate_PsbtFund{
PsbtFund: &lnrpc.ReadyForPsbtFunding{
FundingAddress: addr.EncodeAddress(),
FundingAmount: amt,
Psbt: buf.Bytes(),
},
},
}
psbtIntent = psbtErr.Intent
} else if err != nil {
fndgLog.Errorf("Unable to process contribution from %v: %v",
peerKey, err)
f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
@ -1559,6 +1595,105 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
fndgLog.Debugf("Remote party accepted commitment constraints: %v",
spew.Sdump(remoteContribution.ChannelConfig.ChannelConstraints))
// If the user requested funding through a PSBT, we cannot directly
// continue now and need to wait for the fully funded and signed PSBT
// to arrive. To not block any other channels from opening, we wait in
// a separate goroutine.
if psbtIntent != nil {
f.wg.Add(1)
go func() {
defer f.wg.Done()
f.waitForPsbt(psbtIntent, resCtx, pendingChanID)
}()
// With the new goroutine spawned, we can now exit to unblock
// the main event loop.
return
}
// In a normal, non-PSBT funding flow, we can jump directly to the next
// step where we expect our contribution to be finalized.
f.continueFundingAccept(resCtx, pendingChanID)
}
// waitForPsbt blocks until either a signed PSBT arrives, an error occurs or
// the funding manager shuts down. In the case of a valid PSBT, the funding flow
// is continued.
//
// NOTE: This method must be called as a goroutine.
func (f *fundingManager) waitForPsbt(intent *chanfunding.PsbtIntent,
resCtx *reservationWithCtx, pendingChanID [32]byte) {
// failFlow is a helper that logs an error message with the current
// context and then fails the funding flow.
peerKey := resCtx.peer.IdentityKey()
failFlow := func(errMsg string, cause error) {
fndgLog.Errorf("Unable to handle funding accept message "+
"for peer_key=%x, pending_chan_id=%x: %s: %v",
peerKey.SerializeCompressed(), pendingChanID, errMsg,
cause)
f.failFundingFlow(resCtx.peer, pendingChanID, cause)
}
// We'll now wait until the intent has received the final and complete
// funding transaction. If the channel is closed without any error being
// sent, we know everything's going as expected.
select {
case err := <-intent.PsbtReady:
switch err {
// If the user canceled the funding reservation, we need to
// inform the other peer about us canceling the reservation.
case chanfunding.ErrUserCanceled:
failFlow("aborting PSBT flow", err)
return
// If the remote canceled the funding reservation, we don't need
// to send another fail message. But we want to inform the user
// about what happened.
case chanfunding.ErrRemoteCanceled:
fndgLog.Infof("Remote canceled, aborting PSBT flow "+
"for peer_key=%x, pending_chan_id=%x",
peerKey.SerializeCompressed(), pendingChanID)
return
// Nil error means the flow continues normally now.
case nil:
// For any other error, we'll fail the funding flow.
default:
failFlow("error waiting for PSBT flow", err)
return
}
// A non-nil error means we can continue the funding flow.
// Notify the wallet so it can prepare everything we need to
// continue.
err = resCtx.reservation.ProcessPsbt()
if err != nil {
failFlow("error continuing PSBT flow", err)
return
}
// We are now ready to continue the funding flow.
f.continueFundingAccept(resCtx, pendingChanID)
// Handle a server shutdown as well because the reservation won't
// survive a restart as it's in memory only.
case <-f.quit:
fndgLog.Errorf("Unable to handle funding accept message "+
"for peer_key=%x, pending_chan_id=%x: funding manager "+
"shutting down", peerKey.SerializeCompressed(),
pendingChanID)
return
}
}
// continueFundingAccept continues the channel funding flow once our
// contribution is finalized, the channel output is known and the funding
// transaction is signed.
func (f *fundingManager) continueFundingAccept(resCtx *reservationWithCtx,
pendingChanID [32]byte) {
// Now that we have their contribution, we can extract, then send over
// both the funding out point and our signature for their version of
// the commitment transaction to the remote peer.
@ -1586,6 +1721,7 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
fndgLog.Infof("Generated ChannelPoint(%v) for pending_id(%x)", outPoint,
pendingChanID[:])
var err error
fundingCreated := &lnwire.FundingCreated{
PendingChannelID: pendingChanID,
FundingPoint: *outPoint,
@ -1593,12 +1729,12 @@ func (f *fundingManager) handleFundingAccept(fmsg *fundingAcceptMsg) {
fundingCreated.CommitSig, err = lnwire.NewSigFromRawSignature(sig)
if err != nil {
fndgLog.Errorf("Unable to parse signature: %v", err)
f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
f.failFundingFlow(resCtx.peer, pendingChanID, err)
return
}
if err := fmsg.peer.SendMessage(true, fundingCreated); err != nil {
if err := resCtx.peer.SendMessage(true, fundingCreated); err != nil {
fndgLog.Errorf("Unable to send funding complete message: %v", err)
f.failFundingFlow(fmsg.peer, msg.PendingChannelID, err)
f.failFundingFlow(resCtx.peer, pendingChanID, err)
return
}
}
@ -3070,7 +3206,8 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// Since we were unable to send the initial message to the peer
// and start the funding flow, we'll cancel this reservation.
if _, err := f.cancelReservationCtx(peerKey, chanID); err != nil {
_, err := f.cancelReservationCtx(peerKey, chanID, false)
if err != nil {
fndgLog.Errorf("unable to cancel reservation: %v", err)
}
@ -3130,7 +3267,7 @@ func (f *fundingManager) handleErrorMsg(fmsg *fundingErrorMsg) {
// First, we'll attempt to retrieve and cancel the funding workflow
// that this error was tied to. If we're unable to do so, then we'll
// exit early as this was an unwarranted error.
resCtx, err := f.cancelReservationCtx(fmsg.peerKey, chanID)
resCtx, err := f.cancelReservationCtx(fmsg.peerKey, chanID, true)
if err != nil {
fndgLog.Warnf("Received error for non-existent funding "+
"flow: %v (%v)", err, protocolErr.Error())
@ -3144,6 +3281,14 @@ func (f *fundingManager) handleErrorMsg(fmsg *fundingErrorMsg) {
)
fndgLog.Errorf(fundingErr.Error())
// If this was a PSBT funding flow, the remote likely timed out because
// we waited too long. Return a nice error message to the user in that
// case so the user knows what's the problem.
if resCtx.reservation.IsPsbt() {
fundingErr = fmt.Errorf("%w: %v", chanfunding.ErrRemoteCanceled,
fundingErr)
}
resCtx.err <- fundingErr
}
@ -3160,7 +3305,14 @@ func (f *fundingManager) pruneZombieReservations() {
continue
}
if time.Since(resCtx.lastUpdated) > f.cfg.ReservationTimeout {
// We don't want to expire PSBT funding reservations.
// These reservations are always initiated by us and the
// remote peer is likely going to cancel them after some
// idle time anyway. So no need for us to also prune
// them.
sinceLastUpdate := time.Since(resCtx.lastUpdated)
isExpired := sinceLastUpdate > f.cfg.ReservationTimeout
if !resCtx.reservation.IsPsbt() && isExpired {
zombieReservations[pendingChanID] = resCtx
}
}
@ -3169,7 +3321,7 @@ func (f *fundingManager) pruneZombieReservations() {
for pendingChanID, resCtx := range zombieReservations {
err := fmt.Errorf("reservation timed out waiting for peer "+
"(peer_id:%v, chan_id:%x)", resCtx.peer.IdentityKey(),
"(peer_id:%x, chan_id:%x)", resCtx.peer.IdentityKey(),
pendingChanID[:])
fndgLog.Warnf(err.Error())
f.failFundingFlow(resCtx.peer, pendingChanID, err)
@ -3179,7 +3331,7 @@ func (f *fundingManager) pruneZombieReservations() {
// cancelReservationCtx does all needed work in order to securely cancel the
// reservation.
func (f *fundingManager) cancelReservationCtx(peerKey *btcec.PublicKey,
pendingChanID [32]byte) (*reservationWithCtx, error) {
pendingChanID [32]byte, byRemote bool) (*reservationWithCtx, error) {
fndgLog.Infof("Cancelling funding reservation for node_key=%x, "+
"chan_id=%x", peerKey.SerializeCompressed(), pendingChanID[:])
@ -3201,6 +3353,14 @@ func (f *fundingManager) cancelReservationCtx(peerKey *btcec.PublicKey,
"peer(%x)", pendingChanID[:], peerIDKey[:])
}
// If the reservation was a PSBT funding flow and it was canceled by the
// remote peer, then we need to thread through a different error message
// to the subroutine that's waiting for the user input so it can return
// a nice error message to the user.
if ctx.reservation.IsPsbt() && byRemote {
ctx.reservation.RemoteCanceled()
}
if err := ctx.reservation.Cancel(); err != nil {
return nil, errors.Errorf("unable to cancel reservation: %v",
err)

7
go.mod

@ -8,6 +8,7 @@ require (
github.com/btcsuite/btcd v0.20.1-beta
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d
github.com/btcsuite/btcutil/psbt v1.0.2-0.20200323233600-8bf941f57059
github.com/btcsuite/btcwallet v0.11.1-0.20200323235326-015c045a3bb7
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0
github.com/btcsuite/btcwallet/wallet/txrules v1.0.0
@ -45,7 +46,7 @@ require (
github.com/rogpeppe/fastuuid v1.2.0 // indirect
github.com/tv42/zbase32 v0.0.0-20160707012821-501572607d02
github.com/urfave/cli v1.18.0
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922
@ -64,4 +65,8 @@ replace github.com/lightningnetwork/lnd/cert => ./cert
replace git.schwanenlied.me/yawning/bsaes.git => github.com/Yawning/bsaes v0.0.0-20180720073208-c0276d75487e
// Pin this version that we know works explicitly, even though the
// btcsuite/btcutil package requests a newer version.
replace golang.org/x/crypto => golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67
go 1.12

4
go.sum

@ -26,6 +26,8 @@ github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil/psbt v1.0.2-0.20200323233600-8bf941f57059 h1:RU+MRFz83kf5hgJrGryakeYv/Xj2wZ7pwu9Eb7tna30=
github.com/btcsuite/btcutil/psbt v1.0.2-0.20200323233600-8bf941f57059/go.mod h1:LVveMu4VaNSkIRTZu2+ut0HDBRuYjqGocxDMNS1KuGQ=
github.com/btcsuite/btcwallet v0.11.1-0.20200323235326-015c045a3bb7 h1:ubYJYIi13atgwPCX7FZQZV2mytkaRHWPycDFdF28U0o=
github.com/btcsuite/btcwallet v0.11.1-0.20200323235326-015c045a3bb7/go.mod h1:1O1uRHMPXHdwA4/od8nqYqrgclVKp+wtfXUAqHmeRvE=
github.com/btcsuite/btcwallet/wallet/txauthor v1.0.0 h1:KGHMW5sd7yDdDMkCZ/JpP0KltolFsQcB973brBnfj4c=
@ -182,8 +184,6 @@ github.com/urfave/cli v1.18.0 h1:m9MfmZWX7bwr9kUcs/Asr95j0IVXzGNNc+/5ku2m26Q=
github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=

@ -374,7 +374,7 @@ func (x PendingChannelsResponse_ForceClosedChannel_AnchorState) String() string
}
func (PendingChannelsResponse_ForceClosedChannel_AnchorState) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{72, 5, 0}
return fileDescriptor_77a6da22d6a3feb1, []int{76, 5, 0}
}
type ChannelEventUpdate_UpdateType int32
@ -408,7 +408,7 @@ func (x ChannelEventUpdate_UpdateType) String() string {
}
func (ChannelEventUpdate_UpdateType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{74, 0}
return fileDescriptor_77a6da22d6a3feb1, []int{78, 0}
}
type Invoice_InvoiceState int32
@ -439,7 +439,7 @@ func (x Invoice_InvoiceState) String() string {
}
func (Invoice_InvoiceState) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{109, 0}
return fileDescriptor_77a6da22d6a3feb1, []int{113, 0}
}
type Payment_PaymentStatus int32
@ -470,7 +470,7 @@ func (x Payment_PaymentStatus) String() string {
}
func (Payment_PaymentStatus) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{116, 0}
return fileDescriptor_77a6da22d6a3feb1, []int{120, 0}
}
type HTLCAttempt_HTLCStatus int32
@ -498,7 +498,7 @@ func (x HTLCAttempt_HTLCStatus) String() string {
}
func (HTLCAttempt_HTLCStatus) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{117, 0}
return fileDescriptor_77a6da22d6a3feb1, []int{121, 0}
}
type Failure_FailureCode int32
@ -609,7 +609,7 @@ func (x Failure_FailureCode) String() string {
}
func (Failure_FailureCode) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{150, 0}
return fileDescriptor_77a6da22d6a3feb1, []int{154, 0}
}
type GenSeedRequest struct {
@ -4694,6 +4694,72 @@ func (m *PendingUpdate) GetOutputIndex() uint32 {
return 0
}
type ReadyForPsbtFunding struct {
//*
//The P2WSH address of the channel funding multisig address that the below
//specified amount in satoshis needs to be sent to.
FundingAddress string `protobuf:"bytes,1,opt,name=funding_address,json=fundingAddress,proto3" json:"funding_address,omitempty"`
//*
//The exact amount in satoshis that needs to be sent to the above address to
//fund the pending channel.
FundingAmount int64 `protobuf:"varint,2,opt,name=funding_amount,json=fundingAmount,proto3" json:"funding_amount,omitempty"`
//*
//A raw PSBT that contains the pending channel output. If a base PSBT was
//provided in the PsbtShim, this is the base PSBT with one additional output.
//If no base PSBT was specified, this is an otherwise empty PSBT with exactly
//one output.
Psbt []byte `protobuf:"bytes,3,opt,name=psbt,proto3" json:"psbt,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReadyForPsbtFunding) Reset() { *m = ReadyForPsbtFunding{} }
func (m *ReadyForPsbtFunding) String() string { return proto.CompactTextString(m) }
func (*ReadyForPsbtFunding) ProtoMessage() {}
func (*ReadyForPsbtFunding) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{61}
}
func (m *ReadyForPsbtFunding) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReadyForPsbtFunding.Unmarshal(m, b)
}
func (m *ReadyForPsbtFunding) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReadyForPsbtFunding.Marshal(b, m, deterministic)
}
func (m *ReadyForPsbtFunding) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReadyForPsbtFunding.Merge(m, src)
}
func (m *ReadyForPsbtFunding) XXX_Size() int {
return xxx_messageInfo_ReadyForPsbtFunding.Size(m)
}
func (m *ReadyForPsbtFunding) XXX_DiscardUnknown() {
xxx_messageInfo_ReadyForPsbtFunding.DiscardUnknown(m)
}
var xxx_messageInfo_ReadyForPsbtFunding proto.InternalMessageInfo
func (m *ReadyForPsbtFunding) GetFundingAddress() string {
if m != nil {
return m.FundingAddress
}
return ""
}
func (m *ReadyForPsbtFunding) GetFundingAmount() int64 {
if m != nil {
return m.FundingAmount
}
return 0
}
func (m *ReadyForPsbtFunding) GetPsbt() []byte {
if m != nil {
return m.Psbt
}
return nil
}
type OpenChannelRequest struct {
//*
//The pubkey of the node to open a channel with. When using REST, this field
@ -4755,7 +4821,7 @@ func (m *OpenChannelRequest) Reset() { *m = OpenChannelRequest{} }
func (m *OpenChannelRequest) String() string { return proto.CompactTextString(m) }
func (*OpenChannelRequest) ProtoMessage() {}
func (*OpenChannelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{61}
return fileDescriptor_77a6da22d6a3feb1, []int{62}
}
func (m *OpenChannelRequest) XXX_Unmarshal(b []byte) error {
@ -4872,6 +4938,7 @@ type OpenStatusUpdate struct {
// Types that are valid to be assigned to Update:
// *OpenStatusUpdate_ChanPending
// *OpenStatusUpdate_ChanOpen
// *OpenStatusUpdate_PsbtFund
Update isOpenStatusUpdate_Update `protobuf_oneof:"update"`
//*
//The pending channel ID of the created channel. This value may be used to
@ -4886,7 +4953,7 @@ func (m *OpenStatusUpdate) Reset() { *m = OpenStatusUpdate{} }
func (m *OpenStatusUpdate) String() string { return proto.CompactTextString(m) }
func (*OpenStatusUpdate) ProtoMessage() {}
func (*OpenStatusUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{62}
return fileDescriptor_77a6da22d6a3feb1, []int{63}
}
func (m *OpenStatusUpdate) XXX_Unmarshal(b []byte) error {
@ -4919,10 +4986,16 @@ type OpenStatusUpdate_ChanOpen struct {
ChanOpen *ChannelOpenUpdate `protobuf:"bytes,3,opt,name=chan_open,json=chanOpen,proto3,oneof"`
}
type OpenStatusUpdate_PsbtFund struct {
PsbtFund *ReadyForPsbtFunding `protobuf:"bytes,5,opt,name=psbt_fund,json=psbtFund,proto3,oneof"`
}
func (*OpenStatusUpdate_ChanPending) isOpenStatusUpdate_Update() {}
func (*OpenStatusUpdate_ChanOpen) isOpenStatusUpdate_Update() {}
func (*OpenStatusUpdate_PsbtFund) isOpenStatusUpdate_Update() {}
func (m *OpenStatusUpdate) GetUpdate() isOpenStatusUpdate_Update {
if m != nil {
return m.Update
@ -4944,6 +5017,13 @@ func (m *OpenStatusUpdate) GetChanOpen() *ChannelOpenUpdate {
return nil
}
func (m *OpenStatusUpdate) GetPsbtFund() *ReadyForPsbtFunding {
if x, ok := m.GetUpdate().(*OpenStatusUpdate_PsbtFund); ok {
return x.PsbtFund
}
return nil
}
func (m *OpenStatusUpdate) GetPendingChanId() []byte {
if m != nil {
return m.PendingChanId
@ -4956,6 +5036,7 @@ func (*OpenStatusUpdate) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*OpenStatusUpdate_ChanPending)(nil),
(*OpenStatusUpdate_ChanOpen)(nil),
(*OpenStatusUpdate_PsbtFund)(nil),
}
}
@ -4973,7 +5054,7 @@ func (m *KeyLocator) Reset() { *m = KeyLocator{} }
func (m *KeyLocator) String() string { return proto.CompactTextString(m) }
func (*KeyLocator) ProtoMessage() {}
func (*KeyLocator) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{63}
return fileDescriptor_77a6da22d6a3feb1, []int{64}
}
func (m *KeyLocator) XXX_Unmarshal(b []byte) error {
@ -5024,7 +5105,7 @@ func (m *KeyDescriptor) Reset() { *m = KeyDescriptor{} }
func (m *KeyDescriptor) String() string { return proto.CompactTextString(m) }
func (*KeyDescriptor) ProtoMessage() {}
func (*KeyDescriptor) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{64}
return fileDescriptor_77a6da22d6a3feb1, []int{65}
}
func (m *KeyDescriptor) XXX_Unmarshal(b []byte) error {
@ -5091,7 +5172,7 @@ func (m *ChanPointShim) Reset() { *m = ChanPointShim{} }
func (m *ChanPointShim) String() string { return proto.CompactTextString(m) }
func (*ChanPointShim) ProtoMessage() {}
func (*ChanPointShim) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{65}
return fileDescriptor_77a6da22d6a3feb1, []int{66}
}
func (m *ChanPointShim) XXX_Unmarshal(b []byte) error {
@ -5154,9 +5235,64 @@ func (m *ChanPointShim) GetThawHeight() uint32 {
return 0
}
type PsbtShim struct {
//*
//A unique identifier of 32 random bytes that will be used as the pending
//channel ID to identify the PSBT state machine when interacting with it and
//on the wire protocol to initiate the funding request.
PendingChanId []byte `protobuf:"bytes,1,opt,name=pending_chan_id,json=pendingChanId,proto3" json:"pending_chan_id,omitempty"`
//*
//An optional base PSBT the new channel output will be added to. If this is
//non-empty, it must be a binary serialized PSBT.
BasePsbt []byte `protobuf:"bytes,2,opt,name=base_psbt,json=basePsbt,proto3" json:"base_psbt,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *PsbtShim) Reset() { *m = PsbtShim{} }
func (m *PsbtShim) String() string { return proto.CompactTextString(m) }
func (*PsbtShim) ProtoMessage() {}
func (*PsbtShim) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{67}
}
func (m *PsbtShim) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PsbtShim.Unmarshal(m, b)
}
func (m *PsbtShim) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PsbtShim.Marshal(b, m, deterministic)
}
func (m *PsbtShim) XXX_Merge(src proto.Message) {
xxx_messageInfo_PsbtShim.Merge(m, src)
}
func (m *PsbtShim) XXX_Size() int {
return xxx_messageInfo_PsbtShim.Size(m)
}
func (m *PsbtShim) XXX_DiscardUnknown() {
xxx_messageInfo_PsbtShim.DiscardUnknown(m)
}
var xxx_messageInfo_PsbtShim proto.InternalMessageInfo
func (m *PsbtShim) GetPendingChanId() []byte {
if m != nil {
return m.PendingChanId
}
return nil
}
func (m *PsbtShim) GetBasePsbt() []byte {
if m != nil {
return m.BasePsbt
}
return nil
}
type FundingShim struct {
// Types that are valid to be assigned to Shim:
// *FundingShim_ChanPointShim
// *FundingShim_PsbtShim
Shim isFundingShim_Shim `protobuf_oneof:"shim"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@ -5167,7 +5303,7 @@ func (m *FundingShim) Reset() { *m = FundingShim{} }
func (m *FundingShim) String() string { return proto.CompactTextString(m) }
func (*FundingShim) ProtoMessage() {}
func (*FundingShim) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{66}
return fileDescriptor_77a6da22d6a3feb1, []int{68}
}
func (m *FundingShim) XXX_Unmarshal(b []byte) error {
@ -5196,8 +5332,14 @@ type FundingShim_ChanPointShim struct {
ChanPointShim *ChanPointShim `protobuf:"bytes,1,opt,name=chan_point_shim,json=chanPointShim,proto3,oneof"`
}
type FundingShim_PsbtShim struct {
PsbtShim *PsbtShim `protobuf:"bytes,2,opt,name=psbt_shim,json=psbtShim,proto3,oneof"`
}
func (*FundingShim_ChanPointShim) isFundingShim_Shim() {}
func (*FundingShim_PsbtShim) isFundingShim_Shim() {}
func (m *FundingShim) GetShim() isFundingShim_Shim {
if m != nil {
return m.Shim
@ -5212,10 +5354,18 @@ func (m *FundingShim) GetChanPointShim() *ChanPointShim {
return nil
}
func (m *FundingShim) GetPsbtShim() *PsbtShim {
if x, ok := m.GetShim().(*FundingShim_PsbtShim); ok {
return x.PsbtShim
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*FundingShim) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*FundingShim_ChanPointShim)(nil),
(*FundingShim_PsbtShim)(nil),
}
}
@ -5231,7 +5381,7 @@ func (m *FundingShimCancel) Reset() { *m = FundingShimCancel{} }
func (m *FundingShimCancel) String() string { return proto.CompactTextString(m) }
func (*FundingShimCancel) ProtoMessage() {}
func (*FundingShimCancel) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{67}
return fileDescriptor_77a6da22d6a3feb1, []int{69}
}
func (m *FundingShimCancel) XXX_Unmarshal(b []byte) error {
@ -5259,10 +5409,116 @@ func (m *FundingShimCancel) GetPendingChanId() []byte {
return nil
}
type FundingPsbtVerify struct {
//*
//The funded but not yet signed PSBT that sends the exact channel capacity
//amount to the PK script returned in the open channel message in a previous
//step.
FundedPsbt []byte `protobuf:"bytes,1,opt,name=funded_psbt,json=fundedPsbt,proto3" json:"funded_psbt,omitempty"`
/// The pending channel ID of the channel to get the PSBT for.
PendingChanId []byte `protobuf:"bytes,2,opt,name=pending_chan_id,json=pendingChanId,proto3" json:"pending_chan_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *FundingPsbtVerify) Reset() { *m = FundingPsbtVerify{} }
func (m *FundingPsbtVerify) String() string { return proto.CompactTextString(m) }
func (*FundingPsbtVerify) ProtoMessage() {}
func (*FundingPsbtVerify) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{70}
}
func (m *FundingPsbtVerify) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FundingPsbtVerify.Unmarshal(m, b)
}
func (m *FundingPsbtVerify) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_FundingPsbtVerify.Marshal(b, m, deterministic)
}
func (m *FundingPsbtVerify) XXX_Merge(src proto.Message) {
xxx_messageInfo_FundingPsbtVerify.Merge(m, src)
}
func (m *FundingPsbtVerify) XXX_Size() int {
return xxx_messageInfo_FundingPsbtVerify.Size(m)
}
func (m *FundingPsbtVerify) XXX_DiscardUnknown() {
xxx_messageInfo_FundingPsbtVerify.DiscardUnknown(m)
}
var xxx_messageInfo_FundingPsbtVerify proto.InternalMessageInfo
func (m *FundingPsbtVerify) GetFundedPsbt() []byte {
if m != nil {
return m.FundedPsbt
}
return nil
}
func (m *FundingPsbtVerify) GetPendingChanId() []byte {
if m != nil {
return m.PendingChanId
}
return nil
}
type FundingPsbtFinalize struct {
//*
//The funded PSBT that contains all witness data to send the exact channel
//capacity amount to the PK script returned in the open channel message in a
//previous step.
SignedPsbt []byte `protobuf:"bytes,1,opt,name=signed_psbt,json=signedPsbt,proto3" json:"signed_psbt,omitempty"`
/// The pending channel ID of the channel to get the PSBT for.
PendingChanId []byte `protobuf:"bytes,2,opt,name=pending_chan_id,json=pendingChanId,proto3" json:"pending_chan_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *FundingPsbtFinalize) Reset() { *m = FundingPsbtFinalize{} }
func (m *FundingPsbtFinalize) String() string { return proto.CompactTextString(m) }
func (*FundingPsbtFinalize) ProtoMessage() {}
func (*FundingPsbtFinalize) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{71}
}
func (m *FundingPsbtFinalize) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FundingPsbtFinalize.Unmarshal(m, b)
}
func (m *FundingPsbtFinalize) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_FundingPsbtFinalize.Marshal(b, m, deterministic)
}
func (m *FundingPsbtFinalize) XXX_Merge(src proto.Message) {
xxx_messageInfo_FundingPsbtFinalize.Merge(m, src)
}
func (m *FundingPsbtFinalize) XXX_Size() int {
return xxx_messageInfo_FundingPsbtFinalize.Size(m)
}
func (m *FundingPsbtFinalize) XXX_DiscardUnknown() {
xxx_messageInfo_FundingPsbtFinalize.DiscardUnknown(m)
}
var xxx_messageInfo_FundingPsbtFinalize proto.InternalMessageInfo
func (m *FundingPsbtFinalize) GetSignedPsbt() []byte {
if m != nil {
return m.SignedPsbt
}
return nil
}
func (m *FundingPsbtFinalize) GetPendingChanId() []byte {
if m != nil {
return m.PendingChanId
}
return nil
}
type FundingTransitionMsg struct {
// Types that are valid to be assigned to Trigger:
// *FundingTransitionMsg_ShimRegister
// *FundingTransitionMsg_ShimCancel
// *FundingTransitionMsg_PsbtVerify
// *FundingTransitionMsg_PsbtFinalize
Trigger isFundingTransitionMsg_Trigger `protobuf_oneof:"trigger"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@ -5273,7 +5529,7 @@ func (m *FundingTransitionMsg) Reset() { *m = FundingTransitionMsg{} }
func (m *FundingTransitionMsg) String() string { return proto.CompactTextString(m) }
func (*FundingTransitionMsg) ProtoMessage() {}
func (*FundingTransitionMsg) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{68}
return fileDescriptor_77a6da22d6a3feb1, []int{72}
}
func (m *FundingTransitionMsg) XXX_Unmarshal(b []byte) error {
@ -5306,10 +5562,22 @@ type FundingTransitionMsg_ShimCancel struct {
ShimCancel *FundingShimCancel `protobuf:"bytes,2,opt,name=shim_cancel,json=shimCancel,proto3,oneof"`
}
type FundingTransitionMsg_PsbtVerify struct {
PsbtVerify *FundingPsbtVerify `protobuf:"bytes,3,opt,name=psbt_verify,json=psbtVerify,proto3,oneof"`
}
type FundingTransitionMsg_PsbtFinalize struct {
PsbtFinalize *FundingPsbtFinalize `protobuf:"bytes,4,opt,name=psbt_finalize,json=psbtFinalize,proto3,oneof"`
}
func (*FundingTransitionMsg_ShimRegister) isFundingTransitionMsg_Trigger() {}
func (*FundingTransitionMsg_ShimCancel) isFundingTransitionMsg_Trigger() {}
func (*FundingTransitionMsg_PsbtVerify) isFundingTransitionMsg_Trigger() {}
func (*FundingTransitionMsg_PsbtFinalize) isFundingTransitionMsg_Trigger() {}
func (m *FundingTransitionMsg) GetTrigger() isFundingTransitionMsg_Trigger {
if m != nil {
return m.Trigger
@ -5331,11 +5599,27 @@ func (m *FundingTransitionMsg) GetShimCancel() *FundingShimCancel {
return nil
}
func (m *FundingTransitionMsg) GetPsbtVerify() *FundingPsbtVerify {
if x, ok := m.GetTrigger().(*FundingTransitionMsg_PsbtVerify); ok {
return x.PsbtVerify
}
return nil
}
func (m *FundingTransitionMsg) GetPsbtFinalize() *FundingPsbtFinalize {
if x, ok := m.GetTrigger().(*FundingTransitionMsg_PsbtFinalize); ok {
return x.PsbtFinalize
}
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*FundingTransitionMsg) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*FundingTransitionMsg_ShimRegister)(nil),
(*FundingTransitionMsg_ShimCancel)(nil),
(*FundingTransitionMsg_PsbtVerify)(nil),
(*FundingTransitionMsg_PsbtFinalize)(nil),
}
}
@ -5349,7 +5633,7 @@ func (m *FundingStateStepResp) Reset() { *m = FundingStateStepResp{} }
func (m *FundingStateStepResp) String() string { return proto.CompactTextString(m) }
func (*FundingStateStepResp) ProtoMessage() {}
func (*FundingStateStepResp) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{69}
return fileDescriptor_77a6da22d6a3feb1, []int{73}
}
func (m *FundingStateStepResp) XXX_Unmarshal(b []byte) error {
@ -5395,7 +5679,7 @@ func (m *PendingHTLC) Reset() { *m = PendingHTLC{} }
func (m *PendingHTLC) String() string { return proto.CompactTextString(m) }
func (*PendingHTLC) ProtoMessage() {}
func (*PendingHTLC) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{70}
return fileDescriptor_77a6da22d6a3feb1, []int{74}
}
func (m *PendingHTLC) XXX_Unmarshal(b []byte) error {
@ -5468,7 +5752,7 @@ func (m *PendingChannelsRequest) Reset() { *m = PendingChannelsRequest{}
func (m *PendingChannelsRequest) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsRequest) ProtoMessage() {}
func (*PendingChannelsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{71}
return fileDescriptor_77a6da22d6a3feb1, []int{75}
}
func (m *PendingChannelsRequest) XXX_Unmarshal(b []byte) error {
@ -5512,7 +5796,7 @@ func (m *PendingChannelsResponse) Reset() { *m = PendingChannelsResponse
func (m *PendingChannelsResponse) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsResponse) ProtoMessage() {}
func (*PendingChannelsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{72}
return fileDescriptor_77a6da22d6a3feb1, []int{76}
}
func (m *PendingChannelsResponse) XXX_Unmarshal(b []byte) error {
@ -5595,7 +5879,7 @@ func (m *PendingChannelsResponse_PendingChannel) Reset() {
func (m *PendingChannelsResponse_PendingChannel) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsResponse_PendingChannel) ProtoMessage() {}
func (*PendingChannelsResponse_PendingChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{72, 0}
return fileDescriptor_77a6da22d6a3feb1, []int{76, 0}
}
func (m *PendingChannelsResponse_PendingChannel) XXX_Unmarshal(b []byte) error {
@ -5704,7 +5988,7 @@ func (m *PendingChannelsResponse_PendingOpenChannel) String() string {
}
func (*PendingChannelsResponse_PendingOpenChannel) ProtoMessage() {}
func (*PendingChannelsResponse_PendingOpenChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{72, 1}
return fileDescriptor_77a6da22d6a3feb1, []int{76, 1}
}
func (m *PendingChannelsResponse_PendingOpenChannel) XXX_Unmarshal(b []byte) error {
@ -5782,7 +6066,7 @@ func (m *PendingChannelsResponse_WaitingCloseChannel) String() string {
}
func (*PendingChannelsResponse_WaitingCloseChannel) ProtoMessage() {}
func (*PendingChannelsResponse_WaitingCloseChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{72, 2}
return fileDescriptor_77a6da22d6a3feb1, []int{76, 2}
}
func (m *PendingChannelsResponse_WaitingCloseChannel) XXX_Unmarshal(b []byte) error {
@ -5852,7 +6136,7 @@ func (m *PendingChannelsResponse_Commitments) Reset() { *m = PendingChan
func (m *PendingChannelsResponse_Commitments) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsResponse_Commitments) ProtoMessage() {}
func (*PendingChannelsResponse_Commitments) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{72, 3}
return fileDescriptor_77a6da22d6a3feb1, []int{76, 3}
}
func (m *PendingChannelsResponse_Commitments) XXX_Unmarshal(b []byte) error {
@ -5929,7 +6213,7 @@ func (m *PendingChannelsResponse_ClosedChannel) Reset() { *m = PendingCh
func (m *PendingChannelsResponse_ClosedChannel) String() string { return proto.CompactTextString(m) }
func (*PendingChannelsResponse_ClosedChannel) ProtoMessage() {}
func (*PendingChannelsResponse_ClosedChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{72, 4}
return fileDescriptor_77a6da22d6a3feb1, []int{76, 4}
}
func (m *PendingChannelsResponse_ClosedChannel) XXX_Unmarshal(b []byte) error {
@ -5995,7 +6279,7 @@ func (m *PendingChannelsResponse_ForceClosedChannel) String() string {
}
func (*PendingChannelsResponse_ForceClosedChannel) ProtoMessage() {}
func (*PendingChannelsResponse_ForceClosedChannel) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{72, 5}
return fileDescriptor_77a6da22d6a3feb1, []int{76, 5}
}
func (m *PendingChannelsResponse_ForceClosedChannel) XXX_Unmarshal(b []byte) error {
@ -6082,7 +6366,7 @@ func (m *ChannelEventSubscription) Reset() { *m = ChannelEventSubscripti
func (m *ChannelEventSubscription) String() string { return proto.CompactTextString(m) }
func (*ChannelEventSubscription) ProtoMessage() {}
func (*ChannelEventSubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{73}
return fileDescriptor_77a6da22d6a3feb1, []int{77}
}
func (m *ChannelEventSubscription) XXX_Unmarshal(b []byte) error {
@ -6121,7 +6405,7 @@ func (m *ChannelEventUpdate) Reset() { *m = ChannelEventUpdate{} }
func (m *ChannelEventUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelEventUpdate) ProtoMessage() {}
func (*ChannelEventUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{74}
return fileDescriptor_77a6da22d6a3feb1, []int{78}
}
func (m *ChannelEventUpdate) XXX_Unmarshal(b []byte) error {
@ -6246,7 +6530,7 @@ func (m *WalletBalanceRequest) Reset() { *m = WalletBalanceRequest{} }
func (m *WalletBalanceRequest) String() string { return proto.CompactTextString(m) }
func (*WalletBalanceRequest) ProtoMessage() {}
func (*WalletBalanceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{75}
return fileDescriptor_77a6da22d6a3feb1, []int{79}
}
func (m *WalletBalanceRequest) XXX_Unmarshal(b []byte) error {
@ -6283,7 +6567,7 @@ func (m *WalletBalanceResponse) Reset() { *m = WalletBalanceResponse{} }
func (m *WalletBalanceResponse) String() string { return proto.CompactTextString(m) }
func (*WalletBalanceResponse) ProtoMessage() {}
func (*WalletBalanceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{76}
return fileDescriptor_77a6da22d6a3feb1, []int{80}
}
func (m *WalletBalanceResponse) XXX_Unmarshal(b []byte) error {
@ -6335,7 +6619,7 @@ func (m *ChannelBalanceRequest) Reset() { *m = ChannelBalanceRequest{} }
func (m *ChannelBalanceRequest) String() string { return proto.CompactTextString(m) }
func (*ChannelBalanceRequest) ProtoMessage() {}
func (*ChannelBalanceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{77}
return fileDescriptor_77a6da22d6a3feb1, []int{81}
}
func (m *ChannelBalanceRequest) XXX_Unmarshal(b []byte) error {
@ -6370,7 +6654,7 @@ func (m *ChannelBalanceResponse) Reset() { *m = ChannelBalanceResponse{}
func (m *ChannelBalanceResponse) String() string { return proto.CompactTextString(m) }
func (*ChannelBalanceResponse) ProtoMessage() {}
func (*ChannelBalanceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{78}
return fileDescriptor_77a6da22d6a3feb1, []int{82}
}
func (m *ChannelBalanceResponse) XXX_Unmarshal(b []byte) error {
@ -6488,7 +6772,7 @@ func (m *QueryRoutesRequest) Reset() { *m = QueryRoutesRequest{} }
func (m *QueryRoutesRequest) String() string { return proto.CompactTextString(m) }
func (*QueryRoutesRequest) ProtoMessage() {}
func (*QueryRoutesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{79}
return fileDescriptor_77a6da22d6a3feb1, []int{83}
}
func (m *QueryRoutesRequest) XXX_Unmarshal(b []byte) error {
@ -6640,7 +6924,7 @@ func (m *NodePair) Reset() { *m = NodePair{} }
func (m *NodePair) String() string { return proto.CompactTextString(m) }
func (*NodePair) ProtoMessage() {}
func (*NodePair) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{80}
return fileDescriptor_77a6da22d6a3feb1, []int{84}
}
func (m *NodePair) XXX_Unmarshal(b []byte) error {
@ -6693,7 +6977,7 @@ func (m *EdgeLocator) Reset() { *m = EdgeLocator{} }
func (m *EdgeLocator) String() string { return proto.CompactTextString(m) }
func (*EdgeLocator) ProtoMessage() {}
func (*EdgeLocator) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{81}
return fileDescriptor_77a6da22d6a3feb1, []int{85}
}
func (m *EdgeLocator) XXX_Unmarshal(b []byte) error {
@ -6746,7 +7030,7 @@ func (m *QueryRoutesResponse) Reset() { *m = QueryRoutesResponse{} }
func (m *QueryRoutesResponse) String() string { return proto.CompactTextString(m) }
func (*QueryRoutesResponse) ProtoMessage() {}
func (*QueryRoutesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{82}
return fileDescriptor_77a6da22d6a3feb1, []int{86}
}
func (m *QueryRoutesResponse) XXX_Unmarshal(b []byte) error {
@ -6822,7 +7106,7 @@ func (m *Hop) Reset() { *m = Hop{} }
func (m *Hop) String() string { return proto.CompactTextString(m) }
func (*Hop) ProtoMessage() {}
func (*Hop) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{83}
return fileDescriptor_77a6da22d6a3feb1, []int{87}
}
func (m *Hop) XXX_Unmarshal(b []byte) error {
@ -6944,7 +7228,7 @@ func (m *MPPRecord) Reset() { *m = MPPRecord{} }
func (m *MPPRecord) String() string { return proto.CompactTextString(m) }
func (*MPPRecord) ProtoMessage() {}
func (*MPPRecord) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{84}
return fileDescriptor_77a6da22d6a3feb1, []int{88}
}
func (m *MPPRecord) XXX_Unmarshal(b []byte) error {
@ -7022,7 +7306,7 @@ func (m *Route) Reset() { *m = Route{} }
func (m *Route) String() string { return proto.CompactTextString(m) }
func (*Route) ProtoMessage() {}
func (*Route) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{85}
return fileDescriptor_77a6da22d6a3feb1, []int{89}
}
func (m *Route) XXX_Unmarshal(b []byte) error {
@ -7101,7 +7385,7 @@ func (m *NodeInfoRequest) Reset() { *m = NodeInfoRequest{} }
func (m *NodeInfoRequest) String() string { return proto.CompactTextString(m) }
func (*NodeInfoRequest) ProtoMessage() {}
func (*NodeInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{86}
return fileDescriptor_77a6da22d6a3feb1, []int{90}
}
func (m *NodeInfoRequest) XXX_Unmarshal(b []byte) error {
@ -7158,7 +7442,7 @@ func (m *NodeInfo) Reset() { *m = NodeInfo{} }
func (m *NodeInfo) String() string { return proto.CompactTextString(m) }
func (*NodeInfo) ProtoMessage() {}
func (*NodeInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{87}
return fileDescriptor_77a6da22d6a3feb1, []int{91}
}
func (m *NodeInfo) XXX_Unmarshal(b []byte) error {
@ -7228,7 +7512,7 @@ func (m *LightningNode) Reset() { *m = LightningNode{} }
func (m *LightningNode) String() string { return proto.CompactTextString(m) }
func (*LightningNode) ProtoMessage() {}
func (*LightningNode) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{88}
return fileDescriptor_77a6da22d6a3feb1, []int{92}
}
func (m *LightningNode) XXX_Unmarshal(b []byte) error {
@ -7303,7 +7587,7 @@ func (m *NodeAddress) Reset() { *m = NodeAddress{} }
func (m *NodeAddress) String() string { return proto.CompactTextString(m) }
func (*NodeAddress) ProtoMessage() {}
func (*NodeAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{89}
return fileDescriptor_77a6da22d6a3feb1, []int{93}
}
func (m *NodeAddress) XXX_Unmarshal(b []byte) error {
@ -7355,7 +7639,7 @@ func (m *RoutingPolicy) Reset() { *m = RoutingPolicy{} }
func (m *RoutingPolicy) String() string { return proto.CompactTextString(m) }
func (*RoutingPolicy) ProtoMessage() {}
func (*RoutingPolicy) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{90}
return fileDescriptor_77a6da22d6a3feb1, []int{94}
}
func (m *RoutingPolicy) XXX_Unmarshal(b []byte) error {
@ -7453,7 +7737,7 @@ func (m *ChannelEdge) Reset() { *m = ChannelEdge{} }
func (m *ChannelEdge) String() string { return proto.CompactTextString(m) }
func (*ChannelEdge) ProtoMessage() {}
func (*ChannelEdge) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{91}
return fileDescriptor_77a6da22d6a3feb1, []int{95}
}
func (m *ChannelEdge) XXX_Unmarshal(b []byte) error {
@ -7546,7 +7830,7 @@ func (m *ChannelGraphRequest) Reset() { *m = ChannelGraphRequest{} }
func (m *ChannelGraphRequest) String() string { return proto.CompactTextString(m) }
func (*ChannelGraphRequest) ProtoMessage() {}
func (*ChannelGraphRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{92}
return fileDescriptor_77a6da22d6a3feb1, []int{96}
}
func (m *ChannelGraphRequest) XXX_Unmarshal(b []byte) error {
@ -7589,7 +7873,7 @@ func (m *ChannelGraph) Reset() { *m = ChannelGraph{} }
func (m *ChannelGraph) String() string { return proto.CompactTextString(m) }
func (*ChannelGraph) ProtoMessage() {}
func (*ChannelGraph) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{93}
return fileDescriptor_77a6da22d6a3feb1, []int{97}
}
func (m *ChannelGraph) XXX_Unmarshal(b []byte) error {
@ -7636,7 +7920,7 @@ func (m *NodeMetricsRequest) Reset() { *m = NodeMetricsRequest{} }
func (m *NodeMetricsRequest) String() string { return proto.CompactTextString(m) }
func (*NodeMetricsRequest) ProtoMessage() {}
func (*NodeMetricsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{94}
return fileDescriptor_77a6da22d6a3feb1, []int{98}
}
func (m *NodeMetricsRequest) XXX_Unmarshal(b []byte) error {
@ -7681,7 +7965,7 @@ func (m *NodeMetricsResponse) Reset() { *m = NodeMetricsResponse{} }
func (m *NodeMetricsResponse) String() string { return proto.CompactTextString(m) }
func (*NodeMetricsResponse) ProtoMessage() {}
func (*NodeMetricsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{95}
return fileDescriptor_77a6da22d6a3feb1, []int{99}
}
func (m *NodeMetricsResponse) XXX_Unmarshal(b []byte) error {
@ -7723,7 +8007,7 @@ func (m *FloatMetric) Reset() { *m = FloatMetric{} }
func (m *FloatMetric) String() string { return proto.CompactTextString(m) }
func (*FloatMetric) ProtoMessage() {}
func (*FloatMetric) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{96}
return fileDescriptor_77a6da22d6a3feb1, []int{100}
}
func (m *FloatMetric) XXX_Unmarshal(b []byte) error {
@ -7773,7 +8057,7 @@ func (m *ChanInfoRequest) Reset() { *m = ChanInfoRequest{} }
func (m *ChanInfoRequest) String() string { return proto.CompactTextString(m) }
func (*ChanInfoRequest) ProtoMessage() {}
func (*ChanInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{97}
return fileDescriptor_77a6da22d6a3feb1, []int{101}
}
func (m *ChanInfoRequest) XXX_Unmarshal(b []byte) error {
@ -7811,7 +8095,7 @@ func (m *NetworkInfoRequest) Reset() { *m = NetworkInfoRequest{} }
func (m *NetworkInfoRequest) String() string { return proto.CompactTextString(m) }
func (*NetworkInfoRequest) ProtoMessage() {}
func (*NetworkInfoRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{98}
return fileDescriptor_77a6da22d6a3feb1, []int{102}
}
func (m *NetworkInfoRequest) XXX_Unmarshal(b []byte) error {
@ -7854,7 +8138,7 @@ func (m *NetworkInfo) Reset() { *m = NetworkInfo{} }
func (m *NetworkInfo) String() string { return proto.CompactTextString(m) }
func (*NetworkInfo) ProtoMessage() {}
func (*NetworkInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{99}
return fileDescriptor_77a6da22d6a3feb1, []int{103}
}
func (m *NetworkInfo) XXX_Unmarshal(b []byte) error {
@ -7962,7 +8246,7 @@ func (m *StopRequest) Reset() { *m = StopRequest{} }
func (m *StopRequest) String() string { return proto.CompactTextString(m) }
func (*StopRequest) ProtoMessage() {}
func (*StopRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{100}
return fileDescriptor_77a6da22d6a3feb1, []int{104}
}
func (m *StopRequest) XXX_Unmarshal(b []byte) error {
@ -7993,7 +8277,7 @@ func (m *StopResponse) Reset() { *m = StopResponse{} }
func (m *StopResponse) String() string { return proto.CompactTextString(m) }
func (*StopResponse) ProtoMessage() {}
func (*StopResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{101}
return fileDescriptor_77a6da22d6a3feb1, []int{105}
}
func (m *StopResponse) XXX_Unmarshal(b []byte) error {
@ -8024,7 +8308,7 @@ func (m *GraphTopologySubscription) Reset() { *m = GraphTopologySubscrip
func (m *GraphTopologySubscription) String() string { return proto.CompactTextString(m) }
func (*GraphTopologySubscription) ProtoMessage() {}
func (*GraphTopologySubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{102}
return fileDescriptor_77a6da22d6a3feb1, []int{106}
}
func (m *GraphTopologySubscription) XXX_Unmarshal(b []byte) error {
@ -8058,7 +8342,7 @@ func (m *GraphTopologyUpdate) Reset() { *m = GraphTopologyUpdate{} }
func (m *GraphTopologyUpdate) String() string { return proto.CompactTextString(m) }
func (*GraphTopologyUpdate) ProtoMessage() {}
func (*GraphTopologyUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{103}
return fileDescriptor_77a6da22d6a3feb1, []int{107}
}
func (m *GraphTopologyUpdate) XXX_Unmarshal(b []byte) error {
@ -8115,7 +8399,7 @@ func (m *NodeUpdate) Reset() { *m = NodeUpdate{} }
func (m *NodeUpdate) String() string { return proto.CompactTextString(m) }
func (*NodeUpdate) ProtoMessage() {}
func (*NodeUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{104}
return fileDescriptor_77a6da22d6a3feb1, []int{108}
}
func (m *NodeUpdate) XXX_Unmarshal(b []byte) error {
@ -8191,7 +8475,7 @@ func (m *ChannelEdgeUpdate) Reset() { *m = ChannelEdgeUpdate{} }
func (m *ChannelEdgeUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelEdgeUpdate) ProtoMessage() {}
func (*ChannelEdgeUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{105}
return fileDescriptor_77a6da22d6a3feb1, []int{109}
}
func (m *ChannelEdgeUpdate) XXX_Unmarshal(b []byte) error {
@ -8272,7 +8556,7 @@ func (m *ClosedChannelUpdate) Reset() { *m = ClosedChannelUpdate{} }
func (m *ClosedChannelUpdate) String() string { return proto.CompactTextString(m) }
func (*ClosedChannelUpdate) ProtoMessage() {}
func (*ClosedChannelUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{106}
return fileDescriptor_77a6da22d6a3feb1, []int{110}
}
func (m *ClosedChannelUpdate) XXX_Unmarshal(b []byte) error {
@ -8343,7 +8627,7 @@ func (m *HopHint) Reset() { *m = HopHint{} }
func (m *HopHint) String() string { return proto.CompactTextString(m) }
func (*HopHint) ProtoMessage() {}
func (*HopHint) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{107}
return fileDescriptor_77a6da22d6a3feb1, []int{111}
}
func (m *HopHint) XXX_Unmarshal(b []byte) error {
@ -8413,7 +8697,7 @@ func (m *RouteHint) Reset() { *m = RouteHint{} }
func (m *RouteHint) String() string { return proto.CompactTextString(m) }
func (*RouteHint) ProtoMessage() {}
func (*RouteHint) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{108}
return fileDescriptor_77a6da22d6a3feb1, []int{112}
}
func (m *RouteHint) XXX_Unmarshal(b []byte) error {
@ -8546,7 +8830,7 @@ func (m *Invoice) Reset() { *m = Invoice{} }
func (m *Invoice) String() string { return proto.CompactTextString(m) }
func (*Invoice) ProtoMessage() {}
func (*Invoice) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{109}
return fileDescriptor_77a6da22d6a3feb1, []int{113}
}
func (m *Invoice) XXX_Unmarshal(b []byte) error {
@ -8768,7 +9052,7 @@ func (m *InvoiceHTLC) Reset() { *m = InvoiceHTLC{} }
func (m *InvoiceHTLC) String() string { return proto.CompactTextString(m) }
func (*InvoiceHTLC) ProtoMessage() {}
func (*InvoiceHTLC) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{110}
return fileDescriptor_77a6da22d6a3feb1, []int{114}
}
func (m *InvoiceHTLC) XXX_Unmarshal(b []byte) error {
@ -8881,7 +9165,7 @@ func (m *AddInvoiceResponse) Reset() { *m = AddInvoiceResponse{} }
func (m *AddInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*AddInvoiceResponse) ProtoMessage() {}
func (*AddInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{111}
return fileDescriptor_77a6da22d6a3feb1, []int{115}
}
func (m *AddInvoiceResponse) XXX_Unmarshal(b []byte) error {
@ -8943,7 +9227,7 @@ func (m *PaymentHash) Reset() { *m = PaymentHash{} }
func (m *PaymentHash) String() string { return proto.CompactTextString(m) }
func (*PaymentHash) ProtoMessage() {}
func (*PaymentHash) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{112}
return fileDescriptor_77a6da22d6a3feb1, []int{116}
}
func (m *PaymentHash) XXX_Unmarshal(b []byte) error {
@ -9003,7 +9287,7 @@ func (m *ListInvoiceRequest) Reset() { *m = ListInvoiceRequest{} }
func (m *ListInvoiceRequest) String() string { return proto.CompactTextString(m) }
func (*ListInvoiceRequest) ProtoMessage() {}
func (*ListInvoiceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{113}
return fileDescriptor_77a6da22d6a3feb1, []int{117}
}
func (m *ListInvoiceRequest) XXX_Unmarshal(b []byte) error {
@ -9074,7 +9358,7 @@ func (m *ListInvoiceResponse) Reset() { *m = ListInvoiceResponse{} }
func (m *ListInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*ListInvoiceResponse) ProtoMessage() {}
func (*ListInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{114}
return fileDescriptor_77a6da22d6a3feb1, []int{118}
}
func (m *ListInvoiceResponse) XXX_Unmarshal(b []byte) error {
@ -9138,7 +9422,7 @@ func (m *InvoiceSubscription) Reset() { *m = InvoiceSubscription{} }
func (m *InvoiceSubscription) String() string { return proto.CompactTextString(m) }
func (*InvoiceSubscription) ProtoMessage() {}
func (*InvoiceSubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{115}
return fileDescriptor_77a6da22d6a3feb1, []int{119}
}
func (m *InvoiceSubscription) XXX_Unmarshal(b []byte) error {
@ -9211,7 +9495,7 @@ func (m *Payment) Reset() { *m = Payment{} }
func (m *Payment) String() string { return proto.CompactTextString(m) }
func (*Payment) ProtoMessage() {}
func (*Payment) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{116}
return fileDescriptor_77a6da22d6a3feb1, []int{120}
}
func (m *Payment) XXX_Unmarshal(b []byte) error {
@ -9356,7 +9640,7 @@ func (m *HTLCAttempt) Reset() { *m = HTLCAttempt{} }
func (m *HTLCAttempt) String() string { return proto.CompactTextString(m) }
func (*HTLCAttempt) ProtoMessage() {}
func (*HTLCAttempt) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{117}
return fileDescriptor_77a6da22d6a3feb1, []int{121}
}
func (m *HTLCAttempt) XXX_Unmarshal(b []byte) error {
@ -9427,7 +9711,7 @@ func (m *ListPaymentsRequest) Reset() { *m = ListPaymentsRequest{} }
func (m *ListPaymentsRequest) String() string { return proto.CompactTextString(m) }
func (*ListPaymentsRequest) ProtoMessage() {}
func (*ListPaymentsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{118}
return fileDescriptor_77a6da22d6a3feb1, []int{122}
}
func (m *ListPaymentsRequest) XXX_Unmarshal(b []byte) error {
@ -9467,7 +9751,7 @@ func (m *ListPaymentsResponse) Reset() { *m = ListPaymentsResponse{} }
func (m *ListPaymentsResponse) String() string { return proto.CompactTextString(m) }
func (*ListPaymentsResponse) ProtoMessage() {}
func (*ListPaymentsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{119}
return fileDescriptor_77a6da22d6a3feb1, []int{123}
}
func (m *ListPaymentsResponse) XXX_Unmarshal(b []byte) error {
@ -9505,7 +9789,7 @@ func (m *DeleteAllPaymentsRequest) Reset() { *m = DeleteAllPaymentsReque
func (m *DeleteAllPaymentsRequest) String() string { return proto.CompactTextString(m) }
func (*DeleteAllPaymentsRequest) ProtoMessage() {}
func (*DeleteAllPaymentsRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{120}
return fileDescriptor_77a6da22d6a3feb1, []int{124}
}
func (m *DeleteAllPaymentsRequest) XXX_Unmarshal(b []byte) error {
@ -9536,7 +9820,7 @@ func (m *DeleteAllPaymentsResponse) Reset() { *m = DeleteAllPaymentsResp
func (m *DeleteAllPaymentsResponse) String() string { return proto.CompactTextString(m) }
func (*DeleteAllPaymentsResponse) ProtoMessage() {}
func (*DeleteAllPaymentsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{121}
return fileDescriptor_77a6da22d6a3feb1, []int{125}
}
func (m *DeleteAllPaymentsResponse) XXX_Unmarshal(b []byte) error {
@ -9568,7 +9852,7 @@ func (m *AbandonChannelRequest) Reset() { *m = AbandonChannelRequest{} }
func (m *AbandonChannelRequest) String() string { return proto.CompactTextString(m) }
func (*AbandonChannelRequest) ProtoMessage() {}
func (*AbandonChannelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{122}
return fileDescriptor_77a6da22d6a3feb1, []int{126}
}
func (m *AbandonChannelRequest) XXX_Unmarshal(b []byte) error {
@ -9606,7 +9890,7 @@ func (m *AbandonChannelResponse) Reset() { *m = AbandonChannelResponse{}
func (m *AbandonChannelResponse) String() string { return proto.CompactTextString(m) }
func (*AbandonChannelResponse) ProtoMessage() {}
func (*AbandonChannelResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{123}
return fileDescriptor_77a6da22d6a3feb1, []int{127}
}
func (m *AbandonChannelResponse) XXX_Unmarshal(b []byte) error {
@ -9639,7 +9923,7 @@ func (m *DebugLevelRequest) Reset() { *m = DebugLevelRequest{} }
func (m *DebugLevelRequest) String() string { return proto.CompactTextString(m) }
func (*DebugLevelRequest) ProtoMessage() {}
func (*DebugLevelRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{124}
return fileDescriptor_77a6da22d6a3feb1, []int{128}
}
func (m *DebugLevelRequest) XXX_Unmarshal(b []byte) error {
@ -9685,7 +9969,7 @@ func (m *DebugLevelResponse) Reset() { *m = DebugLevelResponse{} }
func (m *DebugLevelResponse) String() string { return proto.CompactTextString(m) }
func (*DebugLevelResponse) ProtoMessage() {}
func (*DebugLevelResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{125}
return fileDescriptor_77a6da22d6a3feb1, []int{129}
}
func (m *DebugLevelResponse) XXX_Unmarshal(b []byte) error {
@ -9725,7 +10009,7 @@ func (m *PayReqString) Reset() { *m = PayReqString{} }
func (m *PayReqString) String() string { return proto.CompactTextString(m) }
func (*PayReqString) ProtoMessage() {}
func (*PayReqString) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{126}
return fileDescriptor_77a6da22d6a3feb1, []int{130}
}
func (m *PayReqString) XXX_Unmarshal(b []byte) error {
@ -9776,7 +10060,7 @@ func (m *PayReq) Reset() { *m = PayReq{} }
func (m *PayReq) String() string { return proto.CompactTextString(m) }
func (*PayReq) ProtoMessage() {}
func (*PayReq) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{127}
return fileDescriptor_77a6da22d6a3feb1, []int{131}
}
func (m *PayReq) XXX_Unmarshal(b []byte) error {
@ -9901,7 +10185,7 @@ func (m *Feature) Reset() { *m = Feature{} }
func (m *Feature) String() string { return proto.CompactTextString(m) }
func (*Feature) ProtoMessage() {}
func (*Feature) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{128}
return fileDescriptor_77a6da22d6a3feb1, []int{132}
}
func (m *Feature) XXX_Unmarshal(b []byte) error {
@ -9953,7 +10237,7 @@ func (m *FeeReportRequest) Reset() { *m = FeeReportRequest{} }
func (m *FeeReportRequest) String() string { return proto.CompactTextString(m) }
func (*FeeReportRequest) ProtoMessage() {}
func (*FeeReportRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{129}
return fileDescriptor_77a6da22d6a3feb1, []int{133}
}
func (m *FeeReportRequest) XXX_Unmarshal(b []byte) error {
@ -9996,7 +10280,7 @@ func (m *ChannelFeeReport) Reset() { *m = ChannelFeeReport{} }
func (m *ChannelFeeReport) String() string { return proto.CompactTextString(m) }
func (*ChannelFeeReport) ProtoMessage() {}
func (*ChannelFeeReport) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{130}
return fileDescriptor_77a6da22d6a3feb1, []int{134}
}
func (m *ChannelFeeReport) XXX_Unmarshal(b []byte) error {
@ -10074,7 +10358,7 @@ func (m *FeeReportResponse) Reset() { *m = FeeReportResponse{} }
func (m *FeeReportResponse) String() string { return proto.CompactTextString(m) }
func (*FeeReportResponse) ProtoMessage() {}
func (*FeeReportResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{131}
return fileDescriptor_77a6da22d6a3feb1, []int{135}
}
func (m *FeeReportResponse) XXX_Unmarshal(b []byte) error {
@ -10152,7 +10436,7 @@ func (m *PolicyUpdateRequest) Reset() { *m = PolicyUpdateRequest{} }
func (m *PolicyUpdateRequest) String() string { return proto.CompactTextString(m) }
func (*PolicyUpdateRequest) ProtoMessage() {}
func (*PolicyUpdateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{132}
return fileDescriptor_77a6da22d6a3feb1, []int{136}
}
func (m *PolicyUpdateRequest) XXX_Unmarshal(b []byte) error {
@ -10270,7 +10554,7 @@ func (m *PolicyUpdateResponse) Reset() { *m = PolicyUpdateResponse{} }
func (m *PolicyUpdateResponse) String() string { return proto.CompactTextString(m) }
func (*PolicyUpdateResponse) ProtoMessage() {}
func (*PolicyUpdateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{133}
return fileDescriptor_77a6da22d6a3feb1, []int{137}
}
func (m *PolicyUpdateResponse) XXX_Unmarshal(b []byte) error {
@ -10315,7 +10599,7 @@ func (m *ForwardingHistoryRequest) Reset() { *m = ForwardingHistoryReque
func (m *ForwardingHistoryRequest) String() string { return proto.CompactTextString(m) }
func (*ForwardingHistoryRequest) ProtoMessage() {}
func (*ForwardingHistoryRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{134}
return fileDescriptor_77a6da22d6a3feb1, []int{138}
}
func (m *ForwardingHistoryRequest) XXX_Unmarshal(b []byte) error {
@ -10398,7 +10682,7 @@ func (m *ForwardingEvent) Reset() { *m = ForwardingEvent{} }
func (m *ForwardingEvent) String() string { return proto.CompactTextString(m) }
func (*ForwardingEvent) ProtoMessage() {}
func (*ForwardingEvent) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{135}
return fileDescriptor_77a6da22d6a3feb1, []int{139}
}
func (m *ForwardingEvent) XXX_Unmarshal(b []byte) error {
@ -10498,7 +10782,7 @@ func (m *ForwardingHistoryResponse) Reset() { *m = ForwardingHistoryResp
func (m *ForwardingHistoryResponse) String() string { return proto.CompactTextString(m) }
func (*ForwardingHistoryResponse) ProtoMessage() {}
func (*ForwardingHistoryResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{136}
return fileDescriptor_77a6da22d6a3feb1, []int{140}
}
func (m *ForwardingHistoryResponse) XXX_Unmarshal(b []byte) error {
@ -10545,7 +10829,7 @@ func (m *ExportChannelBackupRequest) Reset() { *m = ExportChannelBackupR
func (m *ExportChannelBackupRequest) String() string { return proto.CompactTextString(m) }
func (*ExportChannelBackupRequest) ProtoMessage() {}
func (*ExportChannelBackupRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{137}
return fileDescriptor_77a6da22d6a3feb1, []int{141}
}
func (m *ExportChannelBackupRequest) XXX_Unmarshal(b []byte) error {
@ -10592,7 +10876,7 @@ func (m *ChannelBackup) Reset() { *m = ChannelBackup{} }
func (m *ChannelBackup) String() string { return proto.CompactTextString(m) }
func (*ChannelBackup) ProtoMessage() {}
func (*ChannelBackup) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{138}
return fileDescriptor_77a6da22d6a3feb1, []int{142}
}
func (m *ChannelBackup) XXX_Unmarshal(b []byte) error {
@ -10646,7 +10930,7 @@ func (m *MultiChanBackup) Reset() { *m = MultiChanBackup{} }
func (m *MultiChanBackup) String() string { return proto.CompactTextString(m) }
func (*MultiChanBackup) ProtoMessage() {}
func (*MultiChanBackup) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{139}
return fileDescriptor_77a6da22d6a3feb1, []int{143}
}
func (m *MultiChanBackup) XXX_Unmarshal(b []byte) error {
@ -10691,7 +10975,7 @@ func (m *ChanBackupExportRequest) Reset() { *m = ChanBackupExportRequest
func (m *ChanBackupExportRequest) String() string { return proto.CompactTextString(m) }
func (*ChanBackupExportRequest) ProtoMessage() {}
func (*ChanBackupExportRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{140}
return fileDescriptor_77a6da22d6a3feb1, []int{144}
}
func (m *ChanBackupExportRequest) XXX_Unmarshal(b []byte) error {
@ -10730,7 +11014,7 @@ func (m *ChanBackupSnapshot) Reset() { *m = ChanBackupSnapshot{} }
func (m *ChanBackupSnapshot) String() string { return proto.CompactTextString(m) }
func (*ChanBackupSnapshot) ProtoMessage() {}
func (*ChanBackupSnapshot) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{141}
return fileDescriptor_77a6da22d6a3feb1, []int{145}
}
func (m *ChanBackupSnapshot) XXX_Unmarshal(b []byte) error {
@ -10778,7 +11062,7 @@ func (m *ChannelBackups) Reset() { *m = ChannelBackups{} }
func (m *ChannelBackups) String() string { return proto.CompactTextString(m) }
func (*ChannelBackups) ProtoMessage() {}
func (*ChannelBackups) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{142}
return fileDescriptor_77a6da22d6a3feb1, []int{146}
}
func (m *ChannelBackups) XXX_Unmarshal(b []byte) error {
@ -10820,7 +11104,7 @@ func (m *RestoreChanBackupRequest) Reset() { *m = RestoreChanBackupReque
func (m *RestoreChanBackupRequest) String() string { return proto.CompactTextString(m) }
func (*RestoreChanBackupRequest) ProtoMessage() {}
func (*RestoreChanBackupRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{143}
return fileDescriptor_77a6da22d6a3feb1, []int{147}
}
func (m *RestoreChanBackupRequest) XXX_Unmarshal(b []byte) error {
@ -10896,7 +11180,7 @@ func (m *RestoreBackupResponse) Reset() { *m = RestoreBackupResponse{} }
func (m *RestoreBackupResponse) String() string { return proto.CompactTextString(m) }
func (*RestoreBackupResponse) ProtoMessage() {}
func (*RestoreBackupResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{144}
return fileDescriptor_77a6da22d6a3feb1, []int{148}
}
func (m *RestoreBackupResponse) XXX_Unmarshal(b []byte) error {
@ -10927,7 +11211,7 @@ func (m *ChannelBackupSubscription) Reset() { *m = ChannelBackupSubscrip
func (m *ChannelBackupSubscription) String() string { return proto.CompactTextString(m) }
func (*ChannelBackupSubscription) ProtoMessage() {}
func (*ChannelBackupSubscription) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{145}
return fileDescriptor_77a6da22d6a3feb1, []int{149}
}
func (m *ChannelBackupSubscription) XXX_Unmarshal(b []byte) error {
@ -10958,7 +11242,7 @@ func (m *VerifyChanBackupResponse) Reset() { *m = VerifyChanBackupRespon
func (m *VerifyChanBackupResponse) String() string { return proto.CompactTextString(m) }
func (*VerifyChanBackupResponse) ProtoMessage() {}
func (*VerifyChanBackupResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{146}
return fileDescriptor_77a6da22d6a3feb1, []int{150}
}
func (m *VerifyChanBackupResponse) XXX_Unmarshal(b []byte) error {
@ -10993,7 +11277,7 @@ func (m *MacaroonPermission) Reset() { *m = MacaroonPermission{} }
func (m *MacaroonPermission) String() string { return proto.CompactTextString(m) }
func (*MacaroonPermission) ProtoMessage() {}
func (*MacaroonPermission) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{147}
return fileDescriptor_77a6da22d6a3feb1, []int{151}
}
func (m *MacaroonPermission) XXX_Unmarshal(b []byte) error {
@ -11040,7 +11324,7 @@ func (m *BakeMacaroonRequest) Reset() { *m = BakeMacaroonRequest{} }
func (m *BakeMacaroonRequest) String() string { return proto.CompactTextString(m) }
func (*BakeMacaroonRequest) ProtoMessage() {}
func (*BakeMacaroonRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{148}
return fileDescriptor_77a6da22d6a3feb1, []int{152}
}
func (m *BakeMacaroonRequest) XXX_Unmarshal(b []byte) error {
@ -11080,7 +11364,7 @@ func (m *BakeMacaroonResponse) Reset() { *m = BakeMacaroonResponse{} }
func (m *BakeMacaroonResponse) String() string { return proto.CompactTextString(m) }
func (*BakeMacaroonResponse) ProtoMessage() {}
func (*BakeMacaroonResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{149}
return fileDescriptor_77a6da22d6a3feb1, []int{153}
}
func (m *BakeMacaroonResponse) XXX_Unmarshal(b []byte) error {
@ -11136,7 +11420,7 @@ func (m *Failure) Reset() { *m = Failure{} }
func (m *Failure) String() string { return proto.CompactTextString(m) }
func (*Failure) ProtoMessage() {}
func (*Failure) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{150}
return fileDescriptor_77a6da22d6a3feb1, []int{154}
}
func (m *Failure) XXX_Unmarshal(b []byte) error {
@ -11280,7 +11564,7 @@ func (m *ChannelUpdate) Reset() { *m = ChannelUpdate{} }
func (m *ChannelUpdate) String() string { return proto.CompactTextString(m) }
func (*ChannelUpdate) ProtoMessage() {}
func (*ChannelUpdate) Descriptor() ([]byte, []int) {
return fileDescriptor_77a6da22d6a3feb1, []int{151}
return fileDescriptor_77a6da22d6a3feb1, []int{155}
}
func (m *ChannelUpdate) XXX_Unmarshal(b []byte) error {
@ -11467,13 +11751,17 @@ func init() {
proto.RegisterType((*CloseChannelRequest)(nil), "lnrpc.CloseChannelRequest")
proto.RegisterType((*CloseStatusUpdate)(nil), "lnrpc.CloseStatusUpdate")
proto.RegisterType((*PendingUpdate)(nil), "lnrpc.PendingUpdate")
proto.RegisterType((*ReadyForPsbtFunding)(nil), "lnrpc.ReadyForPsbtFunding")
proto.RegisterType((*OpenChannelRequest)(nil), "lnrpc.OpenChannelRequest")
proto.RegisterType((*OpenStatusUpdate)(nil), "lnrpc.OpenStatusUpdate")
proto.RegisterType((*KeyLocator)(nil), "lnrpc.KeyLocator")
proto.RegisterType((*KeyDescriptor)(nil), "lnrpc.KeyDescriptor")
proto.RegisterType((*ChanPointShim)(nil), "lnrpc.ChanPointShim")
proto.RegisterType((*PsbtShim)(nil), "lnrpc.PsbtShim")
proto.RegisterType((*FundingShim)(nil), "lnrpc.FundingShim")
proto.RegisterType((*FundingShimCancel)(nil), "lnrpc.FundingShimCancel")
proto.RegisterType((*FundingPsbtVerify)(nil), "lnrpc.FundingPsbtVerify")
proto.RegisterType((*FundingPsbtFinalize)(nil), "lnrpc.FundingPsbtFinalize")
proto.RegisterType((*FundingTransitionMsg)(nil), "lnrpc.FundingTransitionMsg")
proto.RegisterType((*FundingStateStepResp)(nil), "lnrpc.FundingStateStepResp")
proto.RegisterType((*PendingHTLC)(nil), "lnrpc.PendingHTLC")
@ -11576,735 +11864,747 @@ func init() {
func init() { proto.RegisterFile("rpc.proto", fileDescriptor_77a6da22d6a3feb1) }
var fileDescriptor_77a6da22d6a3feb1 = []byte{
// 11641 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0xbd, 0xeb, 0x6f, 0x23, 0x59,
0x76, 0x18, 0xde, 0x7c, 0x89, 0xe4, 0xe1, 0x43, 0xd4, 0xd5, 0x8b, 0xad, 0x9e, 0x9e, 0xee, 0xa9,
0x99, 0x9d, 0xe9, 0xe9, 0xd9, 0xed, 0xee, 0xe9, 0xdd, 0x9e, 0xdd, 0x9d, 0xf9, 0x79, 0xbd, 0x94,
0x44, 0xb5, 0xb8, 0x2d, 0x51, 0x9a, 0x22, 0x35, 0xe3, 0x59, 0xdb, 0xbf, 0xda, 0x12, 0x79, 0x25,
0x95, 0x9b, 0xac, 0xe2, 0x54, 0x15, 0xf5, 0xd8, 0xc5, 0xe4, 0x43, 0x90, 0x18, 0x41, 0x90, 0x04,
0x30, 0x12, 0x07, 0x88, 0x13, 0x23, 0x41, 0x8c, 0x20, 0x08, 0x0c, 0x18, 0x06, 0xd6, 0x01, 0x12,
0x20, 0xdf, 0x8d, 0x00, 0x09, 0x8c, 0xc0, 0xce, 0x97, 0xc0, 0x30, 0x10, 0x24, 0xd9, 0x7c, 0x0b,
0xfc, 0x27, 0x04, 0xf7, 0x9c, 0x7b, 0xab, 0x6e, 0x91, 0xa5, 0xee, 0x9e, 0xdd, 0xc9, 0x7e, 0x91,
0x58, 0xe7, 0x9c, 0xfb, 0xac, 0x73, 0xcf, 0x3d, 0xaf, 0x7b, 0x0b, 0xca, 0xfe, 0x64, 0xf0, 0x60,
0xe2, 0x7b, 0xa1, 0xc7, 0x0a, 0x23, 0xd7, 0x9f, 0x0c, 0x36, 0x5e, 0x3b, 0xf5, 0xbc, 0xd3, 0x11,
0x7f, 0x68, 0x4f, 0x9c, 0x87, 0xb6, 0xeb, 0x7a, 0xa1, 0x1d, 0x3a, 0x9e, 0x1b, 0x10, 0x91, 0xf1,
0x23, 0xa8, 0x3f, 0xe5, 0x6e, 0x8f, 0xf3, 0xa1, 0xc9, 0x3f, 0x9f, 0xf2, 0x20, 0x64, 0xef, 0xc1,
0x92, 0xcd, 0x7f, 0xcc, 0xf9, 0xd0, 0x9a, 0xd8, 0x41, 0x30, 0x39, 0xf3, 0xed, 0x80, 0x37, 0x33,
0x77, 0x33, 0xf7, 0xaa, 0x66, 0x83, 0x10, 0x87, 0x11, 0x9c, 0xbd, 0x01, 0xd5, 0x40, 0x90, 0x72,
0x37, 0xf4, 0xbd, 0xc9, 0x55, 0x33, 0x8b, 0x74, 0x15, 0x01, 0x6b, 0x13, 0xc8, 0x18, 0xc1, 0x62,
0xd4, 0x42, 0x30, 0xf1, 0xdc, 0x80, 0xb3, 0x47, 0xb0, 0x32, 0x70, 0x26, 0x67, 0xdc, 0xb7, 0xb0,
0xf0, 0xd8, 0xe5, 0x63, 0xcf, 0x75, 0x06, 0xcd, 0xcc, 0xdd, 0xdc, 0xbd, 0xb2, 0xc9, 0x08, 0x27,
0x4a, 0xec, 0x4b, 0x0c, 0x7b, 0x07, 0x16, 0xb9, 0x4b, 0x70, 0x3e, 0xc4, 0x52, 0xb2, 0xa9, 0x7a,
0x0c, 0x16, 0x05, 0x8c, 0xbf, 0x93, 0x85, 0xa5, 0x8e, 0xeb, 0x84, 0x9f, 0xda, 0xa3, 0x11, 0x0f,
0xd5, 0x98, 0xde, 0x81, 0xc5, 0x0b, 0x04, 0xe0, 0x98, 0x2e, 0x3c, 0x7f, 0x28, 0x47, 0x54, 0x27,
0xf0, 0xa1, 0x84, 0x5e, 0xdb, 0xb3, 0xec, 0xb5, 0x3d, 0x4b, 0x9d, 0xae, 0xdc, 0x35, 0xd3, 0xf5,
0x0e, 0x2c, 0xfa, 0x7c, 0xe0, 0x9d, 0x73, 0xff, 0xca, 0xba, 0x70, 0xdc, 0xa1, 0x77, 0xd1, 0xcc,
0xdf, 0xcd, 0xdc, 0x2b, 0x98, 0x75, 0x05, 0xfe, 0x14, 0xa1, 0x6c, 0x13, 0x16, 0x07, 0x67, 0xb6,
0xeb, 0xf2, 0x91, 0x75, 0x6c, 0x0f, 0x9e, 0x4f, 0x27, 0x41, 0xb3, 0x70, 0x37, 0x73, 0xaf, 0xf2,
0xf8, 0xe6, 0x03, 0x7c, 0xab, 0x0f, 0xb6, 0xce, 0x6c, 0x77, 0x13, 0x31, 0x3d, 0xd7, 0x9e, 0x04,
0x67, 0x5e, 0x68, 0xd6, 0x65, 0x09, 0x02, 0x07, 0xc6, 0x0a, 0x30, 0x7d, 0x26, 0x68, 0xee, 0x8d,
0x3f, 0xcc, 0xc0, 0xf2, 0x91, 0x3b, 0xf2, 0x06, 0xcf, 0x7f, 0xce, 0x29, 0x4a, 0x19, 0x43, 0xf6,
0x55, 0xc7, 0x90, 0xfb, 0xb2, 0x63, 0x58, 0x83, 0x95, 0x64, 0x67, 0xe5, 0x28, 0x38, 0xac, 0x8a,
0xd2, 0xa7, 0x5c, 0x75, 0x4b, 0x0d, 0xe3, 0x5d, 0x68, 0x0c, 0xa6, 0xbe, 0xcf, 0xdd, 0xb9, 0x71,
0x2c, 0x4a, 0x78, 0x34, 0x90, 0x37, 0xa0, 0xea, 0xf2, 0x8b, 0x98, 0x4c, 0xf2, 0xae, 0xcb, 0x2f,
0x14, 0x89, 0xd1, 0x84, 0xb5, 0xd9, 0x66, 0x64, 0x07, 0x7e, 0x96, 0x81, 0xfc, 0x51, 0x78, 0xe9,
0xb1, 0x27, 0x50, 0xb5, 0x87, 0x43, 0x9f, 0x07, 0x81, 0x15, 0x5e, 0x4d, 0x68, 0xa5, 0xd4, 0x1f,
0x33, 0x39, 0xc4, 0x16, 0xa1, 0xfa, 0x57, 0x13, 0x6e, 0x56, 0xec, 0xf8, 0x81, 0x35, 0xa1, 0x28,
0x1f, 0xb1, 0xdd, 0xb2, 0xa9, 0x1e, 0xd9, 0x6d, 0x00, 0x7b, 0xec, 0x4d, 0xdd, 0xd0, 0x0a, 0xec,
0x10, 0x67, 0x2c, 0x67, 0x96, 0x09, 0xd2, 0xb3, 0x43, 0x76, 0x0b, 0xca, 0x93, 0xe7, 0x56, 0x30,
0xf0, 0x9d, 0x49, 0x88, 0xcc, 0x53, 0x36, 0x4b, 0x93, 0xe7, 0x3d, 0x7c, 0x66, 0xef, 0x41, 0xc9,
0x9b, 0x86, 0x13, 0xcf, 0x71, 0x43, 0xc9, 0x2f, 0x8b, 0xb2, 0x23, 0x07, 0xd3, 0xf0, 0x50, 0x80,
0xcd, 0x88, 0x80, 0xbd, 0x05, 0xb5, 0x81, 0xe7, 0x9e, 0x38, 0xfe, 0x98, 0x24, 0x42, 0x73, 0x01,
0xdb, 0x4a, 0x02, 0x8d, 0x3f, 0xce, 0x42, 0xa5, 0xef, 0xdb, 0x6e, 0x60, 0x0f, 0x04, 0x80, 0xad,
0x43, 0x31, 0xbc, 0xb4, 0xce, 0xec, 0xe0, 0x0c, 0x87, 0x5a, 0x36, 0x17, 0xc2, 0xcb, 0x5d, 0x3b,
0x38, 0x63, 0x6b, 0xb0, 0x40, 0xbd, 0xc4, 0x01, 0xe5, 0x4c, 0xf9, 0x24, 0x16, 0x88, 0x3b, 0x1d,
0x5b, 0xc9, 0xa6, 0x72, 0xc8, 0x31, 0x0d, 0x77, 0x3a, 0xde, 0xd2, 0xe1, 0x62, 0xf0, 0xc7, 0xe2,
0x75, 0x53, 0x03, 0x34, 0xbc, 0x32, 0x42, 0xb0, 0x8d, 0x37, 0xa0, 0x2a, 0xd1, 0xdc, 0x39, 0x3d,
0xa3, 0x31, 0x16, 0xcc, 0x0a, 0x11, 0x20, 0x48, 0xd4, 0x10, 0x3a, 0x63, 0x6e, 0x05, 0xa1, 0x3d,
0x9e, 0xc8, 0x21, 0x95, 0x05, 0xa4, 0x27, 0x00, 0x88, 0xf6, 0x42, 0x7b, 0x64, 0x9d, 0x70, 0x1e,
0x34, 0x8b, 0x12, 0x2d, 0x20, 0x3b, 0x9c, 0x07, 0xec, 0x6b, 0x50, 0x1f, 0xf2, 0x20, 0xb4, 0xe4,
0xcb, 0xe0, 0x41, 0xb3, 0x84, 0x2b, 0xbf, 0x26, 0xa0, 0x2d, 0x05, 0x64, 0xaf, 0x01, 0xf8, 0xf6,
0x85, 0x25, 0x26, 0x82, 0x5f, 0x36, 0xcb, 0xf4, 0x16, 0x7c, 0xfb, 0xa2, 0x7f, 0xb9, 0xcb, 0x2f,
0x05, 0xd7, 0x3c, 0xe5, 0xa1, 0x36, 0x69, 0x81, 0xe4, 0x4e, 0x63, 0x0f, 0x98, 0x06, 0xde, 0xe6,
0xa1, 0xed, 0x8c, 0x02, 0xf6, 0x01, 0x54, 0x43, 0x8d, 0x18, 0xc5, 0x60, 0x25, 0x62, 0x21, 0xad,
0x80, 0x99, 0xa0, 0x33, 0xce, 0xa0, 0xb4, 0xc3, 0xf9, 0x9e, 0x33, 0x76, 0x42, 0xb6, 0x06, 0x85,
0x13, 0xe7, 0x92, 0x13, 0xb3, 0xe7, 0x76, 0x6f, 0x98, 0xf4, 0xc8, 0xee, 0x00, 0xe0, 0x0f, 0x6b,
0x1c, 0x71, 0xd3, 0xee, 0x0d, 0xb3, 0x8c, 0xb0, 0xfd, 0xc0, 0x0e, 0xd9, 0x06, 0x14, 0x27, 0xdc,
0x1f, 0x70, 0xf5, 0xde, 0x76, 0x6f, 0x98, 0x0a, 0xb0, 0x59, 0x84, 0xc2, 0x48, 0xd4, 0x6e, 0xfc,
0x69, 0x01, 0x2a, 0x3d, 0xee, 0x46, 0xab, 0x8c, 0x41, 0x5e, 0x4c, 0x88, 0x5c, 0x59, 0xf8, 0x9b,
0xbd, 0x09, 0x15, 0x9c, 0xba, 0x20, 0xf4, 0x1d, 0xf7, 0x94, 0xb8, 0x7a, 0x33, 0xdb, 0xcc, 0x98,
0x20, 0xc0, 0x3d, 0x84, 0xb2, 0x06, 0xe4, 0xec, 0xb1, 0xe2, 0x6a, 0xf1, 0x93, 0xdd, 0x84, 0x92,
0x3d, 0x0e, 0xa9, 0x7b, 0x55, 0x04, 0x17, 0xed, 0x71, 0x88, 0x5d, 0x7b, 0x03, 0xaa, 0x13, 0xfb,
0x6a, 0x2c, 0xd6, 0x72, 0xc4, 0x0e, 0x55, 0xb3, 0x22, 0x61, 0xc8, 0x10, 0x8f, 0x61, 0x59, 0x27,
0x51, 0x8d, 0x17, 0xa2, 0xc6, 0x97, 0x34, 0x6a, 0xd9, 0x87, 0x77, 0x60, 0x51, 0x95, 0xf1, 0x69,
0x3c, 0xc8, 0x26, 0x65, 0xb3, 0x2e, 0xc1, 0x6a, 0x94, 0xf7, 0xa0, 0x71, 0xe2, 0xb8, 0xf6, 0xc8,
0x1a, 0x8c, 0xc2, 0x73, 0x6b, 0xc8, 0x47, 0xa1, 0x8d, 0x1c, 0x53, 0x30, 0xeb, 0x08, 0xdf, 0x1a,
0x85, 0xe7, 0xdb, 0x02, 0xca, 0xbe, 0x0e, 0xe5, 0x13, 0xce, 0x2d, 0x9c, 0xac, 0x66, 0x29, 0xb1,
0xf0, 0xd4, 0x1b, 0x32, 0x4b, 0x27, 0xea, 0x5d, 0x7d, 0x1d, 0x1a, 0xde, 0x34, 0x3c, 0xf5, 0x1c,
0xf7, 0xd4, 0x12, 0xf2, 0xce, 0x72, 0x86, 0xc8, 0x43, 0xf9, 0xcd, 0xec, 0xa3, 0x8c, 0x59, 0x57,
0x38, 0x21, 0x79, 0x3a, 0x43, 0xf6, 0x36, 0x2c, 0x8e, 0xec, 0x20, 0xb4, 0xce, 0xbc, 0x89, 0x35,
0x99, 0x1e, 0x3f, 0xe7, 0x57, 0xcd, 0x1a, 0x4e, 0x44, 0x4d, 0x80, 0x77, 0xbd, 0xc9, 0x21, 0x02,
0x05, 0x67, 0x63, 0x3f, 0xa9, 0x13, 0x70, 0x37, 0x73, 0xaf, 0x66, 0x96, 0x05, 0x84, 0x1a, 0xfd,
0x0c, 0x96, 0xf1, 0xf5, 0x0c, 0xa6, 0x41, 0xe8, 0x8d, 0x2d, 0x21, 0xab, 0xfd, 0x61, 0xd0, 0xac,
0x20, 0xaf, 0xbd, 0x2b, 0x3b, 0xab, 0xbd, 0xe3, 0x07, 0xdb, 0x3c, 0x08, 0xb7, 0x90, 0xd8, 0x24,
0x5a, 0xb1, 0xa1, 0x5f, 0x99, 0x4b, 0xc3, 0x59, 0x38, 0xfb, 0x3a, 0x30, 0x7b, 0x34, 0xf2, 0x2e,
0xac, 0x80, 0x8f, 0x4e, 0x2c, 0x39, 0x89, 0xcd, 0xfa, 0xdd, 0xcc, 0xbd, 0x92, 0xd9, 0x40, 0x4c,
0x8f, 0x8f, 0x4e, 0x0e, 0x09, 0xce, 0x3e, 0x00, 0x5c, 0x4c, 0xd6, 0x09, 0xb7, 0xc3, 0xa9, 0xcf,
0x83, 0xe6, 0xe2, 0xdd, 0xdc, 0xbd, 0xfa, 0xe3, 0xa5, 0x68, 0xbe, 0x10, 0xbc, 0xe9, 0x84, 0x66,
0x55, 0xd0, 0xc9, 0xe7, 0x60, 0x63, 0x1b, 0xd6, 0xd2, 0xbb, 0x24, 0x98, 0x4a, 0xcc, 0x8a, 0x60,
0xc6, 0xbc, 0x29, 0x7e, 0xb2, 0x15, 0x28, 0x9c, 0xdb, 0xa3, 0x29, 0x97, 0x32, 0x9d, 0x1e, 0x3e,
0xcc, 0x7e, 0x27, 0x63, 0xfc, 0x49, 0x06, 0xaa, 0x34, 0x4a, 0xa9, 0x8b, 0xbc, 0x09, 0x35, 0xc5,
0x0d, 0xdc, 0xf7, 0x3d, 0x5f, 0x4a, 0x35, 0xc5, 0x79, 0x6d, 0x01, 0x13, 0xbb, 0x8a, 0x22, 0x9a,
0xf8, 0xdc, 0x19, 0xdb, 0xa7, 0xaa, 0x6a, 0xc5, 0x4a, 0x87, 0x12, 0xcc, 0xde, 0x8f, 0xeb, 0xf3,
0xbd, 0x69, 0xc8, 0xe5, 0x9e, 0x57, 0x95, 0xc3, 0x33, 0x05, 0x2c, 0xaa, 0x1d, 0x9f, 0x5e, 0x81,
0xcf, 0x8d, 0xdf, 0xcd, 0x00, 0x13, 0xdd, 0xee, 0x7b, 0x54, 0x81, 0xe4, 0xd0, 0xd9, 0x92, 0x99,
0x57, 0x5e, 0x21, 0xd9, 0x17, 0xad, 0x10, 0x03, 0x0a, 0xd4, 0xf7, 0x7c, 0x4a, 0xdf, 0x09, 0xf5,
0x83, 0x7c, 0x29, 0xd7, 0xc8, 0x1b, 0xff, 0x2d, 0x07, 0x2b, 0x5b, 0xb4, 0x65, 0xb7, 0x06, 0x03,
0x3e, 0x89, 0xd6, 0xce, 0x1d, 0xa8, 0xb8, 0xde, 0x90, 0x2b, 0x8e, 0xa5, 0x8e, 0x81, 0x00, 0x69,
0xec, 0x7a, 0x66, 0x3b, 0x2e, 0x75, 0x9c, 0x26, 0xb3, 0x8c, 0x10, 0xec, 0xf6, 0xdb, 0xb0, 0x38,
0xe1, 0xee, 0x50, 0x5f, 0x22, 0xa4, 0x54, 0xd5, 0x24, 0x58, 0xae, 0x8e, 0x3b, 0x50, 0x39, 0x99,
0x12, 0x9d, 0x10, 0x2c, 0x79, 0xe4, 0x01, 0x90, 0xa0, 0x16, 0xc9, 0x97, 0xc9, 0x34, 0x38, 0x43,
0x6c, 0x01, 0xb1, 0x45, 0xf1, 0x2c, 0x50, 0xb7, 0x01, 0x86, 0xd3, 0x20, 0x94, 0x2b, 0x66, 0x01,
0x91, 0x65, 0x01, 0xa1, 0x15, 0xf3, 0x0d, 0x58, 0x1e, 0xdb, 0x97, 0x16, 0xf2, 0x8e, 0xe5, 0xb8,
0xd6, 0xc9, 0x08, 0xf7, 0x9c, 0x22, 0xd2, 0x35, 0xc6, 0xf6, 0xe5, 0x27, 0x02, 0xd3, 0x71, 0x77,
0x10, 0x2e, 0xc4, 0x8a, 0x52, 0x77, 0x7c, 0x1e, 0x70, 0xff, 0x9c, 0xa3, 0x24, 0xc8, 0x47, 0x3a,
0x8d, 0x49, 0x50, 0xd1, 0xa3, 0xb1, 0x18, 0x77, 0x38, 0x1a, 0xd0, 0xb2, 0x37, 0x8b, 0x63, 0xc7,
0xdd, 0x0d, 0x47, 0x03, 0xb1, 0xaf, 0x08, 0x39, 0x32, 0xe1, 0xbe, 0xf5, 0xfc, 0x02, 0xd7, 0x70,
0x1e, 0xe5, 0xc6, 0x21, 0xf7, 0x9f, 0x5d, 0x88, 0xad, 0x7f, 0x10, 0xa0, 0x20, 0xb2, 0xaf, 0x9a,
0x15, 0x5c, 0xe0, 0xa5, 0x41, 0x20, 0x44, 0x90, 0x7d, 0x25, 0x16, 0xa1, 0xe8, 0xad, 0x8d, 0x6f,
0x81, 0x0f, 0xb1, 0xfa, 0x00, 0x25, 0x6a, 0x0d, 0x3b, 0xdb, 0x92, 0x08, 0xd1, 0x4e, 0x20, 0xb8,
0x5e, 0x75, 0xf6, 0x64, 0x64, 0x9f, 0x06, 0x28, 0x52, 0x6a, 0x66, 0x55, 0x02, 0x77, 0x04, 0xcc,
0xf8, 0x94, 0x94, 0x2c, 0xed, 0xdd, 0xca, 0x35, 0x23, 0xb6, 0x7a, 0x84, 0xe0, 0x7b, 0x2d, 0x99,
0xf2, 0x29, 0xed, 0xa5, 0x65, 0x53, 0x5e, 0x9a, 0xf1, 0xfb, 0x19, 0xa8, 0xca, 0x9a, 0x51, 0x29,
0x61, 0x0f, 0x80, 0xa9, 0xb7, 0x18, 0x5e, 0x3a, 0x43, 0xeb, 0xf8, 0x2a, 0xe4, 0x01, 0x31, 0xcd,
0xee, 0x0d, 0xb3, 0x21, 0x71, 0xfd, 0x4b, 0x67, 0xb8, 0x29, 0x30, 0xec, 0x3e, 0x34, 0x12, 0xf4,
0x41, 0xe8, 0x13, 0x47, 0xef, 0xde, 0x30, 0xeb, 0x1a, 0x75, 0x2f, 0xf4, 0xc5, 0x1a, 0x11, 0x2a,
0xcf, 0x34, 0xb4, 0x1c, 0x77, 0xc8, 0x2f, 0x91, 0x8d, 0x6a, 0x66, 0x85, 0x60, 0x1d, 0x01, 0xda,
0xac, 0x43, 0x55, 0xaf, 0xce, 0x38, 0x85, 0x92, 0xd2, 0x97, 0x50, 0x61, 0x98, 0xe9, 0x92, 0x59,
0x0e, 0xa3, 0x9e, 0xdc, 0x84, 0x52, 0xb2, 0x07, 0x66, 0x31, 0x7c, 0xe5, 0x86, 0x8d, 0xef, 0x41,
0x63, 0x4f, 0x30, 0x8f, 0x2b, 0x98, 0x55, 0xea, 0x7f, 0x6b, 0xb0, 0xa0, 0x2d, 0x9a, 0xb2, 0x29,
0x9f, 0xc4, 0x9e, 0x7b, 0xe6, 0x05, 0xa1, 0x6c, 0x05, 0x7f, 0x1b, 0x7f, 0x9a, 0x01, 0xd6, 0x0e,
0x42, 0x67, 0x6c, 0x87, 0x7c, 0x87, 0x47, 0x62, 0xe1, 0x00, 0xaa, 0xa2, 0xb6, 0xbe, 0xd7, 0x22,
0x85, 0x8c, 0x14, 0x8a, 0xf7, 0xe4, 0x32, 0x9e, 0x2f, 0xf0, 0x40, 0xa7, 0x26, 0x31, 0x9f, 0xa8,
0x40, 0xac, 0xb2, 0xd0, 0xf6, 0x4f, 0x79, 0x88, 0x6a, 0x9c, 0xd4, 0xf7, 0x81, 0x40, 0x42, 0x81,
0xdb, 0xf8, 0x55, 0x58, 0x9a, 0xab, 0x43, 0x97, 0xcb, 0xe5, 0x14, 0xb9, 0x9c, 0xd3, 0xe5, 0xb2,
0x05, 0xcb, 0x89, 0x7e, 0x49, 0x4e, 0x5b, 0x87, 0xa2, 0x58, 0x10, 0x42, 0x39, 0xc8, 0x90, 0x56,
0x79, 0xc2, 0xb9, 0x50, 0x83, 0x1f, 0xc2, 0xca, 0x09, 0xe7, 0xbe, 0x1d, 0x22, 0x12, 0x57, 0x8c,
0x78, 0x43, 0xb2, 0xe2, 0x25, 0x89, 0xeb, 0xd9, 0xe1, 0x21, 0xf7, 0xc5, 0x9b, 0x32, 0xfe, 0x47,
0x06, 0x16, 0x85, 0x04, 0xdd, 0xb7, 0xdd, 0x2b, 0x35, 0x4f, 0x7b, 0xa9, 0xf3, 0x74, 0x4f, 0xdb,
0x0c, 0x35, 0xea, 0x2f, 0x3b, 0x49, 0xb9, 0xd9, 0x49, 0x62, 0x77, 0xa1, 0x9a, 0xe8, 0x6b, 0x01,
0xfb, 0x0a, 0x41, 0xd4, 0xc9, 0x5f, 0x7c, 0x1a, 0xdf, 0x86, 0x46, 0xdc, 0x6d, 0x39, 0x87, 0x0c,
0xf2, 0x82, 0x25, 0x65, 0x05, 0xf8, 0xdb, 0xf8, 0x67, 0x19, 0x22, 0xdc, 0xf2, 0x9c, 0x48, 0x3b,
0x15, 0x84, 0x42, 0xef, 0x55, 0x84, 0xe2, 0xf7, 0xb5, 0x5a, 0xfd, 0x2f, 0x3e, 0x58, 0xb1, 0x74,
0x02, 0xee, 0x0e, 0x2d, 0x7b, 0x34, 0x42, 0xe1, 0x5b, 0x32, 0x8b, 0xe2, 0xb9, 0x35, 0x1a, 0x19,
0xef, 0xc0, 0x92, 0xd6, 0xbb, 0x17, 0x8c, 0xa3, 0x0b, 0x6c, 0xcf, 0x09, 0xc2, 0x23, 0x37, 0x98,
0x68, 0x8a, 0xdb, 0x2d, 0x28, 0x0b, 0x09, 0x2b, 0x7a, 0x46, 0x4b, 0xb6, 0x60, 0x0a, 0x91, 0x2b,
0xfa, 0x15, 0x20, 0xd2, 0xbe, 0x94, 0xc8, 0xac, 0x44, 0xda, 0x97, 0x88, 0x34, 0xbe, 0x03, 0xcb,
0x89, 0xfa, 0x64, 0xd3, 0x6f, 0x40, 0x61, 0x1a, 0x5e, 0x7a, 0x4a, 0x35, 0xaf, 0x48, 0x0e, 0x11,
0x06, 0xa0, 0x49, 0x18, 0xe3, 0x23, 0x58, 0xea, 0xf2, 0x0b, 0xb9, 0x88, 0x55, 0x47, 0xde, 0x86,
0xfc, 0x4b, 0x8c, 0x42, 0xc4, 0x1b, 0x0f, 0x80, 0xe9, 0x85, 0x65, 0xab, 0x9a, 0x8d, 0x98, 0x49,
0xd8, 0x88, 0xc6, 0xdb, 0xc0, 0x7a, 0xce, 0xa9, 0xbb, 0xcf, 0x83, 0xc0, 0x3e, 0x8d, 0x96, 0x7d,
0x03, 0x72, 0xe3, 0xe0, 0x54, 0xca, 0x28, 0xf1, 0xd3, 0xf8, 0x26, 0x2c, 0x27, 0xe8, 0x64, 0xc5,
0xaf, 0x41, 0x39, 0x70, 0x4e, 0x5d, 0x54, 0xac, 0x64, 0xd5, 0x31, 0xc0, 0xd8, 0x81, 0x95, 0x4f,
0xb8, 0xef, 0x9c, 0x5c, 0xbd, 0xac, 0xfa, 0x64, 0x3d, 0xd9, 0xd9, 0x7a, 0xda, 0xb0, 0x3a, 0x53,
0x8f, 0x6c, 0x9e, 0xd8, 0x57, 0xbe, 0xc9, 0x92, 0x49, 0x0f, 0x9a, 0xdc, 0xcb, 0xea, 0x72, 0xcf,
0x38, 0x02, 0xb6, 0xe5, 0xb9, 0x2e, 0x1f, 0x84, 0x87, 0x9c, 0xfb, 0xb1, 0x97, 0x2a, 0xe6, 0xd5,
0xca, 0xe3, 0x75, 0x39, 0xb3, 0xb3, 0xc2, 0x54, 0x32, 0x31, 0x83, 0xfc, 0x84, 0xfb, 0x63, 0xac,
0xb8, 0x64, 0xe2, 0x6f, 0x63, 0x15, 0x96, 0x13, 0xd5, 0x4a, 0xbb, 0xfe, 0x11, 0xac, 0x6e, 0x3b,
0xc1, 0x60, 0xbe, 0xc1, 0x75, 0x28, 0x4e, 0xa6, 0xc7, 0x56, 0x52, 0x2e, 0x3f, 0xe3, 0x57, 0xc2,
0xda, 0x9b, 0x2d, 0x21, 0xeb, 0xfa, 0x5b, 0x19, 0xc8, 0xef, 0xf6, 0xf7, 0xb6, 0xd8, 0x06, 0x94,
0x1c, 0x77, 0xe0, 0x8d, 0x85, 0xe2, 0x45, 0x63, 0x8e, 0x9e, 0xaf, 0x5d, 0x60, 0xb7, 0xa0, 0x8c,
0xfa, 0x9a, 0x30, 0x6d, 0xa5, 0xea, 0x53, 0x12, 0x80, 0x3d, 0x6f, 0xf0, 0x5c, 0xd8, 0xd4, 0xfc,
0x72, 0xe2, 0xf8, 0x68, 0x35, 0x2b, 0x63, 0x38, 0x4f, 0x7b, 0x7d, 0x8c, 0x20, 0x8b, 0xd8, 0xf8,
0xf7, 0x25, 0x28, 0xca, 0xdd, 0x96, 0x76, 0xee, 0xd0, 0x39, 0xe7, 0xf1, 0xce, 0x2d, 0x9e, 0x84,
0x3e, 0xe0, 0xf3, 0xb1, 0x17, 0x46, 0x0a, 0x1b, 0xbd, 0x83, 0x2a, 0x01, 0xa5, 0xca, 0xa6, 0x29,
0x0d, 0xe4, 0x62, 0xc8, 0x11, 0xd1, 0x40, 0xdf, 0xca, 0x6f, 0x41, 0x51, 0xed, 0xfd, 0xf9, 0xc8,
0xa6, 0x59, 0x18, 0x90, 0xb6, 0xb6, 0x01, 0xa5, 0x81, 0x3d, 0xb1, 0x07, 0x4e, 0x78, 0x25, 0x05,
0x42, 0xf4, 0x2c, 0x6a, 0x1f, 0x79, 0x03, 0x7b, 0x64, 0x1d, 0xdb, 0x23, 0xdb, 0x1d, 0x70, 0x69,
0xbb, 0x57, 0x11, 0xb8, 0x49, 0x30, 0x61, 0x9f, 0xcb, 0x7e, 0x2a, 0x2a, 0x32, 0xe1, 0x65, 0xef,
0x15, 0x99, 0x50, 0x2e, 0xbd, 0xf1, 0xd8, 0x11, 0x56, 0x06, 0xa9, 0x61, 0x39, 0xb3, 0x4c, 0x90,
0x1d, 0x8e, 0xa3, 0x95, 0xe8, 0x0b, 0x9a, 0xba, 0x32, 0x35, 0x45, 0xc0, 0x4f, 0xc9, 0x91, 0x30,
0xaf, 0x8b, 0xe5, 0x34, 0x5d, 0xec, 0x3d, 0x58, 0x9a, 0xba, 0x01, 0x0f, 0xc3, 0x11, 0x1f, 0x46,
0x7d, 0xa9, 0x20, 0x51, 0x23, 0x42, 0xa8, 0xee, 0x3c, 0x80, 0x65, 0x72, 0x3a, 0x04, 0x76, 0xe8,
0x05, 0x67, 0x4e, 0x60, 0x05, 0xc2, 0x42, 0x22, 0x73, 0x77, 0x09, 0x51, 0x3d, 0x89, 0xe9, 0x91,
0x89, 0xb4, 0x3e, 0x43, 0xef, 0xf3, 0x01, 0x77, 0xce, 0xf9, 0x10, 0xf5, 0xb4, 0x9c, 0xb9, 0x9a,
0x28, 0x63, 0x4a, 0x24, 0x2a, 0xdd, 0xd3, 0xb1, 0x35, 0x9d, 0x0c, 0x6d, 0xa1, 0xac, 0xd4, 0x49,
0x19, 0x76, 0xa7, 0xe3, 0x23, 0x82, 0xb0, 0x47, 0xa0, 0x34, 0x31, 0xa9, 0x1f, 0x2e, 0x26, 0xe4,
0x99, 0x60, 0x56, 0xb3, 0x2a, 0x29, 0x48, 0x51, 0x4c, 0xe8, 0x9c, 0x8d, 0x19, 0x9d, 0xb3, 0x09,
0xc5, 0x89, 0xef, 0x9c, 0xdb, 0x21, 0x6f, 0x2e, 0x91, 0x00, 0x97, 0x8f, 0x42, 0x32, 0x38, 0xae,
0x13, 0x3a, 0x76, 0xe8, 0xf9, 0x4d, 0x86, 0xb8, 0x18, 0xc0, 0xee, 0xc3, 0x12, 0xf2, 0x48, 0x10,
0xda, 0xe1, 0x34, 0x90, 0x1a, 0xe8, 0x32, 0x32, 0x13, 0xea, 0xd0, 0x3d, 0x84, 0xa3, 0x12, 0xca,
0xbe, 0x09, 0x6b, 0xc4, 0x16, 0x58, 0x42, 0x6a, 0xd6, 0xa8, 0x10, 0xac, 0xe0, 0x54, 0x2c, 0x23,
0x56, 0xf0, 0xb7, 0xd4, 0xaf, 0x85, 0x76, 0xf0, 0x04, 0xd6, 0x25, 0x9b, 0xcc, 0x95, 0x5a, 0xc5,
0x52, 0x2b, 0x84, 0x9e, 0x29, 0xf6, 0x00, 0x96, 0x44, 0x97, 0x9c, 0x81, 0x25, 0x4b, 0x8b, 0x95,
0xb0, 0x26, 0x7a, 0x8f, 0x96, 0xd2, 0x22, 0x21, 0x4d, 0xc4, 0x3d, 0xe3, 0x57, 0xec, 0x7b, 0xb0,
0x48, 0x2c, 0x83, 0xe6, 0x15, 0x4a, 0xfa, 0x0d, 0x94, 0xf4, 0xab, 0xca, 0xc3, 0x19, 0x61, 0x51,
0xd8, 0xd7, 0x07, 0x89, 0x67, 0xb1, 0x1c, 0x46, 0xce, 0x09, 0x0f, 0x9d, 0x31, 0x6f, 0xae, 0x13,
0x83, 0xa9, 0x67, 0xb1, 0x52, 0xa7, 0x13, 0xc4, 0x34, 0x49, 0x2e, 0xd0, 0x13, 0xf2, 0xee, 0xc8,
0x0b, 0xb8, 0x72, 0x51, 0x35, 0x6f, 0xca, 0x45, 0x28, 0x80, 0x4a, 0x87, 0x14, 0x8a, 0x38, 0x19,
0x3d, 0x91, 0x23, 0xf1, 0x16, 0x32, 0x43, 0x8d, 0x6c, 0x1f, 0xe5, 0x4c, 0x14, 0xbb, 0xf8, 0x99,
0x7d, 0xa1, 0x24, 0xc8, 0x6b, 0xf8, 0x7e, 0x41, 0x80, 0xa4, 0xec, 0xf8, 0x69, 0x86, 0x36, 0x44,
0x29, 0x3f, 0x02, 0xcd, 0xbc, 0x23, 0xc9, 0x61, 0x79, 0xee, 0xe8, 0x4a, 0x0a, 0x13, 0x20, 0xd0,
0x81, 0x3b, 0xc2, 0xd5, 0xec, 0xb8, 0x3a, 0x09, 0xc9, 0xde, 0xaa, 0x02, 0x22, 0xd1, 0x1d, 0xa8,
0x4c, 0xa6, 0xc7, 0x23, 0x67, 0x40, 0x24, 0x39, 0xaa, 0x85, 0x40, 0x48, 0x20, 0xec, 0x5b, 0xe2,
0x28, 0xa2, 0xc8, 0x23, 0x45, 0x45, 0xc2, 0x90, 0x04, 0x65, 0x3b, 0xf7, 0x51, 0x9c, 0x54, 0x4d,
0xfc, 0x6d, 0x6c, 0xc2, 0x4a, 0xb2, 0xd3, 0x72, 0xe3, 0xb9, 0x0f, 0x25, 0x29, 0xab, 0x94, 0xe3,
0xa3, 0xae, 0xb9, 0xa2, 0x85, 0x89, 0x16, 0xe1, 0x8d, 0xdf, 0x5e, 0x80, 0x65, 0x09, 0xdd, 0x12,
0x53, 0xdb, 0x9b, 0x8e, 0xc7, 0xb6, 0x9f, 0x22, 0x04, 0x33, 0x2f, 0x16, 0x82, 0xd9, 0x39, 0x21,
0x98, 0xb4, 0x7c, 0x49, 0x86, 0x26, 0x2d, 0x5f, 0xf1, 0x2e, 0xc9, 0x18, 0xd1, 0xfd, 0xa0, 0x35,
0x09, 0xee, 0x93, 0xbf, 0x75, 0x4e, 0x64, 0x17, 0x52, 0x44, 0xb6, 0x2e, 0x70, 0x17, 0x66, 0x04,
0xee, 0x1b, 0x40, 0x4c, 0xa3, 0xde, 0x7e, 0x91, 0xec, 0x13, 0x84, 0x49, 0x67, 0xea, 0x3b, 0xb0,
0x38, 0x2b, 0xe3, 0x48, 0x98, 0xd6, 0x53, 0x24, 0x9c, 0x33, 0xe6, 0xb8, 0x5b, 0x69, 0xc4, 0x65,
0x29, 0xe1, 0x9c, 0x31, 0xdf, 0x43, 0x8c, 0xa2, 0x6f, 0x03, 0x50, 0xdb, 0xb8, 0x68, 0x00, 0x17,
0xcd, 0xdb, 0xc9, 0x77, 0xa1, 0xcf, 0xfa, 0x03, 0xf1, 0x30, 0xf5, 0x39, 0xae, 0xa2, 0x32, 0x96,
0xc4, 0x05, 0xf4, 0x0c, 0xea, 0xde, 0x84, 0xbb, 0x56, 0x2c, 0x6b, 0x2a, 0x58, 0xd5, 0x5b, 0x2f,
0xa8, 0xaa, 0xa3, 0x68, 0xcd, 0x9a, 0x28, 0x1b, 0x3d, 0xb2, 0x7d, 0x9a, 0x78, 0xae, 0xd5, 0x56,
0xfd, 0x12, 0xb5, 0xd5, 0xb1, 0x70, 0xf4, 0x6c, 0xfc, 0xdd, 0x0c, 0x54, 0xb4, 0x6e, 0xb3, 0x55,
0x58, 0xda, 0x3a, 0x38, 0x38, 0x6c, 0x9b, 0xad, 0x7e, 0xe7, 0x93, 0xb6, 0xb5, 0xb5, 0x77, 0xd0,
0x6b, 0x37, 0x6e, 0x08, 0xf0, 0xde, 0xc1, 0x56, 0x6b, 0xcf, 0xda, 0x39, 0x30, 0xb7, 0x14, 0x38,
0xc3, 0xd6, 0x80, 0x99, 0xed, 0xfd, 0x83, 0x7e, 0x3b, 0x01, 0xcf, 0xb2, 0x06, 0x54, 0x37, 0xcd,
0x76, 0x6b, 0x6b, 0x57, 0x42, 0x72, 0x6c, 0x05, 0x1a, 0x3b, 0x47, 0xdd, 0xed, 0x4e, 0xf7, 0xa9,
0xb5, 0xd5, 0xea, 0x6e, 0xb5, 0xf7, 0xda, 0xdb, 0x8d, 0x3c, 0xab, 0x41, 0xb9, 0xb5, 0xd9, 0xea,
0x6e, 0x1f, 0x74, 0xdb, 0xdb, 0x8d, 0x82, 0xf1, 0x5d, 0x28, 0xc7, 0x03, 0xad, 0x40, 0xf1, 0xa8,
0xfb, 0xac, 0x7b, 0xf0, 0x69, 0xb7, 0x71, 0x83, 0x95, 0xa1, 0x80, 0xed, 0x37, 0x32, 0x0c, 0x60,
0x81, 0xda, 0x6c, 0x64, 0x59, 0x09, 0xf2, 0x9b, 0x07, 0xfd, 0xdd, 0x46, 0xce, 0xf8, 0xab, 0x0c,
0xac, 0xe2, 0x90, 0x87, 0xb3, 0x42, 0xe0, 0x2e, 0x54, 0x06, 0x9e, 0x37, 0x11, 0x96, 0x56, 0xac,
0x51, 0xe8, 0x20, 0xb1, 0xc0, 0x49, 0x78, 0x9f, 0x78, 0xfe, 0x80, 0x4b, 0x19, 0x00, 0x08, 0xda,
0x11, 0x10, 0xc1, 0x83, 0x92, 0x89, 0x89, 0x82, 0x44, 0x40, 0x85, 0x60, 0x44, 0xb2, 0x06, 0x0b,
0xc7, 0x3e, 0xb7, 0x07, 0x67, 0x72, 0xf5, 0xcb, 0x27, 0xf6, 0x6e, 0xec, 0x03, 0x18, 0x08, 0x9e,
0x1a, 0xf1, 0x21, 0x2e, 0x81, 0x92, 0xb9, 0x28, 0xe1, 0x5b, 0x12, 0x2c, 0x76, 0x23, 0xfb, 0xd8,
0x76, 0x87, 0x9e, 0xcb, 0x87, 0xd2, 0xd4, 0x88, 0x01, 0xc6, 0x21, 0xac, 0xcd, 0x8e, 0x4f, 0xca,
0x8b, 0x0f, 0x34, 0x79, 0x41, 0x9a, 0xff, 0xc6, 0xf5, 0xac, 0xa0, 0xc9, 0x8e, 0xbf, 0x9f, 0x87,
0xbc, 0xd0, 0x04, 0xaf, 0x55, 0x1a, 0x75, 0xd5, 0x3e, 0x37, 0x17, 0xfe, 0x41, 0x57, 0x03, 0xa9,
0x08, 0xe4, 0xcf, 0x2a, 0x23, 0x04, 0x55, 0x83, 0x08, 0xed, 0xf3, 0xc1, 0xb9, 0x74, 0x68, 0x11,
0xda, 0xe4, 0x83, 0x73, 0xb4, 0xa9, 0xec, 0x90, 0xca, 0xd2, 0x7a, 0x2f, 0x06, 0x76, 0x88, 0x25,
0x25, 0x0a, 0xcb, 0x15, 0x23, 0x14, 0x96, 0x6a, 0x42, 0xd1, 0x71, 0x8f, 0xbd, 0xa9, 0x3b, 0xc4,
0xe5, 0x5d, 0x32, 0xd5, 0x23, 0x46, 0x9b, 0x50, 0x12, 0x89, 0x8d, 0x88, 0x56, 0x73, 0x49, 0x00,
0xfa, 0x62, 0x2b, 0x7a, 0x1f, 0xca, 0xc1, 0x95, 0x3b, 0xd0, 0xd7, 0xf0, 0x8a, 0x9c, 0x1f, 0x31,
0xfa, 0x07, 0xbd, 0x2b, 0x77, 0x80, 0x2b, 0xb6, 0x14, 0xc8, 0x5f, 0xec, 0x09, 0x94, 0x22, 0xbf,
0x2f, 0x49, 0xe0, 0x9b, 0x7a, 0x09, 0xe5, 0xec, 0x25, 0xf3, 0x3a, 0x22, 0x65, 0x0f, 0x61, 0x01,
0x9d, 0xb3, 0x41, 0xb3, 0x8a, 0x85, 0x94, 0xbe, 0x2f, 0xba, 0x81, 0x81, 0x1e, 0x3e, 0x44, 0x47,
0xad, 0x29, 0xc9, 0x36, 0x9e, 0x41, 0x2d, 0x51, 0x97, 0x6e, 0x44, 0xd7, 0xc8, 0x88, 0x7e, 0x4b,
0x37, 0xa2, 0xe3, 0x9d, 0x40, 0x16, 0xd3, 0x8d, 0xea, 0x5f, 0x85, 0x92, 0x1a, 0x8a, 0x58, 0x7f,
0x72, 0xed, 0x58, 0xbd, 0xcf, 0xba, 0x5b, 0x8d, 0x1b, 0x6c, 0x11, 0x2a, 0xad, 0x2d, 0x5c, 0xd2,
0x08, 0xc8, 0x08, 0x92, 0xc3, 0x56, 0xaf, 0x17, 0x41, 0xb2, 0xc6, 0x0e, 0x34, 0x66, 0x7b, 0x2a,
0x78, 0x32, 0x54, 0x30, 0xe9, 0xba, 0x8e, 0x01, 0xc2, 0x44, 0x22, 0x6f, 0x34, 0xe9, 0xe1, 0xf4,
0x60, 0x3c, 0x81, 0x86, 0xd8, 0xd7, 0xc4, 0x54, 0x05, 0x9a, 0x0b, 0x78, 0x24, 0x74, 0x3b, 0xdd,
0x7d, 0x5d, 0x32, 0x2b, 0x04, 0xc3, 0xa6, 0x8c, 0x0f, 0x60, 0x49, 0x2b, 0x16, 0x9b, 0xb4, 0x62,
0xaf, 0x9c, 0x35, 0x69, 0xd1, 0x80, 0x21, 0x8c, 0xb1, 0x0e, 0xab, 0xe2, 0xb1, 0x7d, 0xce, 0xdd,
0xb0, 0x37, 0x3d, 0xa6, 0x98, 0xa3, 0xe3, 0xb9, 0xc2, 0xb0, 0x29, 0x47, 0x98, 0xeb, 0x99, 0xfc,
0x81, 0xb4, 0x7e, 0xb3, 0xc8, 0x1a, 0x1b, 0x5a, 0x0b, 0x58, 0xf0, 0x01, 0xfe, 0x4d, 0x58, 0xc1,
0xe5, 0x08, 0x24, 0xa6, 0xf5, 0xb0, 0xdd, 0x36, 0xad, 0x83, 0xee, 0x5e, 0xa7, 0x2b, 0x04, 0xa5,
0x98, 0x56, 0x04, 0xec, 0xec, 0x20, 0x24, 0x63, 0x34, 0xa0, 0xfe, 0x94, 0x87, 0x1d, 0xf7, 0xc4,
0x53, 0xf1, 0xb5, 0x9f, 0x15, 0x60, 0x31, 0x02, 0xc5, 0x56, 0xf4, 0x39, 0xf7, 0x03, 0xc7, 0x73,
0x51, 0x21, 0x2e, 0x9b, 0xea, 0x51, 0xec, 0x6e, 0xce, 0x90, 0xbb, 0xa1, 0x13, 0x5e, 0x59, 0x09,
0x97, 0x5b, 0x5d, 0x81, 0xe5, 0x2e, 0xba, 0x02, 0x05, 0x7b, 0xe4, 0xd8, 0x2a, 0x54, 0x4b, 0x0f,
0x02, 0x3a, 0xf0, 0x46, 0x9e, 0x8f, 0xba, 0x6f, 0xd9, 0xa4, 0x07, 0xf6, 0x08, 0x56, 0x84, 0x0e,
0xae, 0xfb, 0x41, 0x51, 0x7e, 0x90, 0xf7, 0x8f, 0xb9, 0xd3, 0xf1, 0x61, 0xec, 0x0b, 0x15, 0x18,
0xb1, 0x77, 0x8a, 0x12, 0x52, 0x59, 0x8a, 0x0a, 0x90, 0x39, 0xb7, 0xe4, 0x4e, 0xc7, 0x2d, 0xc4,
0x44, 0xf4, 0x8f, 0x61, 0x55, 0xd0, 0x47, 0xea, 0x55, 0x54, 0x62, 0x11, 0x4b, 0x88, 0xca, 0x3a,
0x12, 0x17, 0x95, 0xb9, 0x05, 0x65, 0xea, 0x95, 0x78, 0xe3, 0x05, 0x52, 0xe3, 0xb1, 0x2b, 0xdc,
0x0f, 0xe6, 0xa2, 0xaa, 0x0b, 0xa4, 0x08, 0xcc, 0x44, 0x55, 0xb5, 0xb8, 0x6c, 0x69, 0x36, 0x2e,
0xfb, 0x18, 0x56, 0x8f, 0x05, 0x0b, 0x9e, 0x71, 0x7b, 0xc8, 0x7d, 0x2b, 0x66, 0x6c, 0x32, 0x57,
0x96, 0x05, 0x72, 0x17, 0x71, 0xd1, 0x3a, 0x10, 0x7a, 0x8e, 0x10, 0x0b, 0x7c, 0x68, 0x85, 0x9e,
0x85, 0xea, 0x0f, 0x0a, 0x98, 0x92, 0x59, 0x23, 0x70, 0xdf, 0xdb, 0x12, 0xc0, 0x24, 0xdd, 0xa9,
0x6f, 0x4f, 0xce, 0xa4, 0x41, 0x11, 0xd1, 0x3d, 0x15, 0x40, 0xf6, 0x1a, 0x14, 0x05, 0xcb, 0xbb,
0x9c, 0x82, 0x5f, 0xa4, 0xb2, 0x2b, 0x10, 0x7b, 0x0b, 0x16, 0xb0, 0x8d, 0xa0, 0xd9, 0x40, 0x7e,
0xaf, 0xc6, 0x82, 0xdc, 0x71, 0x4d, 0x89, 0x13, 0xca, 0xe4, 0xd4, 0x77, 0x48, 0xca, 0x94, 0x4d,
0xfc, 0xcd, 0xbe, 0xaf, 0x89, 0xac, 0x65, 0x2c, 0xab, 0xf4, 0x81, 0x19, 0x4e, 0xbb, 0x4e, 0x7a,
0x7d, 0xa5, 0xc2, 0xe8, 0x07, 0xf9, 0x52, 0xa5, 0x51, 0x35, 0xbe, 0x0d, 0x05, 0x9a, 0x1d, 0xc1,
0x84, 0x38, 0x77, 0x19, 0xc9, 0x84, 0x08, 0x6d, 0x42, 0xd1, 0xe5, 0xe1, 0x85, 0xe7, 0x3f, 0x57,
0x4e, 0x69, 0xf9, 0x68, 0xfc, 0x18, 0xbd, 0x29, 0x51, 0xc4, 0x9d, 0x0c, 0x43, 0xc1, 0x1e, 0xf4,
0x7a, 0x83, 0x33, 0x5b, 0x3a, 0x78, 0x4a, 0x08, 0xe8, 0x9d, 0xd9, 0x73, 0xec, 0x91, 0x9d, 0x0f,
0xba, 0xbf, 0x05, 0x75, 0x15, 0xe3, 0x0f, 0xac, 0x11, 0x3f, 0x09, 0x25, 0xbb, 0x57, 0x65, 0x80,
0x3f, 0xd8, 0xe3, 0x27, 0xa1, 0xb1, 0x0f, 0x4b, 0x92, 0x21, 0x0f, 0x26, 0x5c, 0x35, 0xfd, 0x9d,
0x34, 0x7d, 0xba, 0xf2, 0x78, 0x39, 0xb9, 0xd1, 0x52, 0xee, 0x42, 0x42, 0xc9, 0x36, 0x3e, 0x06,
0xa6, 0x6f, 0xc3, 0xb2, 0x3e, 0xa9, 0xd5, 0x2a, 0x5f, 0xbe, 0x0a, 0x89, 0x45, 0xba, 0xb3, 0x33,
0x14, 0xb3, 0x13, 0x4c, 0x07, 0x03, 0x95, 0x7b, 0x51, 0x32, 0xd5, 0xa3, 0xf1, 0xe7, 0x19, 0x58,
0xc6, 0xca, 0x94, 0x3d, 0x20, 0x85, 0xec, 0xcf, 0xdd, 0x49, 0xf1, 0x7e, 0x74, 0xdd, 0x87, 0x1e,
0xbe, 0xbc, 0xf7, 0x34, 0x3f, 0xe7, 0x3d, 0x7d, 0x17, 0x1a, 0x43, 0x3e, 0x72, 0x30, 0x0d, 0x47,
0xa9, 0x12, 0x64, 0x01, 0x2c, 0x2a, 0xb8, 0xb4, 0x06, 0x8d, 0x7f, 0x9c, 0x81, 0x25, 0xd2, 0x54,
0xd0, 0xae, 0x96, 0x13, 0xf5, 0x91, 0x32, 0x24, 0xa5, 0xa8, 0x92, 0x63, 0x8a, 0x77, 0x70, 0x84,
0x12, 0xf1, 0xee, 0x0d, 0x69, 0x60, 0x4a, 0x28, 0xfb, 0x10, 0x6d, 0x18, 0xd7, 0x42, 0x60, 0x4a,
0x5a, 0x4f, 0xf2, 0xa5, 0xec, 0xde, 0x40, 0x03, 0xc7, 0x45, 0xd0, 0x66, 0x49, 0x58, 0xb6, 0x02,
0x6c, 0xec, 0x40, 0x2d, 0xd1, 0x4c, 0xc2, 0xc5, 0x5b, 0x25, 0x17, 0xef, 0x5c, 0x18, 0x25, 0x3b,
0x1f, 0x46, 0xf9, 0xdb, 0x79, 0x60, 0x82, 0xa5, 0x66, 0xde, 0xda, 0x4c, 0x0c, 0x32, 0x3b, 0x17,
0x83, 0x7c, 0x04, 0x4c, 0x23, 0x50, 0xa1, 0xd1, 0x5c, 0x14, 0x1a, 0x6d, 0xc4, 0xb4, 0x32, 0x32,
0xfa, 0x08, 0x56, 0xa4, 0x42, 0x1b, 0x05, 0x1d, 0xd1, 0x77, 0x47, 0xef, 0x87, 0x91, 0x66, 0xab,
0x82, 0x8f, 0xe8, 0xc7, 0x53, 0xf1, 0x47, 0x61, 0x83, 0x93, 0xcb, 0x0b, 0xe3, 0x8f, 0xca, 0xfa,
0xd6, 0xb8, 0x60, 0xe1, 0xa5, 0x5c, 0x50, 0x9c, 0xe3, 0x02, 0xcd, 0x03, 0x53, 0x4a, 0x7a, 0x60,
0x0c, 0xa8, 0xa9, 0x28, 0x23, 0x25, 0x57, 0x90, 0xf6, 0x56, 0x91, 0xa1, 0x46, 0x4c, 0xb0, 0xb8,
0x07, 0x0d, 0xe5, 0x26, 0x89, 0x7c, 0x3c, 0x94, 0x38, 0x20, 0xbd, 0x6c, 0x5b, 0xca, 0xd3, 0x93,
0xf0, 0xa8, 0x57, 0x66, 0x3c, 0xea, 0xef, 0xc1, 0x52, 0x20, 0x98, 0xc8, 0x9a, 0xba, 0x32, 0xcb,
0x87, 0x0f, 0xd1, 0x74, 0x2a, 0x99, 0x0d, 0x44, 0x1c, 0xc5, 0xf0, 0x79, 0xff, 0x45, 0x2d, 0xc5,
0x7f, 0xf1, 0x24, 0x0e, 0xc8, 0x05, 0x67, 0xce, 0x18, 0x37, 0xee, 0x38, 0x23, 0x46, 0x4e, 0x70,
0xef, 0xcc, 0x19, 0x9b, 0x2a, 0xfa, 0x2b, 0x1e, 0x8c, 0x7f, 0x97, 0x81, 0x86, 0xe0, 0x83, 0x04,
0x9f, 0x7f, 0x17, 0x70, 0x45, 0xbe, 0x22, 0x9b, 0x57, 0x04, 0xad, 0xe2, 0xf2, 0x6f, 0x03, 0xb2,
0xad, 0x25, 0xec, 0x44, 0xc9, 0xe4, 0xcd, 0x24, 0x93, 0xc7, 0x82, 0x6c, 0xf7, 0x06, 0x19, 0x00,
0x02, 0x92, 0x16, 0x08, 0xcd, 0xa7, 0x04, 0x42, 0xb5, 0xa5, 0xb0, 0x0b, 0xf0, 0x8c, 0x5f, 0xed,
0x79, 0x03, 0xb4, 0xd0, 0x6e, 0x03, 0x08, 0x86, 0x3c, 0xb1, 0xc7, 0x8e, 0xf4, 0xae, 0x14, 0xcc,
0xf2, 0x73, 0x7e, 0xb5, 0x83, 0x00, 0xf1, 0x36, 0x04, 0x3a, 0x5e, 0x0f, 0x05, 0xb3, 0xf4, 0x9c,
0x5f, 0xd1, 0x62, 0xb0, 0xa0, 0xf6, 0x8c, 0x5f, 0x6d, 0x73, 0x52, 0xd7, 0x3c, 0x5f, 0x70, 0x82,
0x6f, 0x5f, 0x08, 0xfd, 0x2c, 0x11, 0xc4, 0xac, 0xf8, 0xf6, 0xc5, 0x33, 0x7e, 0xa5, 0x02, 0xaa,
0x45, 0x81, 0x1f, 0x79, 0x03, 0xb9, 0x03, 0xa9, 0x74, 0x8c, 0xb8, 0x53, 0xe6, 0xc2, 0x73, 0xfc,
0x6d, 0xfc, 0x75, 0x06, 0x6a, 0xa2, 0xff, 0x28, 0xe0, 0xc4, 0xbc, 0xab, 0xac, 0x9e, 0x4c, 0x9c,
0xd5, 0xf3, 0x58, 0xca, 0x07, 0x92, 0x96, 0xd9, 0xeb, 0xa5, 0x25, 0x4e, 0x30, 0x89, 0xca, 0xf7,
0xa1, 0x4c, 0x6b, 0x4b, 0x2c, 0xd6, 0x5c, 0xe2, 0x2d, 0x25, 0x06, 0x64, 0x96, 0x90, 0xec, 0x19,
0x25, 0x11, 0x68, 0x9e, 0x3a, 0x9a, 0xe2, 0xb2, 0x1f, 0xf9, 0xe7, 0x52, 0x5e, 0x43, 0xe1, 0x9a,
0x24, 0x02, 0xdd, 0x0d, 0xb6, 0x30, 0xe7, 0x06, 0x3b, 0x82, 0x8a, 0xc6, 0x74, 0xe8, 0xf7, 0x8b,
0x46, 0x47, 0x1c, 0x9a, 0xe4, 0xaa, 0xc4, 0xf4, 0xec, 0xde, 0x30, 0x6b, 0x03, 0x1d, 0xb0, 0xb9,
0x00, 0x79, 0x51, 0xc8, 0xf8, 0x08, 0x96, 0xb4, 0x6a, 0xc9, 0x5c, 0x4d, 0xeb, 0x74, 0x26, 0x2d,
0x88, 0xfe, 0x4f, 0x32, 0xb0, 0x22, 0x4b, 0x63, 0x8a, 0x98, 0x23, 0xf6, 0xf3, 0xfd, 0xe0, 0x94,
0x7d, 0x17, 0x6a, 0xa2, 0x76, 0xcb, 0xe7, 0xa7, 0x4e, 0x10, 0x72, 0x15, 0x23, 0x49, 0x59, 0x3d,
0x42, 0xac, 0x0b, 0x52, 0x53, 0x52, 0xb2, 0x8f, 0xa0, 0x82, 0x45, 0xc9, 0xa0, 0x96, 0xef, 0xad,
0x39, 0x5f, 0x90, 0xba, 0xba, 0x7b, 0xc3, 0x84, 0x20, 0x7a, 0xda, 0x2c, 0x43, 0x31, 0xf4, 0x9d,
0xd3, 0x53, 0xee, 0x1b, 0x6b, 0x51, 0xd7, 0xc4, 0x52, 0xe4, 0xbd, 0x90, 0x4f, 0x84, 0x96, 0x64,
0xfc, 0xa7, 0x0c, 0x54, 0xe4, 0xe2, 0xfa, 0xb9, 0x03, 0x23, 0x1b, 0x5a, 0x8e, 0x23, 0xd9, 0xce,
0x71, 0x4a, 0xe3, 0x3b, 0xb0, 0x38, 0x16, 0x1a, 0x93, 0xd0, 0xe8, 0x13, 0x51, 0x91, 0xba, 0x02,
0x4b, 0x85, 0xe5, 0x01, 0x2c, 0xa3, 0xfe, 0x12, 0x58, 0xa1, 0x33, 0xb2, 0x14, 0x52, 0xe6, 0x13,
0x2e, 0x11, 0xaa, 0xef, 0x8c, 0xf6, 0x25, 0x42, 0x6c, 0xe3, 0x41, 0x68, 0x9f, 0x72, 0xc9, 0x1b,
0xf4, 0x60, 0x34, 0x61, 0x6d, 0x46, 0x99, 0x57, 0x86, 0xc8, 0x1f, 0x2e, 0xc1, 0xfa, 0x1c, 0x4a,
0x1a, 0x24, 0x51, 0x34, 0x60, 0xe4, 0x8c, 0x8f, 0xbd, 0xc8, 0x57, 0x96, 0xd1, 0xa2, 0x01, 0x7b,
0x02, 0xa3, 0x7c, 0x65, 0x1c, 0x56, 0x15, 0x43, 0xa0, 0xb3, 0x2b, 0xd2, 0xf7, 0xb3, 0xa8, 0x8d,
0xbe, 0x9f, 0x94, 0x64, 0xb3, 0xcd, 0x29, 0xb8, 0xbe, 0x3f, 0x2e, 0x4f, 0xe6, 0x60, 0x01, 0xfb,
0x2d, 0x68, 0x46, 0x7c, 0x27, 0x15, 0x28, 0xcd, 0x78, 0x11, 0x2d, 0x7d, 0xfd, 0x25, 0x2d, 0x25,
0xbc, 0x28, 0xb8, 0x81, 0xae, 0x29, 0x96, 0xa5, 0x0a, 0xa3, 0xb6, 0xce, 0xe1, 0x75, 0xd5, 0x16,
0x2a, 0x44, 0xf3, 0x2d, 0xe6, 0x5f, 0x69, 0x6c, 0xe8, 0x21, 0x4a, 0x34, 0x6b, 0xde, 0x92, 0x15,
0x47, 0x28, 0xbd, 0xdd, 0x33, 0x58, 0xbb, 0xb0, 0x9d, 0x50, 0x8d, 0x51, 0xb3, 0x9d, 0x0a, 0xd8,
0xde, 0xe3, 0x97, 0xb4, 0xf7, 0x29, 0x15, 0x4e, 0xa8, 0x88, 0x2b, 0x17, 0xf3, 0xc0, 0x60, 0xe3,
0xcf, 0xb2, 0x50, 0x4f, 0xd6, 0x22, 0x16, 0xb6, 0x14, 0x56, 0x4a, 0xe9, 0x90, 0x4a, 0xbb, 0xf4,
0xe3, 0x76, 0x49, 0xd9, 0x98, 0xf7, 0x30, 0x67, 0x53, 0x3c, 0xcc, 0xba, 0x63, 0x37, 0xf7, 0xb2,
0x48, 0x5a, 0xfe, 0x95, 0x22, 0x69, 0x85, 0xb4, 0x48, 0xda, 0xf5, 0xe1, 0x97, 0x85, 0x9f, 0x2b,
0xfc, 0x52, 0x7c, 0x41, 0xf8, 0x25, 0x11, 0x34, 0x2a, 0xcd, 0x04, 0x8d, 0x36, 0xfe, 0x3a, 0x03,
0x6c, 0x9e, 0x97, 0xd9, 0x53, 0x72, 0xb5, 0xbb, 0x7c, 0x24, 0xe5, 0xdc, 0x37, 0x5e, 0x6d, 0x3d,
0xa8, 0xd7, 0xa7, 0x4a, 0xb3, 0x87, 0xb0, 0xac, 0xe7, 0x28, 0xeb, 0xd6, 0x4e, 0xcd, 0x64, 0x3a,
0x2a, 0xb6, 0x89, 0xb5, 0x20, 0x63, 0xfe, 0xa5, 0x41, 0xc6, 0xc2, 0x4b, 0x83, 0x8c, 0x0b, 0xc9,
0x20, 0xe3, 0xc6, 0x7f, 0xc9, 0xc0, 0x72, 0x0a, 0xcb, 0x7d, 0x75, 0x63, 0x16, 0x9c, 0x92, 0x10,
0x42, 0x59, 0xc9, 0x29, 0xba, 0xfc, 0xd9, 0x83, 0x4a, 0x1c, 0xb7, 0x52, 0x39, 0xfc, 0xf7, 0x5f,
0x26, 0x0b, 0xe2, 0x12, 0xa6, 0x5e, 0x7c, 0xe3, 0x0f, 0xb2, 0x50, 0xd1, 0x90, 0x62, 0x16, 0x89,
0xc1, 0xb4, 0xdc, 0x0e, 0xd2, 0x03, 0xd0, 0x56, 0xbb, 0x03, 0xd2, 0x19, 0x4c, 0x78, 0x5a, 0x0a,
0x72, 0xd3, 0x47, 0x82, 0x07, 0xb0, 0xac, 0xc2, 0x20, 0x3c, 0x4e, 0xe1, 0x92, 0x3b, 0xc3, 0x92,
0x0c, 0x86, 0xf0, 0x28, 0x23, 0x8c, 0x3d, 0x54, 0x1a, 0x7c, 0xfc, 0xee, 0x90, 0x31, 0xc9, 0xd3,
0xba, 0x44, 0xec, 0xac, 0x5e, 0xa2, 0xe0, 0xca, 0xf7, 0x61, 0x55, 0x31, 0x73, 0xb2, 0x04, 0x39,
0x5f, 0x99, 0x64, 0x65, 0xbd, 0xc8, 0xf7, 0xe1, 0xf6, 0x4c, 0x9f, 0x66, 0x8a, 0x52, 0xae, 0xe1,
0xcd, 0x44, 0xef, 0xf4, 0x1a, 0x36, 0x7e, 0x02, 0xb5, 0x84, 0x58, 0xfb, 0xea, 0x5e, 0xf9, 0xac,
0x7d, 0x4c, 0x33, 0xaa, 0xdb, 0xc7, 0x1b, 0xff, 0x27, 0x07, 0x6c, 0x5e, 0xb2, 0xfe, 0x32, 0xbb,
0x30, 0xcf, 0x98, 0xb9, 0x14, 0xc6, 0xfc, 0x7f, 0xb6, 0xdb, 0xbf, 0x07, 0x4b, 0xf2, 0x2c, 0x8b,
0x16, 0xcb, 0xa2, 0xc5, 0xd9, 0x88, 0x10, 0xaa, 0x17, 0xdf, 0x9e, 0x8d, 0xa9, 0x97, 0x12, 0xe9,
0xfb, 0x9a, 0xba, 0x33, 0x13, 0x5a, 0x3f, 0x82, 0x05, 0xdb, 0x1d, 0x9c, 0x79, 0x3e, 0x9a, 0x66,
0xf5, 0xc7, 0xbf, 0xf2, 0xa5, 0x37, 0xbb, 0x07, 0x2d, 0x2c, 0x8f, 0x3a, 0x96, 0x29, 0x2b, 0x33,
0xde, 0x87, 0x8a, 0x06, 0xc6, 0xf8, 0x4e, 0x67, 0x7f, 0xf3, 0xa0, 0x71, 0x83, 0xd5, 0xa0, 0x6c,
0xb6, 0xb7, 0x0e, 0x3e, 0x69, 0x9b, 0xed, 0xed, 0x46, 0x86, 0x95, 0x20, 0xbf, 0x77, 0xd0, 0xeb,
0x37, 0xb2, 0xc6, 0x06, 0x34, 0x65, 0x8d, 0xf3, 0xbe, 0xde, 0xdf, 0xcd, 0x47, 0x6e, 0x16, 0x44,
0x4a, 0xab, 0xea, 0x9b, 0x50, 0xd5, 0x95, 0x11, 0xc9, 0x11, 0x33, 0xe1, 0x54, 0x61, 0x4f, 0x79,
0x9a, 0xac, 0xde, 0x02, 0x0a, 0x92, 0x0d, 0xa3, 0x62, 0xa4, 0x61, 0xbe, 0x20, 0xaa, 0x82, 0xca,
0x73, 0x82, 0x0d, 0xff, 0x3f, 0xa8, 0x27, 0x1d, 0x9f, 0x52, 0x22, 0xa5, 0x99, 0x17, 0xa2, 0x74,
0xc2, 0x13, 0xca, 0xbe, 0x0f, 0x8d, 0x59, 0xc7, 0xa9, 0xcc, 0x72, 0xbe, 0xa6, 0xfc, 0xa2, 0x93,
0xf4, 0xa5, 0xb2, 0x5d, 0x58, 0x49, 0x53, 0xc7, 0x90, 0x3f, 0xae, 0xb7, 0x2b, 0xd9, 0xbc, 0xca,
0xc5, 0xbe, 0x23, 0xfd, 0xe3, 0x85, 0xb4, 0x28, 0xa3, 0x36, 0xd9, 0x0f, 0xe8, 0x9f, 0xe6, 0x29,
0x3f, 0x07, 0x88, 0x61, 0xac, 0x01, 0xd5, 0x83, 0xc3, 0x76, 0xd7, 0xda, 0xda, 0x6d, 0x75, 0xbb,
0xed, 0xbd, 0xc6, 0x0d, 0xc6, 0xa0, 0x8e, 0xe1, 0xc1, 0xed, 0x08, 0x96, 0x11, 0x30, 0x19, 0xa7,
0x50, 0xb0, 0x2c, 0x5b, 0x81, 0x46, 0xa7, 0x3b, 0x03, 0xcd, 0xb1, 0x26, 0xac, 0x1c, 0xb6, 0x29,
0xa2, 0x98, 0xa8, 0x37, 0x2f, 0x54, 0x7c, 0x39, 0x5c, 0xa1, 0xe2, 0xd3, 0x99, 0x2c, 0xb9, 0x0e,
0x94, 0xe6, 0xfb, 0x7b, 0x19, 0x58, 0x9d, 0x41, 0xc4, 0x99, 0xf6, 0xa4, 0xf7, 0x26, 0x35, 0xde,
0x2a, 0x02, 0xd5, 0x6a, 0x7a, 0x0f, 0x96, 0x22, 0x5f, 0xc1, 0xcc, 0xae, 0xd4, 0x88, 0x10, 0x8a,
0xf8, 0x21, 0x2c, 0x6b, 0x2e, 0x87, 0x19, 0x59, 0xc1, 0x34, 0x94, 0x2c, 0x60, 0xac, 0x47, 0x19,
0xcd, 0x33, 0xbd, 0x1e, 0xd2, 0x41, 0x2f, 0x1d, 0x11, 0x87, 0x0f, 0x92, 0xfd, 0x55, 0x8f, 0xec,
0xd1, 0x0c, 0x23, 0x24, 0x7b, 0xab, 0xbf, 0x70, 0xd5, 0xfc, 0x1f, 0x2d, 0x00, 0xfb, 0x78, 0xca,
0xfd, 0x2b, 0xcc, 0xa4, 0x0f, 0x5e, 0x96, 0x5a, 0xa6, 0xec, 0xea, 0xec, 0x2b, 0x9d, 0x96, 0x49,
0x3b, 0xad, 0x92, 0x7f, 0xf9, 0x69, 0x95, 0xc2, 0xcb, 0x4e, 0xab, 0xbc, 0x09, 0x35, 0xe7, 0xd4,
0xf5, 0x84, 0x28, 0x14, 0x7a, 0x6b, 0xd0, 0x5c, 0xb8, 0x9b, 0xbb, 0x57, 0x35, 0xab, 0x12, 0x28,
0xb4, 0xd6, 0x80, 0x7d, 0x14, 0x13, 0xf1, 0xe1, 0x29, 0x9e, 0xac, 0xd2, 0x85, 0x60, 0x7b, 0x78,
0xca, 0xa5, 0x1b, 0x01, 0xed, 0x02, 0x55, 0x58, 0xc0, 0x03, 0xf6, 0x16, 0xd4, 0x03, 0x6f, 0x2a,
0xcc, 0x00, 0x35, 0x0d, 0x14, 0x60, 0xa8, 0x12, 0xf4, 0x50, 0x45, 0x93, 0x96, 0xa7, 0x01, 0xb7,
0xc6, 0x4e, 0x10, 0x08, 0xf5, 0x6c, 0xe0, 0xb9, 0xa1, 0xef, 0x8d, 0x64, 0xcc, 0x60, 0x69, 0x1a,
0xf0, 0x7d, 0xc2, 0x6c, 0x11, 0x82, 0x7d, 0x2b, 0xee, 0xd2, 0xc4, 0x76, 0xfc, 0xa0, 0x09, 0xd8,
0x25, 0x35, 0x52, 0xd4, 0xb6, 0x6d, 0xc7, 0x8f, 0xfa, 0x22, 0x1e, 0x82, 0x99, 0x53, 0x34, 0x95,
0xd9, 0x53, 0x34, 0x3f, 0x4a, 0x3f, 0x45, 0x53, 0xc3, 0xaa, 0x1f, 0xc9, 0xaa, 0xe7, 0x5f, 0xf1,
0x97, 0x3a, 0x4c, 0x33, 0x7f, 0x38, 0xa8, 0xfe, 0x65, 0x0e, 0x07, 0x2d, 0xa6, 0x1d, 0x0e, 0x7a,
0x1f, 0x2a, 0x78, 0x6c, 0xc3, 0x3a, 0x73, 0x84, 0x0e, 0x47, 0x31, 0x90, 0x86, 0x7e, 0xae, 0x63,
0xd7, 0x71, 0x43, 0x13, 0x7c, 0xf5, 0x33, 0x98, 0x3f, 0xa7, 0xb3, 0xf4, 0x4b, 0x3c, 0xa7, 0x23,
0x8f, 0x97, 0x3c, 0x80, 0x92, 0x7a, 0x4f, 0x8c, 0x41, 0xfe, 0xc4, 0xf7, 0xc6, 0xca, 0x37, 0x2c,
0x7e, 0xb3, 0x3a, 0x64, 0x43, 0x4f, 0x16, 0xce, 0x86, 0x9e, 0xf1, 0x9b, 0x50, 0xd1, 0x58, 0x8d,
0xbd, 0x41, 0x5e, 0x28, 0x61, 0x49, 0x49, 0xdd, 0x92, 0x66, 0xb1, 0x2c, 0xa1, 0x9d, 0xa1, 0x90,
0x37, 0x43, 0xc7, 0xe7, 0x78, 0xa2, 0xce, 0xf2, 0xf9, 0x39, 0xf7, 0x03, 0xe5, 0xab, 0x6f, 0x44,
0x08, 0x93, 0xe0, 0xc6, 0xff, 0x0f, 0xcb, 0x89, 0x77, 0x2b, 0x45, 0xc4, 0x5b, 0xb0, 0x80, 0xf3,
0xa6, 0x62, 0xa9, 0xc9, 0xf3, 0x32, 0x12, 0x87, 0x47, 0xa5, 0x29, 0xcc, 0x60, 0x4d, 0x7c, 0xef,
0x18, 0x1b, 0xc9, 0x98, 0x15, 0x09, 0x3b, 0xf4, 0xbd, 0x63, 0xe3, 0x2f, 0x73, 0x90, 0xdb, 0xf5,
0x26, 0x7a, 0xfa, 0x50, 0x66, 0x2e, 0x7d, 0x48, 0x9a, 0x87, 0x56, 0x64, 0xfe, 0x49, 0x9d, 0x1d,
0x1d, 0xec, 0xca, 0x04, 0xbc, 0x07, 0x75, 0x21, 0x27, 0x42, 0x4f, 0xd8, 0xd7, 0x17, 0xb6, 0x4f,
0x0a, 0x71, 0x8e, 0x16, 0x9f, 0x3d, 0x0e, 0xfb, 0xde, 0x0e, 0xc1, 0xd9, 0x0a, 0xe4, 0x22, 0xf3,
0x05, 0xd1, 0xe2, 0x91, 0xad, 0xc1, 0x02, 0xe6, 0x91, 0x5e, 0xc9, 0x60, 0xa1, 0x7c, 0x62, 0xdf,
0x80, 0xe5, 0x64, 0xbd, 0x24, 0x8a, 0xa4, 0x6e, 0xa4, 0x57, 0x8c, 0x32, 0xe9, 0x26, 0x08, 0x39,
0x42, 0x34, 0x32, 0xe7, 0xe0, 0x84, 0x73, 0x44, 0x69, 0x42, 0xaf, 0x94, 0x10, 0x7a, 0x77, 0xa0,
0x12, 0x8e, 0xce, 0xad, 0x89, 0x7d, 0x35, 0xf2, 0xec, 0xa1, 0x5c, 0xdf, 0x10, 0x8e, 0xce, 0x0f,
0x09, 0xc2, 0x1e, 0x02, 0x8c, 0x27, 0x13, 0xb9, 0xf6, 0xd0, 0x5f, 0x1d, 0xb3, 0xf2, 0xfe, 0xe1,
0x21, 0xb1, 0x9c, 0x59, 0x1e, 0x4f, 0x26, 0xf4, 0x93, 0x6d, 0x43, 0x3d, 0xf5, 0xd4, 0xdb, 0x6d,
0x95, 0xf6, 0xe8, 0x4d, 0x1e, 0xa4, 0x2c, 0xce, 0xda, 0x40, 0x87, 0x6d, 0x7c, 0x1f, 0xd8, 0x2f,
0x78, 0xf6, 0xac, 0x0f, 0xe5, 0xa8, 0x7f, 0xfa, 0xd1, 0x2d, 0x4c, 0x64, 0xae, 0x24, 0x8e, 0x6e,
0xb5, 0x86, 0x43, 0x5f, 0xc8, 0x45, 0xda, 0x30, 0x23, 0x91, 0x0f, 0xda, 0x8e, 0xd9, 0x22, 0xb9,
0x6f, 0xfc, 0xf7, 0x0c, 0x14, 0xe8, 0x1c, 0xd9, 0xdb, 0xb0, 0x48, 0xf4, 0x51, 0x2a, 0x96, 0x0c,
0x31, 0xd2, 0xbe, 0xdb, 0x97, 0x59, 0x58, 0x62, 0x59, 0x68, 0x67, 0x60, 0xb3, 0xd1, 0x9b, 0xd7,
0xce, 0xc1, 0xde, 0x81, 0x72, 0xd4, 0xb4, 0xc6, 0x3a, 0x25, 0xd5, 0x32, 0x7b, 0x1d, 0xf2, 0x67,
0xde, 0x44, 0xf9, 0x69, 0x20, 0x9e, 0x49, 0x13, 0xe1, 0x71, 0x5f, 0x44, 0x1b, 0xd4, 0x79, 0xe9,
0x5f, 0x88, 0x1a, 0x41, 0x36, 0x98, 0x1f, 0xe3, 0x42, 0xca, 0x18, 0x8f, 0x60, 0x51, 0xc8, 0x01,
0x2d, 0xd4, 0x7f, 0xfd, 0xa6, 0xf9, 0xae, 0xd0, 0xf0, 0x06, 0xa3, 0xe9, 0x90, 0xeb, 0x9e, 0x32,
0xcc, 0x0b, 0x92, 0x70, 0xa5, 0x59, 0x1b, 0x7f, 0x94, 0x21, 0xf9, 0x22, 0xea, 0x65, 0xf7, 0x20,
0x2f, 0xf6, 0xb7, 0x19, 0x4f, 0x6e, 0x94, 0x51, 0x2e, 0xe8, 0x4c, 0xa4, 0xc0, 0x83, 0xe3, 0xd3,
0x71, 0xb2, 0xf6, 0x9a, 0x59, 0x71, 0xa7, 0xe3, 0xc8, 0xd1, 0xf4, 0x35, 0x35, 0xac, 0x19, 0x27,
0x0d, 0x8d, 0x3e, 0x5a, 0xa6, 0x0f, 0xb4, 0x04, 0xa3, 0x7c, 0x62, 0xc7, 0x54, 0x5a, 0xe0, 0xf0,
0x94, 0x6b, 0x89, 0x45, 0x7f, 0x92, 0x85, 0x5a, 0xa2, 0x47, 0x98, 0x61, 0x25, 0x36, 0x00, 0x0a,
0x23, 0xc8, 0xf7, 0x0d, 0x02, 0x24, 0x15, 0x75, 0x6d, 0x9e, 0xb2, 0x89, 0x79, 0x8a, 0x92, 0x1a,
0x72, 0x7a, 0x52, 0xc3, 0x23, 0x28, 0xc7, 0x67, 0x9f, 0x93, 0x5d, 0x12, 0xed, 0xa9, 0xbc, 0xfa,
0x98, 0x28, 0x4e, 0x83, 0x28, 0xe8, 0x69, 0x10, 0xdf, 0xd3, 0xa2, 0xe6, 0x0b, 0x58, 0x8d, 0x91,
0x36, 0xa3, 0xbf, 0x94, 0x98, 0xb9, 0xf1, 0x11, 0x54, 0xb4, 0xce, 0xeb, 0xd1, 0xf1, 0x4c, 0x22,
0x3a, 0x1e, 0x9d, 0x80, 0xc9, 0xc6, 0x27, 0x60, 0x8c, 0xdf, 0xce, 0x42, 0x4d, 0xac, 0x2f, 0xc7,
0x3d, 0x3d, 0xf4, 0x46, 0xce, 0x00, 0xc3, 0x0a, 0xd1, 0x0a, 0x93, 0x8a, 0x96, 0x5a, 0x67, 0x72,
0x89, 0x91, 0x9e, 0xa5, 0x1f, 0xf4, 0x23, 0x21, 0x1d, 0x1d, 0xf4, 0x33, 0xa0, 0x26, 0x04, 0xe3,
0xb1, 0x1d, 0x70, 0xed, 0x64, 0xb6, 0x59, 0x39, 0xe1, 0x7c, 0xd3, 0x0e, 0x48, 0x42, 0x7e, 0x03,
0x96, 0x05, 0x0d, 0x9e, 0x71, 0x1a, 0x3b, 0xa3, 0x91, 0x43, 0x94, 0xe4, 0x68, 0x6a, 0x9c, 0x70,
0x6e, 0xda, 0x21, 0xdf, 0x17, 0x08, 0x79, 0x90, 0xbb, 0x34, 0x74, 0x02, 0xfb, 0x38, 0xce, 0x83,
0x8b, 0x9e, 0x31, 0x18, 0x68, 0x5f, 0x6a, 0xc1, 0x40, 0x72, 0x40, 0x54, 0xc6, 0xf6, 0x65, 0x14,
0x0c, 0x9c, 0xe1, 0xa4, 0xe2, 0x2c, 0x27, 0x19, 0xff, 0x21, 0x0b, 0x15, 0x8d, 0x2d, 0x5f, 0x65,
0x77, 0xbd, 0x3d, 0x17, 0x06, 0x2a, 0xeb, 0x11, 0x9f, 0x37, 0x93, 0x4d, 0x62, 0xce, 0x00, 0x1d,
0x19, 0xd7, 0x18, 0xf8, 0x16, 0x94, 0xc5, 0xaa, 0x7b, 0x1f, 0x1d, 0xa6, 0xf2, 0xc2, 0x03, 0x04,
0x1c, 0x4e, 0x8f, 0x15, 0xf2, 0x31, 0x22, 0x0b, 0x31, 0xf2, 0xb1, 0x40, 0xbe, 0x28, 0xf9, 0xf5,
0xdb, 0x50, 0x95, 0xb5, 0xe2, 0x3b, 0xc5, 0xe1, 0xc6, 0xab, 0x3e, 0xf1, 0xbe, 0xcd, 0x0a, 0x35,
0x47, 0x2f, 0x5f, 0x16, 0x7c, 0xac, 0x0a, 0x96, 0x5e, 0x56, 0xf0, 0x31, 0x3d, 0x18, 0x3b, 0x51,
0x3e, 0x31, 0xe6, 0xab, 0x28, 0x39, 0xf6, 0x10, 0x96, 0x95, 0xb8, 0x9a, 0xba, 0xb6, 0xeb, 0x7a,
0x53, 0x77, 0xc0, 0xd5, 0xd1, 0x18, 0x26, 0x51, 0x47, 0x31, 0xc6, 0x18, 0x46, 0x67, 0x27, 0x29,
0xef, 0xe5, 0x3e, 0x14, 0x48, 0x2f, 0x27, 0xe5, 0x23, 0x5d, 0x70, 0x11, 0x09, 0xbb, 0x07, 0x05,
0x52, 0xcf, 0xb3, 0xd7, 0x0a, 0x1b, 0x22, 0x30, 0x5a, 0xc0, 0x44, 0xc1, 0x7d, 0x1e, 0xfa, 0xce,
0x20, 0x88, 0x4f, 0xdd, 0x14, 0x84, 0xfd, 0x49, 0x6d, 0xc5, 0x69, 0xee, 0x31, 0x25, 0xda, 0xa8,
0x44, 0x23, 0x36, 0xa6, 0xe5, 0x44, 0x1d, 0x52, 0x5d, 0x1a, 0xc1, 0xda, 0x31, 0x0f, 0x2f, 0x38,
0x77, 0x5d, 0xa1, 0x0c, 0x0d, 0xb8, 0x1b, 0xfa, 0xf6, 0x48, 0xbc, 0x24, 0x1a, 0xc1, 0x93, 0xb9,
0x5a, 0x63, 0x1f, 0xc8, 0x66, 0x5c, 0x70, 0x2b, 0x2a, 0x47, 0xb2, 0x63, 0xf5, 0x38, 0x0d, 0xb7,
0xf1, 0x1b, 0xb0, 0x71, 0x7d, 0xa1, 0x94, 0xb3, 0x75, 0xf7, 0x92, 0x52, 0x25, 0x8a, 0x9a, 0x8d,
0x3c, 0x3b, 0xa4, 0xde, 0xe8, 0x92, 0xa5, 0x0b, 0x15, 0x0d, 0x13, 0xef, 0xfd, 0x19, 0x54, 0xee,
0xe8, 0x41, 0xec, 0x48, 0xae, 0xe7, 0x8f, 0xed, 0x91, 0xf3, 0x63, 0x3e, 0xb4, 0xe2, 0xda, 0x33,
0xe6, 0x62, 0x0c, 0xc7, 0xc3, 0xc4, 0xc6, 0x03, 0x58, 0x44, 0xcd, 0x5e, 0xdb, 0xe8, 0x5e, 0xa4,
0x0c, 0x1a, 0x2b, 0xc0, 0xba, 0x24, 0xbb, 0xf4, 0x34, 0xb8, 0xff, 0x9a, 0x83, 0x8a, 0x06, 0x16,
0xbb, 0x11, 0x26, 0x4e, 0x59, 0x43, 0xc7, 0x1e, 0x73, 0x15, 0x12, 0xac, 0x99, 0x35, 0x84, 0x6e,
0x4b, 0xa0, 0xd8, 0x8b, 0xed, 0xf3, 0x53, 0xcb, 0x9b, 0x86, 0xd6, 0x90, 0x9f, 0xfa, 0x5c, 0xf5,
0xb2, 0x6a, 0x9f, 0x9f, 0x1e, 0x4c, 0xc3, 0x6d, 0x84, 0x09, 0x2a, 0x21, 0x4b, 0x34, 0x2a, 0x99,
0xeb, 0x33, 0xb6, 0x2f, 0x63, 0x2a, 0x99, 0x70, 0x46, 0x9c, 0x99, 0x8f, 0x12, 0xce, 0xc8, 0x5a,
0x9c, 0xdd, 0x40, 0x0b, 0xf3, 0x1b, 0xe8, 0xb7, 0x60, 0x8d, 0x36, 0x50, 0x29, 0x9a, 0xad, 0x99,
0x95, 0xbc, 0x82, 0x58, 0x39, 0x48, 0x4d, 0xed, 0x6d, 0x88, 0x11, 0x28, 0xb1, 0x14, 0x38, 0x3f,
0x26, 0x41, 0x96, 0x31, 0xc5, 0xc8, 0x64, 0xe5, 0x3d, 0xe7, 0xc7, 0x5c, 0x50, 0x62, 0x42, 0x83,
0x4e, 0x29, 0x53, 0xdb, 0xc7, 0x8e, 0x3b, 0x4b, 0x69, 0x5f, 0x26, 0x29, 0xcb, 0x92, 0xd2, 0xbe,
0xd4, 0x29, 0x9f, 0xc0, 0xfa, 0x98, 0x0f, 0x1d, 0x3b, 0x59, 0xad, 0x15, 0x2b, 0x6e, 0x2b, 0x84,
0xd6, 0xca, 0xf4, 0xc8, 0x70, 0x17, 0xb3, 0xf1, 0x63, 0x6f, 0x7c, 0xec, 0x90, 0xce, 0x42, 0x29,
0x16, 0x79, 0xb3, 0xee, 0x4e, 0xc7, 0x3f, 0x44, 0xb0, 0x28, 0x12, 0x18, 0x35, 0xa8, 0xf4, 0x42,
0x6f, 0xa2, 0x5e, 0x73, 0x1d, 0xaa, 0xf4, 0x28, 0xcf, 0x9b, 0xdd, 0x82, 0x9b, 0x28, 0x12, 0xfa,
0xde, 0xc4, 0x1b, 0x79, 0xa7, 0x57, 0x09, 0x3f, 0xde, 0x7f, 0xce, 0xc0, 0x72, 0x02, 0x2b, 0xc5,
0xeb, 0xb7, 0x48, 0x9e, 0x45, 0x87, 0x86, 0x68, 0x0d, 0x2e, 0x69, 0x6b, 0x90, 0x08, 0x49, 0x98,
0xa9, 0x83, 0x44, 0xad, 0xf8, 0xb0, 0xbb, 0x2a, 0x48, 0x22, 0xa5, 0x39, 0x2f, 0x52, 0x64, 0x79,
0x75, 0x0c, 0x5e, 0x55, 0xf1, 0x2b, 0xf2, 0xf8, 0xc1, 0x50, 0x0e, 0x39, 0x97, 0x4c, 0xb0, 0xd6,
0x7d, 0x7e, 0xaa, 0x07, 0xb1, 0x23, 0x30, 0x30, 0xfe, 0x65, 0x06, 0x20, 0xee, 0x1d, 0xa6, 0x78,
0x47, 0x7a, 0x0b, 0xdd, 0x23, 0xa5, 0xe9, 0x28, 0x6f, 0x40, 0x35, 0xca, 0xf4, 0x8c, 0x35, 0xa1,
0x8a, 0x82, 0x09, 0x75, 0xe8, 0x1d, 0x58, 0x3c, 0x1d, 0x79, 0xc7, 0xa8, 0xb1, 0x4a, 0xbd, 0x85,
0x4e, 0xdd, 0xd5, 0x09, 0xac, 0xb4, 0x91, 0x58, 0x6f, 0xca, 0xa7, 0x26, 0x83, 0xea, 0x5a, 0x90,
0xf1, 0x3b, 0xd9, 0x28, 0xe5, 0x2d, 0x9e, 0x89, 0x17, 0x9b, 0x77, 0x3f, 0x4f, 0xe6, 0xc4, 0x8b,
0x82, 0x81, 0x1f, 0x41, 0xdd, 0xa7, 0x4d, 0x49, 0xed, 0x58, 0xf9, 0x17, 0xec, 0x58, 0x35, 0x3f,
0xa1, 0xe9, 0xbc, 0x0b, 0x0d, 0x7b, 0x78, 0xce, 0xfd, 0xd0, 0x41, 0x6f, 0x3d, 0xea, 0xc7, 0x32,
0xc9, 0x4c, 0x83, 0xa3, 0x22, 0xfa, 0x0e, 0x2c, 0xca, 0x33, 0x90, 0x11, 0xa5, 0xbc, 0x55, 0x25,
0x06, 0x0b, 0x42, 0xe3, 0x5f, 0xab, 0x1c, 0xbb, 0xe4, 0xdb, 0x7d, 0xf1, 0xac, 0xe8, 0x23, 0xcc,
0xce, 0x87, 0x3b, 0x25, 0x23, 0xc9, 0x20, 0x80, 0x94, 0x47, 0x04, 0x94, 0x21, 0x80, 0xe4, 0xb4,
0xe6, 0x5f, 0x65, 0x5a, 0x8d, 0x3f, 0xcb, 0x40, 0x71, 0xd7, 0x9b, 0xec, 0x3a, 0x94, 0xe4, 0x8c,
0xcb, 0x24, 0x8a, 0x51, 0x2d, 0x88, 0xc7, 0xce, 0xf0, 0xc5, 0x47, 0x7d, 0x52, 0xd5, 0xbc, 0x5a,
0x52, 0xcd, 0xfb, 0x1e, 0xdc, 0xc2, 0x10, 0xa0, 0xef, 0x4d, 0x3c, 0x5f, 0x2c, 0x55, 0x7b, 0x44,
0xea, 0x9e, 0xe7, 0x86, 0x67, 0x4a, 0x76, 0xde, 0x3c, 0xe1, 0xfc, 0x50, 0xa3, 0xd8, 0x8f, 0x08,
0xf0, 0x30, 0xdd, 0x28, 0x3c, 0xb7, 0xc8, 0x42, 0x97, 0xfa, 0x28, 0x49, 0xd4, 0x45, 0x81, 0x68,
0x23, 0x1c, 0x35, 0x52, 0xe3, 0x3b, 0x50, 0x8e, 0x9c, 0x3d, 0xec, 0x3d, 0x28, 0x9f, 0x79, 0x13,
0xe9, 0x11, 0xca, 0x24, 0x8e, 0x43, 0xc9, 0x51, 0x9b, 0xa5, 0x33, 0xfa, 0x11, 0x18, 0x7f, 0x59,
0x84, 0x62, 0xc7, 0x3d, 0xf7, 0x9c, 0x01, 0x66, 0xe9, 0x8d, 0xf9, 0xd8, 0x53, 0x07, 0xb1, 0xc5,
0x6f, 0xcc, 0xc4, 0x89, 0xef, 0x46, 0xc9, 0xc9, 0x4c, 0x9c, 0xe8, 0x56, 0x94, 0x55, 0x58, 0xf0,
0xf5, 0xcb, 0x4d, 0x0a, 0x3e, 0xe6, 0x0d, 0x47, 0xfb, 0x65, 0x41, 0x3b, 0xc8, 0x2e, 0xea, 0xa2,
0x4b, 0x37, 0x70, 0xca, 0xe8, 0x60, 0x5c, 0x19, 0x21, 0x38, 0x61, 0xaf, 0x41, 0x51, 0x9e, 0x3e,
0xa2, 0xb3, 0x1c, 0x94, 0xe8, 0x2b, 0x41, 0xc8, 0x0d, 0x3e, 0xa7, 0x10, 0x6e, 0xa4, 0xc8, 0xe6,
0xcc, 0xaa, 0x02, 0x6e, 0x0b, 0x5e, 0xbb, 0x03, 0x15, 0xa2, 0x27, 0x92, 0x92, 0xcc, 0xab, 0x43,
0x10, 0x12, 0xa4, 0xdc, 0x11, 0x54, 0x4e, 0xbd, 0x23, 0x08, 0xd3, 0x30, 0x23, 0x29, 0x4b, 0x43,
0x04, 0xba, 0x19, 0x46, 0x83, 0xab, 0x0b, 0xb2, 0xa4, 0x4f, 0x85, 0xce, 0x89, 0x2a, 0x9f, 0xca,
0x9b, 0x50, 0x3b, 0xb1, 0x47, 0xa3, 0x63, 0x7b, 0xf0, 0x9c, 0x5c, 0x01, 0x55, 0xf2, 0x7e, 0x2a,
0x20, 0xfa, 0x02, 0xee, 0x40, 0x45, 0x7b, 0xcb, 0x98, 0x34, 0x97, 0x37, 0x21, 0x7e, 0xbf, 0xb3,
0x1e, 0xbe, 0xfa, 0x2b, 0x78, 0xf8, 0xb4, 0xe4, 0xc1, 0xc5, 0x64, 0xf2, 0xe0, 0x2d, 0x94, 0xa6,
0x32, 0xc1, 0xac, 0x41, 0xd7, 0x90, 0xd8, 0xc3, 0x21, 0x26, 0x98, 0xd1, 0x9d, 0x7f, 0x38, 0x79,
0x84, 0x5f, 0x22, 0x5b, 0x82, 0x60, 0x44, 0x72, 0x9b, 0xdc, 0xd4, 0x13, 0xdb, 0x19, 0x62, 0xb2,
0x36, 0x79, 0x0f, 0x8a, 0xf6, 0x38, 0x3c, 0xb4, 0x9d, 0x21, 0xbb, 0x0b, 0x55, 0x85, 0xc6, 0xdd,
0x71, 0x99, 0xe6, 0x5f, 0xa2, 0xc5, 0x9e, 0x68, 0x40, 0x2d, 0xa2, 0x18, 0xc7, 0x87, 0x3d, 0x2b,
0x92, 0x04, 0xf9, 0xe0, 0x7d, 0xcc, 0xc9, 0x09, 0x39, 0x1e, 0xe9, 0xac, 0x3f, 0xbe, 0x25, 0xc7,
0x2a, 0xb9, 0x54, 0xfd, 0xa7, 0xe0, 0x18, 0x51, 0x0a, 0xe5, 0x8e, 0x62, 0x74, 0x6b, 0x09, 0xfd,
0x57, 0x92, 0x62, 0x8c, 0x8e, 0x08, 0xd8, 0x77, 0x34, 0xfb, 0xb5, 0x89, 0xc4, 0xaf, 0xcd, 0xd4,
0x7f, 0xdd, 0x59, 0x95, 0xdb, 0x00, 0x4e, 0x20, 0x76, 0x99, 0x80, 0xbb, 0x43, 0x3c, 0x9d, 0x59,
0x32, 0xcb, 0x4e, 0xf0, 0x8c, 0x00, 0x5f, 0xad, 0x61, 0xdb, 0x82, 0xaa, 0x3e, 0x4c, 0x56, 0x82,
0xfc, 0xc1, 0x61, 0xbb, 0xdb, 0xb8, 0xc1, 0x2a, 0x50, 0xec, 0xb5, 0xfb, 0xfd, 0x3d, 0x8c, 0xf4,
0x55, 0xa1, 0x14, 0x1d, 0x0d, 0xcb, 0x8a, 0xa7, 0xd6, 0xd6, 0x56, 0xfb, 0xb0, 0xdf, 0xde, 0x6e,
0xe4, 0x7e, 0x90, 0x2f, 0x65, 0x1b, 0x39, 0xe3, 0xaf, 0x72, 0x50, 0xd1, 0x66, 0xe1, 0xc5, 0xc2,
0xf8, 0x36, 0x00, 0x5a, 0x92, 0x71, 0xfe, 0x61, 0xde, 0x2c, 0x0b, 0x08, 0xbd, 0x7c, 0x3d, 0x46,
0x91, 0xa3, 0xfb, 0x6d, 0x54, 0x8c, 0xe2, 0x4d, 0xa8, 0xd1, 0x55, 0x31, 0x7a, 0xbc, 0xb6, 0x60,
0x56, 0x09, 0x28, 0x45, 0x35, 0x9e, 0x2d, 0x45, 0x22, 0x3c, 0x75, 0x24, 0x2f, 0x8e, 0x20, 0x10,
0x9e, 0x3b, 0xc2, 0x43, 0x63, 0x81, 0x37, 0x3a, 0xe7, 0x44, 0x41, 0x1a, 0x61, 0x45, 0xc2, 0xfa,
0xf2, 0x94, 0xac, 0x94, 0x87, 0xda, 0xe1, 0xc6, 0x82, 0x59, 0x25, 0xa0, 0x6c, 0xe8, 0x1b, 0x8a,
0x81, 0x4a, 0xc8, 0x40, 0xeb, 0xf3, 0xdc, 0x90, 0x60, 0x9e, 0xbd, 0x39, 0x37, 0x62, 0x19, 0x19,
0xe3, 0x6b, 0xf3, 0xe5, 0x5e, 0xee, 0x4e, 0x64, 0xef, 0x01, 0x1b, 0x4f, 0x26, 0x56, 0x8a, 0x83,
0x2f, 0x6f, 0x2e, 0x8e, 0x27, 0x93, 0xbe, 0xe6, 0xff, 0xfa, 0x0a, 0x7c, 0x8f, 0x9f, 0x03, 0x6b,
0x89, 0x05, 0x8c, 0x5d, 0x8c, 0x4c, 0xb1, 0x58, 0x2c, 0x67, 0x74, 0xb1, 0x9c, 0x22, 0xfd, 0xb2,
0xa9, 0xd2, 0xef, 0x45, 0x72, 0xc2, 0xd8, 0x81, 0xca, 0xa1, 0x76, 0x11, 0xd5, 0x5d, 0xb1, 0x43,
0xa8, 0x2b, 0xa8, 0x68, 0xef, 0x20, 0x9f, 0xa2, 0x2f, 0x6f, 0x9e, 0xd2, 0x7a, 0x93, 0xd5, 0x7a,
0x63, 0xfc, 0x8b, 0x0c, 0x5d, 0xf2, 0x11, 0x75, 0x3e, 0xbe, 0xfb, 0x4a, 0x85, 0xdf, 0xe2, 0x33,
0xc8, 0x15, 0x15, 0x76, 0x93, 0xc7, 0x87, 0xb1, 0x6b, 0x96, 0x77, 0x72, 0x12, 0x70, 0x95, 0xe3,
0x51, 0x41, 0xd8, 0x01, 0x82, 0x94, 0xf2, 0x2d, 0x34, 0x7c, 0x87, 0xea, 0x0f, 0x64, 0x62, 0x87,
0x50, 0xbe, 0xf7, 0xed, 0x4b, 0xd9, 0x6a, 0x20, 0x54, 0x10, 0x19, 0x1f, 0x50, 0x67, 0x08, 0xa3,
0x67, 0xe3, 0x9f, 0xca, 0x63, 0xd2, 0xb3, 0xf3, 0x7b, 0x1f, 0x4a, 0x51, 0xad, 0xc9, 0x1d, 0x56,
0x51, 0x46, 0x78, 0xb1, 0x8f, 0xa3, 0x33, 0x24, 0xd1, 0x63, 0x5a, 0x5c, 0x18, 0xe3, 0xe9, 0x68,
0xbd, 0xfe, 0x3a, 0xb0, 0x13, 0xc7, 0x9f, 0x25, 0xa6, 0xc5, 0xd6, 0x40, 0x8c, 0x46, 0x6d, 0x1c,
0xc1, 0xb2, 0x92, 0x12, 0x9a, 0x45, 0x90, 0x7c, 0x79, 0x99, 0x97, 0x08, 0xf9, 0xec, 0x9c, 0x90,
0x37, 0x7e, 0x9a, 0x87, 0xa2, 0xba, 0xd4, 0x2d, 0xed, 0x22, 0xb2, 0x72, 0xf2, 0x22, 0xb2, 0x66,
0xe2, 0xd2, 0x1a, 0x7c, 0xf5, 0x72, 0xbf, 0x7f, 0x67, 0x76, 0xcb, 0xd6, 0x62, 0x15, 0x89, 0x6d,
0x7b, 0x0d, 0xf2, 0x13, 0x3b, 0x3c, 0x43, 0xbf, 0x24, 0x31, 0x0f, 0x3e, 0xab, 0x18, 0x46, 0x21,
0x19, 0xc3, 0x48, 0xbb, 0xb4, 0x8d, 0x54, 0xd2, 0xb9, 0x4b, 0xdb, 0x6e, 0x01, 0xe9, 0x17, 0x5a,
0x8a, 0x5a, 0x09, 0x01, 0x62, 0x2f, 0x4a, 0xaa, 0x23, 0xa5, 0x59, 0x75, 0xe4, 0x95, 0x55, 0x85,
0x6f, 0xc1, 0x02, 0x5d, 0x78, 0x20, 0xcf, 0x4a, 0xaa, 0x0d, 0x45, 0xce, 0xa1, 0xfa, 0x4f, 0xc9,
0xeb, 0xa6, 0xa4, 0xd5, 0x6f, 0x40, 0xaa, 0x24, 0x6e, 0x40, 0xd2, 0x63, 0x2b, 0xd5, 0x64, 0x6c,
0xe5, 0x1e, 0x34, 0xa2, 0x09, 0x45, 0x4f, 0xa5, 0x1b, 0xc8, 0x93, 0x58, 0x75, 0x05, 0x17, 0x52,
0xb2, 0x1b, 0xc4, 0x1b, 0x62, 0x3d, 0xb1, 0x21, 0x0a, 0x19, 0xd6, 0x0a, 0x43, 0x3e, 0x9e, 0x84,
0x72, 0x43, 0xc4, 0xb3, 0x1a, 0x7a, 0x07, 0x93, 0xa7, 0x88, 0x6b, 0x50, 0xee, 0x74, 0xad, 0x9d,
0xbd, 0xce, 0xd3, 0xdd, 0x7e, 0x23, 0x23, 0x1e, 0x7b, 0x47, 0x5b, 0x5b, 0xed, 0xf6, 0x36, 0xee,
0x38, 0x00, 0x0b, 0x3b, 0xad, 0x8e, 0xd8, 0x7d, 0x72, 0xc6, 0xef, 0x65, 0xa1, 0xa2, 0x55, 0xcf,
0x9e, 0x44, 0xb3, 0x42, 0x97, 0xe4, 0xdc, 0x9e, 0xef, 0xc2, 0x03, 0x25, 0x8a, 0xb5, 0x69, 0x89,
0xae, 0xa8, 0xcb, 0x5e, 0x7b, 0x45, 0x1d, 0x7b, 0x1b, 0x16, 0x6d, 0xaa, 0x21, 0x9a, 0x05, 0xe9,
0x85, 0x97, 0x60, 0x39, 0x09, 0x98, 0x98, 0x19, 0xef, 0x27, 0x82, 0x2e, 0xaf, 0x72, 0x21, 0xa3,
0x2d, 0x05, 0x27, 0xab, 0x78, 0x62, 0x3b, 0xa3, 0xa9, 0xcf, 0x65, 0xd4, 0x3c, 0xda, 0x99, 0x09,
0x6a, 0x2a, 0xb4, 0xf1, 0x01, 0x40, 0xdc, 0xe7, 0xe4, 0xe4, 0xdc, 0x48, 0x4e, 0x4e, 0x46, 0x9b,
0x9c, 0xac, 0xb1, 0x4d, 0x62, 0x44, 0x4e, 0x74, 0xe4, 0x76, 0xfb, 0x06, 0x28, 0x47, 0xa0, 0x85,
0xe9, 0xd1, 0x93, 0x11, 0x0f, 0xd5, 0x79, 0xeb, 0x25, 0x89, 0xe9, 0x44, 0x08, 0x75, 0xfd, 0x41,
0x5c, 0x4b, 0x2c, 0x8d, 0x24, 0x4b, 0xce, 0x4a, 0x23, 0x49, 0x6a, 0x46, 0x78, 0x63, 0x03, 0x9a,
0xdb, 0x5c, 0xd4, 0xd6, 0x1a, 0x8d, 0x66, 0xba, 0x63, 0xdc, 0x82, 0x9b, 0x29, 0x38, 0xe9, 0x84,
0xf8, 0x18, 0x56, 0x5b, 0x74, 0xb4, 0xfa, 0xab, 0x3a, 0x43, 0x65, 0x34, 0x61, 0x6d, 0xb6, 0x4a,
0xd9, 0xd8, 0x0e, 0x2c, 0x6d, 0xf3, 0xe3, 0xe9, 0xe9, 0x1e, 0x3f, 0x8f, 0x1b, 0x62, 0x90, 0x0f,
0xce, 0xbc, 0x0b, 0x39, 0x3f, 0xf8, 0x1b, 0xb3, 0x0c, 0x05, 0x8d, 0x15, 0x4c, 0xf8, 0x40, 0x39,
0xa2, 0x11, 0xd2, 0x9b, 0xf0, 0x81, 0xf1, 0x04, 0x98, 0x5e, 0x8f, 0x9c, 0x2f, 0x61, 0x25, 0x4c,
0x8f, 0xad, 0xe0, 0x2a, 0x08, 0xf9, 0x58, 0xdd, 0xc1, 0x04, 0xc1, 0xf4, 0xb8, 0x47, 0x10, 0xe3,
0x1d, 0xa8, 0x1e, 0xda, 0x57, 0x26, 0xff, 0x5c, 0x9e, 0x0e, 0x5a, 0x87, 0xe2, 0xc4, 0xbe, 0x12,
0x62, 0x20, 0x8a, 0x49, 0x21, 0xda, 0xf8, 0xe3, 0x3c, 0x2c, 0x10, 0x25, 0xbb, 0x4b, 0xd7, 0xa4,
0x3a, 0x2e, 0x2e, 0x43, 0x25, 0x28, 0x35, 0xd0, 0x9c, 0x2c, 0xcd, 0xce, 0xcb, 0x52, 0xe9, 0x40,
0x53, 0xd7, 0xc3, 0xa8, 0xe8, 0x81, 0x3b, 0x1d, 0xab, 0x3b, 0x61, 0x92, 0xe7, 0x8b, 0xf3, 0xf1,
0x35, 0xb8, 0x74, 0xf8, 0x32, 0x19, 0xdf, 0x8d, 0x6d, 0x11, 0xea, 0x9d, 0xda, 0x22, 0xa4, 0xb8,
0xd4, 0x41, 0xa9, 0x06, 0x4f, 0x51, 0x9d, 0x3b, 0x4b, 0x1a, 0x3c, 0x73, 0x86, 0x4d, 0xe9, 0xe5,
0x86, 0x0d, 0x79, 0xd6, 0x5e, 0x60, 0xd8, 0xc0, 0x2b, 0x18, 0x36, 0xaf, 0x10, 0x5b, 0xbd, 0x09,
0x25, 0xdc, 0xf7, 0x35, 0xe9, 0x29, 0xf6, 0x7b, 0x21, 0x3d, 0xbf, 0xad, 0xa9, 0xfe, 0x94, 0xd8,
0x71, 0x2b, 0x5e, 0x26, 0x26, 0xff, 0xfc, 0x97, 0x13, 0xb3, 0xfa, 0x0c, 0x8a, 0x12, 0x2a, 0x18,
0xda, 0xb5, 0xc7, 0xea, 0x86, 0x2d, 0xfc, 0x2d, 0xa6, 0x0d, 0xaf, 0x05, 0xfa, 0x7c, 0xea, 0xf8,
0x7c, 0xa8, 0xae, 0x4e, 0x71, 0x70, 0x8d, 0x0a, 0x88, 0x18, 0xa0, 0x30, 0x43, 0x5c, 0xef, 0xc2,
0x95, 0x17, 0x27, 0x14, 0x9d, 0xe0, 0x99, 0x78, 0x34, 0x18, 0x34, 0xf0, 0x8e, 0xbd, 0x89, 0xe7,
0xab, 0xcd, 0xc9, 0xf8, 0x69, 0x06, 0x1a, 0x72, 0x75, 0x45, 0x38, 0xdd, 0x0a, 0x28, 0x5c, 0x97,
0x87, 0xf0, 0xe2, 0x8b, 0x50, 0x0c, 0xa8, 0xa1, 0xf3, 0x23, 0xda, 0xa9, 0xc8, 0x79, 0x53, 0x11,
0xc0, 0x1d, 0xb9, 0x5b, 0xbd, 0x0e, 0x15, 0x95, 0x03, 0x3d, 0x76, 0x46, 0xea, 0xc6, 0x6b, 0x4a,
0x82, 0xde, 0x77, 0x46, 0x6a, 0xa3, 0xf3, 0x6d, 0x79, 0x0e, 0x32, 0x83, 0x1b, 0x9d, 0x69, 0x87,
0xdc, 0xf8, 0xb7, 0x19, 0x58, 0xd2, 0x86, 0x22, 0xd7, 0xed, 0x87, 0x50, 0x8d, 0x2e, 0xb7, 0xe4,
0x91, 0xe6, 0xb5, 0x9e, 0x14, 0x34, 0x71, 0xb1, 0xca, 0x20, 0x82, 0x04, 0xa2, 0x33, 0x43, 0xfb,
0x8a, 0x12, 0x75, 0xa7, 0x63, 0x65, 0xdc, 0x0c, 0xed, 0xab, 0x1d, 0xce, 0x7b, 0xd3, 0xb1, 0x30,
0x5d, 0x2f, 0x38, 0x7f, 0x1e, 0x11, 0x90, 0xce, 0x05, 0x02, 0x26, 0x29, 0x0c, 0xa8, 0x8d, 0x3d,
0x37, 0x3c, 0x8b, 0x48, 0xa4, 0xd6, 0x89, 0x40, 0xa2, 0x31, 0xfe, 0x22, 0x0b, 0xcb, 0xe4, 0x62,
0x93, 0xae, 0x4d, 0x29, 0xba, 0x9a, 0xb0, 0x40, 0xde, 0x46, 0x12, 0x5e, 0xbb, 0x37, 0x4c, 0xf9,
0xcc, 0xbe, 0xf5, 0x8a, 0x6e, 0x41, 0x75, 0xd4, 0xf2, 0x9a, 0xe9, 0xcf, 0xcd, 0x4f, 0xff, 0xf5,
0xd3, 0x9b, 0x16, 0xe8, 0x2c, 0xa4, 0x05, 0x3a, 0x5f, 0x25, 0xbc, 0x38, 0x77, 0x1e, 0xb1, 0x28,
0x69, 0xb4, 0xf3, 0x88, 0x4f, 0x60, 0x3d, 0x41, 0x83, 0xd2, 0xda, 0x39, 0x71, 0xb8, 0xba, 0x97,
0x62, 0x45, 0xa3, 0xee, 0x29, 0xdc, 0x66, 0x11, 0x0a, 0xc1, 0xc0, 0x9b, 0x70, 0x63, 0x0d, 0x56,
0x92, 0xb3, 0x2a, 0xb7, 0x89, 0xdf, 0xcf, 0x40, 0x53, 0xa6, 0xa5, 0x38, 0xee, 0xe9, 0xae, 0x13,
0x84, 0x9e, 0x1f, 0x5d, 0x02, 0x79, 0x1b, 0x20, 0x08, 0x6d, 0x5f, 0x5a, 0x9b, 0xf2, 0x26, 0x06,
0x84, 0xa0, 0x25, 0x79, 0x13, 0x4a, 0xdc, 0x1d, 0x12, 0x92, 0xb8, 0xa1, 0xc8, 0xdd, 0xa1, 0xb2,
0x43, 0xe7, 0xf4, 0xef, 0x5a, 0xd2, 0xbc, 0x90, 0x07, 0xa3, 0xc5, 0xec, 0xf0, 0x73, 0xdc, 0x78,
0xf3, 0xd1, 0xc1, 0xe8, 0x7d, 0xfb, 0x12, 0x93, 0x3c, 0x03, 0xe3, 0x1f, 0x65, 0x61, 0x31, 0xee,
0x1f, 0xdd, 0xaa, 0xf0, 0xe2, 0xfb, 0x21, 0xee, 0x4a, 0x76, 0x70, 0x84, 0xfe, 0xae, 0x39, 0x1e,
0x4b, 0xb4, 0x38, 0x3b, 0x2e, 0x33, 0xa0, 0xa2, 0x28, 0xbc, 0x69, 0xa8, 0xdd, 0xc5, 0x56, 0x26,
0x92, 0x83, 0x69, 0x28, 0x0c, 0x2e, 0x61, 0x79, 0x3a, 0xae, 0x34, 0x79, 0x0a, 0xf6, 0x38, 0xec,
0xe0, 0x15, 0xef, 0x02, 0x2c, 0x8a, 0xd1, 0x8b, 0x14, 0x54, 0x82, 0xbe, 0x41, 0x7a, 0x36, 0xbd,
0x39, 0xd4, 0xb1, 0x75, 0x25, 0x94, 0x6e, 0xbb, 0x8d, 0x94, 0xd0, 0xd7, 0xa1, 0x42, 0x95, 0xc7,
0xc7, 0x4f, 0xf3, 0x66, 0x19, 0x5b, 0x40, 0xbc, 0x74, 0x02, 0x79, 0xd3, 0x84, 0xe9, 0x0b, 0xd4,
0x14, 0x66, 0x7d, 0xfc, 0xbd, 0x0c, 0xdc, 0x4c, 0x79, 0x6d, 0x72, 0x95, 0x6f, 0xc1, 0xd2, 0x49,
0x84, 0x54, 0xb3, 0x4b, 0x4b, 0x7d, 0x4d, 0x89, 0xd5, 0xe4, 0x9c, 0x9a, 0x8d, 0x93, 0x24, 0x20,
0x36, 0xba, 0xe8, 0x0d, 0x26, 0x4e, 0x18, 0xa3, 0xd1, 0x45, 0xaf, 0x91, 0xec, 0x9d, 0x43, 0xd8,
0x68, 0x5f, 0x0a, 0x89, 0xb1, 0xa5, 0x7f, 0xa3, 0x40, 0xb1, 0x51, 0xd2, 0xc1, 0x9c, 0x79, 0x25,
0x07, 0xf3, 0x90, 0x0e, 0x52, 0x46, 0x75, 0xfd, 0x3c, 0x95, 0xe0, 0x06, 0x2a, 0xca, 0xd0, 0x37,
0x16, 0xd4, 0x29, 0xe7, 0x41, 0xf4, 0x6d, 0x05, 0x23, 0x80, 0xc5, 0xfd, 0xe9, 0x28, 0x74, 0xe2,
0xcf, 0x2d, 0xb0, 0x6f, 0xc9, 0x32, 0xd8, 0x8e, 0x9a, 0xb5, 0xd4, 0x86, 0x20, 0x6a, 0x08, 0x27,
0x6b, 0x2c, 0x2a, 0xb2, 0xe6, 0xdb, 0x5b, 0x1c, 0x27, 0x5b, 0x30, 0x6e, 0xc2, 0x7a, 0xfc, 0x44,
0xd3, 0xa6, 0xb6, 0x9a, 0x7f, 0x9e, 0xa1, 0x8c, 0xf2, 0xe4, 0xa7, 0x1f, 0x58, 0x1b, 0x96, 0x03,
0xc7, 0x3d, 0x1d, 0x71, 0xbd, 0xfa, 0x40, 0x4e, 0xc2, 0x6a, 0xb2, 0x6f, 0xf2, 0xf3, 0x10, 0xe6,
0x12, 0x95, 0x88, 0x6b, 0x0b, 0xd8, 0xe6, 0x75, 0x9d, 0x8c, 0xd9, 0x62, 0x66, 0x36, 0xe6, 0x3b,
0xdf, 0x81, 0x7a, 0xb2, 0x21, 0xf6, 0x6d, 0x79, 0x88, 0x38, 0xee, 0x55, 0x6e, 0xe6, 0xb8, 0x67,
0xcc, 0x10, 0x95, 0x78, 0xee, 0x03, 0xe3, 0x1f, 0x64, 0xa0, 0x69, 0x72, 0xc1, 0xb9, 0x5a, 0x2f,
0x15, 0xcf, 0x7c, 0x38, 0x57, 0xeb, 0xf5, 0x63, 0x55, 0x67, 0x93, 0x55, 0x8f, 0xbe, 0x7e, 0xed,
0xcb, 0xd8, 0xbd, 0x31, 0x37, 0xa2, 0xcd, 0x12, 0x2c, 0x10, 0x89, 0xb1, 0x0e, 0xab, 0xb2, 0x3f,
0xaa, 0x2f, 0x71, 0xf4, 0x30, 0xd1, 0x62, 0x22, 0x7a, 0xb8, 0x01, 0x4d, 0xba, 0xcb, 0x53, 0x1f,
0x84, 0x2c, 0xb8, 0x0d, 0x6c, 0xdf, 0x1e, 0xd8, 0xbe, 0xe7, 0xb9, 0x87, 0xdc, 0x97, 0xf9, 0xb9,
0xa8, 0x61, 0x62, 0x70, 0x4d, 0xa9, 0xc2, 0xf4, 0xa4, 0x6e, 0xa0, 0xf4, 0x5c, 0x95, 0x8e, 0x44,
0x4f, 0x86, 0x09, 0xcb, 0x9b, 0xf6, 0x73, 0xae, 0x6a, 0x52, 0x53, 0xf4, 0x11, 0x54, 0x26, 0x51,
0xa5, 0x6a, 0xde, 0xd5, 0x4d, 0x03, 0xf3, 0xcd, 0x9a, 0x3a, 0xb5, 0xf1, 0x18, 0x56, 0x92, 0x75,
0x4a, 0xd1, 0xb1, 0x01, 0xa5, 0xb1, 0x84, 0xc9, 0xde, 0x45, 0xcf, 0xc6, 0xef, 0x96, 0xa0, 0x28,
0xed, 0x39, 0xf6, 0x00, 0xf2, 0x03, 0x95, 0x12, 0x16, 0x5f, 0x60, 0x23, 0xb1, 0xea, 0xff, 0x16,
0x26, 0x86, 0x09, 0x3a, 0xf6, 0x11, 0xd4, 0x93, 0x51, 0xd1, 0x99, 0x63, 0xcc, 0xc9, 0x70, 0x66,
0x6d, 0x30, 0x13, 0xff, 0x2a, 0xc7, 0x9b, 0x23, 0xe9, 0x0c, 0xa5, 0x33, 0x6d, 0xf7, 0xf4, 0x5c,
0xa1, 0x6f, 0x07, 0x67, 0xb6, 0xf5, 0xf8, 0xc9, 0x07, 0xf2, 0x1c, 0x73, 0x05, 0x81, 0xbd, 0x33,
0xfb, 0xf1, 0x93, 0x0f, 0x66, 0x35, 0x69, 0x79, 0x8a, 0x59, 0xd3, 0xa4, 0x57, 0xa0, 0x40, 0x57,
0x2d, 0x52, 0x6e, 0x0f, 0x3d, 0xb0, 0x47, 0xb0, 0x22, 0xcd, 0x56, 0x4b, 0x66, 0x61, 0x93, 0x14,
0x2c, 0xd1, 0xc1, 0x37, 0x89, 0xeb, 0x21, 0x8a, 0x7c, 0x43, 0x6b, 0xb0, 0x70, 0x16, 0xdf, 0x9b,
0x59, 0x33, 0xe5, 0x93, 0xf1, 0x17, 0x05, 0xa8, 0x68, 0x93, 0xc2, 0xaa, 0x50, 0x32, 0xdb, 0xbd,
0xb6, 0xf9, 0x49, 0x7b, 0xbb, 0x71, 0x83, 0xdd, 0x83, 0xb7, 0x3a, 0xdd, 0xad, 0x03, 0xd3, 0x6c,
0x6f, 0xf5, 0xad, 0x03, 0xd3, 0x52, 0xd7, 0x28, 0x1d, 0xb6, 0x3e, 0xdb, 0x6f, 0x77, 0xfb, 0xd6,
0x76, 0xbb, 0xdf, 0xea, 0xec, 0xf5, 0x1a, 0x19, 0xf6, 0x1a, 0x34, 0x63, 0x4a, 0x85, 0x6e, 0xed,
0x1f, 0x1c, 0x75, 0xfb, 0x8d, 0x2c, 0xbb, 0x03, 0xb7, 0x76, 0x3a, 0xdd, 0xd6, 0x9e, 0x15, 0xd3,
0x6c, 0xed, 0xf5, 0x3f, 0xb1, 0xda, 0xbf, 0x76, 0xd8, 0x31, 0x3f, 0x6b, 0xe4, 0xd2, 0x08, 0x84,
0x31, 0xae, 0x6a, 0xc8, 0xb3, 0x9b, 0xb0, 0x4a, 0x04, 0x54, 0xc4, 0xea, 0x1f, 0x1c, 0x58, 0xbd,
0x83, 0x83, 0x6e, 0xa3, 0xc0, 0x96, 0xa0, 0xd6, 0xe9, 0x7e, 0xd2, 0xda, 0xeb, 0x6c, 0x5b, 0x66,
0xbb, 0xb5, 0xb7, 0xdf, 0x58, 0x60, 0xcb, 0xb0, 0x38, 0x4b, 0x57, 0x14, 0x55, 0x28, 0xba, 0x83,
0x6e, 0xe7, 0xa0, 0x6b, 0x7d, 0xd2, 0x36, 0x7b, 0x9d, 0x83, 0x6e, 0xa3, 0xc4, 0xd6, 0x80, 0x25,
0x51, 0xbb, 0xfb, 0xad, 0xad, 0x46, 0x99, 0xad, 0xc2, 0x52, 0x12, 0xfe, 0xac, 0xfd, 0x59, 0x03,
0x58, 0x13, 0x56, 0xa8, 0x63, 0xd6, 0x66, 0x7b, 0xef, 0xe0, 0x53, 0x6b, 0xbf, 0xd3, 0xed, 0xec,
0x1f, 0xed, 0x37, 0x2a, 0x78, 0xb1, 0x5b, 0xbb, 0x6d, 0x75, 0xba, 0xbd, 0xa3, 0x9d, 0x9d, 0xce,
0x56, 0xa7, 0xdd, 0xed, 0x37, 0xaa, 0xd4, 0x72, 0xda, 0xc0, 0x6b, 0xa2, 0x80, 0x3c, 0xaa, 0x61,
0x6d, 0x77, 0x7a, 0xad, 0xcd, 0xbd, 0xf6, 0x76, 0xa3, 0xce, 0x6e, 0xc3, 0xcd, 0x7e, 0x7b, 0xff,
0xf0, 0xc0, 0x6c, 0x99, 0x9f, 0xa9, 0xa3, 0x1c, 0xd6, 0x4e, 0xab, 0xb3, 0x77, 0x64, 0xb6, 0x1b,
0x8b, 0xec, 0x0d, 0xb8, 0x6d, 0xb6, 0x3f, 0x3e, 0xea, 0x98, 0xed, 0x6d, 0xab, 0x7b, 0xb0, 0xdd,
0xb6, 0x76, 0xda, 0xad, 0xfe, 0x91, 0xd9, 0xb6, 0xf6, 0x3b, 0xbd, 0x5e, 0xa7, 0xfb, 0xb4, 0xd1,
0x60, 0x6f, 0xc1, 0xdd, 0x88, 0x24, 0xaa, 0x60, 0x86, 0x6a, 0x49, 0x8c, 0x4f, 0xbd, 0xd2, 0x6e,
0xfb, 0xd7, 0xfa, 0xd6, 0x61, 0xbb, 0x6d, 0x36, 0x18, 0xdb, 0x80, 0xb5, 0xb8, 0x79, 0x6a, 0x40,
0xb6, 0xbd, 0x2c, 0x70, 0x87, 0x6d, 0x73, 0xbf, 0xd5, 0x15, 0x2f, 0x38, 0x81, 0x5b, 0x11, 0xdd,
0x8e, 0x71, 0xb3, 0xdd, 0x5e, 0x65, 0x0c, 0xea, 0xda, 0x5b, 0xd9, 0x69, 0x99, 0x8d, 0x35, 0xb6,
0x08, 0x95, 0xfd, 0xc3, 0x43, 0xab, 0xdf, 0xd9, 0x6f, 0x1f, 0x1c, 0xf5, 0x1b, 0xeb, 0x6c, 0x15,
0x1a, 0x9d, 0x6e, 0xbf, 0x6d, 0x8a, 0x77, 0xad, 0x8a, 0xfe, 0xaf, 0x22, 0x5b, 0x81, 0x45, 0xd5,
0x53, 0x05, 0xfd, 0x59, 0x91, 0xad, 0x03, 0x3b, 0xea, 0x9a, 0xed, 0xd6, 0xb6, 0x98, 0xb8, 0x08,
0xf1, 0xbf, 0x8b, 0x32, 0x42, 0xf2, 0xd3, 0x5c, 0xb4, 0x59, 0xc7, 0x29, 0x07, 0xc9, 0x5b, 0x94,
0xab, 0xda, 0xed, 0xc7, 0x2f, 0xfb, 0xbe, 0x81, 0x66, 0x5a, 0xe5, 0xe6, 0x4c, 0xab, 0x39, 0xdb,
0xbd, 0xa6, 0xeb, 0x7e, 0x6f, 0x42, 0x6d, 0x4c, 0x37, 0x2a, 0xcb, 0x9b, 0x53, 0x41, 0xe6, 0xdf,
0x10, 0x90, 0xae, 0x4d, 0x9d, 0xbb, 0xe0, 0xbf, 0x30, 0x7f, 0xc1, 0x7f, 0x9a, 0x7e, 0xbf, 0x90,
0xa6, 0xdf, 0xdf, 0x87, 0x25, 0x12, 0x4d, 0x8e, 0xeb, 0x8c, 0x95, 0xd5, 0x4c, 0x5a, 0xe0, 0x22,
0x8a, 0x28, 0x82, 0x2b, 0x73, 0x42, 0x99, 0x1c, 0x52, 0x84, 0x14, 0xa5, 0xb5, 0x91, 0xb0, 0x34,
0x48, 0x72, 0x44, 0x96, 0x46, 0xd4, 0x82, 0x7d, 0x19, 0xb7, 0x50, 0xd1, 0x5a, 0x20, 0x38, 0xb6,
0x70, 0x1f, 0x96, 0xf8, 0x65, 0xe8, 0xdb, 0x96, 0x37, 0xb1, 0x3f, 0x9f, 0x62, 0x08, 0xd7, 0x46,
0x1b, 0xbe, 0x6a, 0x2e, 0x22, 0xe2, 0x00, 0xe1, 0xdb, 0x76, 0x68, 0xdf, 0xff, 0x02, 0x2a, 0xda,
0x6d, 0xdb, 0x6c, 0x1d, 0x96, 0x3f, 0xed, 0xf4, 0xbb, 0xed, 0x5e, 0xcf, 0x3a, 0x3c, 0xda, 0x7c,
0xd6, 0xfe, 0xcc, 0xda, 0x6d, 0xf5, 0x76, 0x1b, 0x37, 0xc4, 0xa2, 0xed, 0xb6, 0x7b, 0xfd, 0xf6,
0x76, 0x02, 0x9e, 0x61, 0xaf, 0xc3, 0xc6, 0x51, 0xf7, 0xa8, 0xd7, 0xde, 0xb6, 0xd2, 0xca, 0x65,
0x05, 0x97, 0x4a, 0x7c, 0x4a, 0xf1, 0xdc, 0xfd, 0xef, 0x43, 0x3d, 0x79, 0x05, 0x2c, 0x03, 0x58,
0xd8, 0x6b, 0x3f, 0x6d, 0x6d, 0x7d, 0x46, 0x57, 0x3f, 0xf6, 0xfa, 0xad, 0x7e, 0x67, 0xcb, 0x92,
0x57, 0x3d, 0x0a, 0x89, 0x90, 0x61, 0x15, 0x28, 0xb6, 0xba, 0x5b, 0xbb, 0x07, 0x66, 0xaf, 0x91,
0xbd, 0xff, 0x5d, 0xa8, 0x27, 0xb3, 0xeb, 0x92, 0x7e, 0xd7, 0x0d, 0x58, 0xdb, 0x6c, 0xf7, 0x3f,
0x6d, 0xb7, 0xbb, 0xd8, 0xb9, 0xad, 0x76, 0xb7, 0x6f, 0xb6, 0xf6, 0x3a, 0xfd, 0xcf, 0x1a, 0x99,
0xfb, 0x1f, 0x41, 0x63, 0x36, 0x94, 0x95, 0x88, 0xfd, 0xbd, 0x28, 0x48, 0x78, 0xff, 0x5f, 0xe5,
0x00, 0xe2, 0x23, 0x1e, 0x42, 0x4a, 0x6d, 0xb7, 0xfa, 0xad, 0xbd, 0x03, 0x31, 0x03, 0xe6, 0x41,
0x5f, 0x08, 0x1f, 0xb3, 0xfd, 0x71, 0xe3, 0x46, 0x2a, 0xe6, 0xe0, 0xb0, 0xdf, 0xc8, 0x88, 0xc9,
0xee, 0x74, 0x3b, 0xfd, 0x4e, 0x6b, 0xcf, 0x32, 0x0f, 0x8e, 0x3a, 0xdd, 0xa7, 0x74, 0x1d, 0x1e,
0x0a, 0xe8, 0xa3, 0xc3, 0x1d, 0xf3, 0xa0, 0xdb, 0xb7, 0x7a, 0xbb, 0x47, 0xfd, 0x6d, 0xbc, 0x4c,
0x6f, 0xcb, 0xec, 0x1c, 0x52, 0x9d, 0xf9, 0x17, 0x11, 0x88, 0xaa, 0x0b, 0xe2, 0x75, 0x3d, 0x3d,
0xe8, 0xf5, 0x3a, 0x87, 0xd6, 0xc7, 0x47, 0x6d, 0xb3, 0xd3, 0xee, 0x61, 0xc1, 0x85, 0x14, 0xb8,
0xa0, 0x2f, 0x0a, 0xb1, 0xde, 0xdf, 0xfb, 0x44, 0xca, 0x5d, 0x41, 0x5a, 0x4a, 0x82, 0x04, 0x55,
0x59, 0x4c, 0xa6, 0x10, 0x5c, 0x29, 0x35, 0xc3, 0x35, 0x38, 0x51, 0xae, 0x22, 0x44, 0xf2, 0xdc,
0x7b, 0xc4, 0x62, 0xd5, 0x74, 0x94, 0x28, 0x85, 0xd2, 0x3a, 0xda, 0xdb, 0xb6, 0xb7, 0x4d, 0x2c,
0x50, 0x9f, 0x83, 0x0a, 0xda, 0x45, 0xf1, 0xa2, 0x84, 0x64, 0x13, 0x24, 0x0d, 0xf5, 0x20, 0x30,
0x4b, 0x8f, 0x7f, 0x27, 0x07, 0x75, 0x3a, 0x6e, 0x47, 0xdf, 0x49, 0xe3, 0x3e, 0xdb, 0x87, 0xa2,
0xfc, 0xe0, 0x1e, 0x5b, 0x8d, 0x6e, 0x2a, 0xd3, 0x3f, 0xf1, 0xb7, 0xb1, 0x36, 0x0b, 0x96, 0x9a,
0xdc, 0xf2, 0xdf, 0xfc, 0xf3, 0xff, 0xf9, 0x0f, 0xb3, 0x35, 0x56, 0x79, 0x78, 0xfe, 0xfe, 0xc3,
0x53, 0xee, 0x06, 0xa2, 0x8e, 0xdf, 0x00, 0x88, 0x3f, 0x23, 0xc7, 0x9a, 0x51, 0xfc, 0x6a, 0xe6,
0x1b, 0x7b, 0x1b, 0x37, 0x53, 0x30, 0xb2, 0xde, 0x9b, 0x58, 0xef, 0xb2, 0x51, 0x17, 0xf5, 0x3a,
0xae, 0x13, 0xd2, 0x27, 0xe5, 0x3e, 0xcc, 0xdc, 0x67, 0x43, 0xa8, 0xea, 0x1f, 0x78, 0x63, 0x4a,
0xc9, 0x4a, 0xf9, 0x44, 0xdd, 0xc6, 0xad, 0x54, 0x9c, 0x52, 0x5f, 0xb1, 0x8d, 0x55, 0xa3, 0x21,
0xda, 0x98, 0x22, 0x45, 0xdc, 0xca, 0x88, 0x14, 0xfa, 0xf8, 0x3b, 0x6e, 0xec, 0x35, 0x4d, 0x25,
0x9b, 0xfb, 0x8a, 0xdc, 0xc6, 0xed, 0x6b, 0xb0, 0xb2, 0xad, 0xdb, 0xd8, 0xd6, 0xba, 0xc1, 0x44,
0x5b, 0x03, 0xa4, 0x51, 0x5f, 0x91, 0xfb, 0x30, 0x73, 0xff, 0xf1, 0x7f, 0x7c, 0x17, 0xca, 0x51,
0xfa, 0x2d, 0xfb, 0x2d, 0xa8, 0x25, 0xce, 0x43, 0x32, 0x35, 0x8c, 0xb4, 0xe3, 0x93, 0x1b, 0xaf,
0xa5, 0x23, 0x65, 0xc3, 0xaf, 0x63, 0xc3, 0x4d, 0xb6, 0x26, 0x1a, 0x96, 0xe7, 0x0d, 0x1f, 0xe2,
0xf9, 0x65, 0xba, 0xf7, 0xed, 0xb9, 0x66, 0xb8, 0x50, 0x63, 0xaf, 0xcd, 0x1a, 0x13, 0x89, 0xd6,
0x6e, 0x5f, 0x83, 0x95, 0xcd, 0xbd, 0x86, 0xcd, 0xad, 0xb1, 0x15, 0xbd, 0x39, 0x95, 0xb5, 0xc9,
0x38, 0xde, 0xb5, 0xa8, 0x7f, 0xe6, 0x8c, 0xdd, 0x8e, 0x6f, 0xc6, 0x4b, 0xf9, 0xfc, 0x59, 0xc4,
0x22, 0xf3, 0xdf, 0x40, 0x33, 0x9a, 0xd8, 0x14, 0x63, 0xf8, 0xfa, 0xf4, 0xaf, 0x9c, 0xb1, 0x63,
0xa8, 0x68, 0x5f, 0x06, 0x61, 0x37, 0xaf, 0xfd, 0x8a, 0xc9, 0xc6, 0x46, 0x1a, 0x2a, 0x6d, 0x28,
0x7a, 0xfd, 0x0f, 0x4f, 0x38, 0x67, 0xbf, 0x0e, 0xe5, 0xe8, 0x7b, 0x13, 0x6c, 0x5d, 0xfb, 0xfe,
0x87, 0xfe, 0x7d, 0x8c, 0x8d, 0xe6, 0x3c, 0x22, 0x8d, 0xf9, 0xf4, 0xda, 0x05, 0xf3, 0x7d, 0x0a,
0x15, 0xed, 0x9b, 0x12, 0xd1, 0x00, 0xe6, 0xbf, 0x5b, 0x11, 0x0d, 0x20, 0xe5, 0x13, 0x14, 0xc6,
0x12, 0x36, 0x51, 0x61, 0x65, 0xe4, 0xef, 0xf0, 0xd2, 0x0b, 0xd8, 0x1e, 0xac, 0x4a, 0x23, 0xed,
0x98, 0x7f, 0x99, 0xd7, 0x90, 0xf2, 0x65, 0xb9, 0x47, 0x19, 0xf6, 0x11, 0x94, 0xd4, 0xa7, 0x43,
0xd8, 0x5a, 0xfa, 0x27, 0x50, 0x36, 0xd6, 0xe7, 0xe0, 0xd2, 0xa2, 0xfa, 0x0c, 0x20, 0xfe, 0x80,
0x45, 0x24, 0x24, 0xe6, 0x3e, 0x88, 0x11, 0x71, 0xc0, 0xfc, 0xd7, 0x2e, 0x8c, 0x35, 0x1c, 0x60,
0x83, 0xa1, 0x90, 0x70, 0xf9, 0x85, 0xba, 0x10, 0xf7, 0x47, 0x50, 0xd1, 0xbe, 0x61, 0x11, 0x4d,
0xdf, 0xfc, 0xf7, 0x2f, 0xa2, 0xe9, 0x4b, 0xf9, 0xe4, 0x85, 0xb1, 0x81, 0xb5, 0xaf, 0x18, 0x8b,
0xa2, 0x76, 0xa1, 0xa5, 0x49, 0x6d, 0x49, 0xbc, 0xa0, 0x33, 0xa8, 0x25, 0x3e, 0x54, 0x11, 0xad,
0xd0, 0xb4, 0xcf, 0x60, 0x44, 0x2b, 0x34, 0xf5, 0xdb, 0x16, 0x8a, 0xcf, 0x8c, 0x25, 0xd1, 0xce,
0x39, 0x92, 0x68, 0x2d, 0xfd, 0x10, 0x2a, 0xda, 0x47, 0x27, 0xa2, 0xb1, 0xcc, 0x7f, 0xdf, 0x22,
0x1a, 0x4b, 0xda, 0x37, 0x2a, 0x56, 0xb0, 0x8d, 0xba, 0x81, 0xac, 0x80, 0x57, 0x7a, 0x8a, 0xba,
0x7f, 0x0b, 0xea, 0xc9, 0xef, 0x50, 0x44, 0x6b, 0x3f, 0xf5, 0x83, 0x16, 0xd1, 0xda, 0xbf, 0xe6,
0xe3, 0x15, 0x92, 0xa5, 0xef, 0x2f, 0x47, 0x8d, 0x3c, 0xfc, 0x89, 0x3c, 0x48, 0xf4, 0x05, 0xfb,
0x58, 0x08, 0x38, 0x79, 0xa3, 0x2c, 0x5b, 0xd7, 0xb8, 0x56, 0xbf, 0x9a, 0x36, 0x5a, 0x2f, 0x73,
0x97, 0xcf, 0x26, 0x99, 0x19, 0x2b, 0x67, 0x4f, 0x61, 0x39, 0x62, 0xe6, 0xe8, 0x8a, 0xd8, 0x20,
0x1a, 0x43, 0xea, 0x45, 0xb4, 0x1b, 0x8d, 0x59, 0xec, 0xa3, 0x0c, 0x6d, 0x7f, 0x78, 0x31, 0xa7,
0xb6, 0xfd, 0xe9, 0xb7, 0xc4, 0x6a, 0xdb, 0x5f, 0xe2, 0xfe, 0xce, 0xd9, 0xed, 0x2f, 0x74, 0x44,
0x1d, 0x2e, 0x2c, 0xce, 0x5e, 0xd8, 0x7a, 0xfb, 0xba, 0x8b, 0x1a, 0xa8, 0xfa, 0xd7, 0x5f, 0x7c,
0x8f, 0x43, 0x52, 0x14, 0x29, 0x69, 0xfa, 0x50, 0xe6, 0xad, 0xb0, 0xdf, 0x84, 0xaa, 0x7e, 0x77,
0x3d, 0xd3, 0x65, 0xc2, 0x6c, 0x4b, 0xb7, 0x52, 0x71, 0x49, 0x2e, 0x61, 0x55, 0xbd, 0x19, 0xf6,
0x09, 0xac, 0x45, 0xd3, 0xac, 0xdf, 0x34, 0x10, 0xb0, 0x3b, 0x29, 0xf7, 0x0f, 0x24, 0x26, 0xfb,
0xe6, 0xb5, 0x17, 0x14, 0x3c, 0xca, 0x08, 0xee, 0x4b, 0x5e, 0xa2, 0x1d, 0xef, 0x3c, 0x69, 0x77,
0x87, 0xc7, 0x3b, 0x4f, 0xea, 0xcd, 0xdb, 0x8a, 0xfb, 0xd8, 0x72, 0x62, 0x8e, 0x28, 0xa3, 0x97,
0xfd, 0x10, 0x16, 0xb5, 0x6b, 0x14, 0x7a, 0x57, 0xee, 0x20, 0x5a, 0x49, 0xf3, 0xb7, 0x40, 0x6e,
0xa4, 0xb9, 0x35, 0x8d, 0x75, 0xac, 0x7f, 0xc9, 0x48, 0x4c, 0x8e, 0x58, 0x45, 0x5b, 0x50, 0xd1,
0xaf, 0x68, 0x78, 0x41, 0xbd, 0xeb, 0x1a, 0x4a, 0xbf, 0x70, 0xf0, 0x51, 0x86, 0xed, 0x41, 0x63,
0xf6, 0xfa, 0xb3, 0x48, 0xa6, 0xa4, 0x5d, 0xd9, 0xb6, 0x31, 0x83, 0x4c, 0x5c, 0x9a, 0xc6, 0x0e,
0xe9, 0x4c, 0x48, 0xf4, 0x19, 0x36, 0xcf, 0x9f, 0xdd, 0xd5, 0x93, 0x9f, 0x67, 0x8b, 0x6a, 0x4b,
0xfb, 0x30, 0xdf, 0xbd, 0xcc, 0xa3, 0x0c, 0xfb, 0xbd, 0x0c, 0x54, 0x13, 0x17, 0x0a, 0x25, 0xb2,
0xee, 0x67, 0xc6, 0xd9, 0xd4, 0x71, 0xfa, 0x40, 0x0d, 0x13, 0x27, 0x71, 0xef, 0xfe, 0x0f, 0x12,
0x2f, 0xe9, 0x27, 0x89, 0xa8, 0xe0, 0x83, 0xd9, 0xef, 0xb4, 0x7d, 0x31, 0x4b, 0xa0, 0x5f, 0xee,
0xf9, 0xc5, 0xa3, 0x0c, 0xfb, 0x37, 0x19, 0xa8, 0x27, 0xc3, 0xfd, 0xd1, 0x70, 0x53, 0x13, 0x0b,
0x22, 0x56, 0xba, 0x26, 0x47, 0xe0, 0x87, 0xd8, 0xcb, 0xfe, 0x7d, 0x33, 0xd1, 0x4b, 0x79, 0xfd,
0xfb, 0x2f, 0xd6, 0x5b, 0xf6, 0x21, 0x7d, 0x16, 0x55, 0x65, 0x41, 0xb1, 0xf9, 0xcf, 0x68, 0x46,
0xec, 0xa7, 0x7f, 0x74, 0x12, 0x5f, 0xc2, 0x8f, 0xe8, 0x7b, 0x64, 0x2a, 0xa9, 0x46, 0x70, 0xf1,
0xab, 0x96, 0x37, 0xde, 0xc2, 0x31, 0xbd, 0x6e, 0xdc, 0x4c, 0x8c, 0x69, 0x56, 0xf1, 0x68, 0x51,
0xef, 0xe4, 0x37, 0x23, 0xe3, 0x9d, 0x73, 0xee, 0x3b, 0x92, 0xd7, 0x77, 0x72, 0x4c, 0x9d, 0x94,
0xe4, 0x89, 0xa5, 0xf6, 0x8a, 0xd5, 0x18, 0xf7, 0xb1, 0xaf, 0x6f, 0x19, 0x77, 0xae, 0xed, 0xeb,
0x43, 0x0c, 0xdd, 0x8b, 0x1e, 0x1f, 0x02, 0xc4, 0x59, 0x8a, 0x6c, 0x26, 0x57, 0x2e, 0x12, 0x40,
0xf3, 0x89, 0x8c, 0xc9, 0xf5, 0xac, 0x52, 0xea, 0x44, 0x8d, 0xbf, 0x4e, 0xe2, 0x34, 0xca, 0xe2,
0xd3, 0xb5, 0xaf, 0x64, 0x42, 0x61, 0x42, 0xfb, 0x9a, 0xad, 0x3f, 0x21, 0x4c, 0xa3, 0x94, 0xbd,
0x23, 0xa8, 0xed, 0x79, 0xde, 0xf3, 0xe9, 0x24, 0xca, 0x8c, 0x4f, 0xe6, 0xd3, 0xec, 0xda, 0xc1,
0xd9, 0xc6, 0xcc, 0x28, 0x8c, 0xbb, 0x58, 0xd5, 0x06, 0x6b, 0x6a, 0x55, 0x3d, 0xfc, 0x49, 0x9c,
0x1a, 0xf9, 0x05, 0xb3, 0x61, 0x29, 0x92, 0xd1, 0x71, 0xfa, 0x61, 0xb2, 0x9a, 0x84, 0x64, 0x9e,
0x6d, 0x22, 0x61, 0x26, 0xa8, 0xde, 0x3e, 0x0c, 0x54, 0x9d, 0x8f, 0x32, 0xec, 0x10, 0xaa, 0xdb,
0x7c, 0x80, 0x57, 0x2b, 0x60, 0x56, 0xca, 0x72, 0x22, 0xc3, 0x81, 0xd2, 0x59, 0x36, 0x6a, 0x09,
0x60, 0x72, 0xdf, 0x9a, 0xd8, 0x57, 0x3e, 0xff, 0xfc, 0xe1, 0x4f, 0x64, 0xbe, 0xcb, 0x17, 0x6a,
0xdf, 0x52, 0xf9, 0x40, 0x89, 0x7d, 0x6b, 0x26, 0x81, 0x28, 0xb1, 0x6f, 0xcd, 0x25, 0x10, 0x25,
0xa6, 0x5a, 0xe5, 0x23, 0xb1, 0x11, 0x2c, 0xcd, 0xe5, 0x1c, 0x45, 0x5b, 0xd6, 0x75, 0x99, 0x4a,
0x1b, 0x77, 0xaf, 0x27, 0x48, 0xb6, 0x76, 0x3f, 0xd9, 0x5a, 0x0f, 0x6a, 0x74, 0xdf, 0xe8, 0x31,
0xa7, 0x43, 0x96, 0x33, 0x37, 0x14, 0xe9, 0x27, 0x38, 0x67, 0x37, 0x18, 0xc4, 0x25, 0x35, 0x1c,
0x3c, 0x66, 0xc7, 0x4e, 0xf0, 0xba, 0x7a, 0xed, 0x54, 0x63, 0xc4, 0x8c, 0xf3, 0x27, 0x2d, 0x23,
0x66, 0x4c, 0x39, 0x04, 0xa9, 0xcc, 0x4f, 0xb6, 0x1a, 0xd5, 0xfd, 0xd0, 0xf5, 0x86, 0x7c, 0x2c,
0x6b, 0xfd, 0x75, 0xa8, 0x3c, 0xe5, 0xa1, 0x3a, 0x46, 0x18, 0xe9, 0xf2, 0x33, 0xe7, 0x0a, 0x37,
0x52, 0x0e, 0x7f, 0x26, 0x79, 0x93, 0x6a, 0xe6, 0xc3, 0x53, 0x4e, 0x42, 0xd0, 0x72, 0x86, 0x5f,
0xb0, 0x5f, 0xc3, 0xca, 0xa3, 0x43, 0xf3, 0x6b, 0x5a, 0x37, 0xf5, 0xca, 0x17, 0x67, 0xe0, 0x69,
0x35, 0x8b, 0x3e, 0x6b, 0x3a, 0xa5, 0x0b, 0x15, 0xed, 0x72, 0x8d, 0x68, 0x6e, 0xe6, 0x2f, 0x53,
0x89, 0xe6, 0x26, 0xe5, 0x2e, 0x0e, 0xe3, 0x1e, 0xb6, 0x63, 0xb0, 0xbb, 0x71, 0x3b, 0x74, 0xff,
0x46, 0xdc, 0xd2, 0xc3, 0x9f, 0xd8, 0xe3, 0xf0, 0x0b, 0xf6, 0x29, 0xbd, 0x0e, 0xed, 0x98, 0x64,
0x6c, 0x9c, 0xcc, 0x9e, 0xa8, 0x8c, 0x26, 0x4b, 0x43, 0x25, 0x0d, 0x16, 0x6a, 0x0a, 0x35, 0xc6,
0x27, 0x00, 0xbd, 0xd0, 0x9b, 0x6c, 0xdb, 0x7c, 0xec, 0xb9, 0xb1, 0x4c, 0x8f, 0x0f, 0xee, 0xc5,
0x72, 0x52, 0x3b, 0xbd, 0xc7, 0x3e, 0xd5, 0xac, 0xb9, 0xc4, 0x01, 0x5f, 0xc5, 0xc4, 0xd7, 0x9e,
0xed, 0x8b, 0x26, 0x24, 0xe5, 0x7c, 0xdf, 0xa3, 0x0c, 0x6b, 0x01, 0xc4, 0xc9, 0x6d, 0x91, 0x6d,
0x36, 0x97, 0x37, 0x17, 0x89, 0xd7, 0x94, 0x4c, 0xb8, 0x43, 0x28, 0xc7, 0x59, 0x41, 0xeb, 0xf1,
0x5d, 0x41, 0x89, 0x1c, 0xa2, 0x48, 0x53, 0x98, 0xcb, 0xc8, 0x31, 0x1a, 0x38, 0x55, 0xc0, 0x4a,
0x62, 0xaa, 0x4e, 0x38, 0x0f, 0x98, 0x03, 0xcb, 0xd4, 0xc1, 0x48, 0x2d, 0xc3, 0x03, 0x67, 0xd1,
0x47, 0x22, 0xe6, 0x93, 0x63, 0x22, 0xa9, 0x91, 0x9a, 0xe2, 0x91, 0x70, 0x31, 0x09, 0x6e, 0xa5,
0xc3, 0x6e, 0x62, 0x0b, 0x18, 0xc3, 0xd2, 0x5c, 0x16, 0x41, 0x24, 0x3a, 0xae, 0x4b, 0x0b, 0x89,
0x44, 0xc7, 0xb5, 0x09, 0x08, 0xc6, 0x2a, 0x36, 0xb9, 0x68, 0x00, 0x9a, 0x94, 0x17, 0x4e, 0x38,
0x38, 0x13, 0xcd, 0xfd, 0x41, 0x06, 0x96, 0x53, 0xf2, 0x04, 0xd8, 0x1b, 0xca, 0x3b, 0x71, 0x6d,
0x0e, 0xc1, 0x46, 0x6a, 0x3c, 0xd9, 0xe8, 0x61, 0x3b, 0xfb, 0xec, 0x59, 0x62, 0x03, 0xa5, 0x70,
0xae, 0x5c, 0x99, 0x2f, 0x54, 0x5e, 0x52, 0x35, 0x97, 0xcf, 0x61, 0x9d, 0x3a, 0xd2, 0x1a, 0x8d,
0x66, 0x62, 0xdd, 0xaf, 0x6b, 0xbd, 0x48, 0x89, 0xdf, 0x27, 0xec, 0x80, 0x64, 0x0c, 0xff, 0x1a,
0xb5, 0x9d, 0xba, 0xca, 0xa6, 0xd0, 0x98, 0x8d, 0x21, 0xb3, 0xeb, 0xeb, 0xda, 0xb8, 0x93, 0xb0,
0xb3, 0x53, 0xe2, 0xce, 0x5f, 0xc3, 0xc6, 0xee, 0x18, 0x1b, 0x69, 0xf3, 0x42, 0xa6, 0xb7, 0x78,
0x1f, 0x7f, 0x23, 0x0a, 0x78, 0xcf, 0x8c, 0x53, 0x35, 0x70, 0x5d, 0x78, 0x3e, 0xb2, 0xf4, 0xd3,
0xe3, 0xe5, 0x6f, 0x63, 0xf3, 0x77, 0x8d, 0x5b, 0x69, 0xcd, 0xfb, 0x54, 0x84, 0x6c, 0xfe, 0xf5,
0xd9, 0x75, 0xad, 0x7a, 0x70, 0x37, 0xed, 0x7d, 0x5f, 0x6b, 0x73, 0xcd, 0xcc, 0xf5, 0x0d, 0xd4,
0x21, 0xab, 0x7a, 0x80, 0x3b, 0x5a, 0x3e, 0x29, 0x91, 0xf4, 0x68, 0xf9, 0xa4, 0x45, 0xc4, 0x93,
0xfa, 0x93, 0x8a, 0x85, 0x7f, 0x98, 0xb9, 0xbf, 0xf9, 0xce, 0x0f, 0xbf, 0x76, 0xea, 0x84, 0x67,
0xd3, 0xe3, 0x07, 0x03, 0x6f, 0xfc, 0x70, 0xa4, 0xbc, 0x9a, 0xf2, 0x54, 0xf6, 0xc3, 0x91, 0x3b,
0x7c, 0x88, 0xd5, 0x1e, 0x2f, 0x4c, 0x7c, 0x2f, 0xf4, 0xbe, 0xf9, 0x7f, 0x03, 0x00, 0x00, 0xff,
0xff, 0x25, 0xc9, 0xbe, 0xb5, 0x81, 0x86, 0x00, 0x00,
// 11837 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7d, 0x5d, 0x6f, 0x24, 0x49,
0x72, 0xd8, 0xf4, 0x17, 0xbb, 0x3b, 0xfa, 0x83, 0xcd, 0xe4, 0x57, 0x0f, 0x67, 0x67, 0x67, 0xb6,
0x6e, 0x6f, 0x77, 0x76, 0xf6, 0x8e, 0x33, 0x3b, 0x77, 0xbb, 0x77, 0xb7, 0x6b, 0x9d, 0xae, 0x49,
0x36, 0x87, 0x7d, 0x43, 0x36, 0xb9, 0xd5, 0xcd, 0x5d, 0xed, 0xe9, 0xa3, 0xae, 0xd8, 0x9d, 0x24,
0x4b, 0xd3, 0x5d, 0xd5, 0x5b, 0x55, 0xcd, 0x8f, 0x3b, 0xac, 0x1f, 0x0c, 0x5b, 0x30, 0x0c, 0xdb,
0x80, 0x60, 0xcb, 0x80, 0x65, 0x0b, 0x36, 0x2c, 0x18, 0x86, 0x21, 0x40, 0x10, 0x70, 0xf2, 0x83,
0x01, 0xbf, 0x0b, 0x06, 0x6c, 0x08, 0x86, 0xe4, 0x17, 0x43, 0x10, 0x60, 0xd8, 0x96, 0xdf, 0x0c,
0x01, 0xfe, 0x03, 0x46, 0x46, 0x64, 0x56, 0x65, 0x75, 0x17, 0x67, 0x66, 0xef, 0xce, 0xf7, 0x42,
0x76, 0x45, 0x46, 0x7e, 0x47, 0x46, 0x46, 0x64, 0x44, 0x64, 0x42, 0xd9, 0x9f, 0x0c, 0x36, 0x27,
0xbe, 0x17, 0x7a, 0xac, 0x30, 0x72, 0xfd, 0xc9, 0x60, 0xe3, 0xb5, 0x33, 0xcf, 0x3b, 0x1b, 0xf1,
0x47, 0xf6, 0xc4, 0x79, 0x64, 0xbb, 0xae, 0x17, 0xda, 0xa1, 0xe3, 0xb9, 0x01, 0x21, 0x19, 0x3f,
0x84, 0xfa, 0x53, 0xee, 0xf6, 0x38, 0x1f, 0x9a, 0xfc, 0xf3, 0x29, 0x0f, 0x42, 0xf6, 0x2e, 0x2c,
0xd9, 0xfc, 0x47, 0x9c, 0x0f, 0xad, 0x89, 0x1d, 0x04, 0x93, 0x73, 0xdf, 0x0e, 0x78, 0x33, 0x73,
0x3f, 0xf3, 0xa0, 0x6a, 0x36, 0x28, 0xe1, 0x28, 0x82, 0xb3, 0x37, 0xa0, 0x1a, 0x08, 0x54, 0xee,
0x86, 0xbe, 0x37, 0xb9, 0x6e, 0x66, 0x11, 0xaf, 0x22, 0x60, 0x6d, 0x02, 0x19, 0x23, 0x58, 0x8c,
0x6a, 0x08, 0x26, 0x9e, 0x1b, 0x70, 0xf6, 0x18, 0x56, 0x06, 0xce, 0xe4, 0x9c, 0xfb, 0x16, 0x66,
0x1e, 0xbb, 0x7c, 0xec, 0xb9, 0xce, 0xa0, 0x99, 0xb9, 0x9f, 0x7b, 0x50, 0x36, 0x19, 0xa5, 0x89,
0x1c, 0x07, 0x32, 0x85, 0xbd, 0x0d, 0x8b, 0xdc, 0x25, 0x38, 0x1f, 0x62, 0x2e, 0x59, 0x55, 0x3d,
0x06, 0x8b, 0x0c, 0xc6, 0xdf, 0xcd, 0xc2, 0x52, 0xc7, 0x75, 0xc2, 0x4f, 0xed, 0xd1, 0x88, 0x87,
0xaa, 0x4f, 0x6f, 0xc3, 0xe2, 0x25, 0x02, 0xb0, 0x4f, 0x97, 0x9e, 0x3f, 0x94, 0x3d, 0xaa, 0x13,
0xf8, 0x48, 0x42, 0x6f, 0x6c, 0x59, 0xf6, 0xc6, 0x96, 0xa5, 0x0e, 0x57, 0xee, 0x86, 0xe1, 0x7a,
0x1b, 0x16, 0x7d, 0x3e, 0xf0, 0x2e, 0xb8, 0x7f, 0x6d, 0x5d, 0x3a, 0xee, 0xd0, 0xbb, 0x6c, 0xe6,
0xef, 0x67, 0x1e, 0x14, 0xcc, 0xba, 0x02, 0x7f, 0x8a, 0x50, 0xb6, 0x05, 0x8b, 0x83, 0x73, 0xdb,
0x75, 0xf9, 0xc8, 0x3a, 0xb1, 0x07, 0xcf, 0xa7, 0x93, 0xa0, 0x59, 0xb8, 0x9f, 0x79, 0x50, 0x79,
0x72, 0x7b, 0x13, 0x67, 0x75, 0x73, 0xfb, 0xdc, 0x76, 0xb7, 0x30, 0xa5, 0xe7, 0xda, 0x93, 0xe0,
0xdc, 0x0b, 0xcd, 0xba, 0xcc, 0x41, 0xe0, 0xc0, 0x58, 0x01, 0xa6, 0x8f, 0x04, 0x8d, 0xbd, 0xf1,
0x07, 0x19, 0x58, 0x3e, 0x76, 0x47, 0xde, 0xe0, 0xf9, 0x4f, 0x39, 0x44, 0x29, 0x7d, 0xc8, 0xbe,
0x6a, 0x1f, 0x72, 0x5f, 0xb6, 0x0f, 0x6b, 0xb0, 0x92, 0x6c, 0xac, 0xec, 0x05, 0x87, 0x55, 0x91,
0xfb, 0x8c, 0xab, 0x66, 0xa9, 0x6e, 0xbc, 0x03, 0x8d, 0xc1, 0xd4, 0xf7, 0xb9, 0x3b, 0xd7, 0x8f,
0x45, 0x09, 0x8f, 0x3a, 0xf2, 0x06, 0x54, 0x5d, 0x7e, 0x19, 0xa3, 0x49, 0xda, 0x75, 0xf9, 0xa5,
0x42, 0x31, 0x9a, 0xb0, 0x36, 0x5b, 0x8d, 0x6c, 0xc0, 0x5f, 0x65, 0x20, 0x7f, 0x1c, 0x5e, 0x79,
0xec, 0x7d, 0xa8, 0xda, 0xc3, 0xa1, 0xcf, 0x83, 0xc0, 0x0a, 0xaf, 0x27, 0xb4, 0x52, 0xea, 0x4f,
0x98, 0xec, 0x62, 0x8b, 0x92, 0xfa, 0xd7, 0x13, 0x6e, 0x56, 0xec, 0xf8, 0x83, 0x35, 0xa1, 0x28,
0x3f, 0xb1, 0xde, 0xb2, 0xa9, 0x3e, 0xd9, 0x5d, 0x00, 0x7b, 0xec, 0x4d, 0xdd, 0xd0, 0x0a, 0xec,
0x10, 0x47, 0x2c, 0x67, 0x96, 0x09, 0xd2, 0xb3, 0x43, 0x76, 0x07, 0xca, 0x93, 0xe7, 0x56, 0x30,
0xf0, 0x9d, 0x49, 0x88, 0xc4, 0x53, 0x36, 0x4b, 0x93, 0xe7, 0x3d, 0xfc, 0x66, 0xef, 0x42, 0xc9,
0x9b, 0x86, 0x13, 0xcf, 0x71, 0x43, 0x49, 0x2f, 0x8b, 0xb2, 0x21, 0x87, 0xd3, 0xf0, 0x48, 0x80,
0xcd, 0x08, 0x81, 0xbd, 0x09, 0xb5, 0x81, 0xe7, 0x9e, 0x3a, 0xfe, 0x98, 0x38, 0x42, 0x73, 0x01,
0xeb, 0x4a, 0x02, 0x8d, 0x3f, 0xca, 0x42, 0xa5, 0xef, 0xdb, 0x6e, 0x60, 0x0f, 0x04, 0x80, 0xad,
0x43, 0x31, 0xbc, 0xb2, 0xce, 0xed, 0xe0, 0x1c, 0xbb, 0x5a, 0x36, 0x17, 0xc2, 0xab, 0x3d, 0x3b,
0x38, 0x67, 0x6b, 0xb0, 0x40, 0xad, 0xc4, 0x0e, 0xe5, 0x4c, 0xf9, 0x25, 0x16, 0x88, 0x3b, 0x1d,
0x5b, 0xc9, 0xaa, 0x72, 0x48, 0x31, 0x0d, 0x77, 0x3a, 0xde, 0xd6, 0xe1, 0xa2, 0xf3, 0x27, 0x62,
0xba, 0xa9, 0x02, 0xea, 0x5e, 0x19, 0x21, 0x58, 0xc7, 0x1b, 0x50, 0x95, 0xc9, 0xdc, 0x39, 0x3b,
0xa7, 0x3e, 0x16, 0xcc, 0x0a, 0x21, 0x20, 0x48, 0x94, 0x10, 0x3a, 0x63, 0x6e, 0x05, 0xa1, 0x3d,
0x9e, 0xc8, 0x2e, 0x95, 0x05, 0xa4, 0x27, 0x00, 0x98, 0xec, 0x85, 0xf6, 0xc8, 0x3a, 0xe5, 0x3c,
0x68, 0x16, 0x65, 0xb2, 0x80, 0xec, 0x72, 0x1e, 0xb0, 0xaf, 0x42, 0x7d, 0xc8, 0x83, 0xd0, 0x92,
0x93, 0xc1, 0x83, 0x66, 0x09, 0x57, 0x7e, 0x4d, 0x40, 0x5b, 0x0a, 0xc8, 0x5e, 0x03, 0xf0, 0xed,
0x4b, 0x4b, 0x0c, 0x04, 0xbf, 0x6a, 0x96, 0x69, 0x16, 0x7c, 0xfb, 0xb2, 0x7f, 0xb5, 0xc7, 0xaf,
0x04, 0xd5, 0x3c, 0xe5, 0xa1, 0x36, 0x68, 0x81, 0xa4, 0x4e, 0x63, 0x1f, 0x98, 0x06, 0xde, 0xe1,
0xa1, 0xed, 0x8c, 0x02, 0xf6, 0x01, 0x54, 0x43, 0x0d, 0x19, 0xd9, 0x60, 0x25, 0x22, 0x21, 0x2d,
0x83, 0x99, 0xc0, 0x33, 0xce, 0xa1, 0xb4, 0xcb, 0xf9, 0xbe, 0x33, 0x76, 0x42, 0xb6, 0x06, 0x85,
0x53, 0xe7, 0x8a, 0x13, 0xb1, 0xe7, 0xf6, 0x6e, 0x99, 0xf4, 0xc9, 0xee, 0x01, 0xe0, 0x0f, 0x6b,
0x1c, 0x51, 0xd3, 0xde, 0x2d, 0xb3, 0x8c, 0xb0, 0x83, 0xc0, 0x0e, 0xd9, 0x06, 0x14, 0x27, 0xdc,
0x1f, 0x70, 0x35, 0x6f, 0x7b, 0xb7, 0x4c, 0x05, 0xd8, 0x2a, 0x42, 0x61, 0x24, 0x4a, 0x37, 0xfe,
0xa4, 0x00, 0x95, 0x1e, 0x77, 0xa3, 0x55, 0xc6, 0x20, 0x2f, 0x06, 0x44, 0xae, 0x2c, 0xfc, 0xcd,
0xbe, 0x02, 0x15, 0x1c, 0xba, 0x20, 0xf4, 0x1d, 0xf7, 0x8c, 0xa8, 0x7a, 0x2b, 0xdb, 0xcc, 0x98,
0x20, 0xc0, 0x3d, 0x84, 0xb2, 0x06, 0xe4, 0xec, 0xb1, 0xa2, 0x6a, 0xf1, 0x93, 0xdd, 0x86, 0x92,
0x3d, 0x0e, 0xa9, 0x79, 0x55, 0x04, 0x17, 0xed, 0x71, 0x88, 0x4d, 0x7b, 0x03, 0xaa, 0x13, 0xfb,
0x7a, 0x2c, 0xd6, 0x72, 0x44, 0x0e, 0x55, 0xb3, 0x22, 0x61, 0x48, 0x10, 0x4f, 0x60, 0x59, 0x47,
0x51, 0x95, 0x17, 0xa2, 0xca, 0x97, 0x34, 0x6c, 0xd9, 0x86, 0xb7, 0x61, 0x51, 0xe5, 0xf1, 0xa9,
0x3f, 0x48, 0x26, 0x65, 0xb3, 0x2e, 0xc1, 0xaa, 0x97, 0x0f, 0xa0, 0x71, 0xea, 0xb8, 0xf6, 0xc8,
0x1a, 0x8c, 0xc2, 0x0b, 0x6b, 0xc8, 0x47, 0xa1, 0x8d, 0x14, 0x53, 0x30, 0xeb, 0x08, 0xdf, 0x1e,
0x85, 0x17, 0x3b, 0x02, 0xca, 0xbe, 0x06, 0xe5, 0x53, 0xce, 0x2d, 0x1c, 0xac, 0x66, 0x29, 0xb1,
0xf0, 0xd4, 0x0c, 0x99, 0xa5, 0x53, 0x35, 0x57, 0x5f, 0x83, 0x86, 0x37, 0x0d, 0xcf, 0x3c, 0xc7,
0x3d, 0xb3, 0x04, 0xbf, 0xb3, 0x9c, 0x21, 0xd2, 0x50, 0x7e, 0x2b, 0xfb, 0x38, 0x63, 0xd6, 0x55,
0x9a, 0xe0, 0x3c, 0x9d, 0x21, 0x7b, 0x0b, 0x16, 0x47, 0x76, 0x10, 0x5a, 0xe7, 0xde, 0xc4, 0x9a,
0x4c, 0x4f, 0x9e, 0xf3, 0xeb, 0x66, 0x0d, 0x07, 0xa2, 0x26, 0xc0, 0x7b, 0xde, 0xe4, 0x08, 0x81,
0x82, 0xb2, 0xb1, 0x9d, 0xd4, 0x08, 0xb8, 0x9f, 0x79, 0x50, 0x33, 0xcb, 0x02, 0x42, 0x95, 0x7e,
0x06, 0xcb, 0x38, 0x3d, 0x83, 0x69, 0x10, 0x7a, 0x63, 0x4b, 0xf0, 0x6a, 0x7f, 0x18, 0x34, 0x2b,
0x48, 0x6b, 0xef, 0xc8, 0xc6, 0x6a, 0x73, 0xbc, 0xb9, 0xc3, 0x83, 0x70, 0x1b, 0x91, 0x4d, 0xc2,
0x15, 0x1b, 0xfa, 0xb5, 0xb9, 0x34, 0x9c, 0x85, 0xb3, 0xaf, 0x01, 0xb3, 0x47, 0x23, 0xef, 0xd2,
0x0a, 0xf8, 0xe8, 0xd4, 0x92, 0x83, 0xd8, 0xac, 0xdf, 0xcf, 0x3c, 0x28, 0x99, 0x0d, 0x4c, 0xe9,
0xf1, 0xd1, 0xe9, 0x11, 0xc1, 0xd9, 0x07, 0x80, 0x8b, 0xc9, 0x3a, 0xe5, 0x76, 0x38, 0xf5, 0x79,
0xd0, 0x5c, 0xbc, 0x9f, 0x7b, 0x50, 0x7f, 0xb2, 0x14, 0x8d, 0x17, 0x82, 0xb7, 0x9c, 0xd0, 0xac,
0x0a, 0x3c, 0xf9, 0x1d, 0x6c, 0xec, 0xc0, 0x5a, 0x7a, 0x93, 0x04, 0x51, 0x89, 0x51, 0x11, 0xc4,
0x98, 0x37, 0xc5, 0x4f, 0xb6, 0x02, 0x85, 0x0b, 0x7b, 0x34, 0xe5, 0x92, 0xa7, 0xd3, 0xc7, 0x87,
0xd9, 0x6f, 0x67, 0x8c, 0x3f, 0xce, 0x40, 0x95, 0x7a, 0x29, 0x65, 0x91, 0xaf, 0x40, 0x4d, 0x51,
0x03, 0xf7, 0x7d, 0xcf, 0x97, 0x5c, 0x4d, 0x51, 0x5e, 0x5b, 0xc0, 0xc4, 0xae, 0xa2, 0x90, 0x26,
0x3e, 0x77, 0xc6, 0xf6, 0x99, 0x2a, 0x5a, 0x91, 0xd2, 0x91, 0x04, 0xb3, 0xf7, 0xe2, 0xf2, 0x7c,
0x6f, 0x1a, 0x72, 0xb9, 0xe7, 0x55, 0x65, 0xf7, 0x4c, 0x01, 0x8b, 0x4a, 0xc7, 0xaf, 0x57, 0xa0,
0x73, 0xe3, 0x77, 0x32, 0xc0, 0x44, 0xb3, 0xfb, 0x1e, 0x15, 0x20, 0x29, 0x74, 0x36, 0x67, 0xe6,
0x95, 0x57, 0x48, 0xf6, 0x45, 0x2b, 0xc4, 0x80, 0x02, 0xb5, 0x3d, 0x9f, 0xd2, 0x76, 0x4a, 0xfa,
0x7e, 0xbe, 0x94, 0x6b, 0xe4, 0x8d, 0xff, 0x96, 0x83, 0x95, 0x6d, 0xda, 0xb2, 0x5b, 0x83, 0x01,
0x9f, 0x44, 0x6b, 0xe7, 0x1e, 0x54, 0x5c, 0x6f, 0xc8, 0x15, 0xc5, 0x52, 0xc3, 0x40, 0x80, 0x34,
0x72, 0x3d, 0xb7, 0x1d, 0x97, 0x1a, 0x4e, 0x83, 0x59, 0x46, 0x08, 0x36, 0xfb, 0x2d, 0x58, 0x9c,
0x70, 0x77, 0xa8, 0x2f, 0x11, 0x12, 0xaa, 0x6a, 0x12, 0x2c, 0x57, 0xc7, 0x3d, 0xa8, 0x9c, 0x4e,
0x09, 0x4f, 0x30, 0x96, 0x3c, 0xd2, 0x00, 0x48, 0x50, 0x8b, 0xf8, 0xcb, 0x64, 0x1a, 0x9c, 0x63,
0x6a, 0x01, 0x53, 0x8b, 0xe2, 0x5b, 0x24, 0xdd, 0x05, 0x18, 0x4e, 0x83, 0x50, 0xae, 0x98, 0x05,
0x4c, 0x2c, 0x0b, 0x08, 0xad, 0x98, 0xaf, 0xc3, 0xf2, 0xd8, 0xbe, 0xb2, 0x90, 0x76, 0x2c, 0xc7,
0xb5, 0x4e, 0x47, 0xb8, 0xe7, 0x14, 0x11, 0xaf, 0x31, 0xb6, 0xaf, 0x3e, 0x11, 0x29, 0x1d, 0x77,
0x17, 0xe1, 0x82, 0xad, 0x28, 0x71, 0xc7, 0xe7, 0x01, 0xf7, 0x2f, 0x38, 0x72, 0x82, 0x7c, 0x24,
0xd3, 0x98, 0x04, 0x15, 0x2d, 0x1a, 0x8b, 0x7e, 0x87, 0xa3, 0x01, 0x2d, 0x7b, 0xb3, 0x38, 0x76,
0xdc, 0xbd, 0x70, 0x34, 0x10, 0xfb, 0x8a, 0xe0, 0x23, 0x13, 0xee, 0x5b, 0xcf, 0x2f, 0x71, 0x0d,
0xe7, 0x91, 0x6f, 0x1c, 0x71, 0xff, 0xd9, 0xa5, 0xd8, 0xfa, 0x07, 0x01, 0x32, 0x22, 0xfb, 0xba,
0x59, 0xc1, 0x05, 0x5e, 0x1a, 0x04, 0x82, 0x05, 0xd9, 0xd7, 0x62, 0x11, 0x8a, 0xd6, 0xda, 0x38,
0x0b, 0x7c, 0x88, 0xc5, 0x07, 0xc8, 0x51, 0x6b, 0xd8, 0xd8, 0x96, 0x4c, 0x10, 0xf5, 0x04, 0x82,
0xea, 0x55, 0x63, 0x4f, 0x47, 0xf6, 0x59, 0x80, 0x2c, 0xa5, 0x66, 0x56, 0x25, 0x70, 0x57, 0xc0,
0x8c, 0x4f, 0x49, 0xc8, 0xd2, 0xe6, 0x56, 0xae, 0x19, 0xb1, 0xd5, 0x23, 0x04, 0xe7, 0xb5, 0x64,
0xca, 0xaf, 0xb4, 0x49, 0xcb, 0xa6, 0x4c, 0x9a, 0xf1, 0x7b, 0x19, 0xa8, 0xca, 0x92, 0x51, 0x28,
0x61, 0x9b, 0xc0, 0xd4, 0x2c, 0x86, 0x57, 0xce, 0xd0, 0x3a, 0xb9, 0x0e, 0x79, 0x40, 0x44, 0xb3,
0x77, 0xcb, 0x6c, 0xc8, 0xb4, 0xfe, 0x95, 0x33, 0xdc, 0x12, 0x29, 0xec, 0x21, 0x34, 0x12, 0xf8,
0x41, 0xe8, 0x13, 0x45, 0xef, 0xdd, 0x32, 0xeb, 0x1a, 0x76, 0x2f, 0xf4, 0xc5, 0x1a, 0x11, 0x22,
0xcf, 0x34, 0xb4, 0x1c, 0x77, 0xc8, 0xaf, 0x90, 0x8c, 0x6a, 0x66, 0x85, 0x60, 0x1d, 0x01, 0xda,
0xaa, 0x43, 0x55, 0x2f, 0xce, 0x38, 0x83, 0x92, 0x92, 0x97, 0x50, 0x60, 0x98, 0x69, 0x92, 0x59,
0x0e, 0xa3, 0x96, 0xdc, 0x86, 0x52, 0xb2, 0x05, 0x66, 0x31, 0x7c, 0xe5, 0x8a, 0x8d, 0xef, 0x42,
0x63, 0x5f, 0x10, 0x8f, 0x2b, 0x88, 0x55, 0xca, 0x7f, 0x6b, 0xb0, 0xa0, 0x2d, 0x9a, 0xb2, 0x29,
0xbf, 0xc4, 0x9e, 0x7b, 0xee, 0x05, 0xa1, 0xac, 0x05, 0x7f, 0x1b, 0x7f, 0x92, 0x01, 0xd6, 0x0e,
0x42, 0x67, 0x6c, 0x87, 0x7c, 0x97, 0x47, 0x6c, 0xe1, 0x10, 0xaa, 0xa2, 0xb4, 0xbe, 0xd7, 0x22,
0x81, 0x8c, 0x04, 0x8a, 0x77, 0xe5, 0x32, 0x9e, 0xcf, 0xb0, 0xa9, 0x63, 0x13, 0x9b, 0x4f, 0x14,
0x20, 0x56, 0x59, 0x68, 0xfb, 0x67, 0x3c, 0x44, 0x31, 0x4e, 0xca, 0xfb, 0x40, 0x20, 0x21, 0xc0,
0x6d, 0xfc, 0x32, 0x2c, 0xcd, 0x95, 0xa1, 0xf3, 0xe5, 0x72, 0x0a, 0x5f, 0xce, 0xe9, 0x7c, 0xd9,
0x82, 0xe5, 0x44, 0xbb, 0x24, 0xa5, 0xad, 0x43, 0x51, 0x2c, 0x08, 0x21, 0x1c, 0x64, 0x48, 0xaa,
0x3c, 0xe5, 0x5c, 0x88, 0xc1, 0x8f, 0x60, 0xe5, 0x94, 0x73, 0xdf, 0x0e, 0x31, 0x11, 0x57, 0x8c,
0x98, 0x21, 0x59, 0xf0, 0x92, 0x4c, 0xeb, 0xd9, 0xe1, 0x11, 0xf7, 0xc5, 0x4c, 0x19, 0xff, 0x23,
0x03, 0x8b, 0x82, 0x83, 0x1e, 0xd8, 0xee, 0xb5, 0x1a, 0xa7, 0xfd, 0xd4, 0x71, 0x7a, 0xa0, 0x6d,
0x86, 0x1a, 0xf6, 0x97, 0x1d, 0xa4, 0xdc, 0xec, 0x20, 0xb1, 0xfb, 0x50, 0x4d, 0xb4, 0xb5, 0x80,
0x6d, 0x85, 0x20, 0x6a, 0xe4, 0xcf, 0x3e, 0x8c, 0x6f, 0x41, 0x23, 0x6e, 0xb6, 0x1c, 0x43, 0x06,
0x79, 0x41, 0x92, 0xb2, 0x00, 0xfc, 0x6d, 0xfc, 0xf3, 0x0c, 0x21, 0x6e, 0x7b, 0x4e, 0x24, 0x9d,
0x0a, 0x44, 0x21, 0xf7, 0x2a, 0x44, 0xf1, 0xfb, 0x46, 0xa9, 0xfe, 0x67, 0xef, 0xac, 0x58, 0x3a,
0x01, 0x77, 0x87, 0x96, 0x3d, 0x1a, 0x21, 0xf3, 0x2d, 0x99, 0x45, 0xf1, 0xdd, 0x1a, 0x8d, 0x8c,
0xb7, 0x61, 0x49, 0x6b, 0xdd, 0x0b, 0xfa, 0xd1, 0x05, 0xb6, 0xef, 0x04, 0xe1, 0xb1, 0x1b, 0x4c,
0x34, 0xc1, 0xed, 0x0e, 0x94, 0x05, 0x87, 0x15, 0x2d, 0xa3, 0x25, 0x5b, 0x30, 0x05, 0xcb, 0x15,
0xed, 0x0a, 0x30, 0xd1, 0xbe, 0x92, 0x89, 0x59, 0x99, 0x68, 0x5f, 0x61, 0xa2, 0xf1, 0x6d, 0x58,
0x4e, 0x94, 0x27, 0xab, 0x7e, 0x03, 0x0a, 0xd3, 0xf0, 0xca, 0x53, 0xa2, 0x79, 0x45, 0x52, 0x88,
0x50, 0x00, 0x4d, 0x4a, 0x31, 0x3e, 0x82, 0xa5, 0x2e, 0xbf, 0x94, 0x8b, 0x58, 0x35, 0xe4, 0x2d,
0xc8, 0xbf, 0x44, 0x29, 0xc4, 0x74, 0x63, 0x13, 0x98, 0x9e, 0x59, 0xd6, 0xaa, 0xe9, 0x88, 0x99,
0x84, 0x8e, 0x68, 0xbc, 0x05, 0xac, 0xe7, 0x9c, 0xb9, 0x07, 0x3c, 0x08, 0xec, 0xb3, 0x68, 0xd9,
0x37, 0x20, 0x37, 0x0e, 0xce, 0x24, 0x8f, 0x12, 0x3f, 0x8d, 0x6f, 0xc0, 0x72, 0x02, 0x4f, 0x16,
0xfc, 0x1a, 0x94, 0x03, 0xe7, 0xcc, 0x45, 0xc1, 0x4a, 0x16, 0x1d, 0x03, 0x8c, 0x5d, 0x58, 0xf9,
0x84, 0xfb, 0xce, 0xe9, 0xf5, 0xcb, 0x8a, 0x4f, 0x96, 0x93, 0x9d, 0x2d, 0xa7, 0x0d, 0xab, 0x33,
0xe5, 0xc8, 0xea, 0x89, 0x7c, 0xe5, 0x4c, 0x96, 0x4c, 0xfa, 0xd0, 0xf8, 0x5e, 0x56, 0xe7, 0x7b,
0xc6, 0x31, 0xb0, 0x6d, 0xcf, 0x75, 0xf9, 0x20, 0x3c, 0xe2, 0xdc, 0x8f, 0x4f, 0xa9, 0x62, 0x5a,
0xad, 0x3c, 0x59, 0x97, 0x23, 0x3b, 0xcb, 0x4c, 0x25, 0x11, 0x33, 0xc8, 0x4f, 0xb8, 0x3f, 0xc6,
0x82, 0x4b, 0x26, 0xfe, 0x36, 0x56, 0x61, 0x39, 0x51, 0xac, 0xd4, 0xeb, 0x1f, 0xc3, 0xea, 0x8e,
0x13, 0x0c, 0xe6, 0x2b, 0x5c, 0x87, 0xe2, 0x64, 0x7a, 0x62, 0x25, 0xf9, 0xf2, 0x33, 0x7e, 0x2d,
0xb4, 0xbd, 0xd9, 0x1c, 0xb2, 0xac, 0xbf, 0x9d, 0x81, 0xfc, 0x5e, 0x7f, 0x7f, 0x9b, 0x6d, 0x40,
0xc9, 0x71, 0x07, 0xde, 0x58, 0x08, 0x5e, 0xd4, 0xe7, 0xe8, 0xfb, 0xc6, 0x05, 0x76, 0x07, 0xca,
0x28, 0xaf, 0x09, 0xd5, 0x56, 0x8a, 0x3e, 0x25, 0x01, 0xd8, 0xf7, 0x06, 0xcf, 0x85, 0x4e, 0xcd,
0xaf, 0x26, 0x8e, 0x8f, 0x5a, 0xb3, 0x52, 0x86, 0xf3, 0xb4, 0xd7, 0xc7, 0x09, 0xa4, 0x11, 0x1b,
0xff, 0xbe, 0x04, 0x45, 0xb9, 0xdb, 0xd2, 0xce, 0x1d, 0x3a, 0x17, 0x3c, 0xde, 0xb9, 0xc5, 0x97,
0x90, 0x07, 0x7c, 0x3e, 0xf6, 0xc2, 0x48, 0x60, 0xa3, 0x39, 0xa8, 0x12, 0x50, 0x8a, 0x6c, 0x9a,
0xd0, 0x40, 0x47, 0x0c, 0x39, 0x42, 0x1a, 0xe8, 0x5b, 0xf9, 0x1d, 0x28, 0xaa, 0xbd, 0x3f, 0x1f,
0xe9, 0x34, 0x0b, 0x03, 0x92, 0xd6, 0x36, 0xa0, 0x34, 0xb0, 0x27, 0xf6, 0xc0, 0x09, 0xaf, 0x25,
0x43, 0x88, 0xbe, 0x45, 0xe9, 0x23, 0x6f, 0x60, 0x8f, 0xac, 0x13, 0x7b, 0x64, 0xbb, 0x03, 0x2e,
0x75, 0xf7, 0x2a, 0x02, 0xb7, 0x08, 0x26, 0xf4, 0x73, 0xd9, 0x4e, 0x85, 0x45, 0x2a, 0xbc, 0x6c,
0xbd, 0x42, 0x13, 0xc2, 0xa5, 0x37, 0x1e, 0x3b, 0x42, 0xcb, 0x20, 0x31, 0x2c, 0x67, 0x96, 0x09,
0xb2, 0xcb, 0xb1, 0xb7, 0x32, 0xf9, 0x92, 0x86, 0xae, 0x4c, 0x55, 0x11, 0xf0, 0x53, 0x3a, 0x48,
0x98, 0x97, 0xc5, 0x72, 0x9a, 0x2c, 0xf6, 0x2e, 0x2c, 0x4d, 0xdd, 0x80, 0x87, 0xe1, 0x88, 0x0f,
0xa3, 0xb6, 0x54, 0x10, 0xa9, 0x11, 0x25, 0xa8, 0xe6, 0x6c, 0xc2, 0x32, 0x1d, 0x3a, 0x04, 0x76,
0xe8, 0x05, 0xe7, 0x4e, 0x60, 0x05, 0x42, 0x43, 0x22, 0x75, 0x77, 0x09, 0x93, 0x7a, 0x32, 0xa5,
0x47, 0x2a, 0xd2, 0xfa, 0x0c, 0xbe, 0xcf, 0x07, 0xdc, 0xb9, 0xe0, 0x43, 0x94, 0xd3, 0x72, 0xe6,
0x6a, 0x22, 0x8f, 0x29, 0x13, 0x51, 0xe8, 0x9e, 0x8e, 0xad, 0xe9, 0x64, 0x68, 0x0b, 0x61, 0xa5,
0x4e, 0xc2, 0xb0, 0x3b, 0x1d, 0x1f, 0x13, 0x84, 0x3d, 0x06, 0x25, 0x89, 0x49, 0xf9, 0x70, 0x31,
0xc1, 0xcf, 0x04, 0xb1, 0x9a, 0x55, 0x89, 0x41, 0x82, 0x62, 0x42, 0xe6, 0x6c, 0xcc, 0xc8, 0x9c,
0x4d, 0x28, 0x4e, 0x7c, 0xe7, 0xc2, 0x0e, 0x79, 0x73, 0x89, 0x18, 0xb8, 0xfc, 0x14, 0x9c, 0xc1,
0x71, 0x9d, 0xd0, 0xb1, 0x43, 0xcf, 0x6f, 0x32, 0x4c, 0x8b, 0x01, 0xec, 0x21, 0x2c, 0x21, 0x8d,
0x04, 0xa1, 0x1d, 0x4e, 0x03, 0x29, 0x81, 0x2e, 0x23, 0x31, 0xa1, 0x0c, 0xdd, 0x43, 0x38, 0x0a,
0xa1, 0xec, 0x1b, 0xb0, 0x46, 0x64, 0x81, 0x39, 0xa4, 0x64, 0x8d, 0x02, 0xc1, 0x0a, 0x0e, 0xc5,
0x32, 0xa6, 0x0a, 0xfa, 0x96, 0xf2, 0xb5, 0x90, 0x0e, 0xde, 0x87, 0x75, 0x49, 0x26, 0x73, 0xb9,
0x56, 0x31, 0xd7, 0x0a, 0x25, 0xcf, 0x64, 0xdb, 0x84, 0x25, 0xd1, 0x24, 0x67, 0x60, 0xc9, 0xdc,
0x62, 0x25, 0xac, 0x89, 0xd6, 0xa3, 0xa6, 0xb4, 0x48, 0x89, 0x26, 0xa6, 0x3d, 0xe3, 0xd7, 0xec,
0xbb, 0xb0, 0x48, 0x24, 0x83, 0xea, 0x15, 0x72, 0xfa, 0x0d, 0xe4, 0xf4, 0xab, 0xea, 0x84, 0x33,
0x4a, 0x45, 0x66, 0x5f, 0x1f, 0x24, 0xbe, 0xc5, 0x72, 0x18, 0x39, 0xa7, 0x3c, 0x74, 0xc6, 0xbc,
0xb9, 0x4e, 0x04, 0xa6, 0xbe, 0xc5, 0x4a, 0x9d, 0x4e, 0x30, 0xa5, 0x49, 0x7c, 0x81, 0xbe, 0x90,
0x76, 0x47, 0x5e, 0xc0, 0xd5, 0x11, 0x55, 0xf3, 0xb6, 0x5c, 0x84, 0x02, 0xa8, 0x64, 0x48, 0x21,
0x88, 0x93, 0xd2, 0x13, 0x1d, 0x24, 0xde, 0x41, 0x62, 0xa8, 0x91, 0xee, 0xa3, 0x0e, 0x13, 0xc5,
0x2e, 0x7e, 0x6e, 0x5f, 0x2a, 0x0e, 0xf2, 0x1a, 0xce, 0x2f, 0x08, 0x90, 0xe4, 0x1d, 0x3f, 0xc9,
0xd0, 0x86, 0x28, 0xf9, 0x47, 0xa0, 0xa9, 0x77, 0xc4, 0x39, 0x2c, 0xcf, 0x1d, 0x5d, 0x4b, 0x66,
0x02, 0x04, 0x3a, 0x74, 0x47, 0xb8, 0x9a, 0x1d, 0x57, 0x47, 0x21, 0xde, 0x5b, 0x55, 0x40, 0x44,
0xba, 0x07, 0x95, 0xc9, 0xf4, 0x64, 0xe4, 0x0c, 0x08, 0x25, 0x47, 0xa5, 0x10, 0x08, 0x11, 0x84,
0x7e, 0x4b, 0x14, 0x45, 0x18, 0x79, 0xc4, 0xa8, 0x48, 0x18, 0xa2, 0x20, 0x6f, 0xe7, 0x3e, 0xb2,
0x93, 0xaa, 0x89, 0xbf, 0x8d, 0x2d, 0x58, 0x49, 0x36, 0x5a, 0x6e, 0x3c, 0x0f, 0xa1, 0x24, 0x79,
0x95, 0x3a, 0xf8, 0xa8, 0x6b, 0x47, 0xd1, 0x42, 0x45, 0x8b, 0xd2, 0x8d, 0xdf, 0x5a, 0x80, 0x65,
0x09, 0xdd, 0x16, 0x43, 0xdb, 0x9b, 0x8e, 0xc7, 0xb6, 0x9f, 0xc2, 0x04, 0x33, 0x2f, 0x66, 0x82,
0xd9, 0x39, 0x26, 0x98, 0xd4, 0x7c, 0x89, 0x87, 0x26, 0x35, 0x5f, 0x31, 0x97, 0xa4, 0x8c, 0xe8,
0xe7, 0xa0, 0x35, 0x09, 0xee, 0xd3, 0x79, 0xeb, 0x1c, 0xcb, 0x2e, 0xa4, 0xb0, 0x6c, 0x9d, 0xe1,
0x2e, 0xcc, 0x30, 0xdc, 0x37, 0x80, 0x88, 0x46, 0xcd, 0x7e, 0x91, 0xf4, 0x13, 0x84, 0xc9, 0xc3,
0xd4, 0xb7, 0x61, 0x71, 0x96, 0xc7, 0x11, 0x33, 0xad, 0xa7, 0x70, 0x38, 0x67, 0xcc, 0x71, 0xb7,
0xd2, 0x90, 0xcb, 0x92, 0xc3, 0x39, 0x63, 0xbe, 0x8f, 0x29, 0x0a, 0xbf, 0x0d, 0x40, 0x75, 0xe3,
0xa2, 0x01, 0x5c, 0x34, 0x6f, 0x25, 0xe7, 0x42, 0x1f, 0xf5, 0x4d, 0xf1, 0x31, 0xf5, 0x39, 0xae,
0xa2, 0x32, 0xe6, 0xc4, 0x05, 0xf4, 0x0c, 0xea, 0xde, 0x84, 0xbb, 0x56, 0xcc, 0x6b, 0x2a, 0x58,
0xd4, 0x9b, 0x2f, 0x28, 0xaa, 0xa3, 0x70, 0xcd, 0x9a, 0xc8, 0x1b, 0x7d, 0xb2, 0x03, 0x1a, 0x78,
0xae, 0x95, 0x56, 0xfd, 0x12, 0xa5, 0xd5, 0x31, 0x73, 0xf4, 0x6d, 0xfc, 0xbd, 0x0c, 0x54, 0xb4,
0x66, 0xb3, 0x55, 0x58, 0xda, 0x3e, 0x3c, 0x3c, 0x6a, 0x9b, 0xad, 0x7e, 0xe7, 0x93, 0xb6, 0xb5,
0xbd, 0x7f, 0xd8, 0x6b, 0x37, 0x6e, 0x09, 0xf0, 0xfe, 0xe1, 0x76, 0x6b, 0xdf, 0xda, 0x3d, 0x34,
0xb7, 0x15, 0x38, 0xc3, 0xd6, 0x80, 0x99, 0xed, 0x83, 0xc3, 0x7e, 0x3b, 0x01, 0xcf, 0xb2, 0x06,
0x54, 0xb7, 0xcc, 0x76, 0x6b, 0x7b, 0x4f, 0x42, 0x72, 0x6c, 0x05, 0x1a, 0xbb, 0xc7, 0xdd, 0x9d,
0x4e, 0xf7, 0xa9, 0xb5, 0xdd, 0xea, 0x6e, 0xb7, 0xf7, 0xdb, 0x3b, 0x8d, 0x3c, 0xab, 0x41, 0xb9,
0xb5, 0xd5, 0xea, 0xee, 0x1c, 0x76, 0xdb, 0x3b, 0x8d, 0x82, 0xf1, 0x1d, 0x28, 0xc7, 0x1d, 0xad,
0x40, 0xf1, 0xb8, 0xfb, 0xac, 0x7b, 0xf8, 0x69, 0xb7, 0x71, 0x8b, 0x95, 0xa1, 0x80, 0xf5, 0x37,
0x32, 0x0c, 0x60, 0x81, 0xea, 0x6c, 0x64, 0x59, 0x09, 0xf2, 0x5b, 0x87, 0xfd, 0xbd, 0x46, 0xce,
0xf8, 0xcb, 0x0c, 0xac, 0x62, 0x97, 0x87, 0xb3, 0x4c, 0xe0, 0x3e, 0x54, 0x06, 0x9e, 0x37, 0x11,
0x9a, 0x56, 0x2c, 0x51, 0xe8, 0x20, 0xb1, 0xc0, 0x89, 0x79, 0x9f, 0x7a, 0xfe, 0x80, 0x4b, 0x1e,
0x00, 0x08, 0xda, 0x15, 0x10, 0x41, 0x83, 0x92, 0x88, 0x09, 0x83, 0x58, 0x40, 0x85, 0x60, 0x84,
0xb2, 0x06, 0x0b, 0x27, 0x3e, 0xb7, 0x07, 0xe7, 0x72, 0xf5, 0xcb, 0x2f, 0xf6, 0x4e, 0x7c, 0x06,
0x30, 0x10, 0x34, 0x35, 0xe2, 0x43, 0x5c, 0x02, 0x25, 0x73, 0x51, 0xc2, 0xb7, 0x25, 0x58, 0xec,
0x46, 0xf6, 0x89, 0xed, 0x0e, 0x3d, 0x97, 0x0f, 0xa5, 0xaa, 0x11, 0x03, 0x8c, 0x23, 0x58, 0x9b,
0xed, 0x9f, 0xe4, 0x17, 0x1f, 0x68, 0xfc, 0x82, 0x24, 0xff, 0x8d, 0x9b, 0x49, 0x41, 0xe3, 0x1d,
0xff, 0x20, 0x0f, 0x79, 0x21, 0x09, 0xde, 0x28, 0x34, 0xea, 0xa2, 0x7d, 0x6e, 0xce, 0xfc, 0x83,
0x47, 0x0d, 0x24, 0x22, 0xd0, 0x79, 0x56, 0x19, 0x21, 0x28, 0x1a, 0x44, 0xc9, 0x3e, 0x1f, 0x5c,
0xc8, 0x03, 0x2d, 0x4a, 0x36, 0xf9, 0xe0, 0x02, 0x75, 0x2a, 0x3b, 0xa4, 0xbc, 0xb4, 0xde, 0x8b,
0x81, 0x1d, 0x62, 0x4e, 0x99, 0x84, 0xf9, 0x8a, 0x51, 0x12, 0xe6, 0x6a, 0x42, 0xd1, 0x71, 0x4f,
0xbc, 0xa9, 0x3b, 0xc4, 0xe5, 0x5d, 0x32, 0xd5, 0x27, 0x5a, 0x9b, 0x90, 0x13, 0x89, 0x8d, 0x88,
0x56, 0x73, 0x49, 0x00, 0xfa, 0x62, 0x2b, 0x7a, 0x0f, 0xca, 0xc1, 0xb5, 0x3b, 0xd0, 0xd7, 0xf0,
0x8a, 0x1c, 0x1f, 0xd1, 0xfb, 0xcd, 0xde, 0xb5, 0x3b, 0xc0, 0x15, 0x5b, 0x0a, 0xe4, 0x2f, 0xf6,
0x3e, 0x94, 0xa2, 0x73, 0x5f, 0xe2, 0xc0, 0xb7, 0xf5, 0x1c, 0xea, 0xb0, 0x97, 0xd4, 0xeb, 0x08,
0x95, 0x3d, 0x82, 0x05, 0x3c, 0x9c, 0x0d, 0x9a, 0x55, 0xcc, 0xa4, 0xe4, 0x7d, 0xd1, 0x0c, 0x34,
0xf4, 0xf0, 0x21, 0x1e, 0xd4, 0x9a, 0x12, 0x6d, 0xe3, 0x19, 0xd4, 0x12, 0x65, 0xe9, 0x4a, 0x74,
0x8d, 0x94, 0xe8, 0x37, 0x75, 0x25, 0x3a, 0xde, 0x09, 0x64, 0x36, 0x5d, 0xa9, 0xfe, 0x65, 0x28,
0xa9, 0xae, 0x88, 0xf5, 0x27, 0xd7, 0x8e, 0xd5, 0xfb, 0xac, 0xbb, 0xdd, 0xb8, 0xc5, 0x16, 0xa1,
0xd2, 0xda, 0xc6, 0x25, 0x8d, 0x80, 0x8c, 0x40, 0x39, 0x6a, 0xf5, 0x7a, 0x11, 0x24, 0x6b, 0xec,
0x42, 0x63, 0xb6, 0xa5, 0x82, 0x26, 0x43, 0x05, 0x93, 0x47, 0xd7, 0x31, 0x40, 0xa8, 0x48, 0x74,
0x1a, 0x4d, 0x72, 0x38, 0x7d, 0x18, 0xef, 0x43, 0x43, 0xec, 0x6b, 0x62, 0xa8, 0x02, 0xed, 0x08,
0x78, 0x24, 0x64, 0x3b, 0xfd, 0xf8, 0xba, 0x64, 0x56, 0x08, 0x86, 0x55, 0x19, 0x1f, 0xc0, 0x92,
0x96, 0x2d, 0x56, 0x69, 0xc5, 0x5e, 0x39, 0xab, 0xd2, 0xa2, 0x02, 0x43, 0x29, 0xc6, 0x3a, 0xac,
0x8a, 0xcf, 0xf6, 0x05, 0x77, 0xc3, 0xde, 0xf4, 0x84, 0x6c, 0x8e, 0x8e, 0xe7, 0x0a, 0xc5, 0xa6,
0x1c, 0xa5, 0xdc, 0x4c, 0xe4, 0x9b, 0x52, 0xfb, 0xcd, 0x22, 0x69, 0x6c, 0x68, 0x35, 0x60, 0xc6,
0x4d, 0xfc, 0x9b, 0xd0, 0x82, 0xcb, 0x11, 0x48, 0x0c, 0xeb, 0x51, 0xbb, 0x6d, 0x5a, 0x87, 0xdd,
0xfd, 0x4e, 0x57, 0x30, 0x4a, 0x31, 0xac, 0x08, 0xd8, 0xdd, 0x45, 0x48, 0xc6, 0x68, 0x40, 0xfd,
0x29, 0x0f, 0x3b, 0xee, 0xa9, 0xa7, 0xec, 0x6b, 0x7f, 0x55, 0x80, 0xc5, 0x08, 0x14, 0x6b, 0xd1,
0x17, 0xdc, 0x0f, 0x1c, 0xcf, 0x45, 0x81, 0xb8, 0x6c, 0xaa, 0x4f, 0xb1, 0xbb, 0x39, 0x43, 0xee,
0x86, 0x4e, 0x78, 0x6d, 0x25, 0x8e, 0xdc, 0xea, 0x0a, 0x2c, 0x77, 0xd1, 0x15, 0x28, 0xd8, 0x23,
0xc7, 0x56, 0xa6, 0x5a, 0xfa, 0x10, 0xd0, 0x81, 0x37, 0xf2, 0x7c, 0x94, 0x7d, 0xcb, 0x26, 0x7d,
0xb0, 0xc7, 0xb0, 0x22, 0x64, 0x70, 0xfd, 0x1c, 0x14, 0xf9, 0x07, 0x9d, 0xfe, 0x31, 0x77, 0x3a,
0x3e, 0x8a, 0xcf, 0x42, 0x45, 0x8a, 0xd8, 0x3b, 0x45, 0x0e, 0x29, 0x2c, 0x45, 0x19, 0x48, 0x9d,
0x5b, 0x72, 0xa7, 0xe3, 0x16, 0xa6, 0x44, 0xf8, 0x4f, 0x60, 0x55, 0xe0, 0x47, 0xe2, 0x55, 0x94,
0x63, 0x11, 0x73, 0x88, 0xc2, 0x3a, 0x32, 0x2d, 0xca, 0x73, 0x07, 0xca, 0xd4, 0x2a, 0x31, 0xe3,
0x05, 0x12, 0xe3, 0xb1, 0x29, 0xdc, 0x0f, 0xe6, 0xac, 0xaa, 0x0b, 0x24, 0x08, 0xcc, 0x58, 0x55,
0x35, 0xbb, 0x6c, 0x69, 0xd6, 0x2e, 0xfb, 0x04, 0x56, 0x4f, 0x04, 0x09, 0x9e, 0x73, 0x7b, 0xc8,
0x7d, 0x2b, 0x26, 0x6c, 0x52, 0x57, 0x96, 0x45, 0xe2, 0x1e, 0xa6, 0x45, 0xeb, 0x40, 0xc8, 0x39,
0x82, 0x2d, 0xf0, 0xa1, 0x15, 0x7a, 0x16, 0x8a, 0x3f, 0xc8, 0x60, 0x4a, 0x66, 0x8d, 0xc0, 0x7d,
0x6f, 0x5b, 0x00, 0x93, 0x78, 0x67, 0xbe, 0x3d, 0x39, 0x97, 0x0a, 0x45, 0x84, 0xf7, 0x54, 0x00,
0xd9, 0x6b, 0x50, 0x14, 0x24, 0xef, 0x72, 0x32, 0x7e, 0x91, 0xc8, 0xae, 0x40, 0xec, 0x4d, 0x58,
0xc0, 0x3a, 0x82, 0x66, 0x03, 0xe9, 0xbd, 0x1a, 0x33, 0x72, 0xc7, 0x35, 0x65, 0x9a, 0x10, 0x26,
0xa7, 0xbe, 0x43, 0x5c, 0xa6, 0x6c, 0xe2, 0x6f, 0xf6, 0x3d, 0x8d, 0x65, 0x2d, 0x63, 0x5e, 0x25,
0x0f, 0xcc, 0x50, 0xda, 0x4d, 0xdc, 0xeb, 0xe7, 0xca, 0x8c, 0xbe, 0x9f, 0x2f, 0x55, 0x1a, 0x55,
0xe3, 0x5b, 0x50, 0xa0, 0xd1, 0x11, 0x44, 0x88, 0x63, 0x97, 0x91, 0x44, 0x88, 0xd0, 0x26, 0x14,
0x5d, 0x1e, 0x5e, 0x7a, 0xfe, 0x73, 0x75, 0x28, 0x2d, 0x3f, 0x8d, 0x1f, 0xe1, 0x69, 0x4a, 0x64,
0x71, 0x27, 0xc5, 0x50, 0x90, 0x07, 0x4d, 0x6f, 0x70, 0x6e, 0xcb, 0x03, 0x9e, 0x12, 0x02, 0x7a,
0xe7, 0xf6, 0x1c, 0x79, 0x64, 0xe7, 0x8d, 0xee, 0x6f, 0x42, 0x5d, 0xd9, 0xf8, 0x03, 0x6b, 0xc4,
0x4f, 0x43, 0x49, 0xee, 0x55, 0x69, 0xe0, 0x0f, 0xf6, 0xf9, 0x69, 0x68, 0x1c, 0xc0, 0x92, 0x24,
0xc8, 0xc3, 0x09, 0x57, 0x55, 0x7f, 0x3b, 0x4d, 0x9e, 0xae, 0x3c, 0x59, 0x4e, 0x6e, 0xb4, 0xe4,
0xbb, 0x90, 0x10, 0xb2, 0x8d, 0x8f, 0x81, 0xe9, 0xdb, 0xb0, 0x2c, 0x4f, 0x4a, 0xb5, 0xea, 0x2c,
0x5f, 0x99, 0xc4, 0x22, 0xd9, 0xd9, 0x19, 0x8a, 0xd1, 0x09, 0xa6, 0x83, 0x81, 0xf2, 0xbd, 0x28,
0x99, 0xea, 0xd3, 0xf8, 0xb3, 0x0c, 0x2c, 0x63, 0x61, 0x4a, 0x1f, 0x90, 0x4c, 0xf6, 0xa7, 0x6e,
0xa4, 0x98, 0x1f, 0x5d, 0xf6, 0xa1, 0x8f, 0x2f, 0x7f, 0x7a, 0x9a, 0x9f, 0x3b, 0x3d, 0x7d, 0x07,
0x1a, 0x43, 0x3e, 0x72, 0xd0, 0x0d, 0x47, 0x89, 0x12, 0xa4, 0x01, 0x2c, 0x2a, 0xb8, 0xd4, 0x06,
0x8d, 0x7f, 0x92, 0x81, 0x25, 0x92, 0x54, 0x50, 0xaf, 0x96, 0x03, 0xf5, 0x91, 0x52, 0x24, 0x25,
0xab, 0x92, 0x7d, 0x8a, 0x77, 0x70, 0x84, 0x12, 0xf2, 0xde, 0x2d, 0xa9, 0x60, 0x4a, 0x28, 0xfb,
0x10, 0x75, 0x18, 0xd7, 0x42, 0x60, 0x8a, 0x5b, 0x4f, 0x72, 0x52, 0xf6, 0x6e, 0xa1, 0x82, 0xe3,
0x22, 0x68, 0xab, 0x24, 0x34, 0x5b, 0x01, 0x36, 0x76, 0xa1, 0x96, 0xa8, 0x26, 0x71, 0xc4, 0x5b,
0xa5, 0x23, 0xde, 0x39, 0x33, 0x4a, 0x76, 0xde, 0x8c, 0x72, 0x0d, 0xcb, 0x26, 0xb7, 0x87, 0xd7,
0xbb, 0x9e, 0x7f, 0x14, 0x9c, 0x84, 0xbb, 0x24, 0xfe, 0x09, 0xfe, 0x1e, 0xd9, 0x06, 0x13, 0xe7,
0xa8, 0xca, 0x44, 0xa4, 0xd4, 0xe5, 0xaf, 0x42, 0x3d, 0x36, 0x22, 0x6a, 0x67, 0x71, 0xb5, 0xc8,
0x8e, 0x88, 0x47, 0x72, 0x42, 0xd5, 0x0c, 0x4e, 0x42, 0x79, 0x1a, 0x87, 0xbf, 0x8d, 0xbf, 0x93,
0x07, 0x26, 0xa8, 0x79, 0x86, 0x60, 0x66, 0xcc, 0x9f, 0xd9, 0x39, 0xf3, 0xe7, 0x63, 0x60, 0x1a,
0x82, 0xb2, 0xca, 0xe6, 0x22, 0xab, 0x6c, 0x23, 0xc6, 0x95, 0x46, 0xd9, 0xc7, 0xb0, 0x22, 0x65,
0xe9, 0x64, 0x53, 0x89, 0x34, 0x18, 0x09, 0xd5, 0x89, 0xf6, 0x2a, 0xd3, 0xa7, 0x50, 0xff, 0xe9,
0xb4, 0x0d, 0x4d, 0x9f, 0x4a, 0xf1, 0xd7, 0x08, 0x70, 0xe1, 0xa5, 0x04, 0x58, 0x9c, 0x23, 0x40,
0xed, 0xf0, 0xa7, 0x94, 0x3c, 0xfc, 0x31, 0xa0, 0xa6, 0x0c, 0x9c, 0xe4, 0xd7, 0x41, 0x82, 0x63,
0x45, 0x5a, 0x39, 0xd1, 0xb7, 0xe3, 0x01, 0x34, 0xd4, 0x09, 0x4d, 0x74, 0xbc, 0x44, 0x3e, 0x0b,
0xf2, 0x80, 0x6f, 0x5b, 0x1d, 0x32, 0x25, 0x0e, 0xf3, 0x2b, 0x33, 0x87, 0xf9, 0xef, 0xc2, 0x52,
0x20, 0xe8, 0xd7, 0x9a, 0xba, 0xd2, 0xc1, 0x88, 0x0f, 0x51, 0x6b, 0x2b, 0x99, 0x0d, 0x4c, 0x38,
0x8e, 0xe1, 0xf3, 0x47, 0x27, 0xb5, 0x94, 0xa3, 0x93, 0xf7, 0x63, 0x5b, 0x60, 0x70, 0xee, 0x8c,
0x51, 0x66, 0x88, 0x9d, 0x71, 0xe4, 0x00, 0xf7, 0xce, 0x9d, 0xb1, 0xa9, 0x0c, 0xcf, 0xe2, 0xc3,
0xf8, 0xbf, 0x19, 0x68, 0x08, 0x3a, 0x48, 0x2c, 0xb1, 0xef, 0x00, 0x32, 0x83, 0x57, 0x5c, 0x61,
0x15, 0x81, 0xab, 0x16, 0xd8, 0xb7, 0x00, 0x57, 0x8c, 0x25, 0x54, 0x54, 0xb9, 0xbe, 0x9a, 0xc9,
0xf5, 0x15, 0xf3, 0xd0, 0xbd, 0x5b, 0xa4, 0x7b, 0x08, 0x08, 0xfb, 0x0e, 0x94, 0x05, 0x61, 0x22,
0x95, 0x48, 0x1f, 0x30, 0x25, 0x79, 0xa5, 0xac, 0x11, 0x91, 0x75, 0x22, 0x3f, 0xd3, 0xcc, 0xb7,
0xf9, 0x14, 0xf3, 0xad, 0xb6, 0x80, 0xf7, 0x00, 0x9e, 0xf1, 0xeb, 0x7d, 0x6f, 0x80, 0x7a, 0xe5,
0x5d, 0x00, 0x41, 0xcb, 0xa7, 0xf6, 0xd8, 0x91, 0x67, 0x42, 0x05, 0xb3, 0xfc, 0x9c, 0x5f, 0xef,
0x22, 0x40, 0x4c, 0xa4, 0x48, 0x8e, 0x57, 0x71, 0xc1, 0x2c, 0x3d, 0xe7, 0xd7, 0xb4, 0x84, 0x2d,
0xa8, 0x3d, 0xe3, 0xd7, 0x3b, 0x9c, 0x84, 0x4c, 0xcf, 0x17, 0x44, 0xe4, 0xdb, 0x97, 0x42, 0xaa,
0x4c, 0x98, 0x5e, 0x2b, 0xbe, 0x7d, 0xf9, 0x8c, 0x5f, 0x2b, 0x33, 0x70, 0x51, 0xa4, 0x8f, 0xbc,
0x81, 0xdc, 0x37, 0x95, 0x13, 0x49, 0xdc, 0x28, 0x73, 0xe1, 0x39, 0xfe, 0x36, 0xfe, 0x3a, 0x03,
0x35, 0xd1, 0x7e, 0x64, 0xcb, 0x62, 0xca, 0x94, 0x2f, 0x52, 0x26, 0xf6, 0x45, 0x7a, 0x22, 0xb9,
0x1a, 0xf1, 0xf8, 0xec, 0xcd, 0x3c, 0x1e, 0xe7, 0x86, 0x18, 0xfc, 0x7b, 0x50, 0xa6, 0x65, 0x29,
0xd6, 0x79, 0x2e, 0x31, 0xc1, 0x89, 0x0e, 0x99, 0x25, 0x44, 0x7b, 0x46, 0xae, 0x0f, 0xda, 0xf9,
0x22, 0x0d, 0x71, 0xd9, 0x8f, 0x4e, 0x15, 0x53, 0xa6, 0xa1, 0x70, 0x83, 0xeb, 0x83, 0x7e, 0x78,
0xb7, 0x30, 0x77, 0x78, 0x77, 0x08, 0x25, 0x31, 0xd5, 0xd8, 0xd9, 0x94, 0x42, 0x33, 0x69, 0x85,
0x0a, 0x49, 0xc0, 0x16, 0x9b, 0x82, 0x60, 0x74, 0x59, 0x29, 0x09, 0xd8, 0x01, 0x3f, 0x42, 0x66,
0x97, 0x81, 0x8a, 0xb6, 0x02, 0xf0, 0xfc, 0x33, 0x1a, 0x2f, 0x5a, 0x2e, 0x49, 0x12, 0x4f, 0x0c,
0xf8, 0xde, 0x2d, 0xb3, 0x36, 0x48, 0xcc, 0xc0, 0xa6, 0xa4, 0x55, 0xcc, 0x99, 0x4d, 0xb8, 0x4d,
0xa9, 0x86, 0x2b, 0x02, 0x15, 0xbf, 0xb7, 0x16, 0x20, 0x2f, 0x50, 0x8d, 0x8f, 0x60, 0x49, 0x6b,
0x06, 0xa9, 0xf9, 0xaf, 0xda, 0x43, 0xe3, 0xd7, 0xa2, 0xcc, 0xa2, 0x0e, 0xb2, 0x50, 0x29, 0x37,
0x12, 0x3e, 0xa4, 0x8e, 0x4b, 0x77, 0x15, 0x02, 0x09, 0xb4, 0x57, 0x76, 0x6d, 0xf8, 0x0d, 0x58,
0xd6, 0x4a, 0xdf, 0x75, 0x5c, 0x7b, 0xe4, 0xfc, 0x08, 0x37, 0xfc, 0xc0, 0x39, 0x73, 0x67, 0xca,
0x27, 0xd0, 0x97, 0x2a, 0xff, 0x9f, 0x66, 0x61, 0x45, 0x56, 0x80, 0x8e, 0x81, 0x8e, 0x90, 0xe2,
0x0e, 0x82, 0x33, 0xf6, 0x1d, 0xa8, 0x89, 0xb1, 0xb1, 0x7c, 0x7e, 0xe6, 0x04, 0x21, 0x57, 0x96,
0xb1, 0x14, 0xc6, 0x25, 0x36, 0x73, 0x81, 0x6a, 0x4a, 0x4c, 0xf6, 0x11, 0x54, 0x30, 0x2b, 0x1d,
0xa3, 0xc8, 0x89, 0x68, 0xce, 0x67, 0xa4, 0x81, 0xde, 0xbb, 0x65, 0x42, 0x10, 0x0f, 0xfb, 0x47,
0x50, 0xc1, 0x39, 0xbc, 0xc0, 0x81, 0x9c, 0x61, 0x55, 0x73, 0x03, 0x2d, 0x32, 0x4f, 0xe2, 0x61,
0x6f, 0x41, 0x8d, 0x98, 0x95, 0x1c, 0x27, 0xe9, 0x70, 0xb4, 0x31, 0x9f, 0x5d, 0x8d, 0xa4, 0x68,
0xfc, 0x44, 0xfb, 0xde, 0x2a, 0x43, 0x31, 0xf4, 0x9d, 0xb3, 0x33, 0xee, 0x1b, 0x6b, 0xd1, 0xd0,
0x08, 0x2e, 0xcc, 0x7b, 0x21, 0x9f, 0x08, 0xd9, 0xdc, 0xf8, 0x4f, 0x19, 0xa8, 0x48, 0xbe, 0xfa,
0x53, 0x9b, 0xe3, 0x36, 0x34, 0xcf, 0x5a, 0x3a, 0xb1, 0x89, 0x1d, 0x69, 0xdf, 0x86, 0xc5, 0xb1,
0x90, 0xd3, 0x85, 0x1e, 0x99, 0xb0, 0xc5, 0xd5, 0x15, 0x58, 0x8a, 0xc9, 0x9b, 0xb0, 0x8c, 0x52,
0x73, 0x60, 0x85, 0xce, 0xc8, 0x52, 0x89, 0xd2, 0x8b, 0x75, 0x89, 0x92, 0xfa, 0xce, 0xe8, 0x40,
0x26, 0x08, 0xe1, 0x31, 0x08, 0xed, 0x33, 0x2e, 0xd7, 0x36, 0x7d, 0x18, 0x4d, 0x58, 0x9b, 0x51,
0x21, 0x95, 0xfa, 0xfb, 0x07, 0x4b, 0xb0, 0x3e, 0x97, 0x24, 0xd5, 0xe0, 0xc8, 0x06, 0x35, 0x72,
0xc6, 0x27, 0x5e, 0x74, 0x42, 0x9b, 0xd1, 0x6c, 0x50, 0xfb, 0x22, 0x45, 0x9d, 0xd0, 0x72, 0x58,
0x55, 0x04, 0x89, 0x47, 0xac, 0x91, 0x96, 0x99, 0x45, 0x1d, 0xe8, 0xbd, 0xe4, 0x26, 0x36, 0x5b,
0x9d, 0x82, 0xeb, 0xa2, 0xd1, 0xf2, 0x64, 0x0e, 0x16, 0xb0, 0xdf, 0x84, 0x66, 0x44, 0xf7, 0x52,
0x6c, 0xd7, 0x54, 0x66, 0x51, 0xd3, 0xd7, 0x5e, 0x52, 0x53, 0xe2, 0xec, 0x0e, 0x65, 0xa7, 0x35,
0xb5, 0x64, 0xa8, 0xc0, 0xa8, 0xae, 0x0b, 0x78, 0x5d, 0xd5, 0x85, 0x62, 0xf8, 0x7c, 0x8d, 0xf9,
0x57, 0xea, 0x1b, 0x9e, 0x4b, 0x26, 0xaa, 0x35, 0xef, 0xc8, 0x82, 0xa3, 0x24, 0xbd, 0xde, 0x73,
0x58, 0xbb, 0xb4, 0x9d, 0x50, 0xf5, 0x51, 0xd3, 0xd8, 0x0b, 0x58, 0xdf, 0x93, 0x97, 0xd4, 0xf7,
0x29, 0x65, 0x4e, 0x28, 0x26, 0x2b, 0x97, 0xf3, 0xc0, 0x60, 0xe3, 0x4f, 0xb3, 0x50, 0x4f, 0x96,
0x22, 0x18, 0x8b, 0xdc, 0x6c, 0x94, 0xbc, 0x29, 0x85, 0x60, 0x69, 0x3d, 0xe8, 0x92, 0x9c, 0x39,
0x6f, 0xd7, 0xc8, 0xa6, 0xd8, 0x35, 0x74, 0x73, 0x42, 0xee, 0x65, 0xf6, 0xdb, 0xfc, 0x2b, 0xd9,
0x6f, 0x0b, 0x69, 0xf6, 0xdb, 0x9b, 0x8d, 0x7e, 0x0b, 0x3f, 0x95, 0xd1, 0xaf, 0xf8, 0x02, 0xa3,
0x5f, 0xc2, 0x54, 0x59, 0x9a, 0x31, 0x55, 0x6e, 0xfc, 0x75, 0x06, 0xd8, 0x3c, 0x2d, 0xb3, 0xa7,
0x64, 0xe0, 0x71, 0xf9, 0x48, 0xf2, 0xd9, 0xaf, 0xbf, 0xda, 0x7a, 0x50, 0xd3, 0xa7, 0x72, 0xb3,
0x47, 0xb0, 0xac, 0x7b, 0xc6, 0xeb, 0x3a, 0x76, 0xcd, 0x64, 0x7a, 0x52, 0x7c, 0x12, 0xa3, 0x99,
0xb6, 0xf3, 0x2f, 0x35, 0x6d, 0x17, 0x5e, 0x6a, 0xda, 0x5e, 0x48, 0x9a, 0xb6, 0x37, 0xfe, 0x4b,
0x06, 0x96, 0x53, 0x48, 0xee, 0xe7, 0xd7, 0x67, 0x41, 0x29, 0x09, 0x26, 0x94, 0x95, 0x94, 0xa2,
0xf3, 0x9f, 0x7d, 0xa8, 0xc4, 0xd6, 0x52, 0x15, 0x39, 0xf2, 0xf0, 0x65, 0xbc, 0x20, 0xce, 0x61,
0xea, 0xd9, 0x37, 0x7e, 0x3f, 0x0b, 0x15, 0x2d, 0x51, 0x8c, 0x22, 0x11, 0x98, 0xe6, 0x51, 0x44,
0x72, 0x1c, 0x9e, 0x10, 0xdc, 0x03, 0x69, 0x82, 0xa0, 0x74, 0x5a, 0x0a, 0x52, 0x68, 0x43, 0x84,
0x4d, 0x58, 0x56, 0xc6, 0x37, 0x1e, 0x3b, 0x0e, 0xca, 0x9d, 0x61, 0x49, 0x9a, 0xe0, 0x78, 0xe4,
0x87, 0xc8, 0x1e, 0x29, 0xe5, 0x2d, 0x9e, 0x3b, 0x24, 0x4c, 0x3a, 0xdf, 0x5f, 0x22, 0x72, 0x56,
0x93, 0x28, 0xa8, 0xf2, 0x3d, 0x58, 0x55, 0xc4, 0x9c, 0xcc, 0x41, 0x47, 0xfe, 0x4c, 0x92, 0xb2,
0x9e, 0xe5, 0x7b, 0x70, 0x77, 0xa6, 0x4d, 0x33, 0x59, 0xc9, 0xc3, 0xf5, 0x76, 0xa2, 0x75, 0x7a,
0x09, 0x1b, 0x3f, 0x86, 0x5a, 0x82, 0xad, 0xfd, 0xfc, 0xa6, 0x7c, 0xf6, 0x54, 0x86, 0x46, 0x54,
0x3f, 0x95, 0xd9, 0xf8, 0x3f, 0x39, 0x60, 0xf3, 0x9c, 0xf5, 0x17, 0xd9, 0x84, 0x79, 0xc2, 0xcc,
0xa5, 0x10, 0xe6, 0xff, 0xb7, 0xdd, 0xfe, 0x5d, 0x58, 0x92, 0x11, 0x54, 0x9a, 0x05, 0x95, 0x16,
0x67, 0x23, 0x4a, 0x50, 0xad, 0xf8, 0xd6, 0xac, 0x27, 0x47, 0x29, 0x11, 0x34, 0xa2, 0x89, 0x3b,
0x33, 0x0e, 0x1d, 0xc7, 0xb0, 0x60, 0xbb, 0x83, 0x73, 0xcf, 0x47, 0xad, 0xbc, 0xfe, 0xe4, 0x97,
0xbe, 0xf4, 0x66, 0xb7, 0xd9, 0xc2, 0xfc, 0x28, 0x63, 0x99, 0xb2, 0x30, 0xe3, 0x3d, 0xa8, 0x68,
0x60, 0xb4, 0x2a, 0x76, 0x0e, 0xb6, 0x0e, 0x1b, 0xb7, 0x58, 0x0d, 0xca, 0x66, 0x7b, 0xfb, 0xf0,
0x93, 0xb6, 0xd9, 0xde, 0x69, 0x64, 0x58, 0x09, 0xf2, 0xfb, 0x87, 0xbd, 0x7e, 0x23, 0x6b, 0x6c,
0x40, 0x53, 0x96, 0x38, 0x6f, 0x61, 0xf8, 0x9d, 0x7c, 0x74, 0xb8, 0x87, 0x89, 0x52, 0xa1, 0xfe,
0x06, 0x54, 0x75, 0x61, 0x44, 0x52, 0xc4, 0x8c, 0x11, 0x5f, 0xa8, 0xd2, 0x9e, 0xc6, 0xab, 0xb7,
0x81, 0x4c, 0xb3, 0xc3, 0x28, 0x5b, 0x36, 0x21, 0x65, 0xa6, 0xd8, 0xf2, 0x50, 0x55, 0x49, 0x90,
0xe1, 0xdf, 0x80, 0x7a, 0xf2, 0xb8, 0x5d, 0x72, 0xa4, 0x34, 0xf5, 0x50, 0xe4, 0x4e, 0x9c, 0xbf,
0xb3, 0xef, 0x41, 0x63, 0xf6, 0xb8, 0x5e, 0x8a, 0xba, 0x37, 0xe4, 0x5f, 0x74, 0x92, 0x27, 0xf8,
0x6c, 0x0f, 0x56, 0xd2, 0xc4, 0x31, 0xa4, 0x8f, 0x9b, 0x8f, 0x14, 0xd8, 0xbc, 0xc8, 0xc5, 0xbe,
0x2d, 0xad, 0x32, 0x85, 0x34, 0xdb, 0xb6, 0x36, 0xd8, 0x9b, 0xf4, 0x4f, 0xb3, 0xcf, 0x5c, 0x00,
0xc4, 0x30, 0xd6, 0x80, 0xea, 0xe1, 0x51, 0xbb, 0x6b, 0x6d, 0xef, 0xb5, 0xba, 0xdd, 0xf6, 0x7e,
0xe3, 0x16, 0x63, 0x50, 0x47, 0xa3, 0xf4, 0x4e, 0x04, 0xcb, 0x08, 0x98, 0xb4, 0x8e, 0x29, 0x58,
0x96, 0xad, 0x40, 0xa3, 0xd3, 0x9d, 0x81, 0xe6, 0x58, 0x13, 0x56, 0x8e, 0xda, 0x64, 0xc7, 0x4e,
0x94, 0x9b, 0x17, 0x22, 0xbe, 0xec, 0xae, 0x10, 0xf1, 0x29, 0x12, 0x50, 0xae, 0x03, 0x25, 0xf9,
0xfe, 0x6e, 0x06, 0x56, 0x67, 0x12, 0xe2, 0xf8, 0x0e, 0x92, 0x7b, 0x93, 0x12, 0x6f, 0x15, 0x81,
0x6a, 0x35, 0xbd, 0x0b, 0x4b, 0xd1, 0x31, 0xd1, 0xcc, 0xae, 0xd4, 0x88, 0x12, 0x14, 0xf2, 0x23,
0x58, 0xd6, 0x4e, 0x9b, 0x66, 0x78, 0x05, 0xd3, 0x92, 0x64, 0x06, 0x63, 0x3d, 0xf2, 0xa3, 0x9f,
0x69, 0xf5, 0x90, 0xc2, 0x0b, 0xf5, 0x84, 0xd8, 0x68, 0x95, 0x6c, 0xaf, 0xfa, 0x64, 0x8f, 0x67,
0x08, 0x21, 0xd9, 0x5a, 0x7d, 0xc2, 0x55, 0xf5, 0x7f, 0xb8, 0x00, 0xec, 0xe3, 0x29, 0xf7, 0xaf,
0x31, 0x7e, 0x23, 0x78, 0x99, 0x43, 0xa3, 0x3a, 0x17, 0xc9, 0xbe, 0x52, 0x8c, 0x56, 0x5a, 0x8c,
0x54, 0xfe, 0xe5, 0x31, 0x52, 0x85, 0x97, 0xc5, 0x48, 0x7d, 0x05, 0x6a, 0xce, 0x99, 0xeb, 0x09,
0x56, 0x28, 0xe4, 0xd6, 0xa0, 0xb9, 0x70, 0x3f, 0xf7, 0xa0, 0x6a, 0x56, 0x25, 0x50, 0x48, 0xad,
0x01, 0xfb, 0x28, 0x46, 0xe2, 0xc3, 0x33, 0x8c, 0xe7, 0xd3, 0x99, 0x60, 0x7b, 0x78, 0xc6, 0xe5,
0x31, 0x10, 0xea, 0x05, 0x2a, 0xb3, 0x80, 0x07, 0xec, 0x4d, 0xa8, 0x07, 0xde, 0x54, 0xa8, 0x01,
0x6a, 0x18, 0xc8, 0xac, 0x55, 0x25, 0xe8, 0x91, 0xb2, 0x61, 0x2e, 0x4f, 0x03, 0x6e, 0x8d, 0x9d,
0x20, 0x10, 0xe2, 0xd9, 0xc0, 0x73, 0x43, 0xdf, 0x1b, 0x49, 0x4b, 0xd5, 0xd2, 0x34, 0xe0, 0x07,
0x94, 0xb2, 0x4d, 0x09, 0xec, 0x9b, 0x71, 0x93, 0x26, 0xb6, 0xe3, 0x07, 0x4d, 0xc0, 0x26, 0xa9,
0x9e, 0xa2, 0xb4, 0x6d, 0x3b, 0x7e, 0xd4, 0x16, 0xf1, 0x11, 0xcc, 0xc4, 0x6e, 0x55, 0x66, 0x63,
0xb7, 0x7e, 0x98, 0x1e, 0xbb, 0x55, 0xc3, 0xa2, 0x1f, 0xcb, 0xa2, 0xe7, 0xa7, 0xf8, 0x4b, 0x85,
0x70, 0xcd, 0x87, 0xa4, 0xd5, 0xbf, 0x4c, 0x48, 0xda, 0x62, 0x5a, 0x48, 0xda, 0x7b, 0x50, 0xc1,
0x60, 0x21, 0xeb, 0xdc, 0x11, 0x32, 0x1c, 0x59, 0xde, 0x1a, 0x7a, 0x34, 0xd1, 0x9e, 0xe3, 0x86,
0x26, 0xf8, 0xea, 0x67, 0x30, 0x1f, 0x1d, 0xb6, 0xf4, 0x0b, 0x8c, 0x0e, 0x93, 0x41, 0x4d, 0x9b,
0x50, 0x52, 0xf3, 0xc4, 0x18, 0xe4, 0x4f, 0x7d, 0x6f, 0xac, 0x2c, 0x12, 0xe2, 0x37, 0xab, 0x43,
0x36, 0xf4, 0x64, 0xe6, 0x6c, 0xe8, 0x19, 0xbf, 0x0e, 0x15, 0x8d, 0xd4, 0xd8, 0x1b, 0x74, 0x8a,
0x28, 0x34, 0x29, 0x29, 0x5b, 0xd2, 0x28, 0x96, 0x25, 0xb4, 0x33, 0x14, 0xfc, 0x66, 0xe8, 0xf8,
0x1c, 0xe3, 0x38, 0x2d, 0x9f, 0x5f, 0x70, 0x3f, 0x50, 0x16, 0xa2, 0x46, 0x94, 0x60, 0x12, 0xdc,
0xf8, 0x0d, 0x58, 0x4e, 0xcc, 0xad, 0x64, 0x11, 0x6f, 0xc2, 0x02, 0x8e, 0x9b, 0xb2, 0xe0, 0x27,
0xa3, 0xb4, 0x64, 0x1a, 0x06, 0xe8, 0x93, 0x71, 0xcb, 0x9a, 0xf8, 0xde, 0x09, 0x56, 0x92, 0x31,
0x2b, 0x12, 0x76, 0xe4, 0x7b, 0x27, 0xc6, 0x5f, 0xe4, 0x20, 0xb7, 0xe7, 0x4d, 0x74, 0xa7, 0xb5,
0xcc, 0x9c, 0xd3, 0x9a, 0x54, 0x0f, 0xad, 0x48, 0xfd, 0x93, 0x32, 0x3b, 0x9a, 0x75, 0x94, 0x0a,
0xf8, 0x00, 0xea, 0x82, 0x4f, 0x84, 0x9e, 0xd0, 0xaf, 0x2f, 0x6d, 0x9f, 0x04, 0xe2, 0x1c, 0x2d,
0x3e, 0x7b, 0x1c, 0xf6, 0xbd, 0x5d, 0x82, 0xb3, 0x15, 0xc8, 0x45, 0xea, 0x0b, 0x26, 0x8b, 0x4f,
0xb6, 0x06, 0x0b, 0xe8, 0xbd, 0x7c, 0x2d, 0x4d, 0xd4, 0xf2, 0x8b, 0x7d, 0x1d, 0x96, 0x93, 0xe5,
0x12, 0x2b, 0x92, 0xb2, 0x91, 0x5e, 0x30, 0xf2, 0xa4, 0xdb, 0x20, 0xf8, 0x08, 0xe1, 0x48, 0x4f,
0x97, 0x53, 0xce, 0x31, 0x49, 0x63, 0x7a, 0xa5, 0x04, 0xd3, 0xbb, 0x07, 0x95, 0x70, 0x74, 0x61,
0x4d, 0xec, 0xeb, 0x91, 0x67, 0x0f, 0xe5, 0xfa, 0x86, 0x70, 0x74, 0x71, 0x44, 0x10, 0xf6, 0x08,
0x60, 0x3c, 0x99, 0xc8, 0xb5, 0x87, 0xa6, 0x8a, 0x98, 0x94, 0x0f, 0x8e, 0x8e, 0x88, 0xe4, 0xcc,
0xf2, 0x78, 0x32, 0xa1, 0x9f, 0x6c, 0x07, 0xea, 0xa9, 0xb1, 0x96, 0x77, 0x95, 0xb3, 0xad, 0x37,
0xd9, 0x4c, 0x59, 0x9c, 0xb5, 0x81, 0x0e, 0xdb, 0xf8, 0x1e, 0xb0, 0x9f, 0x31, 0xe2, 0xb1, 0x0f,
0xe5, 0xa8, 0x7d, 0x7a, 0xc0, 0x20, 0xba, 0xcf, 0x57, 0x12, 0x01, 0x83, 0xad, 0xe1, 0xd0, 0x17,
0x7c, 0x91, 0x36, 0xcc, 0x88, 0xe5, 0x83, 0xb6, 0x63, 0xb6, 0x88, 0xef, 0x1b, 0xff, 0x3d, 0x03,
0x05, 0x8a, 0x5e, 0x7c, 0x0b, 0x16, 0x09, 0x3f, 0x72, 0x00, 0x94, 0x86, 0x6d, 0xda, 0x77, 0xfb,
0xd2, 0xf7, 0x4f, 0x2c, 0x0b, 0x2d, 0xf2, 0x3a, 0x1b, 0xcd, 0xbc, 0x16, 0x7d, 0x7d, 0x0f, 0xca,
0x51, 0xd5, 0x1a, 0xe9, 0x94, 0x54, 0xcd, 0xec, 0x75, 0xc8, 0x9f, 0x7b, 0x13, 0x75, 0x4e, 0x03,
0xf1, 0x48, 0x9a, 0x08, 0x8f, 0xdb, 0x22, 0xea, 0xa0, 0xc6, 0xcb, 0xf3, 0x85, 0xa8, 0x12, 0x24,
0x83, 0xf9, 0x3e, 0x2e, 0xa4, 0xf4, 0xf1, 0x18, 0x16, 0x05, 0x1f, 0xd0, 0x1c, 0x4c, 0x6e, 0xde,
0x34, 0xdf, 0x11, 0x12, 0xde, 0x60, 0x34, 0x1d, 0x72, 0xfd, 0xa4, 0x0c, 0xbd, 0xd1, 0x24, 0x5c,
0x49, 0xd6, 0xc6, 0x1f, 0x66, 0x88, 0xbf, 0x88, 0x72, 0xd9, 0x03, 0xc8, 0x8b, 0xfd, 0x6d, 0xe6,
0xdc, 0x3c, 0x8a, 0x63, 0x10, 0x78, 0x26, 0x62, 0xe0, 0x75, 0x05, 0xd3, 0x71, 0xb2, 0xf4, 0x9a,
0x59, 0x71, 0xa7, 0xe3, 0xe8, 0xa0, 0xe9, 0xab, 0xaa, 0x5b, 0x33, 0x87, 0x34, 0xd4, 0xfb, 0x68,
0x99, 0x6e, 0x6a, 0x6e, 0x6d, 0xf9, 0xc4, 0x8e, 0xa9, 0xa4, 0xc0, 0xe1, 0x19, 0xd7, 0xdc, 0xd9,
0xfe, 0x38, 0x0b, 0xb5, 0x44, 0x8b, 0xd0, 0xaf, 0x4f, 0x6c, 0x00, 0x64, 0x06, 0x92, 0xf3, 0x0d,
0x02, 0x24, 0x05, 0x75, 0x6d, 0x9c, 0xb2, 0x89, 0x71, 0x8a, 0x5c, 0x69, 0x72, 0xba, 0x2b, 0xcd,
0x63, 0x28, 0xc7, 0x11, 0xf7, 0xc9, 0x26, 0x89, 0xfa, 0x54, 0x34, 0x47, 0x8c, 0x14, 0x3b, 0xdf,
0x14, 0x74, 0xe7, 0x9b, 0xef, 0x6a, 0xbe, 0x1a, 0x0b, 0x58, 0x8c, 0x91, 0x36, 0xa2, 0xbf, 0x10,
0x4f, 0x0d, 0xe3, 0x23, 0xa8, 0x68, 0x8d, 0xd7, 0x7d, 0x32, 0x32, 0x09, 0x9f, 0x8c, 0x28, 0xee,
0x2a, 0x1b, 0xc7, 0x5d, 0x19, 0xbf, 0x95, 0x85, 0x9a, 0x58, 0x5f, 0x8e, 0x7b, 0x76, 0xe4, 0x8d,
0x9c, 0x01, 0x9a, 0x85, 0xa2, 0x15, 0x26, 0x05, 0x2d, 0xb5, 0xce, 0xe4, 0x12, 0x23, 0x39, 0x4b,
0x0f, 0x2f, 0x25, 0x26, 0x1d, 0x85, 0x97, 0x1a, 0x50, 0x13, 0x8c, 0x11, 0x0d, 0x3c, 0xf1, 0x7d,
0x00, 0x66, 0xe5, 0x94, 0xf3, 0x2d, 0x3b, 0x20, 0x0e, 0xf9, 0x75, 0x58, 0x16, 0x38, 0x18, 0x59,
0x37, 0x76, 0x46, 0x23, 0x87, 0x30, 0xe9, 0xa0, 0xa9, 0x71, 0xca, 0xb9, 0x69, 0x87, 0xfc, 0x40,
0x24, 0xc8, 0xeb, 0x03, 0x4a, 0x43, 0x27, 0xb0, 0x4f, 0x62, 0xef, 0xcb, 0xe8, 0x1b, 0xed, 0xc0,
0xf6, 0x95, 0x66, 0x07, 0xa6, 0x03, 0x88, 0xca, 0xd8, 0xbe, 0x8a, 0xec, 0xc0, 0x33, 0x94, 0x54,
0x9c, 0xa5, 0x24, 0xe3, 0x3f, 0x64, 0xa1, 0xa2, 0x91, 0xe5, 0xab, 0xec, 0xae, 0x77, 0xe7, 0xcc,
0x78, 0x65, 0xdd, 0x62, 0xf7, 0x95, 0x64, 0x95, 0xe8, 0xa9, 0x42, 0x17, 0x15, 0x68, 0x04, 0x7c,
0x07, 0xca, 0x62, 0xd5, 0xbd, 0x87, 0x07, 0xa6, 0xf2, 0x9a, 0x0d, 0x04, 0x1c, 0x4d, 0x4f, 0x54,
0xe2, 0x13, 0x4c, 0x2c, 0xc4, 0x89, 0x4f, 0x44, 0xe2, 0x8b, 0x5c, 0xae, 0xbf, 0x05, 0x55, 0x59,
0x2a, 0xce, 0x29, 0x76, 0x37, 0x5e, 0xf5, 0x89, 0xf9, 0x36, 0x2b, 0x54, 0x1d, 0x4d, 0xbe, 0xcc,
0xf8, 0x44, 0x65, 0x2c, 0xbd, 0x2c, 0xe3, 0x13, 0xfa, 0x30, 0x76, 0x23, 0x2f, 0x76, 0xf4, 0x92,
0x52, 0x7c, 0xec, 0x11, 0x2c, 0x2b, 0x76, 0x35, 0x75, 0x6d, 0xd7, 0xf5, 0xa6, 0xee, 0x80, 0xab,
0x80, 0x2c, 0x26, 0x93, 0x8e, 0xe3, 0x14, 0x63, 0x18, 0x45, 0xec, 0x92, 0xb7, 0xd5, 0x43, 0x28,
0x90, 0x5c, 0x4e, 0xc2, 0x47, 0x3a, 0xe3, 0x22, 0x14, 0xf6, 0x00, 0x0a, 0x24, 0x9e, 0x67, 0x6f,
0x64, 0x36, 0x84, 0x60, 0xb4, 0x80, 0x89, 0x8c, 0x07, 0x3c, 0xf4, 0x9d, 0x41, 0x10, 0xc7, 0x7a,
0x15, 0x84, 0xfe, 0x49, 0x75, 0xc5, 0xc1, 0x15, 0x31, 0x26, 0xea, 0xa8, 0x84, 0x23, 0x36, 0xa6,
0xe5, 0x44, 0x19, 0x52, 0x5c, 0x1a, 0xc1, 0xda, 0x09, 0x0f, 0x2f, 0x39, 0x77, 0x5d, 0x21, 0x0c,
0x0d, 0xb8, 0x1b, 0xfa, 0xf6, 0x48, 0x4c, 0x12, 0xf5, 0xe0, 0xfd, 0xb9, 0x52, 0xe3, 0x33, 0x90,
0xad, 0x38, 0xe3, 0x76, 0x94, 0x8f, 0x78, 0xc7, 0xea, 0x49, 0x5a, 0xda, 0xc6, 0xaf, 0xc1, 0xc6,
0xcd, 0x99, 0x52, 0x22, 0x3a, 0x1f, 0x24, 0xb9, 0x4a, 0x64, 0xb5, 0x1b, 0x79, 0x76, 0x48, 0xad,
0xd1, 0x39, 0x4b, 0x17, 0x2a, 0x5a, 0x4a, 0xbc, 0xf7, 0x67, 0x50, 0xb8, 0xa3, 0x0f, 0xb1, 0x23,
0xb9, 0x9e, 0x3f, 0x46, 0x2b, 0xd9, 0xd0, 0x8a, 0x4b, 0xcf, 0x98, 0x8b, 0x31, 0x1c, 0x43, 0xd8,
0x8d, 0x4d, 0x58, 0x44, 0xc9, 0x5e, 0xdb, 0xe8, 0x5e, 0x24, 0x0c, 0x1a, 0x2b, 0xc0, 0xba, 0xc4,
0xbb, 0x74, 0xe7, 0xcb, 0xff, 0x9a, 0x83, 0x8a, 0x06, 0x16, 0xbb, 0x11, 0xba, 0xeb, 0x59, 0x43,
0xc7, 0x1e, 0x73, 0x65, 0x92, 0xac, 0x99, 0x35, 0x84, 0xee, 0x48, 0xa0, 0xd8, 0x8b, 0xed, 0x8b,
0x33, 0xcb, 0x9b, 0x86, 0xd6, 0x90, 0x9f, 0xf9, 0x5c, 0xb5, 0xb2, 0x6a, 0x5f, 0x9c, 0x1d, 0x4e,
0xc3, 0x1d, 0x84, 0x09, 0x2c, 0xc1, 0x4b, 0x34, 0x2c, 0xe9, 0x61, 0x36, 0xb6, 0xaf, 0x62, 0x2c,
0xe9, 0xe6, 0x48, 0x94, 0x99, 0x8f, 0xdc, 0x1c, 0x49, 0x5b, 0x9c, 0xdd, 0x40, 0x0b, 0xf3, 0x1b,
0xe8, 0x37, 0x61, 0x8d, 0x36, 0x50, 0xc9, 0x9a, 0xad, 0x99, 0x95, 0xbc, 0x82, 0xa9, 0xb2, 0x93,
0x9a, 0xd8, 0xdb, 0x10, 0x3d, 0x50, 0x6c, 0x29, 0x70, 0x7e, 0x44, 0x8c, 0x2c, 0x63, 0x8a, 0x9e,
0xc9, 0xc2, 0x7b, 0xce, 0x8f, 0xb8, 0xc0, 0x44, 0x5f, 0x16, 0x1d, 0x53, 0x06, 0x54, 0x8c, 0x1d,
0x77, 0x16, 0xd3, 0xbe, 0x4a, 0x62, 0x96, 0x25, 0xa6, 0x7d, 0xa5, 0x63, 0xbe, 0x0f, 0xeb, 0x63,
0x3e, 0x74, 0xec, 0x64, 0xb1, 0x56, 0x2c, 0xb8, 0xad, 0x50, 0xb2, 0x96, 0xa7, 0x47, 0x8a, 0xbb,
0x18, 0x8d, 0x1f, 0x79, 0xe3, 0x13, 0x87, 0x64, 0x16, 0xf2, 0xae, 0xc9, 0x9b, 0x75, 0x77, 0x3a,
0xfe, 0x01, 0x82, 0x45, 0x96, 0xc0, 0xa8, 0x41, 0xa5, 0x17, 0x7a, 0x13, 0x35, 0xcd, 0x75, 0xa8,
0xd2, 0xa7, 0x8c, 0x72, 0xbc, 0x03, 0xb7, 0x91, 0x25, 0xf4, 0xbd, 0x89, 0x37, 0xf2, 0xce, 0xae,
0x13, 0xe7, 0x78, 0xff, 0x39, 0x03, 0xcb, 0x89, 0x54, 0xc9, 0x5e, 0xbf, 0x49, 0xfc, 0x2c, 0x0a,
0x55, 0xa3, 0x35, 0xb8, 0xa4, 0xad, 0x41, 0x42, 0x24, 0x66, 0xa6, 0xc2, 0xd7, 0x5a, 0xf1, 0x15,
0x0b, 0x2a, 0x23, 0xb1, 0x94, 0xe6, 0x3c, 0x4b, 0x91, 0xf9, 0xd5, 0xe5, 0x0b, 0xaa, 0x88, 0x5f,
0x92, 0x41, 0x2f, 0x43, 0xd9, 0xe5, 0x5c, 0xd2, 0xad, 0x5f, 0x3f, 0xf3, 0x53, 0x2d, 0x88, 0x0f,
0x02, 0x03, 0xe3, 0x5f, 0x65, 0x00, 0xe2, 0xd6, 0x61, 0x60, 0x41, 0x24, 0xb7, 0xd0, 0xed, 0x65,
0x9a, 0x8c, 0xf2, 0x06, 0x54, 0x23, 0xff, 0xe2, 0x58, 0x12, 0xaa, 0x28, 0x98, 0x10, 0x87, 0xde,
0x86, 0xc5, 0xb3, 0x91, 0x77, 0x82, 0x12, 0xab, 0x94, 0x5b, 0xc8, 0xbb, 0xac, 0x4e, 0x60, 0x25,
0x8d, 0xc4, 0x72, 0x53, 0x3e, 0xd5, 0x05, 0x59, 0x97, 0x82, 0x8c, 0xdf, 0xce, 0x46, 0x8e, 0x96,
0xf1, 0x48, 0xbc, 0x58, 0xbd, 0xfb, 0x69, 0x3c, 0x5f, 0x5e, 0x64, 0x0c, 0xfc, 0x08, 0xea, 0x3e,
0x6d, 0x4a, 0x6a, 0xc7, 0xca, 0xbf, 0x60, 0xc7, 0xaa, 0xf9, 0x09, 0x49, 0xe7, 0x1d, 0x68, 0xd8,
0xc3, 0x0b, 0xee, 0x87, 0x0e, 0x9e, 0xd6, 0xa3, 0x7c, 0x2c, 0x5d, 0x1b, 0x35, 0x38, 0x0a, 0xa2,
0x6f, 0xc3, 0xa2, 0x8c, 0xbc, 0x8d, 0x30, 0xe5, 0x5d, 0x3e, 0x31, 0x58, 0x20, 0x1a, 0xff, 0x46,
0x79, 0x76, 0x26, 0x67, 0xf7, 0xc5, 0xa3, 0xa2, 0xf7, 0x30, 0x3b, 0x6f, 0xee, 0x94, 0x84, 0x24,
0x8d, 0x00, 0x92, 0x1f, 0x11, 0x50, 0x9a, 0x00, 0x92, 0xc3, 0x9a, 0x7f, 0x95, 0x61, 0x35, 0xfe,
0x34, 0x03, 0xc5, 0x3d, 0x6f, 0xb2, 0xe7, 0x90, 0x6b, 0x3d, 0x2e, 0x93, 0xc8, 0x46, 0xb5, 0x20,
0x3e, 0xd1, 0x4d, 0xe7, 0x05, 0x01, 0x66, 0xa9, 0x62, 0x5e, 0x2d, 0x29, 0xe6, 0x7d, 0x17, 0xee,
0xa0, 0x09, 0xd0, 0xf7, 0x26, 0x9e, 0x2f, 0x96, 0xaa, 0x3d, 0x22, 0x71, 0xcf, 0x73, 0xc3, 0x73,
0xc5, 0x3b, 0x6f, 0x9f, 0x72, 0x7e, 0xa4, 0x61, 0x1c, 0x44, 0x08, 0x18, 0xc2, 0x39, 0x0a, 0x2f,
0x2c, 0xd2, 0xd0, 0xa5, 0x3c, 0x4a, 0x1c, 0x75, 0x51, 0x24, 0xb4, 0x11, 0x8e, 0x12, 0xa9, 0xf1,
0x6d, 0x28, 0x47, 0x87, 0x3d, 0xec, 0x5d, 0x28, 0x9f, 0x7b, 0x13, 0x79, 0x22, 0x94, 0x49, 0x04,
0xe1, 0xc9, 0x5e, 0x9b, 0xa5, 0x73, 0xfa, 0x11, 0x18, 0x7f, 0x51, 0x84, 0x62, 0xc7, 0xbd, 0xf0,
0x9c, 0x01, 0xfa, 0x86, 0x8e, 0xf9, 0xd8, 0x53, 0xe1, 0xff, 0xe2, 0x37, 0x7a, 0x52, 0xc5, 0x37,
0xf2, 0xe4, 0xa4, 0x27, 0x55, 0x74, 0x17, 0xcf, 0x2a, 0x2c, 0xf8, 0xfa, 0x95, 0x3a, 0x05, 0x1f,
0xbd, 0xd5, 0xa3, 0xfd, 0xb2, 0xa0, 0x5d, 0x9f, 0x20, 0xca, 0xa2, 0xab, 0x5e, 0x70, 0xc8, 0x28,
0x1c, 0xb3, 0x8c, 0x10, 0x1c, 0xb0, 0xd7, 0xa0, 0x28, 0x63, 0xde, 0x28, 0x82, 0x88, 0xdc, 0xcb,
0x25, 0x08, 0xa9, 0xc1, 0xe7, 0x64, 0xc2, 0x8d, 0x04, 0xd9, 0x9c, 0x59, 0x55, 0xc0, 0x1d, 0x41,
0x6b, 0xf7, 0xa0, 0x42, 0xf8, 0x84, 0x52, 0x92, 0x2e, 0x95, 0x08, 0x42, 0x84, 0x94, 0x9b, 0xa9,
0xca, 0xa9, 0x37, 0x53, 0xa1, 0xf3, 0x6f, 0xc4, 0x65, 0xa9, 0x8b, 0x40, 0xf7, 0x11, 0x69, 0x70,
0x75, 0x2d, 0x9b, 0x3c, 0x53, 0xa1, 0xe8, 0x64, 0x75, 0xa6, 0xf2, 0x15, 0xa8, 0x9d, 0xda, 0xa3,
0xd1, 0x89, 0x3d, 0x78, 0x4e, 0x47, 0x01, 0x55, 0x3a, 0xfd, 0x54, 0x40, 0x3c, 0x0b, 0xb8, 0x07,
0x15, 0x6d, 0x96, 0xd1, 0x5f, 0x32, 0x6f, 0x42, 0x3c, 0xbf, 0xb3, 0x27, 0x7c, 0xf5, 0x57, 0x38,
0xe1, 0xd3, 0xfc, 0x46, 0x17, 0x93, 0x7e, 0xa3, 0x77, 0x90, 0x9b, 0x4a, 0x07, 0xc1, 0x06, 0x5d,
0x7e, 0x63, 0x0f, 0x87, 0xe8, 0x20, 0x48, 0x37, 0x4d, 0xe2, 0xe0, 0x51, 0xfa, 0x12, 0xe9, 0x12,
0x04, 0x23, 0x94, 0xbb, 0x74, 0x4c, 0x3d, 0xb1, 0x9d, 0x21, 0x86, 0x08, 0xd0, 0xe9, 0x41, 0xd1,
0x1e, 0x87, 0x47, 0xb6, 0x33, 0x64, 0xf7, 0xa1, 0xaa, 0x92, 0x71, 0x77, 0x5c, 0xa6, 0xf1, 0x97,
0xc9, 0x62, 0x4f, 0x34, 0xa0, 0x16, 0x61, 0x8c, 0xe3, 0x10, 0xe3, 0x8a, 0x44, 0x41, 0x3a, 0x78,
0x0f, 0x7d, 0x72, 0x42, 0x8e, 0x81, 0xc4, 0xf5, 0x27, 0x77, 0x64, 0x5f, 0x25, 0x95, 0xaa, 0xff,
0x64, 0x1c, 0x23, 0x4c, 0x21, 0xdc, 0x91, 0x8d, 0x6e, 0x2d, 0x21, 0xff, 0x4a, 0x54, 0xb4, 0xd1,
0x11, 0x02, 0xfb, 0xb6, 0xa6, 0xbf, 0x36, 0x11, 0xf9, 0xb5, 0x99, 0xf2, 0x6f, 0x8a, 0x90, 0xba,
0x0b, 0xe0, 0x04, 0x62, 0x97, 0x09, 0xb8, 0x3b, 0xc4, 0x98, 0xe0, 0x92, 0x59, 0x76, 0x82, 0x67,
0x04, 0xf8, 0xf9, 0x2a, 0xb6, 0x2d, 0xa8, 0xea, 0xdd, 0x64, 0x25, 0xc8, 0x1f, 0x1e, 0xb5, 0xbb,
0x8d, 0x5b, 0xac, 0x02, 0xc5, 0x5e, 0xbb, 0xdf, 0xdf, 0x47, 0x4b, 0x5f, 0x15, 0x4a, 0x51, 0x40,
0x62, 0x56, 0x7c, 0xb5, 0xb6, 0xb7, 0xdb, 0x47, 0xfd, 0xf6, 0x4e, 0x23, 0xf7, 0xfd, 0x7c, 0x29,
0xdb, 0xc8, 0x19, 0x7f, 0x99, 0x83, 0x8a, 0x36, 0x0a, 0x2f, 0x66, 0xc6, 0x77, 0x01, 0x50, 0x93,
0x8c, 0xfd, 0x47, 0xf3, 0x66, 0x59, 0x40, 0x68, 0xf2, 0x75, 0x1b, 0x45, 0x8e, 0x6e, 0x55, 0x52,
0x36, 0x8a, 0xaf, 0x40, 0x8d, 0x2e, 0x28, 0xd2, 0xed, 0xb5, 0x05, 0xb3, 0x4a, 0x40, 0xc9, 0xaa,
0x31, 0xa2, 0x19, 0x91, 0x30, 0xd6, 0x4d, 0x5e, 0x57, 0x42, 0x20, 0x8c, 0x76, 0xc3, 0x50, 0xc5,
0xc0, 0x1b, 0x5d, 0x70, 0xc2, 0x20, 0x89, 0xb0, 0x22, 0x61, 0x7d, 0x19, 0x9b, 0x2d, 0xf9, 0xa1,
0x16, 0x52, 0x5b, 0x30, 0xab, 0x04, 0x94, 0x15, 0x7d, 0x5d, 0x11, 0x50, 0x09, 0x09, 0x68, 0x7d,
0x9e, 0x1a, 0x12, 0xc4, 0xb3, 0x3f, 0x77, 0x8c, 0x58, 0x46, 0xc2, 0xf8, 0xea, 0x7c, 0xbe, 0x97,
0x1f, 0x27, 0xb2, 0x77, 0x81, 0x8d, 0x27, 0x13, 0x2b, 0xe5, 0x80, 0x2f, 0x6f, 0x2e, 0x8e, 0x27,
0x93, 0xbe, 0x76, 0xfe, 0xf5, 0x73, 0x38, 0x7b, 0xfc, 0x1c, 0x58, 0x4b, 0x2c, 0x60, 0x6c, 0x62,
0xa4, 0x8a, 0xc5, 0x6c, 0x39, 0xa3, 0xb3, 0xe5, 0x14, 0xee, 0x97, 0x4d, 0xe5, 0x7e, 0x2f, 0xe2,
0x13, 0xc6, 0x2e, 0x54, 0x8e, 0xb4, 0xeb, 0xcf, 0xee, 0x8b, 0x1d, 0x42, 0x5d, 0x7c, 0x46, 0x7b,
0x07, 0x9d, 0x29, 0xfa, 0xf2, 0xbe, 0x33, 0xad, 0x35, 0x59, 0xad, 0x35, 0xc6, 0xbf, 0xcc, 0xd0,
0xd5, 0x32, 0x51, 0xe3, 0xe3, 0x1b, 0xd7, 0x94, 0xf9, 0x2d, 0x8e, 0x7c, 0xaf, 0x28, 0xb3, 0x9b,
0x0c, 0x5a, 0xc7, 0xa6, 0x59, 0xde, 0xe9, 0x69, 0xc0, 0x95, 0x8f, 0x47, 0x05, 0x61, 0x87, 0x08,
0x52, 0xc2, 0xb7, 0x90, 0xf0, 0x1d, 0x2a, 0x3f, 0x90, 0x8e, 0x1d, 0x42, 0xf8, 0x3e, 0xb0, 0xaf,
0x64, 0xad, 0x81, 0x10, 0x41, 0xa4, 0x7d, 0x40, 0x45, 0xae, 0x46, 0xdf, 0xc6, 0x3f, 0x93, 0xc1,
0xf9, 0xb3, 0xe3, 0xfb, 0x10, 0x4a, 0x51, 0xa9, 0xc9, 0x1d, 0x56, 0x61, 0x46, 0xe9, 0x62, 0x1f,
0xc7, 0xc3, 0x90, 0x44, 0x8b, 0x69, 0x71, 0xa1, 0x8d, 0xa7, 0xa3, 0xb5, 0xfa, 0x6b, 0xc0, 0x4e,
0x1d, 0x7f, 0x16, 0x99, 0x16, 0x5b, 0x03, 0x53, 0x34, 0x6c, 0xe3, 0x18, 0x96, 0x15, 0x97, 0xd0,
0x34, 0x82, 0xe4, 0xe4, 0x65, 0x5e, 0xc2, 0xe4, 0xb3, 0x73, 0x4c, 0xde, 0xf8, 0x49, 0x1e, 0x8a,
0xea, 0x2a, 0xc1, 0xb4, 0xeb, 0xef, 0xca, 0xc9, 0xeb, 0xef, 0x9a, 0x89, 0xab, 0x92, 0x70, 0xea,
0xe5, 0x7e, 0xff, 0xf6, 0xec, 0x96, 0xad, 0xd9, 0x2a, 0x12, 0xdb, 0xf6, 0x1a, 0xe4, 0x27, 0x76,
0x78, 0x8e, 0xe7, 0x92, 0x44, 0x3c, 0xf8, 0xad, 0x6c, 0x18, 0x85, 0xa4, 0x0d, 0x23, 0xed, 0xaa,
0x40, 0x12, 0x49, 0xe7, 0xae, 0x0a, 0xbc, 0x03, 0x24, 0x5f, 0x68, 0x2e, 0x6a, 0x25, 0x04, 0x88,
0xbd, 0x28, 0x29, 0x8e, 0x94, 0x66, 0xc5, 0x91, 0x57, 0x16, 0x15, 0xbe, 0x09, 0x0b, 0x74, 0xcd,
0x86, 0x8c, 0xd0, 0x55, 0x1b, 0x8a, 0x1c, 0x43, 0xf5, 0x9f, 0xe2, 0x16, 0x4c, 0x89, 0xab, 0xdf,
0xbb, 0x55, 0x49, 0xdc, 0xbb, 0xa5, 0xdb, 0x56, 0xaa, 0x49, 0xdb, 0xca, 0x03, 0x68, 0x44, 0x03,
0x8a, 0x27, 0x95, 0x6e, 0x20, 0xe3, 0xff, 0xea, 0x0a, 0x2e, 0xb8, 0x64, 0x37, 0x88, 0x37, 0xc4,
0x7a, 0x62, 0x43, 0x14, 0x3c, 0xac, 0x15, 0x86, 0x7c, 0x3c, 0x09, 0xe5, 0x86, 0x88, 0x11, 0x42,
0x7a, 0x03, 0x93, 0xb1, 0xeb, 0x35, 0x28, 0x77, 0xba, 0xd6, 0xee, 0x7e, 0xe7, 0xe9, 0x5e, 0xbf,
0x91, 0x11, 0x9f, 0xbd, 0xe3, 0xed, 0xed, 0x76, 0x7b, 0x07, 0x77, 0x1c, 0x80, 0x85, 0xdd, 0x56,
0x47, 0xec, 0x3e, 0x39, 0xe3, 0x77, 0xb3, 0x50, 0xd1, 0x8a, 0x67, 0xef, 0x47, 0xa3, 0x42, 0x57,
0x33, 0xdd, 0x9d, 0x6f, 0xc2, 0xa6, 0x62, 0xc5, 0xda, 0xb0, 0x44, 0x17, 0x23, 0x66, 0x6f, 0xbc,
0x18, 0x91, 0xbd, 0x05, 0x8b, 0x36, 0x95, 0x10, 0x8d, 0x82, 0x3c, 0x85, 0x97, 0x60, 0x39, 0x08,
0xe8, 0x98, 0x19, 0xef, 0x27, 0x02, 0x2f, 0xaf, 0x7c, 0x21, 0xa3, 0x2d, 0x05, 0x07, 0xab, 0x78,
0x6a, 0x3b, 0xa3, 0xa9, 0xcf, 0xa5, 0xd5, 0x3c, 0xda, 0x99, 0x09, 0x6a, 0xaa, 0x64, 0xe3, 0x03,
0x80, 0xb8, 0xcd, 0xc9, 0xc1, 0xb9, 0x95, 0x1c, 0x9c, 0x8c, 0x36, 0x38, 0x59, 0x63, 0x87, 0xd8,
0x88, 0x1c, 0xe8, 0xe8, 0xd8, 0xed, 0xeb, 0xa0, 0x0e, 0x02, 0x2d, 0x74, 0x8f, 0x9e, 0x8c, 0x78,
0xa8, 0xa2, 0xfc, 0x97, 0x64, 0x4a, 0x27, 0x4a, 0x50, 0x97, 0x6e, 0xc4, 0xa5, 0xc4, 0xdc, 0x48,
0x92, 0xe4, 0x2c, 0x37, 0x92, 0xa8, 0x66, 0x94, 0x6e, 0x6c, 0x40, 0x73, 0x87, 0x8b, 0xd2, 0x5a,
0xa3, 0xd1, 0x4c, 0x73, 0x8c, 0x3b, 0x70, 0x3b, 0x25, 0x4d, 0x1e, 0x42, 0x7c, 0x0c, 0xab, 0x2d,
0x0a, 0xe8, 0xff, 0x79, 0x45, 0xee, 0x19, 0x4d, 0x58, 0x9b, 0x2d, 0x52, 0x56, 0xb6, 0x0b, 0x4b,
0x3b, 0xfc, 0x64, 0x7a, 0xb6, 0xcf, 0x2f, 0xe2, 0x8a, 0x18, 0xe4, 0x83, 0x73, 0xef, 0x52, 0x8e,
0x0f, 0xfe, 0x46, 0x2f, 0x43, 0x81, 0x63, 0x05, 0x13, 0x3e, 0x50, 0x07, 0xd1, 0x08, 0xe9, 0x4d,
0xf8, 0xc0, 0x78, 0x1f, 0x98, 0x5e, 0x8e, 0x1c, 0x2f, 0xa1, 0x25, 0x4c, 0x4f, 0xac, 0xe0, 0x3a,
0x08, 0xf9, 0x58, 0x45, 0xac, 0x41, 0x30, 0x3d, 0xe9, 0x11, 0xc4, 0x78, 0x1b, 0xaa, 0x47, 0xf6,
0xb5, 0xc9, 0x3f, 0x97, 0x81, 0x61, 0xeb, 0x50, 0x9c, 0xd8, 0xd7, 0x82, 0x0d, 0x44, 0x36, 0x29,
0x4c, 0x36, 0xfe, 0x28, 0x0f, 0x0b, 0x84, 0xc9, 0xee, 0xd3, 0xe5, 0xbc, 0x8e, 0x8b, 0xcb, 0x50,
0x31, 0x4a, 0x0d, 0x34, 0xc7, 0x4b, 0xb3, 0xf3, 0xbc, 0x54, 0x1e, 0xa0, 0xa9, 0x4b, 0x89, 0x94,
0xf5, 0xc0, 0x9d, 0x8e, 0xd5, 0x4d, 0x44, 0xc9, 0xa8, 0xf6, 0x7c, 0x7c, 0xf9, 0x32, 0x85, 0xfc,
0x26, 0xed, 0xbb, 0xb1, 0x2e, 0x42, 0xad, 0x53, 0x5b, 0x84, 0x64, 0x97, 0x3a, 0x28, 0x55, 0xe1,
0x29, 0xaa, 0x68, 0xc7, 0xa4, 0xc2, 0x33, 0xa7, 0xd8, 0x94, 0x5e, 0xae, 0xd8, 0xd0, 0xc9, 0xda,
0x0b, 0x14, 0x1b, 0x78, 0x05, 0xc5, 0xe6, 0x15, 0x6c, 0xab, 0xb7, 0xa1, 0x84, 0xfb, 0xbe, 0xc6,
0x3d, 0xc5, 0x7e, 0x2f, 0xb8, 0xe7, 0xb7, 0x34, 0xd1, 0x9f, 0x1c, 0x3b, 0xee, 0xc4, 0xcb, 0xc4,
0xe4, 0x9f, 0xff, 0x62, 0x6c, 0x56, 0x9f, 0x41, 0x51, 0x42, 0x05, 0x41, 0xbb, 0xf6, 0x58, 0xdd,
0xeb, 0x86, 0xbf, 0xc5, 0xb0, 0xe1, 0x65, 0x54, 0x9f, 0x4f, 0x1d, 0x9f, 0x0f, 0xd5, 0x85, 0x3d,
0x0e, 0xae, 0x51, 0x01, 0x11, 0x1d, 0x14, 0x6a, 0x88, 0xeb, 0x5d, 0xba, 0xf2, 0xba, 0x8e, 0xa2,
0x13, 0x3c, 0x13, 0x9f, 0x06, 0x83, 0x06, 0xde, 0xec, 0x38, 0xf1, 0x7c, 0xb5, 0x39, 0x19, 0x3f,
0xc9, 0x40, 0x43, 0xae, 0xae, 0x28, 0x4d, 0xd7, 0x02, 0x0a, 0x37, 0xf9, 0x21, 0xbc, 0xf8, 0xfa,
0x1d, 0x03, 0x6a, 0x78, 0xf8, 0x11, 0xed, 0x54, 0x74, 0x78, 0x53, 0x11, 0xc0, 0x5d, 0xb9, 0x5b,
0xbd, 0x0e, 0x15, 0xe5, 0x03, 0x3d, 0x76, 0x46, 0xea, 0x9e, 0x75, 0x72, 0x82, 0x3e, 0x70, 0x46,
0x6a, 0xa3, 0xf3, 0x6d, 0x19, 0x7d, 0x9b, 0xc1, 0x8d, 0xce, 0xb4, 0x43, 0x6e, 0xfc, 0xbb, 0x0c,
0x2c, 0x69, 0x5d, 0x91, 0xeb, 0xf6, 0x43, 0xa8, 0x46, 0x57, 0xaa, 0xf2, 0x48, 0xf2, 0x5a, 0x4f,
0x32, 0x9a, 0x38, 0x5b, 0x65, 0x10, 0x41, 0x02, 0xd1, 0x98, 0xa1, 0x7d, 0x4d, 0x8e, 0xba, 0xd3,
0xb1, 0x52, 0x6e, 0x86, 0xf6, 0xf5, 0x2e, 0xe7, 0xbd, 0xe9, 0x58, 0xa8, 0xae, 0x97, 0x9c, 0x3f,
0x8f, 0x10, 0x48, 0xe6, 0x02, 0x01, 0x93, 0x18, 0x06, 0xd4, 0xc6, 0x9e, 0x1b, 0x9e, 0x47, 0x28,
0x52, 0xea, 0x44, 0x20, 0xe1, 0x18, 0x7f, 0x9e, 0x85, 0x65, 0x3a, 0x62, 0x93, 0x47, 0x9b, 0x92,
0x75, 0x35, 0x61, 0x81, 0x4e, 0x1b, 0x89, 0x79, 0xed, 0xdd, 0x32, 0xe5, 0x37, 0xfb, 0xe6, 0x2b,
0x1e, 0x0b, 0xaa, 0x00, 0xdf, 0x1b, 0x86, 0x3f, 0x37, 0x3f, 0xfc, 0x37, 0x0f, 0x6f, 0x9a, 0xa1,
0xb3, 0x90, 0x66, 0xe8, 0x7c, 0x15, 0xf3, 0xe2, 0x5c, 0x28, 0x6a, 0x51, 0xe2, 0x68, 0xa1, 0xa8,
0xef, 0xc3, 0x7a, 0x02, 0x07, 0xb9, 0xb5, 0x73, 0xea, 0x70, 0x75, 0x1b, 0xca, 0x8a, 0x86, 0xdd,
0x53, 0x69, 0x5b, 0x45, 0x28, 0x04, 0x03, 0x6f, 0xc2, 0x8d, 0x35, 0x58, 0x49, 0x8e, 0xaa, 0xdc,
0x26, 0x7e, 0x2f, 0x03, 0x4d, 0xe9, 0x96, 0xe2, 0xb8, 0x67, 0x7b, 0x4e, 0x10, 0x7a, 0x7e, 0x74,
0xf5, 0xe8, 0x5d, 0x80, 0x20, 0xb4, 0x7d, 0xa9, 0x6d, 0xca, 0xfb, 0x3f, 0x10, 0x82, 0x9a, 0xe4,
0x6d, 0x28, 0x71, 0x77, 0x48, 0x89, 0x44, 0x0d, 0x45, 0xee, 0x0e, 0x95, 0x1e, 0x3a, 0x27, 0x7f,
0xd7, 0x92, 0xea, 0x85, 0x0c, 0xc7, 0x17, 0xa3, 0xc3, 0x2f, 0x70, 0xe3, 0xcd, 0x47, 0xe1, 0xf8,
0x07, 0xf6, 0x15, 0x3a, 0x79, 0x06, 0xc6, 0x3f, 0xce, 0xc2, 0x62, 0xdc, 0x3e, 0xba, 0xcb, 0xe3,
0xc5, 0xb7, 0x92, 0xdc, 0x97, 0xe4, 0xe0, 0x08, 0xf9, 0x5d, 0x3b, 0x78, 0x2c, 0xd1, 0xe2, 0xec,
0xb8, 0xcc, 0x80, 0x8a, 0xc2, 0xf0, 0xa6, 0xa1, 0x76, 0x03, 0x60, 0x99, 0x50, 0x0e, 0xa7, 0xa1,
0x50, 0xb8, 0x84, 0xe6, 0xe9, 0xb8, 0x52, 0xe5, 0x29, 0xd8, 0xe3, 0xb0, 0x83, 0x0f, 0x0b, 0x08,
0xb0, 0xc8, 0x46, 0x13, 0x29, 0xb0, 0x04, 0x7e, 0x83, 0xe4, 0x6c, 0x9a, 0x39, 0x94, 0xb1, 0x75,
0x21, 0x94, 0xee, 0x58, 0x8e, 0x84, 0xd0, 0xd7, 0xa1, 0x42, 0x85, 0xc7, 0x91, 0xc7, 0x79, 0xb3,
0x8c, 0x35, 0x60, 0xba, 0x3c, 0x04, 0xf2, 0xa6, 0x09, 0xd5, 0x17, 0xa8, 0x2a, 0xf4, 0xfa, 0xf8,
0xfb, 0x19, 0xb8, 0x9d, 0x32, 0x6d, 0x72, 0x95, 0x6f, 0xc3, 0xd2, 0x69, 0x94, 0xa8, 0x46, 0x97,
0x96, 0xfa, 0x9a, 0x62, 0xab, 0xc9, 0x31, 0x35, 0x1b, 0xa7, 0x49, 0x40, 0xac, 0x74, 0xd1, 0x0c,
0x26, 0xe2, 0xda, 0x51, 0xe9, 0xa2, 0x69, 0x24, 0x7d, 0xe7, 0x08, 0x36, 0xda, 0x57, 0x82, 0x63,
0x6c, 0xeb, 0x2f, 0x63, 0x28, 0x32, 0x4a, 0x1e, 0x30, 0x67, 0x5e, 0xe9, 0x80, 0x79, 0x48, 0x81,
0xb0, 0x51, 0x59, 0x3f, 0x4d, 0x21, 0xb8, 0x81, 0x8a, 0x3c, 0xf4, 0xb2, 0x87, 0x0a, 0x70, 0x1f,
0x44, 0x2f, 0x7a, 0x18, 0x01, 0x2c, 0x1e, 0x4c, 0x47, 0xa1, 0x13, 0x3f, 0xf2, 0xc1, 0xbe, 0x29,
0xf3, 0x60, 0x3d, 0x6a, 0xd4, 0x52, 0x2b, 0x82, 0xa8, 0x22, 0x1c, 0xac, 0xb1, 0x28, 0xc8, 0x9a,
0xaf, 0x6f, 0x71, 0x9c, 0xac, 0xc1, 0xb8, 0x0d, 0xeb, 0xf1, 0x17, 0x0d, 0x9b, 0xda, 0x6a, 0xfe,
0x45, 0x86, 0x3c, 0xca, 0x93, 0x0f, 0x8e, 0xb0, 0x36, 0x2c, 0x07, 0x8e, 0x7b, 0x36, 0xe2, 0x7a,
0xf1, 0x81, 0x1c, 0x84, 0xd5, 0x64, 0xdb, 0xe4, 0xa3, 0x24, 0xe6, 0x12, 0xe5, 0x88, 0x4b, 0x0b,
0xd8, 0xd6, 0x4d, 0x8d, 0x8c, 0xc9, 0x62, 0x66, 0x34, 0xe6, 0x1b, 0xdf, 0x81, 0x7a, 0xb2, 0x22,
0xf6, 0x2d, 0x19, 0x3f, 0x1e, 0xb7, 0x2a, 0x37, 0x13, 0x5c, 0x1b, 0x13, 0x44, 0x25, 0x1e, 0xfb,
0xc0, 0xf8, 0x87, 0x19, 0x68, 0x9a, 0x5c, 0x50, 0xae, 0xd6, 0x4a, 0x45, 0x33, 0x1f, 0xce, 0x95,
0x7a, 0x73, 0x5f, 0x55, 0x58, 0xba, 0x6a, 0xd1, 0xd7, 0x6e, 0x9c, 0x8c, 0xbd, 0x5b, 0x73, 0x3d,
0xda, 0x2a, 0xc1, 0x02, 0xa1, 0x18, 0xeb, 0xb0, 0x2a, 0xdb, 0xa3, 0xda, 0x12, 0x5b, 0x0f, 0x13,
0x35, 0x26, 0xac, 0x87, 0x1b, 0xd0, 0xa4, 0x40, 0x51, 0xbd, 0x13, 0x32, 0xe3, 0x0e, 0xb0, 0x03,
0x7b, 0x60, 0xfb, 0x9e, 0xe7, 0x1e, 0x71, 0x5f, 0xfa, 0xe7, 0xa2, 0x84, 0x89, 0xc6, 0x35, 0x25,
0x0a, 0xd3, 0x97, 0xba, 0xf7, 0xd4, 0x73, 0x95, 0x3b, 0x12, 0x7d, 0x19, 0x26, 0x2c, 0x6f, 0xd9,
0xcf, 0xb9, 0x2a, 0x49, 0x0d, 0xd1, 0x47, 0x50, 0x99, 0x44, 0x85, 0xaa, 0x71, 0x57, 0xf7, 0x5b,
0xcc, 0x57, 0x6b, 0xea, 0xd8, 0xc6, 0x13, 0x58, 0x49, 0x96, 0x29, 0x59, 0xc7, 0x06, 0x94, 0xc6,
0x12, 0x26, 0x5b, 0x17, 0x7d, 0x1b, 0xbf, 0x53, 0x82, 0xa2, 0xd4, 0xe7, 0xd8, 0x26, 0xe4, 0x07,
0xca, 0x25, 0x2c, 0xbe, 0x36, 0x49, 0xa6, 0xaa, 0xff, 0xdb, 0xe8, 0x18, 0x26, 0xf0, 0xd8, 0x47,
0x50, 0x4f, 0x5a, 0x45, 0x67, 0xc2, 0xd0, 0x93, 0xe6, 0xcc, 0xda, 0x60, 0xc6, 0xfe, 0x55, 0x8e,
0x37, 0x47, 0x92, 0x19, 0x4a, 0xe7, 0xda, 0xee, 0xe9, 0xb9, 0x42, 0xde, 0x0e, 0xce, 0x6d, 0xeb,
0xc9, 0xfb, 0x1f, 0xc8, 0x38, 0xf4, 0x0a, 0x02, 0x7b, 0xe7, 0xf6, 0x93, 0xf7, 0x3f, 0x98, 0x95,
0xa4, 0x65, 0x14, 0xba, 0x26, 0x49, 0xaf, 0x40, 0x81, 0x2e, 0xf8, 0x24, 0xdf, 0x1e, 0xfa, 0x60,
0x8f, 0x61, 0x45, 0xaa, 0xad, 0x96, 0xf4, 0xc2, 0x26, 0x2e, 0x58, 0xa2, 0xc0, 0x37, 0x99, 0xd6,
0xc3, 0x24, 0x3a, 0x1b, 0x5a, 0x83, 0x85, 0xf3, 0xf8, 0xb6, 0xd6, 0x9a, 0x29, 0xbf, 0x8c, 0x3f,
0x2f, 0x40, 0x45, 0x1b, 0x14, 0x56, 0x85, 0x92, 0xd9, 0xee, 0xb5, 0xcd, 0x4f, 0xda, 0x3b, 0x8d,
0x5b, 0xec, 0x01, 0xbc, 0xd9, 0xe9, 0x6e, 0x1f, 0x9a, 0x66, 0x7b, 0xbb, 0x6f, 0x1d, 0x9a, 0x96,
0xba, 0xbc, 0xeb, 0xa8, 0xf5, 0xd9, 0x41, 0xbb, 0xdb, 0xb7, 0x76, 0xda, 0xfd, 0x56, 0x67, 0xbf,
0xd7, 0xc8, 0xb0, 0xd7, 0xa0, 0x19, 0x63, 0xaa, 0xe4, 0xd6, 0xc1, 0xe1, 0x71, 0xb7, 0xdf, 0xc8,
0xb2, 0x7b, 0x70, 0x67, 0xb7, 0xd3, 0x6d, 0xed, 0x5b, 0x31, 0xce, 0xf6, 0x7e, 0xff, 0x13, 0xab,
0xfd, 0x2b, 0x47, 0x1d, 0xf3, 0xb3, 0x46, 0x2e, 0x0d, 0x41, 0x28, 0xe3, 0xaa, 0x84, 0x3c, 0xbb,
0x0d, 0xab, 0x84, 0x40, 0x59, 0xac, 0xfe, 0xe1, 0xa1, 0xd5, 0x3b, 0x3c, 0xec, 0x36, 0x0a, 0x6c,
0x09, 0x6a, 0x9d, 0xee, 0x27, 0xad, 0xfd, 0xce, 0x8e, 0x65, 0xb6, 0x5b, 0xfb, 0x07, 0x8d, 0x05,
0xb6, 0x0c, 0x8b, 0xb3, 0x78, 0x45, 0x51, 0x84, 0xc2, 0x3b, 0xec, 0x76, 0x0e, 0xbb, 0xd6, 0x27,
0x6d, 0xb3, 0xd7, 0x39, 0xec, 0x36, 0x4a, 0x6c, 0x0d, 0x58, 0x32, 0x69, 0xef, 0xa0, 0xb5, 0xdd,
0x28, 0xb3, 0x55, 0x58, 0x4a, 0xc2, 0x9f, 0xb5, 0x3f, 0x6b, 0x00, 0x6b, 0xc2, 0x0a, 0x35, 0xcc,
0xda, 0x6a, 0xef, 0x1f, 0x7e, 0x6a, 0x1d, 0x74, 0xba, 0x9d, 0x83, 0xe3, 0x83, 0x46, 0x05, 0xaf,
0x13, 0x6c, 0xb7, 0xad, 0x4e, 0xb7, 0x77, 0xbc, 0xbb, 0xdb, 0xd9, 0xee, 0xb4, 0xbb, 0xfd, 0x46,
0x95, 0x6a, 0x4e, 0xeb, 0x78, 0x4d, 0x64, 0x90, 0xa1, 0x1a, 0xd6, 0x4e, 0xa7, 0xd7, 0xda, 0xda,
0x6f, 0xef, 0x34, 0xea, 0xec, 0x2e, 0xdc, 0xee, 0xb7, 0x0f, 0x8e, 0x0e, 0xcd, 0x96, 0xf9, 0x99,
0x0a, 0xe5, 0xb0, 0x76, 0x5b, 0x9d, 0xfd, 0x63, 0xb3, 0xdd, 0x58, 0x64, 0x6f, 0xc0, 0x5d, 0xb3,
0xfd, 0xf1, 0x71, 0xc7, 0x6c, 0xef, 0x58, 0xdd, 0xc3, 0x9d, 0xb6, 0xb5, 0xdb, 0x6e, 0xf5, 0x8f,
0xcd, 0xb6, 0x75, 0xd0, 0xe9, 0xf5, 0x3a, 0xdd, 0xa7, 0x8d, 0x06, 0x7b, 0x13, 0xee, 0x47, 0x28,
0x51, 0x01, 0x33, 0x58, 0x4b, 0xa2, 0x7f, 0x6a, 0x4a, 0xbb, 0xed, 0x5f, 0xe9, 0x5b, 0x47, 0xed,
0xb6, 0xd9, 0x60, 0x6c, 0x03, 0xd6, 0xe2, 0xea, 0xa9, 0x02, 0x59, 0xf7, 0xb2, 0x48, 0x3b, 0x6a,
0x9b, 0x07, 0xad, 0xae, 0x98, 0xe0, 0x44, 0xda, 0x8a, 0x68, 0x76, 0x9c, 0x36, 0xdb, 0xec, 0x55,
0xc6, 0xa0, 0xae, 0xcd, 0xca, 0x6e, 0xcb, 0x6c, 0xac, 0xb1, 0x45, 0xa8, 0x1c, 0x1c, 0x1d, 0x59,
0xfd, 0xce, 0x41, 0xfb, 0xf0, 0xb8, 0xdf, 0x58, 0x67, 0xab, 0xd0, 0xe8, 0x74, 0xfb, 0x6d, 0x53,
0xcc, 0xb5, 0xca, 0xfa, 0xbf, 0x8a, 0x6c, 0x05, 0x16, 0x55, 0x4b, 0x15, 0xf4, 0xaf, 0x8a, 0x6c,
0x1d, 0xd8, 0x71, 0xd7, 0x6c, 0xb7, 0x76, 0xc4, 0xc0, 0x45, 0x09, 0xff, 0xbb, 0x28, 0x2d, 0x24,
0x3f, 0xc9, 0x45, 0x9b, 0x75, 0xec, 0x72, 0x90, 0xbc, 0xbb, 0xbb, 0xaa, 0xdd, 0xb9, 0xfd, 0xb2,
0x57, 0x35, 0x34, 0xd5, 0x2a, 0x37, 0xa7, 0x5a, 0xcd, 0xe9, 0xee, 0x35, 0x5d, 0xf6, 0xfb, 0x0a,
0xd4, 0xc6, 0x74, 0x8f, 0xb7, 0xbc, 0xaf, 0x17, 0xa4, 0xff, 0x0d, 0x01, 0xe9, 0xb2, 0xde, 0xb9,
0x67, 0x25, 0x0a, 0xf3, 0xcf, 0x4a, 0xa4, 0xc9, 0xf7, 0x0b, 0x69, 0xf2, 0xfd, 0x43, 0x58, 0x22,
0xd6, 0xe4, 0xb8, 0xce, 0x58, 0x69, 0xcd, 0x24, 0x05, 0x2e, 0x22, 0x8b, 0x22, 0xb8, 0x52, 0x27,
0x94, 0xca, 0x21, 0x59, 0x48, 0x51, 0x6a, 0x1b, 0x09, 0x4d, 0x83, 0x38, 0x47, 0xa4, 0x69, 0x44,
0x35, 0xd8, 0x57, 0x71, 0x0d, 0x15, 0xad, 0x06, 0x82, 0x63, 0x0d, 0x0f, 0x61, 0x89, 0x5f, 0x85,
0xbe, 0x6d, 0x79, 0x13, 0xfb, 0xf3, 0x29, 0x9a, 0x70, 0x6d, 0xd4, 0xe1, 0xab, 0xe6, 0x22, 0x26,
0x1c, 0x22, 0x7c, 0xc7, 0x0e, 0xed, 0x87, 0x5f, 0x40, 0x45, 0xbb, 0xe3, 0x9d, 0xad, 0xc3, 0xf2,
0xa7, 0x9d, 0x7e, 0xb7, 0xdd, 0xeb, 0x59, 0x47, 0xc7, 0x5b, 0xcf, 0xda, 0x9f, 0x59, 0x7b, 0xad,
0xde, 0x5e, 0xe3, 0x96, 0x58, 0xb4, 0xdd, 0x76, 0xaf, 0xdf, 0xde, 0x49, 0xc0, 0x33, 0xec, 0x75,
0xd8, 0x38, 0xee, 0x1e, 0xf7, 0xda, 0x3b, 0x56, 0x5a, 0xbe, 0xac, 0xa0, 0x52, 0x99, 0x9e, 0x92,
0x3d, 0xf7, 0xf0, 0x7b, 0x50, 0x4f, 0x5e, 0x3c, 0xcc, 0x00, 0x16, 0xf6, 0xdb, 0x4f, 0x5b, 0xdb,
0x9f, 0xd1, 0x85, 0xa3, 0xbd, 0x7e, 0xab, 0xdf, 0xd9, 0xb6, 0xe4, 0x05, 0xa3, 0x82, 0x23, 0x64,
0x58, 0x05, 0x8a, 0xad, 0xee, 0xf6, 0xde, 0xa1, 0xd9, 0x6b, 0x64, 0x1f, 0x7e, 0x07, 0xea, 0x49,
0xef, 0xba, 0xe4, 0xb9, 0xeb, 0x06, 0xac, 0x6d, 0xb5, 0xfb, 0x9f, 0xb6, 0xdb, 0x5d, 0x6c, 0xdc,
0x76, 0xbb, 0xdb, 0x37, 0x5b, 0xfb, 0x9d, 0xfe, 0x67, 0x8d, 0xcc, 0xc3, 0x8f, 0xa0, 0x31, 0x6b,
0xca, 0x4a, 0xd8, 0xfe, 0x5e, 0x64, 0x24, 0x7c, 0xf8, 0xaf, 0x73, 0x00, 0x71, 0x88, 0x87, 0xe0,
0x52, 0x3b, 0xad, 0x7e, 0x6b, 0xff, 0x50, 0x8c, 0x80, 0x79, 0xd8, 0x17, 0xcc, 0xc7, 0x6c, 0x7f,
0xdc, 0xb8, 0x95, 0x9a, 0x72, 0x78, 0xd4, 0x6f, 0x64, 0xc4, 0x60, 0x77, 0xba, 0x9d, 0x7e, 0xa7,
0xb5, 0x6f, 0x99, 0x87, 0xc7, 0x9d, 0xee, 0x53, 0xba, 0x84, 0x11, 0x19, 0xf4, 0xf1, 0xd1, 0xae,
0x79, 0xd8, 0xed, 0x5b, 0xbd, 0xbd, 0xe3, 0xfe, 0x0e, 0x5e, 0xe1, 0xb8, 0x6d, 0x76, 0x8e, 0xa8,
0xcc, 0xfc, 0x8b, 0x10, 0x44, 0xd1, 0x05, 0x31, 0x5d, 0x4f, 0x0f, 0x7b, 0xbd, 0xce, 0x91, 0xf5,
0xf1, 0x71, 0xdb, 0xec, 0xb4, 0x7b, 0x98, 0x71, 0x21, 0x05, 0x2e, 0xf0, 0x8b, 0x82, 0xad, 0xf7,
0xf7, 0x3f, 0x91, 0x7c, 0x57, 0xa0, 0x96, 0x92, 0x20, 0x81, 0x55, 0x16, 0x83, 0x29, 0x18, 0x57,
0x4a, 0xc9, 0x70, 0x43, 0x9a, 0xc8, 0x57, 0x11, 0x2c, 0x79, 0x6e, 0x1e, 0x31, 0x5b, 0x35, 0x3d,
0x49, 0xe4, 0x42, 0x6e, 0x1d, 0xed, 0x6d, 0x3b, 0x3b, 0x26, 0x66, 0xa8, 0xcf, 0x41, 0x05, 0xee,
0xa2, 0x98, 0x28, 0xc1, 0xd9, 0x04, 0x4a, 0x43, 0x7d, 0x88, 0x94, 0xa5, 0x27, 0xbf, 0x9d, 0x83,
0x3a, 0x85, 0xdb, 0xd1, 0xeb, 0x7c, 0xdc, 0x67, 0x07, 0x50, 0x94, 0xcf, 0x3c, 0xb2, 0xd5, 0xe8,
0x7e, 0x3c, 0xfd, 0x61, 0xc9, 0x8d, 0xb5, 0x59, 0xb0, 0x94, 0xe4, 0x96, 0xff, 0xd6, 0x9f, 0xfd,
0xcf, 0x7f, 0x94, 0xad, 0xb1, 0xca, 0xa3, 0x8b, 0xf7, 0x1e, 0x9d, 0x71, 0x37, 0x10, 0x65, 0xfc,
0x1a, 0x40, 0xfc, 0x78, 0x21, 0x6b, 0x46, 0xf6, 0xab, 0x99, 0x97, 0x1d, 0x37, 0x6e, 0xa7, 0xa4,
0xc8, 0x72, 0x6f, 0x63, 0xb9, 0xcb, 0x46, 0x5d, 0x94, 0xeb, 0xb8, 0x4e, 0x48, 0x0f, 0x19, 0x7e,
0x98, 0x79, 0xc8, 0x86, 0x50, 0xd5, 0x9f, 0x15, 0x64, 0x4a, 0xc8, 0x4a, 0x79, 0x18, 0x71, 0xe3,
0x4e, 0x6a, 0x9a, 0x12, 0x5f, 0xb1, 0x8e, 0x55, 0xa3, 0x21, 0xea, 0x98, 0x22, 0x46, 0x5c, 0xcb,
0x88, 0x04, 0xfa, 0xf8, 0xf5, 0x40, 0xf6, 0x9a, 0x26, 0x92, 0xcd, 0xbd, 0x5d, 0xb8, 0x71, 0xf7,
0x86, 0x54, 0x59, 0xd7, 0x5d, 0xac, 0x6b, 0xdd, 0x60, 0xa2, 0xae, 0x01, 0xe2, 0xa8, 0xb7, 0x0b,
0x3f, 0xcc, 0x3c, 0x7c, 0xf2, 0x1f, 0xdf, 0x81, 0x72, 0xe4, 0x7e, 0xcb, 0x7e, 0x13, 0x6a, 0x89,
0x78, 0x48, 0xa6, 0xba, 0x91, 0x16, 0x3e, 0xb9, 0xf1, 0x5a, 0x7a, 0xa2, 0xac, 0xf8, 0x75, 0xac,
0xb8, 0xc9, 0xd6, 0x44, 0xc5, 0x32, 0xde, 0xf0, 0x11, 0xc6, 0x2f, 0xd3, 0x6d, 0x83, 0xcf, 0x35,
0xc5, 0x85, 0x2a, 0x7b, 0x6d, 0x56, 0x99, 0x48, 0xd4, 0x76, 0xf7, 0x86, 0x54, 0x59, 0xdd, 0x6b,
0x58, 0xdd, 0x1a, 0x5b, 0xd1, 0xab, 0x53, 0x5e, 0x9b, 0x8c, 0xe3, 0x0d, 0x9f, 0xfa, 0xe3, 0x7a,
0xec, 0x6e, 0x7c, 0x1f, 0x63, 0xca, 0xa3, 0x7b, 0x11, 0x89, 0xcc, 0xbf, 0xbc, 0x67, 0x34, 0xb1,
0x2a, 0xc6, 0x70, 0xfa, 0xf4, 0xb7, 0xf5, 0xd8, 0x09, 0x54, 0xb4, 0xf7, 0x68, 0xd8, 0xed, 0x1b,
0xdf, 0xce, 0xd9, 0xd8, 0x48, 0x4b, 0x4a, 0xeb, 0x8a, 0x5e, 0xfe, 0xa3, 0x53, 0xce, 0xd9, 0xaf,
0x42, 0x39, 0x7a, 0xe5, 0x84, 0xad, 0x6b, 0xaf, 0xce, 0xe8, 0xaf, 0xb2, 0x6c, 0x34, 0xe7, 0x13,
0xd2, 0x88, 0x4f, 0x2f, 0x5d, 0x10, 0xdf, 0xa7, 0x50, 0xd1, 0x5e, 0x32, 0x89, 0x3a, 0x30, 0xff,
0x5a, 0x4a, 0xd4, 0x81, 0x94, 0x87, 0x4f, 0x8c, 0x25, 0xac, 0xa2, 0xc2, 0xca, 0x48, 0xdf, 0xe1,
0x95, 0x17, 0xb0, 0x7d, 0x58, 0x95, 0x4a, 0xda, 0x09, 0xff, 0x32, 0xd3, 0x90, 0xf2, 0x9e, 0xe1,
0xe3, 0x0c, 0xfb, 0x08, 0x4a, 0xea, 0xc1, 0x1a, 0xb6, 0x96, 0xfe, 0xf0, 0xce, 0xc6, 0xfa, 0x1c,
0x5c, 0x6a, 0x54, 0x9f, 0x01, 0xc4, 0xcf, 0xa6, 0x44, 0x4c, 0x62, 0xee, 0x19, 0x96, 0x88, 0x02,
0xe6, 0xdf, 0x58, 0x31, 0xd6, 0xb0, 0x83, 0x0d, 0x86, 0x4c, 0xc2, 0xe5, 0x97, 0xea, 0x1a, 0xe6,
0x1f, 0x42, 0x45, 0x7b, 0x39, 0x25, 0x1a, 0xbe, 0xf9, 0x57, 0x57, 0xa2, 0xe1, 0x4b, 0x79, 0x68,
0xc5, 0xd8, 0xc0, 0xd2, 0x57, 0x8c, 0x45, 0x51, 0xba, 0x90, 0xd2, 0xa4, 0xb4, 0x24, 0x26, 0xe8,
0x1c, 0x6a, 0x89, 0xe7, 0x51, 0xa2, 0x15, 0x9a, 0xf6, 0xf8, 0x4a, 0xb4, 0x42, 0x53, 0x5f, 0x54,
0x51, 0x74, 0x66, 0x2c, 0x89, 0x7a, 0xe8, 0x26, 0x26, 0xad, 0xa6, 0x1f, 0x40, 0x45, 0x7b, 0xea,
0x24, 0xea, 0xcb, 0xfc, 0xab, 0x2a, 0x51, 0x5f, 0xd2, 0x5e, 0x46, 0x59, 0xc1, 0x3a, 0xea, 0x06,
0x92, 0x02, 0x5e, 0x24, 0x2b, 0xca, 0xfe, 0x4d, 0xa8, 0x27, 0x5f, 0x3f, 0x89, 0xd6, 0x7e, 0xea,
0x33, 0x2a, 0xd1, 0xda, 0xbf, 0xe1, 0xc9, 0x14, 0x49, 0xd2, 0x0f, 0x97, 0xa3, 0x4a, 0x1e, 0xfd,
0x58, 0x06, 0x12, 0x7d, 0xc1, 0x3e, 0x16, 0x0c, 0x4e, 0xde, 0x63, 0xcc, 0xd6, 0x35, 0xaa, 0xd5,
0x2f, 0x44, 0x8e, 0xd6, 0xcb, 0xdc, 0x95, 0xc7, 0x49, 0x62, 0xc6, 0xc2, 0xd9, 0x53, 0x58, 0x8e,
0x88, 0x39, 0xba, 0x98, 0x38, 0x88, 0xfa, 0x90, 0x7a, 0xfd, 0xf1, 0x46, 0x63, 0x36, 0xf5, 0x71,
0x86, 0xb6, 0x3f, 0xbc, 0x0e, 0x56, 0xdb, 0xfe, 0xf4, 0xbb, 0x89, 0xb5, 0xed, 0x2f, 0x71, 0x6b,
0xec, 0xec, 0xf6, 0x17, 0x3a, 0xa2, 0x0c, 0x17, 0x16, 0x67, 0xaf, 0x09, 0xbe, 0x7b, 0xd3, 0x45,
0x0d, 0x54, 0xfc, 0xeb, 0x2f, 0xbe, 0xc7, 0x21, 0xc9, 0x8a, 0x14, 0x37, 0x7d, 0x24, 0xfd, 0x56,
0xd8, 0xaf, 0x43, 0x55, 0x7f, 0x31, 0x81, 0xe9, 0x3c, 0x61, 0xb6, 0xa6, 0x3b, 0xa9, 0x69, 0x49,
0x2a, 0x61, 0x55, 0xbd, 0x1a, 0xf6, 0x09, 0xac, 0x45, 0xc3, 0xac, 0xdf, 0x34, 0x10, 0xb0, 0x7b,
0x29, 0xf7, 0x0f, 0x24, 0x06, 0xfb, 0xf6, 0x8d, 0x17, 0x14, 0x3c, 0xce, 0x08, 0xea, 0x4b, 0x5e,
0xdd, 0x1e, 0xef, 0x3c, 0x69, 0x37, 0xd6, 0xc7, 0x3b, 0x4f, 0xea, 0x7d, 0xef, 0x8a, 0xfa, 0xd8,
0x72, 0x62, 0x8c, 0xc8, 0xa3, 0x97, 0xfd, 0x00, 0x16, 0xb5, 0x6b, 0x14, 0x7a, 0xd7, 0xee, 0x20,
0x5a, 0x49, 0xf3, 0x17, 0x80, 0x6e, 0xa4, 0x1d, 0x6b, 0x1a, 0xeb, 0x58, 0xfe, 0x92, 0x91, 0x18,
0x1c, 0xb1, 0x8a, 0xb6, 0xa1, 0xa2, 0x5f, 0xd1, 0xf0, 0x82, 0x72, 0xd7, 0xb5, 0x24, 0xfd, 0xae,
0xc9, 0xc7, 0x19, 0xb6, 0x0f, 0x8d, 0xd9, 0xeb, 0xcf, 0x22, 0x9e, 0x92, 0x76, 0x65, 0xdc, 0xc6,
0x4c, 0x62, 0xe2, 0xd2, 0x34, 0x76, 0x44, 0x31, 0x21, 0xd1, 0xe3, 0x7f, 0x9e, 0x3f, 0xbb, 0xab,
0x27, 0x1f, 0x05, 0x8c, 0x4a, 0x4b, 0x7b, 0x0e, 0xf2, 0x41, 0xe6, 0x71, 0x86, 0xfd, 0x6e, 0x06,
0xaa, 0x89, 0x0b, 0x85, 0x12, 0x5e, 0xf7, 0x33, 0xfd, 0x6c, 0xea, 0x69, 0x7a, 0x47, 0x0d, 0x13,
0x07, 0x71, 0xff, 0xe1, 0xf7, 0x13, 0x93, 0xf4, 0xe3, 0x84, 0x55, 0x70, 0x73, 0xf6, 0x75, 0xc0,
0x2f, 0x66, 0x11, 0xf4, 0x2b, 0x65, 0xbf, 0x78, 0x9c, 0x61, 0xff, 0x36, 0x03, 0xf5, 0xa4, 0xb9,
0x3f, 0xea, 0x6e, 0xaa, 0x63, 0x41, 0x44, 0x4a, 0x37, 0xf8, 0x08, 0xfc, 0x00, 0x5b, 0xd9, 0x7f,
0x68, 0x26, 0x5a, 0x29, 0x1f, 0x1d, 0xf8, 0xd9, 0x5a, 0xcb, 0x3e, 0xa4, 0xc7, 0x78, 0x95, 0x17,
0x14, 0x9b, 0x7f, 0xbc, 0x35, 0x22, 0x3f, 0xfd, 0xa9, 0x53, 0x9c, 0x84, 0x1f, 0xd2, 0x2b, 0x78,
0xca, 0xa9, 0x46, 0x50, 0xf1, 0xab, 0xe6, 0x37, 0xde, 0xc4, 0x3e, 0xbd, 0x6e, 0xdc, 0x4e, 0xf4,
0x69, 0x56, 0xf0, 0x68, 0x51, 0xeb, 0xe4, 0x4b, 0xa5, 0xf1, 0xce, 0x39, 0xf7, 0x7a, 0xe9, 0xcd,
0x8d, 0x1c, 0x53, 0x23, 0x25, 0x7a, 0x62, 0xa9, 0xbd, 0x62, 0x31, 0xc6, 0x43, 0x6c, 0xeb, 0x9b,
0xc6, 0xbd, 0x1b, 0xdb, 0xfa, 0x08, 0x4d, 0xf7, 0xa2, 0xc5, 0x47, 0x00, 0xb1, 0x97, 0x22, 0x9b,
0xf1, 0x95, 0x8b, 0x18, 0xd0, 0xbc, 0x23, 0x63, 0x72, 0x3d, 0x2b, 0x97, 0x3a, 0x51, 0xe2, 0xaf,
0x12, 0x3b, 0x8d, 0xbc, 0xf8, 0x74, 0xe9, 0x2b, 0xe9, 0x50, 0x98, 0x90, 0xbe, 0x66, 0xcb, 0x4f,
0x30, 0xd3, 0xc8, 0x65, 0xef, 0x18, 0x6a, 0xfb, 0x9e, 0xf7, 0x7c, 0x3a, 0x89, 0x3c, 0xe3, 0x93,
0xfe, 0x34, 0x7b, 0x76, 0x70, 0xbe, 0x31, 0xd3, 0x0b, 0xe3, 0x3e, 0x16, 0xb5, 0xc1, 0x9a, 0x5a,
0x51, 0x8f, 0x7e, 0x1c, 0xbb, 0x46, 0x7e, 0xc1, 0x6c, 0x58, 0x8a, 0x78, 0x74, 0xec, 0x7e, 0x98,
0x2c, 0x26, 0xc1, 0x99, 0x67, 0xab, 0x48, 0xa8, 0x09, 0xaa, 0xb5, 0x8f, 0x02, 0x55, 0xe6, 0xe3,
0x0c, 0x3b, 0x82, 0xea, 0x0e, 0x1f, 0xe0, 0xd5, 0x0a, 0xe8, 0x95, 0xb2, 0x9c, 0xf0, 0x70, 0x20,
0x77, 0x96, 0x8d, 0x5a, 0x02, 0x98, 0xdc, 0xb7, 0x26, 0xf6, 0xb5, 0xcf, 0x3f, 0x7f, 0xf4, 0x63,
0xe9, 0xef, 0xf2, 0x85, 0xda, 0xb7, 0x94, 0x3f, 0x50, 0x62, 0xdf, 0x9a, 0x71, 0x20, 0x4a, 0xec,
0x5b, 0x73, 0x0e, 0x44, 0x89, 0xa1, 0x56, 0xfe, 0x48, 0x6c, 0x04, 0x4b, 0x73, 0x3e, 0x47, 0xd1,
0x96, 0x75, 0x93, 0xa7, 0xd2, 0xc6, 0xfd, 0x9b, 0x11, 0x92, 0xb5, 0x3d, 0x4c, 0xd6, 0xd6, 0x83,
0x1a, 0xdd, 0x17, 0x7b, 0xc2, 0x29, 0xc8, 0x72, 0xe6, 0x86, 0x22, 0x3d, 0x82, 0x73, 0x76, 0x83,
0xc1, 0xb4, 0xa4, 0x84, 0x83, 0x61, 0x76, 0xec, 0x14, 0x1f, 0x49, 0xd0, 0xa2, 0x1a, 0x23, 0x62,
0x9c, 0x8f, 0xb4, 0x8c, 0x88, 0x31, 0x25, 0x08, 0x52, 0xa9, 0x9f, 0x6c, 0x35, 0x2a, 0xfb, 0x91,
0xeb, 0x0d, 0xf9, 0x58, 0x96, 0xfa, 0xab, 0x50, 0x79, 0xca, 0x43, 0x15, 0x46, 0x18, 0xc9, 0xf2,
0x33, 0x71, 0x85, 0x1b, 0x29, 0xc1, 0x9f, 0x49, 0xda, 0xa4, 0x92, 0xf9, 0xf0, 0x8c, 0x13, 0x13,
0xb4, 0x9c, 0xe1, 0x17, 0xec, 0x57, 0xb0, 0xf0, 0x28, 0x68, 0x7e, 0x4d, 0x6b, 0xa6, 0x5e, 0xf8,
0xe2, 0x0c, 0x3c, 0xad, 0x64, 0xd1, 0x66, 0x4d, 0xa6, 0x74, 0xa1, 0xa2, 0x5d, 0xae, 0x11, 0x8d,
0xcd, 0xfc, 0x65, 0x2a, 0xd1, 0xd8, 0xa4, 0xdc, 0xc5, 0x61, 0x3c, 0xc0, 0x7a, 0x0c, 0x76, 0x3f,
0xae, 0x87, 0xee, 0xdf, 0x88, 0x6b, 0x7a, 0xf4, 0x63, 0x7b, 0x1c, 0x7e, 0xc1, 0x3e, 0xa5, 0xe9,
0xd0, 0xc2, 0x24, 0x63, 0xe5, 0x64, 0x36, 0xa2, 0x32, 0x1a, 0x2c, 0x2d, 0x29, 0xa9, 0xb0, 0x50,
0x55, 0x28, 0x31, 0xbe, 0x0f, 0xd0, 0x0b, 0xbd, 0xc9, 0x8e, 0xcd, 0xc7, 0x9e, 0x1b, 0xf3, 0xf4,
0x38, 0x70, 0x2f, 0xe6, 0x93, 0x5a, 0xf4, 0x1e, 0xfb, 0x54, 0xd3, 0xe6, 0x12, 0x01, 0xbe, 0x8a,
0x88, 0x6f, 0x8c, 0xed, 0x8b, 0x06, 0x24, 0x25, 0xbe, 0xef, 0x71, 0x86, 0xb5, 0x00, 0x62, 0xe7,
0xb6, 0x48, 0x37, 0x9b, 0xf3, 0x9b, 0x8b, 0xd8, 0x6b, 0x8a, 0x27, 0xdc, 0x11, 0x94, 0x63, 0xaf,
0xa0, 0xf5, 0xf8, 0xae, 0xa0, 0x84, 0x0f, 0x51, 0x24, 0x29, 0xcc, 0x79, 0xe4, 0x18, 0x0d, 0x1c,
0x2a, 0x60, 0x25, 0x31, 0x54, 0xa7, 0x9c, 0x07, 0xcc, 0x81, 0x65, 0x6a, 0x60, 0x24, 0x96, 0x61,
0xc0, 0x59, 0xf4, 0x34, 0xc9, 0xbc, 0x73, 0x4c, 0xc4, 0x35, 0x52, 0x5d, 0x3c, 0x12, 0x47, 0x4c,
0x82, 0x5a, 0x29, 0xd8, 0x4d, 0x6c, 0x01, 0x63, 0x58, 0x9a, 0xf3, 0x22, 0x88, 0x58, 0xc7, 0x4d,
0x6e, 0x21, 0x11, 0xeb, 0xb8, 0xd1, 0x01, 0xc1, 0x58, 0xc5, 0x2a, 0x17, 0x0d, 0x40, 0x95, 0xf2,
0xd2, 0x09, 0x07, 0xe7, 0xa2, 0xba, 0xdf, 0xcf, 0xc0, 0x72, 0x8a, 0x9f, 0x00, 0x7b, 0x43, 0x9d,
0x4e, 0xdc, 0xe8, 0x43, 0xb0, 0x91, 0x6a, 0x4f, 0x36, 0x7a, 0x58, 0xcf, 0x01, 0x7b, 0x96, 0xd8,
0x40, 0xc9, 0x9c, 0x2b, 0x57, 0xe6, 0x0b, 0x85, 0x97, 0x54, 0xc9, 0xe5, 0x73, 0x58, 0xa7, 0x86,
0xb4, 0x46, 0xa3, 0x19, 0x5b, 0xf7, 0xeb, 0x5a, 0x2b, 0x52, 0xec, 0xf7, 0x09, 0x3d, 0x20, 0x69,
0xc3, 0xbf, 0x41, 0x6c, 0xa7, 0xa6, 0xb2, 0x29, 0x34, 0x66, 0x6d, 0xc8, 0xec, 0xe6, 0xb2, 0x36,
0xee, 0x25, 0xf4, 0xec, 0x14, 0xbb, 0xf3, 0x57, 0xb1, 0xb2, 0x7b, 0xc6, 0x46, 0xda, 0xb8, 0x90,
0xea, 0x2d, 0xe6, 0xe3, 0x6f, 0x46, 0x06, 0xef, 0x99, 0x7e, 0xde, 0x8b, 0x2e, 0x63, 0x4f, 0x37,
0xcf, 0x47, 0x9a, 0x7e, 0xba, 0xbd, 0xfc, 0x2d, 0xac, 0xfe, 0xbe, 0x71, 0x27, 0xad, 0x7a, 0x9f,
0xb2, 0x90, 0xce, 0xbf, 0x3e, 0xbb, 0xae, 0x55, 0x0b, 0xee, 0xa7, 0xcd, 0xf7, 0x8d, 0x3a, 0xd7,
0xcc, 0x58, 0xdf, 0x42, 0x19, 0xb2, 0xaa, 0x1b, 0xb8, 0xa3, 0xe5, 0x93, 0x62, 0x49, 0x8f, 0x96,
0x4f, 0x9a, 0x45, 0x3c, 0x29, 0x3f, 0x29, 0x5b, 0xf8, 0x87, 0x99, 0x87, 0x5b, 0x6f, 0xff, 0xe0,
0xab, 0x67, 0x4e, 0x78, 0x3e, 0x3d, 0xd9, 0x1c, 0x78, 0xe3, 0x47, 0x23, 0x75, 0xaa, 0x29, 0xa3,
0xb2, 0x1f, 0x8d, 0xdc, 0xe1, 0x23, 0x2c, 0xf6, 0x64, 0x61, 0xe2, 0x7b, 0xa1, 0xf7, 0x8d, 0xff,
0x17, 0x00, 0x00, 0xff, 0xff, 0x66, 0xe1, 0x62, 0xc2, 0xf7, 0x88, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

@ -1775,6 +1775,28 @@ message PendingUpdate {
uint32 output_index = 2;
}
message ReadyForPsbtFunding {
/**
The P2WSH address of the channel funding multisig address that the below
specified amount in satoshis needs to be sent to.
*/
string funding_address = 1;
/**
The exact amount in satoshis that needs to be sent to the above address to
fund the pending channel.
*/
int64 funding_amount = 2;
/**
A raw PSBT that contains the pending channel output. If a base PSBT was
provided in the PsbtShim, this is the base PSBT with one additional output.
If no base PSBT was specified, this is an otherwise empty PSBT with exactly
one output.
*/
bytes psbt = 3;
}
message OpenChannelRequest {
/**
The pubkey of the node to open a channel with. When using REST, this field
@ -1846,8 +1868,23 @@ message OpenChannelRequest {
}
message OpenStatusUpdate {
oneof update {
/**
Signals that the channel is now fully negotiated and the funding
transaction published.
*/
PendingUpdate chan_pending = 1;
/**
Signals that the channel's funding transaction has now reached the
required number of confirmations on chain and can be used.
*/
ChannelOpenUpdate chan_open = 3;
/**
Signals that the funding process has been suspended and the construction
of a PSBT that funds the channel PK script is now required.
*/
ReadyForPsbtFunding psbt_fund = 5;
}
/**
@ -1910,9 +1947,34 @@ message ChanPointShim {
uint32 thaw_height = 6;
}
message PsbtShim {
/**
A unique identifier of 32 random bytes that will be used as the pending
channel ID to identify the PSBT state machine when interacting with it and
on the wire protocol to initiate the funding request.
*/
bytes pending_chan_id = 1;
/**
An optional base PSBT the new channel output will be added to. If this is
non-empty, it must be a binary serialized PSBT.
*/
bytes base_psbt = 2;
}
message FundingShim {
oneof shim {
/**
A channel shim where the channel point was fully constructed outside
of lnd's wallet and the transaction might already be published.
*/
ChanPointShim chan_point_shim = 1;
/**
A channel shim that uses a PSBT to fund and sign the channel funding
transaction.
*/
PsbtShim psbt_shim = 2;
}
}
@ -1921,17 +1983,56 @@ message FundingShimCancel {
bytes pending_chan_id = 1;
}
message FundingPsbtVerify {
/**
The funded but not yet signed PSBT that sends the exact channel capacity
amount to the PK script returned in the open channel message in a previous
step.
*/
bytes funded_psbt = 1;
/// The pending channel ID of the channel to get the PSBT for.
bytes pending_chan_id = 2;
}
message FundingPsbtFinalize {
/**
The funded PSBT that contains all witness data to send the exact channel
capacity amount to the PK script returned in the open channel message in a
previous step.
*/
bytes signed_psbt = 1;
/// The pending channel ID of the channel to get the PSBT for.
bytes pending_chan_id = 2;
}
message FundingTransitionMsg {
oneof trigger {
/**
The funding shim to regsiter. This should be used before any
The funding shim to register. This should be used before any
channel funding has began by the remote party, as it is intended as a
prepatory step for the full channel funding.
preparatory step for the full channel funding.
*/
FundingShim shim_register = 1;
/// Used to cancel an existing registered funding shim.
FundingShimCancel shim_cancel = 2;
/**
Used to continue a funding flow that was initiated to be executed
through a PSBT. This step verifies that the PSBT contains the correct
outputs to fund the channel.
*/
FundingPsbtVerify psbt_verify = 3;
/**
Used to continue a funding flow that was initiated to be executed
through a PSBT. This step finalizes the funded and signed PSBT, finishes
negotiation with the peer and finally publishes the resulting funding
transaction.
*/
FundingPsbtFinalize psbt_finalize = 4;
}
}

@ -2825,11 +2825,46 @@
}
}
},
"lnrpcFundingPsbtFinalize": {
"type": "object",
"properties": {
"signed_psbt": {
"type": "string",
"format": "byte",
"description": "*\nThe funded PSBT that contains all witness data to send the exact channel\ncapacity amount to the PK script returned in the open channel message in a\nprevious step."
},
"pending_chan_id": {
"type": "string",
"format": "byte",
"description": "/ The pending channel ID of the channel to get the PSBT for."
}
}
},
"lnrpcFundingPsbtVerify": {
"type": "object",
"properties": {
"funded_psbt": {
"type": "string",
"format": "byte",
"description": "*\nThe funded but not yet signed PSBT that sends the exact channel capacity\namount to the PK script returned in the open channel message in a previous\nstep."
},
"pending_chan_id": {
"type": "string",
"format": "byte",
"description": "/ The pending channel ID of the channel to get the PSBT for."
}
}
},
"lnrpcFundingShim": {
"type": "object",
"properties": {
"chan_point_shim": {
"$ref": "#/definitions/lnrpcChanPointShim"
"$ref": "#/definitions/lnrpcChanPointShim",
"description": "*\nA channel shim where the channel point was fully constructed outside\nof lnd's wallet and the transaction might already be published."
},
"psbt_shim": {
"$ref": "#/definitions/lnrpcPsbtShim",
"description": "*\nA channel shim that uses a PSBT to fund and sign the channel funding\ntransaction."
}
}
},
@ -3753,10 +3788,16 @@
"type": "object",
"properties": {
"chan_pending": {
"$ref": "#/definitions/lnrpcPendingUpdate"
"$ref": "#/definitions/lnrpcPendingUpdate",
"description": "*\nSignals that the channel is now fully negotiated and the funding\ntransaction published."
},
"chan_open": {
"$ref": "#/definitions/lnrpcChannelOpenUpdate"
"$ref": "#/definitions/lnrpcChannelOpenUpdate",
"description": "*\nSignals that the channel's funding transaction has now reached the\nrequired number of confirmations on chain and can be used."
},
"psbt_fund": {
"$ref": "#/definitions/lnrpcReadyForPsbtFunding",
"description": "*\nSignals that the funding process has been suspended and the construction\nof a PSBT that funds the channel PK script is now required."
},
"pending_chan_id": {
"type": "string",
@ -4120,6 +4161,21 @@
"lnrpcPolicyUpdateResponse": {
"type": "object"
},
"lnrpcPsbtShim": {
"type": "object",
"properties": {
"pending_chan_id": {
"type": "string",
"format": "byte",
"description": "*\nA unique identifier of 32 random bytes that will be used as the pending\nchannel ID to identify the PSBT state machine when interacting with it and\non the wire protocol to initiate the funding request."
},
"base_psbt": {
"type": "string",
"format": "byte",
"description": "*\nAn optional base PSBT the new channel output will be added to. If this is\nnon-empty, it must be a binary serialized PSBT."
}
}
},
"lnrpcQueryRoutesResponse": {
"type": "object",
"properties": {
@ -4137,6 +4193,25 @@
}
}
},
"lnrpcReadyForPsbtFunding": {
"type": "object",
"properties": {
"funding_address": {
"type": "string",
"description": "*\nThe P2WSH address of the channel funding multisig address that the below\nspecified amount in satoshis needs to be sent to."
},
"funding_amount": {
"type": "string",
"format": "int64",
"description": "*\nThe exact amount in satoshis that needs to be sent to the above address to\nfund the pending channel."
},
"psbt": {
"type": "string",
"format": "byte",
"description": "*\nA raw PSBT that contains the pending channel output. If a base PSBT was\nprovided in the PsbtShim, this is the base PSBT with one additional output.\nIf no base PSBT was specified, this is an otherwise empty PSBT with exactly\none output."
}
}
},
"lnrpcRestoreBackupResponse": {
"type": "object"
},

@ -14875,6 +14875,10 @@ var testsCases = []*testCase{
name: "external channel funding",
test: testExternalFundingChanPoint,
},
{
name: "psbt channel funding",
test: testPsbtChanFunding,
},
}
// TestLightningNetworkDaemon performs a series of integration tests amongst a

350
lntest/itest/psbt.go Normal file

@ -0,0 +1,350 @@
// +build rpctest
package itest
import (
"bytes"
"context"
"crypto/rand"
"fmt"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/psbt"
"github.com/lightningnetwork/lnd"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntest"
)
// testPsbtChanFunding makes sure a channel can be opened between carol and dave
// by using a Partially Signed Bitcoin Transaction that funds the channel
// multisig funding output.
func testPsbtChanFunding(net *lntest.NetworkHarness, t *harnessTest) {
ctxb := context.Background()
const chanSize = lnd.MaxBtcFundingAmount
// First, we'll create two new nodes that we'll use to open channel
// between for this test.
carol, err := net.NewNode("carol", nil)
if err != nil {
t.Fatalf("unable to start new node: %v", err)
}
defer shutdownAndAssert(net, t, carol)
dave, err := net.NewNode("dave", nil)
if err != nil {
t.Fatalf("unable to start new node: %v", err)
}
defer shutdownAndAssert(net, t, dave)
// Before we start the test, we'll ensure both sides are connected so
// the funding flow can be properly executed.
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
err = net.EnsureConnected(ctxt, carol, dave)
if err != nil {
t.Fatalf("unable to connect peers: %v", err)
}
// At this point, we can begin our PSBT channel funding workflow. We'll
// start by generating a pending channel ID externally that will be used
// to track this new funding type.
var pendingChanID [32]byte
if _, err := rand.Read(pendingChanID[:]); err != nil {
t.Fatalf("unable to gen pending chan ID: %v", err)
}
// Now that we have the pending channel ID, Carol will open the channel
// by specifying a PSBT shim.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
chanUpdates, psbtBytes, err := openChannelPsbt(
ctxt, carol, dave, lntest.OpenChannelParams{
Amt: chanSize,
FundingShim: &lnrpc.FundingShim{
Shim: &lnrpc.FundingShim_PsbtShim{
PsbtShim: &lnrpc.PsbtShim{
PendingChanId: pendingChanID[:],
},
},
},
},
)
if err != nil {
t.Fatalf("unable to open channel: %v", err)
}
packet, err := psbt.NewFromRawBytes(bytes.NewReader(psbtBytes), false)
if err != nil {
t.Fatalf("unable to parse returned PSBT: %v", err)
}
// We'll now create a fully signed transaction that sends to the outputs
// encoded in the PSBT. We'll let the miner do it and convert the final
// TX into a PSBT, that's way easier than assembling a PSBT manually.
tx, err := net.Miner.CreateTransaction(packet.UnsignedTx.TxOut, 5, true)
if err != nil {
t.Fatalf("unable to create funding transaction: %v", err)
}
// The helper function splits the final TX into the non-witness data
// encoded in a PSBT and the witness data returned separately.
unsignedPsbt, scripts, witnesses, err := createPsbtFromSignedTx(tx)
if err != nil {
t.Fatalf("unable to convert funding transaction into PSBT: %v",
err)
}
// The PSBT will also be checked if there are large enough inputs
// present. We need to add some fake UTXO information to the PSBT to
// tell it what size of inputs we have.
for idx, txIn := range unsignedPsbt.UnsignedTx.TxIn {
utxPrevOut := txIn.PreviousOutPoint.Index
fakeUtxo := &wire.MsgTx{
Version: 2,
TxIn: []*wire.TxIn{{}},
TxOut: make([]*wire.TxOut, utxPrevOut+1),
}
for idx := range fakeUtxo.TxOut {
fakeUtxo.TxOut[idx] = &wire.TxOut{}
}
fakeUtxo.TxOut[utxPrevOut].Value = 10000000000
unsignedPsbt.Inputs[idx].NonWitnessUtxo = fakeUtxo
}
// Serialize the PSBT with the faked UTXO information.
var buf bytes.Buffer
err = unsignedPsbt.Serialize(&buf)
if err != nil {
t.Fatalf("error serializing PSBT: %v", err)
}
// We have a PSBT that has no witness data yet, which is exactly what we
// need for the next step: Verify the PSBT with the funding intent.
_, err = carol.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{
Trigger: &lnrpc.FundingTransitionMsg_PsbtVerify{
PsbtVerify: &lnrpc.FundingPsbtVerify{
PendingChanId: pendingChanID[:],
FundedPsbt: buf.Bytes(),
},
},
})
if err != nil {
t.Fatalf("error verifying PSBT with funding intent: %v", err)
}
// Now we'll add the witness data back into the PSBT to make it a
// complete and signed transaction that can be finalized. We'll trick
// a bit by putting the script sig back directly, because we know we
// will only get non-witness outputs from the miner wallet.
for idx := range tx.TxIn {
if len(witnesses[idx]) > 0 {
t.Fatalf("unexpected witness inputs in wallet TX")
}
unsignedPsbt.Inputs[idx].FinalScriptSig = scripts[idx]
}
// We've signed our PSBT now, let's pass it to the intent again.
buf.Reset()
err = unsignedPsbt.Serialize(&buf)
if err != nil {
t.Fatalf("error serializing PSBT: %v", err)
}
_, err = carol.FundingStateStep(ctxb, &lnrpc.FundingTransitionMsg{
Trigger: &lnrpc.FundingTransitionMsg_PsbtFinalize{
PsbtFinalize: &lnrpc.FundingPsbtFinalize{
PendingChanId: pendingChanID[:],
SignedPsbt: buf.Bytes(),
},
},
})
if err != nil {
t.Fatalf("error finalizing PSBT with funding intent: %v", err)
}
// Consume the "channel pending" update. This waits until the funding
// transaction has been published.
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
updateResp, err := receiveChanUpdate(ctxt, chanUpdates)
if err != nil {
t.Fatalf("unable to consume channel update message: %v", err)
}
upd, ok := updateResp.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
if !ok {
t.Fatalf("expected PSBT funding update, instead got %v",
updateResp)
}
chanPoint := &lnrpc.ChannelPoint{
FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
FundingTxidBytes: upd.ChanPending.Txid,
},
OutputIndex: upd.ChanPending.OutputIndex,
}
// Great, now we can mine a block to get the transaction confirmed, then
// wait for the new channel to be propagated through the network.
txHash := tx.TxHash()
block := mineBlocks(t, net, 6, 1)[0]
assertTxInBlock(t, block, &txHash)
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
err = carol.WaitForNetworkChannelOpen(ctxt, chanPoint)
if err != nil {
t.Fatalf("carol didn't report channel: %v", err)
}
// With the channel open, ensure that it is counted towards Carol's
// total channel balance.
balReq := &lnrpc.ChannelBalanceRequest{}
ctxt, cancel = context.WithTimeout(ctxb, defaultTimeout)
defer cancel()
balRes, err := carol.ChannelBalance(ctxt, balReq)
if err != nil {
t.Fatalf("unable to get carol's balance: %v", err)
}
if balRes.Balance == 0 {
t.Fatalf("carol has an empty channel balance")
}
// Next, to make sure the channel functions as normal, we'll make some
// payments within the channel.
payAmt := btcutil.Amount(100000)
invoice := &lnrpc.Invoice{
Memo: "new chans",
Value: int64(payAmt),
}
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
resp, err := dave.AddInvoice(ctxt, invoice)
if err != nil {
t.Fatalf("unable to add invoice: %v", err)
}
ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
err = completePaymentRequests(
ctxt, carol, []string{resp.PaymentRequest}, true,
)
if err != nil {
t.Fatalf("unable to make payments between Carol and Dave")
}
// To conclude, we'll close the newly created channel between Carol and
// Dave. This function will also block until the channel is closed and
// will additionally assert the relevant channel closing post
// conditions.
ctxt, cancel = context.WithTimeout(ctxb, channelCloseTimeout)
defer cancel()
closeChannelAndAssert(ctxt, t, net, carol, chanPoint, false)
}
// openChannelPsbt 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. An error is returned if the expected step
// of funding the PSBT is not received from the source node.
func openChannelPsbt(ctx context.Context, srcNode, destNode *lntest.HarnessNode,
p lntest.OpenChannelParams) (lnrpc.Lightning_OpenChannelClient, []byte,
error) {
// Wait until srcNode and destNode have the latest chain synced.
// Otherwise, we may run into a check within the funding manager that
// prevents any funding workflows from being kicked off if the chain
// isn't yet synced.
if err := srcNode.WaitForBlockchainSync(ctx); err != nil {
return nil, nil, fmt.Errorf("unable to sync srcNode chain: %v",
err)
}
if err := destNode.WaitForBlockchainSync(ctx); err != nil {
return nil, nil, fmt.Errorf("unable to sync destNode chain: %v",
err)
}
// Send the request to open a channel to the source node now. This will
// open a long-lived stream where we'll receive status updates about the
// progress of the channel.
respStream, err := srcNode.OpenChannel(ctx, &lnrpc.OpenChannelRequest{
NodePubkey: destNode.PubKey[:],
LocalFundingAmount: int64(p.Amt),
PushSat: int64(p.PushAmt),
Private: p.Private,
SpendUnconfirmed: p.SpendUnconfirmed,
MinHtlcMsat: int64(p.MinHtlc),
FundingShim: p.FundingShim,
})
if err != nil {
return nil, nil, fmt.Errorf("unable to open channel between "+
"source and dest: %v", err)
}
// Consume the "PSBT funding ready" update. This waits until the node
// notifies us that the PSBT can now be funded.
resp, err := receiveChanUpdate(ctx, respStream)
if err != nil {
return nil, nil, fmt.Errorf("unable to consume channel update "+
"message: %v", err)
}
upd, ok := resp.Update.(*lnrpc.OpenStatusUpdate_PsbtFund)
if !ok {
return nil, nil, fmt.Errorf("expected PSBT funding update, "+
"instead got %v", resp)
}
return respStream, upd.PsbtFund.Psbt, nil
}
// receiveChanUpdate waits until a message is received on the stream or the
// context is canceled. The context must have a timeout or must be canceled
// in case no message is received, otherwise this function will block forever.
func receiveChanUpdate(ctx context.Context,
stream lnrpc.Lightning_OpenChannelClient) (*lnrpc.OpenStatusUpdate,
error) {
chanMsg := make(chan *lnrpc.OpenStatusUpdate)
errChan := make(chan error)
go func() {
// Consume one message. This will block until the message is
// recieved.
resp, err := stream.Recv()
if err != nil {
errChan <- err
return
}
chanMsg <- resp
}()
select {
case <-ctx.Done():
return nil, fmt.Errorf("timeout reached before chan pending " +
"update sent")
case err := <-errChan:
return nil, err
case updateMsg := <-chanMsg:
return updateMsg, nil
}
}
// createPsbtFromSignedTx is a utility function to create a PSBT from an
// already-signed transaction, so we can test reconstructing, signing and
// extracting it. Returned are: an unsigned transaction serialization, a list
// of scriptSigs, one per input, and a list of witnesses, one per input.
func createPsbtFromSignedTx(tx *wire.MsgTx) (*psbt.Packet, [][]byte,
[]wire.TxWitness, error) {
scriptSigs := make([][]byte, 0, len(tx.TxIn))
witnesses := make([]wire.TxWitness, 0, len(tx.TxIn))
tx2 := tx.Copy()
// Blank out signature info in inputs
for i, tin := range tx2.TxIn {
tin.SignatureScript = nil
scriptSigs = append(scriptSigs, tx.TxIn[i].SignatureScript)
tin.Witness = nil
witnesses = append(witnesses, tx.TxIn[i].Witness)
}
// Outputs always contain: (value, scriptPubkey) so don't need
// amending. Now tx2 is tx with all signing data stripped out
unsignedPsbt, err := psbt.NewFromUnsignedTx(tx2)
if err != nil {
return nil, nil, nil, err
}
return unsignedPsbt, scriptSigs, witnesses, nil
}

@ -126,7 +126,7 @@ type Assembler interface {
// FundingTxAssembler is a super-set of the regular Assembler interface that's
// also able to provide a fully populated funding transaction via the intents
// that it produuces.
// that it produces.
type FundingTxAssembler interface {
Assembler

@ -0,0 +1,524 @@
package chanfunding
import (
"bytes"
"crypto/sha256"
"errors"
"fmt"
"sync"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/psbt"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
)
// PsbtState is a type for the state of the PSBT intent state machine.
type PsbtState uint8
const (
// PsbtShimRegistered denotes a channel funding process has started with
// a PSBT shim attached. This is the default state for a PsbtIntent. We
// don't use iota here because the values have to be in sync with the
// RPC constants.
PsbtShimRegistered PsbtState = 1
// PsbtOutputKnown denotes that the local and remote peer have
// negotiated the multisig keys to be used as the channel funding output
// and therefore the PSBT funding process can now start.
PsbtOutputKnown PsbtState = 2
// PsbtVerified denotes that a potential PSBT has been presented to the
// intent and passed all checks. The verified PSBT can be given to a/the
// signer(s).
PsbtVerified PsbtState = 3
// PsbtFinalized denotes that a fully signed PSBT has been given to the
// intent that looks identical to the previously verified transaction
// but has all witness data added and is therefore completely signed.
PsbtFinalized PsbtState = 4
// PsbtFundingTxCompiled denotes that the PSBT processed by this intent
// has been successfully converted into a protocol transaction. It is
// not yet completely certain that the resulting transaction will be
// published because the commitment transactions between the channel
// peers first need to be counter signed. But the job of the intent is
// hereby completed.
PsbtFundingTxCompiled PsbtState = 5
// PsbtInitiatorCanceled denotes that the user has canceled the intent.
PsbtInitiatorCanceled PsbtState = 6
// PsbtResponderCanceled denotes that the remote peer has canceled the
// funding, likely due to a timeout.
PsbtResponderCanceled PsbtState = 7
)
// String returns a string representation of the PsbtState.
func (s PsbtState) String() string {
switch s {
case PsbtShimRegistered:
return "shim_registered"
case PsbtOutputKnown:
return "output_known"
case PsbtVerified:
return "verified"
case PsbtFinalized:
return "finalized"
case PsbtFundingTxCompiled:
return "funding_tx_compiled"
case PsbtInitiatorCanceled:
return "user_canceled"
case PsbtResponderCanceled:
return "remote_canceled"
default:
return fmt.Sprintf("<unknown(%d)>", s)
}
}
var (
// ErrRemoteCanceled is the error that is returned to the user if the
// funding flow was canceled by the remote peer.
ErrRemoteCanceled = errors.New("remote canceled funding, possibly " +
"timed out")
// ErrUserCanceled is the error that is returned through the PsbtReady
// channel if the user canceled the funding flow.
ErrUserCanceled = errors.New("user canceled funding")
)
// PsbtIntent is an intent created by the PsbtAssembler which represents a
// funding output to be created by a PSBT. This might be used when a hardware
// wallet, or a channel factory is the entity crafting the funding transaction,
// and not lnd.
type PsbtIntent struct {
// ShimIntent is the wrapped basic intent that contains common fields
// we also use in the PSBT funding case.
ShimIntent
// State is the current state the intent state machine is in.
State PsbtState
// BasePsbt is the user-supplied base PSBT the channel output should be
// added to. If this is nil we will create a new, empty PSBT as the base
// for the funding transaction.
BasePsbt *psbt.Packet
// PendingPsbt is the parsed version of the current PSBT. This can be
// in two stages: If the user has not yet provided any PSBT, this is
// nil. Once the user sends us an unsigned funded PSBT, we verify that
// we have a valid transaction that sends to the channel output PK
// script and has an input large enough to pay for it. We keep this
// verified but not yet signed version around until the fully signed
// transaction is submitted by the user. At that point we make sure the
// inputs and outputs haven't changed to what was previously verified.
// Only witness data should be added after the verification process.
PendingPsbt *psbt.Packet
// PsbtReady is an error channel the funding manager will listen for
// a signal about the PSBT being ready to continue the funding flow. In
// the normal, happy flow, this channel is only ever closed. If a
// non-nil error is sent through the channel, the funding flow will be
// canceled.
//
// NOTE: This channel must always be buffered.
PsbtReady chan error
// signalPsbtReady is a Once guard to make sure the PsbtReady channel is
// only closed exactly once.
signalPsbtReady sync.Once
// netParams are the network parameters used to encode the P2WSH funding
// address.
netParams *chaincfg.Params
}
// BindKeys sets both the remote and local node's keys that will be used for the
// channel funding multisig output.
func (i *PsbtIntent) BindKeys(localKey *keychain.KeyDescriptor,
remoteKey *btcec.PublicKey) {
i.localKey = localKey
i.remoteKey = remoteKey
i.State = PsbtOutputKnown
}
// FundingParams returns the parameters that are necessary to start funding the
// channel output this intent was created for. It returns the P2WSH funding
// address, the exact funding amount and a PSBT packet that contains exactly one
// output that encodes the previous two parameters.
func (i *PsbtIntent) FundingParams() (btcutil.Address, int64, *psbt.Packet,
error) {
if i.State != PsbtOutputKnown {
return nil, 0, nil, fmt.Errorf("invalid state, got %v "+
"expected %v", i.State, PsbtOutputKnown)
}
// The funding output needs to be known already at this point, which
// means we need to have the local and remote multisig keys bound
// already.
witnessScript, out, err := i.FundingOutput()
if err != nil {
return nil, 0, nil, fmt.Errorf("unable to create funding "+
"output: %v", err)
}
witnessScriptHash := sha256.Sum256(witnessScript)
// Encode the address in the human readable bech32 format.
addr, err := btcutil.NewAddressWitnessScriptHash(
witnessScriptHash[:], i.netParams,
)
if err != nil {
return nil, 0, nil, fmt.Errorf("unable to encode address: %v",
err)
}
// We'll also encode the address/amount in a machine readable raw PSBT
// format. If the user supplied a base PSBT, we'll add the output to
// that one, otherwise we'll create a new one.
packet := i.BasePsbt
if packet == nil {
packet, err = psbt.New(nil, nil, 2, 0, nil)
if err != nil {
return nil, 0, nil, fmt.Errorf("unable to create "+
"PSBT: %v", err)
}
}
packet.UnsignedTx.TxOut = append(packet.UnsignedTx.TxOut, out)
packet.Outputs = append(packet.Outputs, psbt.POutput{})
return addr, out.Value, packet, nil
}
// Verify makes sure the PSBT that is given to the intent has an output that
// sends to the channel funding multisig address with the correct amount. A
// simple check that at least a single input has been specified is performed.
func (i *PsbtIntent) Verify(packet *psbt.Packet) error {
if packet == nil {
return fmt.Errorf("PSBT is nil")
}
if i.State != PsbtOutputKnown {
return fmt.Errorf("invalid state. got %v expected %v", i.State,
PsbtOutputKnown)
}
// Try to locate the channel funding multisig output.
_, expectedOutput, err := i.FundingOutput()
if err != nil {
return fmt.Errorf("funding output cannot be created: %v", err)
}
outputFound := false
outputSum := int64(0)
for _, out := range packet.UnsignedTx.TxOut {
outputSum += out.Value
if txOutsEqual(out, expectedOutput) {
outputFound = true
}
}
if !outputFound {
return fmt.Errorf("funding output not found in PSBT")
}
// At least one input needs to be specified and it must be large enough
// to pay for all outputs. We don't want to dive into fee estimation
// here so we just assume that if the input amount exceeds the output
// amount, the chosen fee is sufficient.
if len(packet.UnsignedTx.TxIn) == 0 {
return fmt.Errorf("PSBT has no inputs")
}
sum, err := sumUtxoInputValues(packet)
if err != nil {
return fmt.Errorf("error determining input sum: %v", err)
}
if sum <= outputSum {
return fmt.Errorf("input amount sum must be larger than " +
"output amount sum")
}
i.PendingPsbt = packet
i.State = PsbtVerified
return nil
}
// Finalize makes sure the final PSBT that is given to the intent is fully valid
// and signed but still contains the same UTXOs and outputs as the pending
// transaction we previously verified. If everything checks out, the funding
// manager is informed that the channel can now be opened and the funding
// transaction be broadcast.
func (i *PsbtIntent) Finalize(packet *psbt.Packet) error {
if packet == nil {
return fmt.Errorf("PSBT is nil")
}
if i.State != PsbtVerified {
return fmt.Errorf("invalid state. got %v expected %v", i.State,
PsbtVerified)
}
// Make sure the PSBT itself thinks it's finalized and ready to be
// broadcast.
err := psbt.MaybeFinalizeAll(packet)
if err != nil {
return fmt.Errorf("error finalizing PSBT: %v", err)
}
_, err = psbt.Extract(packet)
if err != nil {
return fmt.Errorf("unable to extract funding TX: %v", err)
}
// Do a basic check that this is still the same PSBT that we verified in
// the previous step. This is to protect the user from unwanted
// modifications. We only check the outputs and previous outpoints of
// the inputs of the wire transaction because the fields in the PSBT
// part are allowed to change.
if i.PendingPsbt == nil {
return fmt.Errorf("PSBT was not verified first")
}
err = verifyOutputsEqual(
packet.UnsignedTx.TxOut, i.PendingPsbt.UnsignedTx.TxOut,
)
if err != nil {
return fmt.Errorf("outputs differ from verified PSBT: %v", err)
}
err = verifyInputPrevOutpointsEqual(
packet.UnsignedTx.TxIn, i.PendingPsbt.UnsignedTx.TxIn,
)
if err != nil {
return fmt.Errorf("inputs differ from verified PSBT: %v", err)
}
// As far as we can tell, this PSBT is ok to be used as a funding
// transaction.
i.PendingPsbt = packet
i.State = PsbtFinalized
// Signal the funding manager that it can now finally continue with its
// funding flow as the PSBT is now ready to be converted into a real
// transaction and be published.
i.signalPsbtReady.Do(func() {
close(i.PsbtReady)
})
return nil
}
// CompileFundingTx finalizes the previously verified PSBT and returns the
// extracted binary serialized transaction from it. It also prepares the channel
// point for which this funding intent was initiated for.
func (i *PsbtIntent) CompileFundingTx() (*wire.MsgTx, error) {
if i.State != PsbtFinalized {
return nil, fmt.Errorf("invalid state. got %v expected %v",
i.State, PsbtFinalized)
}
// Make sure the PSBT can be finalized and extracted.
err := psbt.MaybeFinalizeAll(i.PendingPsbt)
if err != nil {
return nil, fmt.Errorf("error finalizing PSBT: %v", err)
}
fundingTx, err := psbt.Extract(i.PendingPsbt)
if err != nil {
return nil, fmt.Errorf("unable to extract funding TX: %v", err)
}
// Identify our funding outpoint now that we know everything's ready.
_, txOut, err := i.FundingOutput()
if err != nil {
return nil, fmt.Errorf("cannot get funding output: %v", err)
}
ok, idx := input.FindScriptOutputIndex(fundingTx, txOut.PkScript)
if !ok {
return nil, fmt.Errorf("funding output not found in PSBT")
}
i.chanPoint = &wire.OutPoint{
Hash: fundingTx.TxHash(),
Index: idx,
}
i.State = PsbtFundingTxCompiled
return fundingTx, nil
}
// RemoteCanceled informs the listener of the PSBT ready channel that the
// funding has been canceled by the remote peer and that we can no longer
// continue with it.
func (i *PsbtIntent) RemoteCanceled() {
log.Debugf("PSBT funding intent canceled by remote, state=%v", i.State)
i.signalPsbtReady.Do(func() {
i.PsbtReady <- ErrRemoteCanceled
i.State = PsbtResponderCanceled
})
i.ShimIntent.Cancel()
}
// Cancel allows the caller to cancel a funding Intent at any time. This will
// return make sure the channel funding flow with the remote peer is failed and
// any reservations are canceled.
//
// NOTE: Part of the chanfunding.Intent interface.
func (i *PsbtIntent) Cancel() {
log.Debugf("PSBT funding intent canceled, state=%v", i.State)
i.signalPsbtReady.Do(func() {
i.PsbtReady <- ErrUserCanceled
i.State = PsbtInitiatorCanceled
})
i.ShimIntent.Cancel()
}
// PsbtAssembler is a type of chanfunding.Assembler wherein the funding
// transaction is constructed outside of lnd by using partially signed bitcoin
// transactions (PSBT).
type PsbtAssembler struct {
// fundingAmt is the total amount of coins in the funding output.
fundingAmt btcutil.Amount
// basePsbt is the user-supplied base PSBT the channel output should be
// added to.
basePsbt *psbt.Packet
// netParams are the network parameters used to encode the P2WSH funding
// address.
netParams *chaincfg.Params
}
// NewPsbtAssembler creates a new CannedAssembler from the material required
// to construct a funding output and channel point. An optional base PSBT can
// be supplied which will be used to add the channel output to instead of
// creating a new one.
func NewPsbtAssembler(fundingAmt btcutil.Amount, basePsbt *psbt.Packet,
netParams *chaincfg.Params) *PsbtAssembler {
return &PsbtAssembler{
fundingAmt: fundingAmt,
basePsbt: basePsbt,
netParams: netParams,
}
}
// ProvisionChannel creates a new ShimIntent given the passed funding Request.
// The returned intent is immediately able to provide the channel point and
// funding output as they've already been created outside lnd.
//
// NOTE: This method satisfies the chanfunding.Assembler interface.
func (p *PsbtAssembler) ProvisionChannel(req *Request) (Intent, error) {
// We'll exit out if this field is set as the funding transaction will
// be assembled externally, so we don't influence coin selection.
if req.SubtractFees {
return nil, fmt.Errorf("SubtractFees not supported for PSBT")
}
intent := &PsbtIntent{
ShimIntent: ShimIntent{
localFundingAmt: p.fundingAmt,
},
State: PsbtShimRegistered,
BasePsbt: p.basePsbt,
PsbtReady: make(chan error, 1),
netParams: p.netParams,
}
// A simple sanity check to ensure the provisioned request matches the
// re-made shim intent.
if req.LocalAmt+req.RemoteAmt != p.fundingAmt {
return nil, fmt.Errorf("intent doesn't match PSBT "+
"assembler: local_amt=%v, remote_amt=%v, funding_amt=%v",
req.LocalAmt, req.RemoteAmt, p.fundingAmt)
}
return intent, nil
}
// FundingTxAvailable is an empty method that an assembler can implement to
// signal to callers that its able to provide the funding transaction for the
// channel via the intent it returns.
//
// NOTE: This method is a part of the FundingTxAssembler interface.
func (p *PsbtAssembler) FundingTxAvailable() {}
// A compile-time assertion to ensure PsbtAssembler meets the Assembler
// interface.
var _ Assembler = (*PsbtAssembler)(nil)
// sumUtxoInputValues tries to extract the sum of all inputs specified in the
// UTXO fields of the PSBT. An error is returned if an input is specified that
// does not contain any UTXO information.
func sumUtxoInputValues(packet *psbt.Packet) (int64, error) {
// We take the TX ins of the unsigned TX as the truth for how many
// inputs there should be, as the fields in the extra data part of the
// PSBT can be empty.
if len(packet.UnsignedTx.TxIn) != len(packet.Inputs) {
return 0, fmt.Errorf("TX input length doesn't match PSBT " +
"input length")
}
inputSum := int64(0)
for idx, in := range packet.Inputs {
switch {
case in.WitnessUtxo != nil:
// Witness UTXOs only need to reference the TxOut.
inputSum += in.WitnessUtxo.Value
case in.NonWitnessUtxo != nil:
// Non-witness UTXOs reference to the whole transaction
// the UTXO resides in.
utxOuts := in.NonWitnessUtxo.TxOut
txIn := packet.UnsignedTx.TxIn[idx]
inputSum += utxOuts[txIn.PreviousOutPoint.Index].Value
default:
return 0, fmt.Errorf("input %d has no UTXO information",
idx)
}
}
return inputSum, nil
}
// txOutsEqual returns true if two transaction outputs are equal.
func txOutsEqual(out1, out2 *wire.TxOut) bool {
if out1 == nil || out2 == nil {
return out1 == out2
}
return out1.Value == out2.Value &&
bytes.Equal(out1.PkScript, out2.PkScript)
}
// verifyOutputsEqual verifies that the two slices of transaction outputs are
// deep equal to each other. We do the length check and manual loop to provide
// better error messages to the user than just returning "not equal".
func verifyOutputsEqual(outs1, outs2 []*wire.TxOut) error {
if len(outs1) != len(outs2) {
return fmt.Errorf("number of outputs are different")
}
for idx, out := range outs1 {
// There is a byte slice in the output so we can't use the
// equality operator.
if !txOutsEqual(out, outs2[idx]) {
return fmt.Errorf("output %d is different", idx)
}
}
return nil
}
// verifyInputPrevOutpointsEqual verifies that the previous outpoints of the
// two slices of transaction inputs are deep equal to each other. We do the
// length check and manual loop to provide better error messages to the user
// than just returning "not equal".
func verifyInputPrevOutpointsEqual(ins1, ins2 []*wire.TxIn) error {
if len(ins1) != len(ins2) {
return fmt.Errorf("number of inputs are different")
}
for idx, in := range ins1 {
if in.PreviousOutPoint != ins2[idx].PreviousOutPoint {
return fmt.Errorf("previous outpoint of input %d is "+
"different", idx)
}
}
return nil
}

@ -0,0 +1,577 @@
package chanfunding
import (
"bytes"
"crypto/sha256"
"fmt"
"reflect"
"sync"
"testing"
"time"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/psbt"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
)
var (
localPrivkey = []byte{1, 2, 3, 4, 5, 6}
remotePrivkey = []byte{6, 5, 4, 3, 2, 1}
chanCapacity btcutil.Amount = 644000
params = chaincfg.RegressionNetParams
defaultTimeout = 50 * time.Millisecond
)
// TestPsbtIntent tests the basic happy path of the PSBT assembler and intent.
func TestPsbtIntent(t *testing.T) {
t.Parallel()
// Create a simple assembler and ask it to provision a channel to get
// the funding intent.
a := NewPsbtAssembler(chanCapacity, nil, &params)
intent, err := a.ProvisionChannel(&Request{LocalAmt: chanCapacity})
if err != nil {
t.Fatalf("error provisioning channel: %v", err)
}
psbtIntent, ok := intent.(*PsbtIntent)
if !ok {
t.Fatalf("intent was not a PsbtIntent")
}
if psbtIntent.State != PsbtShimRegistered {
t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
PsbtShimRegistered)
}
// The first step with the intent is that the funding manager starts
// negotiating with the remote peer and they accept. By accepting, they
// send over their multisig key that's going to be used for the funding
// output. With that known, we can start crafting a PSBT.
_, localPubkey := btcec.PrivKeyFromBytes(btcec.S256(), localPrivkey)
_, remotePubkey := btcec.PrivKeyFromBytes(btcec.S256(), remotePrivkey)
psbtIntent.BindKeys(
&keychain.KeyDescriptor{PubKey: localPubkey}, remotePubkey,
)
if psbtIntent.State != PsbtOutputKnown {
t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
PsbtOutputKnown)
}
// Make sure the output script address is correct.
script, _, err := input.GenFundingPkScript(
localPubkey.SerializeCompressed(),
remotePubkey.SerializeCompressed(), int64(chanCapacity),
)
if err != nil {
t.Fatalf("error calculating script: %v", err)
}
witnessScriptHash := sha256.Sum256(script)
addr, err := btcutil.NewAddressWitnessScriptHash(
witnessScriptHash[:], &params,
)
if err != nil {
t.Fatalf("unable to encode address: %v", err)
}
fundingAddr, amt, pendingPsbt, err := psbtIntent.FundingParams()
if err != nil {
t.Fatalf("unable to get funding params: %v", err)
}
if addr.EncodeAddress() != fundingAddr.EncodeAddress() {
t.Fatalf("unexpected address. got %s wanted %s", fundingAddr,
addr)
}
if amt != int64(chanCapacity) {
t.Fatalf("unexpected amount. got %d wanted %d", amt,
chanCapacity)
}
// Parse and check the returned PSBT packet.
if pendingPsbt == nil {
t.Fatalf("expected pending PSBT to be returned")
}
if len(pendingPsbt.UnsignedTx.TxOut) != 1 {
t.Fatalf("unexpected number of outputs. got %d wanted %d",
len(pendingPsbt.UnsignedTx.TxOut), 1)
}
txOut := pendingPsbt.UnsignedTx.TxOut[0]
if !bytes.Equal(txOut.PkScript[2:], witnessScriptHash[:]) {
t.Fatalf("unexpected PK script in output. got %x wanted %x",
txOut.PkScript[2:], witnessScriptHash)
}
if txOut.Value != int64(chanCapacity) {
t.Fatalf("unexpected value in output. got %d wanted %d",
txOut.Value, chanCapacity)
}
// Add an input to the pending TX to simulate it being funded.
pendingPsbt.UnsignedTx.TxIn = []*wire.TxIn{
{PreviousOutPoint: wire.OutPoint{Index: 0}},
}
pendingPsbt.Inputs = []psbt.PInput{
{WitnessUtxo: &wire.TxOut{Value: int64(chanCapacity + 1)}},
}
// Verify the dummy PSBT with the intent.
err = psbtIntent.Verify(pendingPsbt)
if err != nil {
t.Fatalf("error verifying pending PSBT: %v", err)
}
if psbtIntent.State != PsbtVerified {
t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
PsbtVerified)
}
// Add some fake witness data to the transaction so it thinks it's
// signed.
pendingPsbt.Inputs[0].WitnessUtxo = &wire.TxOut{
Value: int64(chanCapacity) * 2,
PkScript: []byte{99, 99, 99},
}
pendingPsbt.Inputs[0].FinalScriptSig = []byte{88, 88, 88}
pendingPsbt.Inputs[0].FinalScriptWitness = []byte{2, 0, 0}
// If we call Finalize, the intent will signal to the funding manager
// that it can continue with the funding flow. We want to make sure
// the signal arrives.
var wg sync.WaitGroup
errChan := make(chan error, 1)
wg.Add(1)
go func() {
defer wg.Done()
select {
case err := <-psbtIntent.PsbtReady:
errChan <- err
case <-time.After(defaultTimeout):
errChan <- fmt.Errorf("timed out")
}
}()
err = psbtIntent.Finalize(pendingPsbt)
if err != nil {
t.Fatalf("error finalizing pending PSBT: %v", err)
}
wg.Wait()
// We should have a nil error in our channel now.
err = <-errChan
if err != nil {
t.Fatalf("unexpected error after finalize: %v", err)
}
if psbtIntent.State != PsbtFinalized {
t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
PsbtFinalized)
}
// Make sure the funding transaction can be compiled.
_, err = psbtIntent.CompileFundingTx()
if err != nil {
t.Fatalf("error compiling funding TX from PSBT: %v", err)
}
if psbtIntent.State != PsbtFundingTxCompiled {
t.Fatalf("unexpected state. got %d wanted %d", psbtIntent.State,
PsbtFundingTxCompiled)
}
}
// TestPsbtIntentBasePsbt tests that a channel funding output can be appended to
// a given base PSBT in the funding flow.
func TestPsbtIntentBasePsbt(t *testing.T) {
t.Parallel()
// First create a dummy PSBT with a single output.
pendingPsbt, err := psbt.New(
[]*wire.OutPoint{{}}, []*wire.TxOut{
{Value: 999, PkScript: []byte{99, 88, 77}},
}, 2, 0, []uint32{0},
)
if err != nil {
t.Fatalf("unable to create dummy PSBT")
}
// Generate the funding multisig keys and the address so we can compare
// it to the output of the intent.
_, localPubkey := btcec.PrivKeyFromBytes(btcec.S256(), localPrivkey)
_, remotePubkey := btcec.PrivKeyFromBytes(btcec.S256(), remotePrivkey)
// Make sure the output script address is correct.
script, _, err := input.GenFundingPkScript(
localPubkey.SerializeCompressed(),
remotePubkey.SerializeCompressed(), int64(chanCapacity),
)
if err != nil {
t.Fatalf("error calculating script: %v", err)
}
witnessScriptHash := sha256.Sum256(script)
addr, err := btcutil.NewAddressWitnessScriptHash(
witnessScriptHash[:], &params,
)
if err != nil {
t.Fatalf("unable to encode address: %v", err)
}
// Now as the next step, create a new assembler/intent pair with a base
// PSBT to see that we can add an additional output to it.
a := NewPsbtAssembler(chanCapacity, pendingPsbt, &params)
intent, err := a.ProvisionChannel(&Request{LocalAmt: chanCapacity})
if err != nil {
t.Fatalf("error provisioning channel: %v", err)
}
psbtIntent, ok := intent.(*PsbtIntent)
if !ok {
t.Fatalf("intent was not a PsbtIntent")
}
psbtIntent.BindKeys(
&keychain.KeyDescriptor{PubKey: localPubkey}, remotePubkey,
)
newAddr, amt, twoOutPsbt, err := psbtIntent.FundingParams()
if err != nil {
t.Fatalf("unable to get funding params: %v", err)
}
if addr.EncodeAddress() != newAddr.EncodeAddress() {
t.Fatalf("unexpected address. got %s wanted %s", newAddr,
addr)
}
if amt != int64(chanCapacity) {
t.Fatalf("unexpected amount. got %d wanted %d", amt,
chanCapacity)
}
if len(twoOutPsbt.UnsignedTx.TxOut) != 2 {
t.Fatalf("unexpected number of outputs. got %d wanted %d",
len(twoOutPsbt.UnsignedTx.TxOut), 2)
}
if len(twoOutPsbt.UnsignedTx.TxIn) != 1 {
t.Fatalf("unexpected number of inputs. got %d wanted %d",
len(twoOutPsbt.UnsignedTx.TxIn), 1)
}
txOld := pendingPsbt.UnsignedTx
txNew := twoOutPsbt.UnsignedTx
prevoutEqual := reflect.DeepEqual(
txOld.TxIn[0].PreviousOutPoint, txNew.TxIn[0].PreviousOutPoint,
)
if !prevoutEqual {
t.Fatalf("inputs changed. got %s wanted %s",
spew.Sdump(txOld.TxIn[0].PreviousOutPoint),
spew.Sdump(txNew.TxIn[0].PreviousOutPoint))
}
if !reflect.DeepEqual(txOld.TxOut[0], txNew.TxOut[0]) {
t.Fatalf("existing output changed. got %v wanted %v",
txOld.TxOut[0], txNew.TxOut[0])
}
}
// TestPsbtVerify tests the PSBT verification process more deeply than just
// the happy path.
func TestPsbtVerify(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
expectedErr string
doVerify func(int64, *psbt.Packet, *PsbtIntent) error
}{
{
name: "nil packet",
expectedErr: "PSBT is nil",
doVerify: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
return i.Verify(nil)
},
},
{
name: "wrong state",
expectedErr: "invalid state. got user_canceled " +
"expected output_known",
doVerify: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
i.State = PsbtInitiatorCanceled
return i.Verify(p)
},
},
{
name: "output not found, value wrong",
expectedErr: "funding output not found in PSBT",
doVerify: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
p.UnsignedTx.TxOut[0].Value = 123
return i.Verify(p)
},
},
{
name: "output not found, pk script wrong",
expectedErr: "funding output not found in PSBT",
doVerify: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
p.UnsignedTx.TxOut[0].PkScript = []byte{1, 2, 3}
return i.Verify(p)
},
},
{
name: "no inputs",
expectedErr: "PSBT has no inputs",
doVerify: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
return i.Verify(p)
},
},
{
name: "input(s) too small",
expectedErr: "input amount sum must be larger than " +
"output amount sum",
doVerify: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
p.UnsignedTx.TxIn = []*wire.TxIn{{}}
p.Inputs = []psbt.PInput{{
WitnessUtxo: &wire.TxOut{
Value: int64(chanCapacity),
},
}}
return i.Verify(p)
},
},
{
name: "input correct",
expectedErr: "",
doVerify: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
txOut := &wire.TxOut{
Value: int64(chanCapacity/2) + 1,
}
p.UnsignedTx.TxIn = []*wire.TxIn{
{},
{
PreviousOutPoint: wire.OutPoint{
Index: 0,
},
},
}
p.Inputs = []psbt.PInput{
{
WitnessUtxo: txOut,
},
{
NonWitnessUtxo: &wire.MsgTx{
TxOut: []*wire.TxOut{
txOut,
},
},
}}
return i.Verify(p)
},
},
}
// Create a simple assembler and ask it to provision a channel to get
// the funding intent.
a := NewPsbtAssembler(chanCapacity, nil, &params)
intent, err := a.ProvisionChannel(&Request{LocalAmt: chanCapacity})
if err != nil {
t.Fatalf("error provisioning channel: %v", err)
}
psbtIntent := intent.(*PsbtIntent)
// Bind our test keys to get the funding parameters.
_, localPubkey := btcec.PrivKeyFromBytes(btcec.S256(), localPrivkey)
_, remotePubkey := btcec.PrivKeyFromBytes(btcec.S256(), remotePrivkey)
psbtIntent.BindKeys(
&keychain.KeyDescriptor{PubKey: localPubkey}, remotePubkey,
)
// Loop through all our test cases.
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
// Reset the state from a previous test and create a new
// pending PSBT that we can manipulate.
psbtIntent.State = PsbtOutputKnown
_, amt, pendingPsbt, err := psbtIntent.FundingParams()
if err != nil {
t.Fatalf("unable to get funding params: %v", err)
}
err = tc.doVerify(amt, pendingPsbt, psbtIntent)
if err != nil && tc.expectedErr != "" &&
err.Error() != tc.expectedErr {
t.Fatalf("unexpected error, got '%v' wanted "+
"'%v'", err, tc.expectedErr)
}
})
}
}
// TestPsbtFinalize tests the PSBT finalization process more deeply than just
// the happy path.
func TestPsbtFinalize(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
expectedErr string
doFinalize func(int64, *psbt.Packet, *PsbtIntent) error
}{
{
name: "nil packet",
expectedErr: "PSBT is nil",
doFinalize: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
return i.Finalize(nil)
},
},
{
name: "wrong state",
expectedErr: "invalid state. got user_canceled " +
"expected verified",
doFinalize: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
i.State = PsbtInitiatorCanceled
return i.Finalize(p)
},
},
{
name: "not verified first",
expectedErr: "PSBT was not verified first",
doFinalize: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
i.State = PsbtVerified
i.PendingPsbt = nil
return i.Finalize(p)
},
},
{
name: "output value changed",
expectedErr: "outputs differ from verified PSBT: " +
"output 0 is different",
doFinalize: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
p.UnsignedTx.TxOut[0].Value = 123
return i.Finalize(p)
},
},
{
name: "output pk script changed",
expectedErr: "outputs differ from verified PSBT: " +
"output 0 is different",
doFinalize: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
p.UnsignedTx.TxOut[0].PkScript = []byte{3, 2, 1}
return i.Finalize(p)
},
},
{
name: "input previous outpoint index changed",
expectedErr: "inputs differ from verified PSBT: " +
"previous outpoint of input 0 is different",
doFinalize: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
p.UnsignedTx.TxIn[0].PreviousOutPoint.Index = 0
return i.Finalize(p)
},
},
{
name: "input previous outpoint hash changed",
expectedErr: "inputs differ from verified PSBT: " +
"previous outpoint of input 0 is different",
doFinalize: func(amt int64, p *psbt.Packet,
i *PsbtIntent) error {
prevout := &p.UnsignedTx.TxIn[0].PreviousOutPoint
prevout.Hash = chainhash.Hash{77, 88, 99, 11}
return i.Finalize(p)
},
},
}
// Create a simple assembler and ask it to provision a channel to get
// the funding intent.
a := NewPsbtAssembler(chanCapacity, nil, &params)
intent, err := a.ProvisionChannel(&Request{LocalAmt: chanCapacity})
if err != nil {
t.Fatalf("error provisioning channel: %v", err)
}
psbtIntent := intent.(*PsbtIntent)
// Bind our test keys to get the funding parameters.
_, localPubkey := btcec.PrivKeyFromBytes(btcec.S256(), localPrivkey)
_, remotePubkey := btcec.PrivKeyFromBytes(btcec.S256(), remotePrivkey)
psbtIntent.BindKeys(
&keychain.KeyDescriptor{PubKey: localPubkey}, remotePubkey,
)
// Loop through all our test cases.
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
// Reset the state from a previous test and create a new
// pending PSBT that we can manipulate.
psbtIntent.State = PsbtOutputKnown
_, amt, pendingPsbt, err := psbtIntent.FundingParams()
if err != nil {
t.Fatalf("unable to get funding params: %v", err)
}
// We need to have a simulated transaction here that is
// fully funded and signed.
pendingPsbt.UnsignedTx.TxIn = []*wire.TxIn{{
PreviousOutPoint: wire.OutPoint{
Index: 1,
Hash: chainhash.Hash{1, 2, 3},
},
}}
pendingPsbt.Inputs = []psbt.PInput{{
WitnessUtxo: &wire.TxOut{
Value: int64(chanCapacity) + 1,
PkScript: []byte{1, 2, 3},
},
FinalScriptWitness: []byte{0x01, 0x00},
}}
err = psbtIntent.Verify(pendingPsbt)
if err != nil {
t.Fatalf("error verifying PSBT: %v", err)
}
// Deep clone the PSBT so we don't modify the pending
// one that was registered during Verify.
pendingPsbt = clonePsbt(t, pendingPsbt)
err = tc.doFinalize(amt, pendingPsbt, psbtIntent)
if (err == nil && tc.expectedErr != "") ||
(err != nil && err.Error() != tc.expectedErr) {
t.Fatalf("unexpected error, got '%v' wanted "+
"'%v'", err, tc.expectedErr)
}
})
}
}
// clonePsbt creates a clone of a PSBT packet by serializing then de-serializing
// it.
func clonePsbt(t *testing.T, p *psbt.Packet) *psbt.Packet {
var buf bytes.Buffer
err := p.Serialize(&buf)
if err != nil {
t.Fatalf("error serializing PSBT: %v", err)
}
newPacket, err := psbt.NewFromRawBytes(&buf, false)
if err != nil {
t.Fatalf("error unserializing PSBT: %v", err)
}
return newPacket
}

@ -590,6 +590,7 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
FundingFeePerKw: feePerKw,
PushMSat: 0,
Flags: lnwire.FFAnnounceChannel,
PendingChanID: [32]byte{0, 1, 2, 3},
}
if _, err := alice.InitChannelReservation(req); err != nil {
t.Fatalf("unable to initialize funding reservation 1: %v", err)
@ -612,6 +613,7 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
FundingFeePerKw: feePerKw,
PushMSat: 0,
Flags: lnwire.FFAnnounceChannel,
PendingChanID: [32]byte{1, 2, 3, 4},
}
failedReservation, err := alice.InitChannelReservation(failedReq)
if err == nil {
@ -648,6 +650,7 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
FundingFeePerKw: feePerKw,
PushMSat: 0,
Flags: lnwire.FFAnnounceChannel,
PendingChanID: [32]byte{2, 3, 4, 5},
}
chanReservation, err := alice.InitChannelReservation(req)
if err != nil {
@ -655,6 +658,7 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
}
// Attempt to create another channel with 44 BTC, this should fail.
req.PendingChanID = [32]byte{3, 4, 5, 6}
_, err = alice.InitChannelReservation(req)
if _, ok := err.(*chanfunding.ErrInsufficientFunds); !ok {
t.Fatalf("coin selection succeeded should have insufficient funds: %v",
@ -684,6 +688,7 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
// attempting coin selection.
// Request to fund a new channel should now succeed.
req.PendingChanID = [32]byte{4, 5, 6, 7, 8}
if _, err := alice.InitChannelReservation(req); err != nil {
t.Fatalf("unable to initialize funding reservation: %v", err)
}

@ -471,6 +471,37 @@ func (r *ChannelReservation) ProcessContribution(theirContribution *ChannelContr
return <-errChan
}
// IsPsbt returns true if there is a PSBT funding intent mapped to this
// reservation.
func (r *ChannelReservation) IsPsbt() bool {
_, ok := r.fundingIntent.(*chanfunding.PsbtIntent)
return ok
}
// ProcessPsbt continues a previously paused funding flow that involves PSBT to
// construct the funding transaction. This method can be called once the PSBT is
// finalized and the signed transaction is available.
func (r *ChannelReservation) ProcessPsbt() error {
errChan := make(chan error, 1)
r.wallet.msgChan <- &continueContributionMsg{
pendingFundingID: r.reservationID,
err: errChan,
}
return <-errChan
}
// RemoteCanceled informs the PSBT funding state machine that the remote peer
// has canceled the pending reservation, likely due to a timeout.
func (r *ChannelReservation) RemoteCanceled() {
psbtIntent, ok := r.fundingIntent.(*chanfunding.PsbtIntent)
if !ok {
return
}
psbtIntent.RemoteCanceled()
}
// ProcessSingleContribution verifies, and records the initiator's contribution
// to this pending single funder channel. Internally, no further action is
// taken other than recording the initiator's contribution to the single funder

@ -15,6 +15,7 @@ import (
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/psbt"
"github.com/btcsuite/btcutil/txsort"
"github.com/davecgh/go-spew/spew"
"github.com/lightningnetwork/lnd/channeldb"
@ -33,6 +34,28 @@ const (
msgBufferSize = 100
)
var (
// ErrPsbtFundingRequired is the error that is returned during the
// contribution handling process if the process should be paused for
// the construction of a PSBT outside of lnd's wallet.
ErrPsbtFundingRequired = errors.New("PSBT funding required")
)
// PsbtFundingRequired is a type that implements the error interface and
// contains the information needed to construct a PSBT.
type PsbtFundingRequired struct {
// Intent is the pending PSBT funding intent that needs to be funded
// if the wrapping error is returned.
Intent *chanfunding.PsbtIntent
}
// Error returns the underlying error.
//
// NOTE: This method is part of the error interface.
func (p *PsbtFundingRequired) Error() string {
return ErrPsbtFundingRequired.Error()
}
// 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
@ -150,6 +173,16 @@ type addContributionMsg struct {
err chan error
}
// continueContributionMsg represents a message that signals that the
// interrupted funding process involving a PSBT can now be continued because the
// finalized transaction is now available.
type continueContributionMsg struct {
pendingFundingID uint64
// NOTE: In order to avoid deadlocks, this channel MUST be buffered.
err chan error
}
// addSingleContributionMsg represents a message executing the second phase of
// a single funder channel reservation workflow. This messages carries the
// counterparty's "contribution" to the payment channel. As this message is
@ -395,6 +428,8 @@ out:
l.handleSingleContribution(msg)
case *addContributionMsg:
l.handleContributionMsg(msg)
case *continueContributionMsg:
l.handleChanPointReady(msg)
case *addSingleFunderSigsMsg:
l.handleSingleFunderSigs(msg)
case *addCounterPartySigsMsg:
@ -462,17 +497,74 @@ func (l *LightningWallet) RegisterFundingIntent(expectedID [32]byte,
return nil
}
// PsbtFundingVerify looks up a previously registered funding intent by its
// pending channel ID and tries to advance the state machine by verifying the
// passed PSBT.
func (l *LightningWallet) PsbtFundingVerify(pid [32]byte,
packet *psbt.Packet) error {
l.intentMtx.Lock()
defer l.intentMtx.Unlock()
intent, ok := l.fundingIntents[pid]
if !ok {
return fmt.Errorf("no funding intent found for "+
"pendingChannelID(%x)", pid[:])
}
psbtIntent, ok := intent.(*chanfunding.PsbtIntent)
if !ok {
return fmt.Errorf("incompatible funding intent")
}
err := psbtIntent.Verify(packet)
if err != nil {
return fmt.Errorf("error verifying PSBT: %v", err)
}
return nil
}
// PsbtFundingFinalize looks up a previously registered funding intent by its
// pending channel ID and tries to advance the state machine by finalizing the
// passed PSBT.
func (l *LightningWallet) PsbtFundingFinalize(pid [32]byte,
packet *psbt.Packet) error {
l.intentMtx.Lock()
defer l.intentMtx.Unlock()
intent, ok := l.fundingIntents[pid]
if !ok {
return fmt.Errorf("no funding intent found for "+
"pendingChannelID(%x)", pid[:])
}
psbtIntent, ok := intent.(*chanfunding.PsbtIntent)
if !ok {
return fmt.Errorf("incompatible funding intent")
}
err := psbtIntent.Finalize(packet)
if err != nil {
return fmt.Errorf("error finalizing PSBT: %v", err)
}
return nil
}
// CancelFundingIntent allows a caller to cancel a previously registered
// funding intent. If no intent was found, then an error will be returned.
func (l *LightningWallet) CancelFundingIntent(pid [32]byte) error {
l.intentMtx.Lock()
defer l.intentMtx.Unlock()
if _, ok := l.fundingIntents[pid]; !ok {
intent, ok := l.fundingIntents[pid]
if !ok {
return fmt.Errorf("no funding intent found for "+
"pendingChannelID(%x)", pid[:])
}
// Give the intent a chance to clean up after itself, removing coin
// locks or similar reserved resources.
intent.Cancel()
delete(l.fundingIntents, pid)
return nil
@ -556,10 +648,28 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
return
}
// Register the funding intent now in case we need to access it
// again later, as it's the case for the PSBT state machine for
// example.
err = l.RegisterFundingIntent(req.PendingChanID, fundingIntent)
if err != nil {
req.err <- err
req.resp <- nil
return
}
localFundingAmt = fundingIntent.LocalFundingAmt()
remoteFundingAmt = fundingIntent.RemoteFundingAmt()
}
// At this point there _has_ to be a funding intent, otherwise something
// went really wrong.
if fundingIntent == nil {
req.err <- fmt.Errorf("no funding intent present")
req.resp <- nil
return
}
// If this is a shim intent, then it may be attempting to use an
// existing set of keys for the funding workflow. In this case, we'll
// make a simple wrapper keychain.KeyRing that will proxy certain
@ -592,9 +702,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
thawHeight,
)
if err != nil {
if fundingIntent != nil {
fundingIntent.Cancel()
}
fundingIntent.Cancel()
req.err <- err
req.resp <- nil
@ -605,9 +713,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
reservation, fundingIntent, req.NodeAddr, req.NodeID, keyRing,
)
if err != nil {
if fundingIntent != nil {
fundingIntent.Cancel()
}
fundingIntent.Cancel()
req.err <- err
req.resp <- nil
@ -852,6 +958,9 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
// which type of intent we obtained from our chanfunding.Assembler,
// we'll carry out a distinct set of steps.
switch fundingIntent := pendingReservation.fundingIntent.(type) {
// The transaction was created outside of the wallet and might already
// be published. Nothing left to do other than using the correct
// outpoint.
case *chanfunding.ShimIntent:
chanPoint, err = fundingIntent.ChanPoint()
if err != nil {
@ -861,6 +970,38 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
pendingReservation.partialState.FundingOutpoint = *chanPoint
// The user has signaled that they want to use a PSBT to construct the
// funding transaction. Because we now have the multisig keys from both
// parties, we can create the multisig script that needs to be funded
// and then pause the process until the user supplies the PSBT
// containing the eventual funding transaction.
case *chanfunding.PsbtIntent:
if fundingIntent.PendingPsbt != nil {
req.err <- fmt.Errorf("PSBT funding already in" +
"progress")
return
}
// Now that we know our contribution, we can bind both the local
// and remote key which will be needed to calculate the multisig
// funding output in a next step.
pendingChanID := pendingReservation.pendingChanID
walletLog.Debugf("Advancing PSBT funding flow for "+
"pending_id(%x), binding keys local_key=%v, "+
"remote_key=%x", pendingChanID,
&ourContribution.MultiSigKey,
theirContribution.MultiSigKey.PubKey.SerializeCompressed())
fundingIntent.BindKeys(
&ourContribution.MultiSigKey,
theirContribution.MultiSigKey.PubKey,
)
// Exit early because we can't continue the funding flow yet.
req.err <- &PsbtFundingRequired{
Intent: fundingIntent,
}
return
case *chanfunding.FullIntent:
// Now that we know their public key, we can bind theirs as
// well as ours to the funding intent.
@ -915,6 +1056,69 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
"generated: %v", chanPoint, spew.Sdump(fundingTx))
}
// If we landed here and didn't exit early, it means we already have
// the channel point ready. We can jump directly to the next step.
l.handleChanPointReady(&continueContributionMsg{
pendingFundingID: req.pendingFundingID,
err: req.err,
})
}
// handleChanPointReady continues the funding process once the channel point
// is known and the funding transaction can be completed.
func (l *LightningWallet) handleChanPointReady(req *continueContributionMsg) {
l.limboMtx.Lock()
pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
l.limboMtx.Unlock()
if !ok {
req.err <- fmt.Errorf("attempted to update non-existent " +
"funding state")
return
}
ourContribution := pendingReservation.ourContribution
theirContribution := pendingReservation.theirContribution
chanPoint := pendingReservation.partialState.FundingOutpoint
// If we're in the PSBT funding flow, we now should have everything that
// is needed to construct and publish the full funding transaction.
intent := pendingReservation.fundingIntent
if psbtIntent, ok := intent.(*chanfunding.PsbtIntent); ok {
// With our keys bound, we can now construct+sign the final
// funding transaction and also obtain the chanPoint that
// creates the channel.
fundingTx, err := psbtIntent.CompileFundingTx()
if err != nil {
req.err <- fmt.Errorf("unable to construct funding "+
"tx: %v", err)
return
}
chanPointPtr, err := psbtIntent.ChanPoint()
if err != nil {
req.err <- fmt.Errorf("unable to obtain chan "+
"point: %v", err)
return
}
// Finally, we'll populate the relevant information in our
// pendingReservation so the rest of the funding flow can
// continue as normal.
pendingReservation.fundingTx = fundingTx
pendingReservation.partialState.FundingOutpoint = *chanPointPtr
chanPoint = *chanPointPtr
pendingReservation.ourFundingInputScripts = make(
[]*input.Script, 0, len(ourContribution.Inputs),
)
for _, txIn := range fundingTx.TxIn {
pendingReservation.ourFundingInputScripts = append(
pendingReservation.ourFundingInputScripts,
&input.Script{
Witness: txIn.Witness,
SigScript: txIn.SignatureScript,
},
)
}
}
// Initialize an empty sha-chain for them, tracking the current pending
// revocation hash (we don't yet know the preimage so we can't add it
// to the chain).
@ -930,7 +1134,7 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
// Create the txin to our commitment transaction; required to construct
// the commitment transactions.
fundingTxIn := wire.TxIn{
PreviousOutPoint: *chanPoint,
PreviousOutPoint: chanPoint,
}
// With the funding tx complete, create both commitment transactions.
@ -991,7 +1195,7 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
chanPoint, spew.Sdump(theirCommitTx))
// Record newly available information within the open channel state.
chanState.FundingOutpoint = *chanPoint
chanState.FundingOutpoint = chanPoint
chanState.LocalCommitment.CommitTx = ourCommitTx
chanState.RemoteCommitment.CommitTx = theirCommitTx

@ -19,10 +19,12 @@ import (
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/psbt"
"github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/davecgh/go-spew/spew"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
@ -1556,6 +1558,51 @@ func newFundingShimAssembler(chanPointShim *lnrpc.ChanPointShim, initiator bool,
), nil
}
// newFundingShimAssembler returns a new fully populated
// chanfunding.PsbtAssembler using a FundingShim obtained from an RPC caller.
func newPsbtAssembler(req *lnrpc.OpenChannelRequest, normalizedMinConfs int32,
psbtShim *lnrpc.PsbtShim, netParams *chaincfg.Params) (
chanfunding.Assembler, error) {
var (
packet *psbt.Packet
err error
)
// Perform some basic sanity checks to ensure that all the expected
// fields are populated and none of the incompatible fields are.
if len(psbtShim.PendingChanId) != 32 {
return nil, fmt.Errorf("pending chan ID not set")
}
if normalizedMinConfs != 1 {
return nil, fmt.Errorf("setting non-default values for " +
"minimum confirmation is not supported for PSBT " +
"funding")
}
if req.SatPerByte != 0 || req.TargetConf != 0 {
return nil, fmt.Errorf("specifying fee estimation parameters " +
"is not supported for PSBT funding")
}
// The base PSBT is optional. But if it's set, it has to be a valid,
// binary serialized PSBT.
if len(psbtShim.BasePsbt) > 0 {
packet, err = psbt.NewFromRawBytes(
bytes.NewReader(psbtShim.BasePsbt), false,
)
if err != nil {
return nil, fmt.Errorf("error parsing base PSBT: %v",
err)
}
}
// With all the parts assembled, we can now make the canned assembler
// to pass into the wallet.
return chanfunding.NewPsbtAssembler(
btcutil.Amount(req.LocalFundingAmount), packet, netParams,
), nil
}
// OpenChannel attempts to open a singly funded channel specified in the
// request to a remote peer.
func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
@ -1675,10 +1722,11 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
// If the user has provided a shim, then we'll now augment the based
// open channel request with this additional logic.
if in.FundingShim != nil {
switch {
// If we have a chan point shim, then this means the funding
// transaction was crafted externally. In this case we only
// need to hand a channel point down into the wallet.
if in.FundingShim.GetChanPointShim() != nil {
case in.FundingShim.GetChanPointShim() != nil:
chanPointShim := in.FundingShim.GetChanPointShim()
// Map the channel point shim into a new
@ -1691,6 +1739,25 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
if err != nil {
return err
}
// If we have a PSBT shim, then this means the funding
// transaction will be crafted outside of the wallet, once the
// funding multisig output script is known. We'll create an
// intent that will supervise the multi-step process.
case in.FundingShim.GetPsbtShim() != nil:
psbtShim := in.FundingShim.GetPsbtShim()
// Instruct the wallet to use the new
// chanfunding.PsbtAssembler to construct the funding
// transaction.
copy(req.pendingChanID[:], psbtShim.PendingChanId)
req.chanFunder, err = newPsbtAssembler(
in, minConfs, psbtShim,
&r.server.cc.wallet.Cfg.NetParams,
)
if err != nil {
return err
}
}
}
@ -6236,6 +6303,7 @@ func (r *rpcServer) BakeMacaroon(ctx context.Context,
func (r *rpcServer) FundingStateStep(ctx context.Context,
in *lnrpc.FundingTransitionMsg) (*lnrpc.FundingStateStepResp, error) {
var pendingChanID [32]byte
switch {
// If this is a message to register a new shim that is an external
@ -6269,7 +6337,6 @@ func (r *rpcServer) FundingStateStep(ctx context.Context,
// Once we receive an incoming funding request that uses this
// pending channel ID, then this shim will be dispatched in
// place of our regular funding workflow.
var pendingChanID [32]byte
copy(pendingChanID[:], rpcShimIntent.PendingChanId)
err = r.server.cc.wallet.RegisterFundingIntent(
pendingChanID, shimIntent,
@ -6278,18 +6345,71 @@ func (r *rpcServer) FundingStateStep(ctx context.Context,
return nil, err
}
// There is no need to register a PSBT shim before opening the channel,
// even though our RPC message structure allows for it. Inform the user
// by returning a proper error instead of just doing nothing.
case in.GetShimRegister() != nil &&
in.GetShimRegister().GetPsbtShim() != nil:
return nil, fmt.Errorf("PSBT shim must only be sent when " +
"opening a channel")
// If this is a transition to cancel an existing shim, then we'll pass
// this message along to the wallet.
// this message along to the wallet, informing it that the intent no
// longer needs to be considered and should be cleaned up.
case in.GetShimCancel() != nil:
pid := in.GetShimCancel().PendingChanId
var pendingChanID [32]byte
copy(pendingChanID[:], pid)
rpcsLog.Debugf("Canceling funding shim for pending_id=%x",
in.GetShimCancel().PendingChanId)
copy(pendingChanID[:], in.GetShimCancel().PendingChanId)
err := r.server.cc.wallet.CancelFundingIntent(pendingChanID)
if err != nil {
return nil, err
}
// If this is a transition to verify the PSBT for an existing shim,
// we'll do so and then store the verified PSBT for later so we can
// compare it to the final, signed one.
case in.GetPsbtVerify() != nil:
rpcsLog.Debugf("Verifying PSBT for pending_id=%x",
in.GetPsbtVerify().PendingChanId)
copy(pendingChanID[:], in.GetPsbtVerify().PendingChanId)
packet, err := psbt.NewFromRawBytes(
bytes.NewReader(in.GetPsbtVerify().FundedPsbt), false,
)
if err != nil {
return nil, fmt.Errorf("error parsing psbt: %v", err)
}
err = r.server.cc.wallet.PsbtFundingVerify(
pendingChanID, packet,
)
if err != nil {
return nil, err
}
// If this is a transition to finalize the PSBT funding flow, we compare
// the final PSBT to the previously verified one and if nothing
// unexpected was changed, continue the channel opening process.
case in.GetPsbtFinalize() != nil:
rpcsLog.Debugf("Finalizing PSBT for pending_id=%x",
in.GetPsbtFinalize().PendingChanId)
copy(pendingChanID[:], in.GetPsbtFinalize().PendingChanId)
packet, err := psbt.NewFromRawBytes(
bytes.NewReader(in.GetPsbtFinalize().SignedPsbt), false,
)
if err != nil {
return nil, fmt.Errorf("error parsing psbt: %v", err)
}
err = r.server.cc.wallet.PsbtFundingFinalize(
pendingChanID, packet,
)
if err != nil {
return nil, err
}
}
// TODO(roasbeef): extend PendingChannels to also show shims