From c824af11a16658777b4be27fd9b7cf4c833dc7d6 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:02:51 -0700 Subject: [PATCH 01/15] aezeed: expose BirthdayTime conversion from offset --- aezeed/cipherseed.go | 13 ++++++++++--- aezeed/cipherseed_test.go | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/aezeed/cipherseed.go b/aezeed/cipherseed.go index 3c34754dd..3459e4cdf 100644 --- a/aezeed/cipherseed.go +++ b/aezeed/cipherseed.go @@ -126,12 +126,12 @@ var ( ) var ( - // bitcoinGenesisDate is the timestamp of Bitcoin's genesis block. + // BitcoinGenesisDate is the timestamp of Bitcoin's genesis block. // We'll use this value in order to create a compact birthday for the // seed. The birthday will be interested as the number of days since // the genesis date. We refer to this time period as ABE (after Bitcoin // era). - bitcoinGenesisDate = time.Unix(1231006505, 0) + BitcoinGenesisDate = time.Unix(1231006505, 0) ) // CipherSeed is a fully decoded instance of the aezeed scheme. At a high @@ -201,7 +201,7 @@ func New(internalVersion uint8, entropy *[EntropySize]byte, // To compute our "birthday", we'll first use the current time, then // subtract that from the Bitcoin Genesis Date. We'll then convert that // value to days. - birthday := uint16(now.Sub(bitcoinGenesisDate) / (time.Hour * 24)) + birthday := uint16(now.Sub(BitcoinGenesisDate) / (time.Hour * 24)) c := &CipherSeed{ InternalVersion: internalVersion, @@ -384,6 +384,13 @@ func (c *CipherSeed) Encipher(pass []byte) ([EncipheredCipherSeedSize]byte, erro return c.encipher(pass) } +// BirthdayTime returns the cipher seed's internal birthday format as a native +// golang Time struct. +func (c *CipherSeed) BirthdayTime() time.Time { + offset := time.Duration(c.Birthday) * 24 * time.Hour + return BitcoinGenesisDate.Add(offset) +} + // Mnemonic is a 24-word passphrase as of CipherSeedVersion zero. This // passphrase encodes an encrypted seed triple (version, birthday, entropy). // Additionally, we also encode the salt used with scrypt to derive the key diff --git a/aezeed/cipherseed_test.go b/aezeed/cipherseed_test.go index 7703bdc54..e17d8e64a 100644 --- a/aezeed/cipherseed_test.go +++ b/aezeed/cipherseed_test.go @@ -33,7 +33,7 @@ var ( version0TestVectors = []TestVector{ { version: 0, - time: bitcoinGenesisDate, + time: BitcoinGenesisDate, entropy: testEntropy, salt: testSalt, password: []byte{}, @@ -466,7 +466,7 @@ func TestSeedEncodeDecode(t *testing.T) { now := time.Unix(nowInt, 0) seed := CipherSeed{ InternalVersion: version, - Birthday: uint16(now.Sub(bitcoinGenesisDate) / (time.Hour * 24)), + Birthday: uint16(now.Sub(BitcoinGenesisDate) / (time.Hour * 24)), Entropy: entropy, } From f8c0357770f289091f4a7491c039b50425f40cd8 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:07:22 -0700 Subject: [PATCH 02/15] walletunlocker: accept recovery window from InitWallet --- walletunlocker/service.go | 74 +++++++++++++++++++++++++--------- walletunlocker/service_test.go | 12 +++--- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/walletunlocker/service.go b/walletunlocker/service.go index b80daca17..af5702dc4 100644 --- a/walletunlocker/service.go +++ b/walletunlocker/service.go @@ -14,7 +14,7 @@ import ( "golang.org/x/net/context" ) -// WalletInitMsg is a message sent to the UnlockerService when a user wishes to +// WalletInitMsg is a message sent by the UnlockerService when a user wishes to // set up the internal wallet for the first time. The user MUST provide a // passphrase, but is also able to provide their own source of entropy. If // provided, then this source of entropy will be used to generate the wallet's @@ -27,6 +27,28 @@ type WalletInitMsg struct { // WalletSeed is the deciphered cipher seed that the wallet should use // to initialize itself. WalletSeed *aezeed.CipherSeed + + // RecoveryWindow is the address look-ahead used when restoring a seed + // with existing funds. A recovery window zero indicates that no + // recovery should be attempted, such as after the wallet's initial + // creation. + RecoveryWindow uint32 +} + +// WalletUnlockMsg is a message sent by the UnlockerService when a user wishes +// to unlock the internal wallet after initial setup. The user can optionally +// specify a recovery window, which will resume an interrupted rescan for used +// addresses. +type WalletUnlockMsg struct { + // Passphrase is the passphrase that will be used to encrypt the wallet + // itself. This MUST be at least 8 characters. + Passphrase []byte + + // RecoveryWindow is the address look-ahead used when restoring a seed + // with existing funds. A recovery window zero indicates that no + // recovery should be attempted, such as after the wallet's initial + // creation, but before any addresses have been created. + RecoveryWindow uint32 } // UnlockerService implements the WalletUnlocker service used to provide lnd @@ -37,10 +59,10 @@ type UnlockerService struct { // InitMsgs is a channel that carries all wallet init messages. InitMsgs chan *WalletInitMsg - // UnlockPasswords is a channel where passwords provided by the rpc + // UnlockMsgs is a channel where unlock parameters provided by the rpc // client to be used to unlock and decrypt an existing wallet will be // sent. - UnlockPasswords chan []byte + UnlockMsgs chan *WalletUnlockMsg chainDir string netParams *chaincfg.Params @@ -52,10 +74,10 @@ func New(authSvc *macaroons.Service, chainDir string, params *chaincfg.Params) *UnlockerService { return &UnlockerService{ - InitMsgs: make(chan *WalletInitMsg, 1), - UnlockPasswords: make(chan []byte, 1), - chainDir: chainDir, - netParams: params, + InitMsgs: make(chan *WalletInitMsg, 1), + UnlockMsgs: make(chan *WalletUnlockMsg, 1), + chainDir: chainDir, + netParams: params, } } @@ -73,7 +95,7 @@ func (u *UnlockerService) GenSeed(ctx context.Context, // Before we start, we'll ensure that the wallet hasn't already created // so we don't show a *new* seed to the user if one already exists. netDir := btcwallet.NetworkDir(u.chainDir, u.netParams) - loader := wallet.NewLoader(u.netParams, netDir) + loader := wallet.NewLoader(u.netParams, netDir, 0) walletExists, err := loader.WalletExists() if err != nil { return nil, err @@ -156,10 +178,17 @@ func (u *UnlockerService) InitWallet(ctx context.Context, "at least 8 characters") } + // Require that the recovery window be non-negative. + recoveryWindow := in.RecoveryWindow + if recoveryWindow < 0 { + return nil, fmt.Errorf("recovery window %d must be "+ + "non-negative", recoveryWindow) + } + // We'll then open up the directory that will be used to store the // wallet's files so we can check if the wallet already exists. netDir := btcwallet.NetworkDir(u.chainDir, u.netParams) - loader := wallet.NewLoader(u.netParams, netDir) + loader := wallet.NewLoader(u.netParams, netDir, uint32(recoveryWindow)) walletExists, err := loader.WalletExists() if err != nil { @@ -198,8 +227,9 @@ func (u *UnlockerService) InitWallet(ctx context.Context, // now send over the wallet password and the seed. This will allow the // daemon to initialize itself and startup. initMsg := &WalletInitMsg{ - Passphrase: password, - WalletSeed: cipherSeed, + Passphrase: password, + WalletSeed: cipherSeed, + RecoveryWindow: uint32(recoveryWindow), } u.InitMsgs <- initMsg @@ -208,13 +238,16 @@ func (u *UnlockerService) InitWallet(ctx context.Context, } // UnlockWallet sends the password provided by the incoming UnlockWalletRequest -// over the UnlockPasswords channel in case it successfully decrypts an -// existing wallet found in the chain's wallet database directory. +// over the UnlockMsgs channel in case it successfully decrypts an existing +// wallet found in the chain's wallet database directory. func (u *UnlockerService) UnlockWallet(ctx context.Context, in *lnrpc.UnlockWalletRequest) (*lnrpc.UnlockWalletResponse, error) { + password := in.WalletPassword + recoveryWindow := uint32(in.RecoveryWindow) + netDir := btcwallet.NetworkDir(u.chainDir, u.netParams) - loader := wallet.NewLoader(u.netParams, netDir) + loader := wallet.NewLoader(u.netParams, netDir, recoveryWindow) // Check if wallet already exists. walletExists, err := loader.WalletExists() @@ -228,7 +261,7 @@ func (u *UnlockerService) UnlockWallet(ctx context.Context, } // Try opening the existing wallet with the provided password. - _, err = loader.OpenExistingWallet(in.WalletPassword, false) + _, err = loader.OpenExistingWallet(password, false) if err != nil { // Could not open wallet, most likely this means that provided // password was incorrect. @@ -244,17 +277,22 @@ func (u *UnlockerService) UnlockWallet(ctx context.Context, // Attempt to create a password for the macaroon service. if u.authSvc != nil { - err = u.authSvc.CreateUnlock(&in.WalletPassword) + err = u.authSvc.CreateUnlock(&password) if err != nil { return nil, fmt.Errorf("unable to create/unlock "+ "macaroon store: %v", err) } } + walletUnlockMsg := &WalletUnlockMsg{ + Passphrase: password, + RecoveryWindow: recoveryWindow, + } + // At this point we was able to open the existing wallet with the - // provided password. We send the password over the UnlockPasswords + // provided password. We send the password over the UnlockMsgs // channel, such that it can be used by lnd to open the wallet. - u.UnlockPasswords <- in.WalletPassword + u.UnlockMsgs <- walletUnlockMsg return &lnrpc.UnlockWalletResponse{}, nil } diff --git a/walletunlocker/service_test.go b/walletunlocker/service_test.go index 4e2514a22..01b413ca4 100644 --- a/walletunlocker/service_test.go +++ b/walletunlocker/service_test.go @@ -37,8 +37,10 @@ var ( func createTestWallet(t *testing.T, dir string, netParams *chaincfg.Params) { netDir := btcwallet.NetworkDir(dir, netParams) - loader := wallet.NewLoader(netParams, netDir) - _, err := loader.CreateNewWallet(testPassword, testPassword, testSeed) + loader := wallet.NewLoader(netParams, netDir, 0) + _, err := loader.CreateNewWallet( + testPassword, testPassword, testSeed, time.Time{}, + ) if err != nil { t.Fatalf("failed creating wallet: %v", err) } @@ -340,10 +342,10 @@ func TestUnlockWallet(t *testing.T) { // Password should be sent over the channel. select { - case pw := <-service.UnlockPasswords: - if !bytes.Equal(pw, testPassword) { + case unlockMsg := <-service.UnlockMsgs: + if !bytes.Equal(unlockMsg.Passphrase, testPassword) { t.Fatalf("expected to receive password %x, got %x", - testPassword, pw) + testPassword, unlockMsg.Passphrase) } case <-time.After(3 * time.Second): t.Fatalf("password not received") From 3cb87f377f06db42ba0a28f922f9f365c9d1af5b Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 2 Apr 2018 16:58:28 -0700 Subject: [PATCH 03/15] walletunlocker/service_test: check recovery window is threaded --- walletunlocker/service_test.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/walletunlocker/service_test.go b/walletunlocker/service_test.go index 01b413ca4..55e587843 100644 --- a/walletunlocker/service_test.go +++ b/walletunlocker/service_test.go @@ -33,6 +33,8 @@ var ( } testNetParams = &chaincfg.MainNetParams + + testRecoveryWindow uint32 = 150 ) func createTestWallet(t *testing.T, dir string, netParams *chaincfg.Params) { @@ -209,6 +211,7 @@ func TestInitWallet(t *testing.T) { WalletPassword: testPassword, CipherSeedMnemonic: []string(mnemonic[:]), AezeedPassphrase: pass, + RecoveryWindow: int32(testRecoveryWindow), } _, err = service.InitWallet(ctx, req) if err != nil { @@ -238,6 +241,11 @@ func TestInitWallet(t *testing.T) { "got %x", cipherSeed.Entropy[:], msg.WalletSeed.Entropy[:]) } + if msg.RecoveryWindow != testRecoveryWindow { + t.Fatalf("mismatched recovery window: expected %v,"+ + "got %v", testRecoveryWindow, + msg.RecoveryWindow) + } case <-time.After(3 * time.Second): t.Fatalf("password not received") @@ -314,6 +322,7 @@ func TestUnlockWallet(t *testing.T) { ctx := context.Background() req := &lnrpc.UnlockWalletRequest{ WalletPassword: testPassword, + RecoveryWindow: int32(testRecoveryWindow), } // Should fail to unlock non-existing wallet. @@ -340,13 +349,18 @@ func TestUnlockWallet(t *testing.T) { t.Fatalf("unable to unlock wallet: %v", err) } - // Password should be sent over the channel. + // Password and recovery window should be sent over the channel. select { case unlockMsg := <-service.UnlockMsgs: if !bytes.Equal(unlockMsg.Passphrase, testPassword) { t.Fatalf("expected to receive password %x, got %x", testPassword, unlockMsg.Passphrase) } + if unlockMsg.RecoveryWindow != testRecoveryWindow { + t.Fatalf("expected to receive recovery window %d, "+ + "got %d", testRecoveryWindow, + unlockMsg.RecoveryWindow) + } case <-time.After(3 * time.Second): t.Fatalf("password not received") } From 0ae62c37202cce7ca032d2e40d6875c9b21fdb4d Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:09:52 -0700 Subject: [PATCH 04/15] lnrpc: add RecoveryWindow to InitWalletRequest --- lnrpc/rpc.pb.go | 734 +++++++++++++++++++++-------------------- lnrpc/rpc.pb.gw.go | 20 +- lnrpc/rpc.proto | 18 + lnrpc/rpc.swagger.json | 10 + 4 files changed, 428 insertions(+), 354 deletions(-) diff --git a/lnrpc/rpc.pb.go b/lnrpc/rpc.pb.go index 50c2ebac2..d40d5b010 100644 --- a/lnrpc/rpc.pb.go +++ b/lnrpc/rpc.pb.go @@ -232,6 +232,13 @@ type InitWalletRequest struct { // aezeed_passphrase is an optional user provided passphrase that will be used // to encrypt the generated aezeed cipher seed. AezeedPassphrase []byte `protobuf:"bytes,3,opt,name=aezeed_passphrase,json=aezeedPassphrase,proto3" json:"aezeed_passphrase,omitempty"` + // * + // recovery_window is an optional argument specifying the address lookahead + // when restoring a wallet seed. The recovery window applies to each + // invdividual branch of the BIP44 derivation paths. Supplying a recovery + // window of zero indicates that no addresses should be recovered, such after + // the first initialization of the wallet. + RecoveryWindow int32 `protobuf:"varint,4,opt,name=recovery_window,json=recoveryWindow" json:"recovery_window,omitempty"` } func (m *InitWalletRequest) Reset() { *m = InitWalletRequest{} } @@ -260,6 +267,13 @@ func (m *InitWalletRequest) GetAezeedPassphrase() []byte { return nil } +func (m *InitWalletRequest) GetRecoveryWindow() int32 { + if m != nil { + return m.RecoveryWindow + } + return 0 +} + type InitWalletResponse struct { } @@ -274,6 +288,13 @@ type UnlockWalletRequest struct { // will be required to decrypt on-disk material that the daemon requires to // function properly. WalletPassword []byte `protobuf:"bytes,1,opt,name=wallet_password,json=walletPassword,proto3" json:"wallet_password,omitempty"` + // * + // recovery_window is an optional argument specifying the address lookahead + // when restoring a wallet seed. The recovery window applies to each + // invdividual branch of the BIP44 derivation paths. Supplying a recovery + // window of zero indicates that no addresses should be recovered, such after + // the first initialization of the wallet. + RecoveryWindow int32 `protobuf:"varint,2,opt,name=recovery_window,json=recoveryWindow" json:"recovery_window,omitempty"` } func (m *UnlockWalletRequest) Reset() { *m = UnlockWalletRequest{} } @@ -288,6 +309,13 @@ func (m *UnlockWalletRequest) GetWalletPassword() []byte { return nil } +func (m *UnlockWalletRequest) GetRecoveryWindow() int32 { + if m != nil { + return m.RecoveryWindow + } + return 0 +} + type UnlockWalletResponse struct { } @@ -6351,356 +6379,358 @@ var _Lightning_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("rpc.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 5611 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0xcb, 0x73, 0x1c, 0xc9, - 0x71, 0x37, 0x7b, 0x30, 0x78, 0x4c, 0xce, 0x60, 0x00, 0x14, 0x40, 0x70, 0x38, 0xe4, 0x72, 0xb9, - 0xad, 0x0d, 0x91, 0x1f, 0xbe, 0x35, 0xc1, 0x85, 0xa4, 0xf5, 0x6a, 0x69, 0x4b, 0xe6, 0x1b, 0x2b, - 0x71, 0x29, 0xa8, 0x41, 0x8a, 0xb6, 0x64, 0x7b, 0xd4, 0x98, 0x29, 0x0c, 0x7a, 0xd9, 0xd3, 0xdd, - 0xdb, 0xdd, 0x03, 0x70, 0x76, 0xcd, 0x08, 0xbf, 0xc2, 0x27, 0x2b, 0x7c, 0xb0, 0x2f, 0xb2, 0xc3, - 0xe1, 0x08, 0xe9, 0x62, 0x1f, 0x7c, 0xf4, 0x49, 0xf6, 0x3f, 0xe0, 0x08, 0x87, 0x0f, 0x7b, 0x52, - 0xf8, 0xe6, 0xc7, 0xc1, 0x56, 0xf8, 0xe2, 0x08, 0x5f, 0x7c, 0x70, 0x38, 0x32, 0xeb, 0xd1, 0x55, - 0xdd, 0x0d, 0x92, 0x7a, 0xd8, 0xb7, 0xa9, 0x5f, 0x65, 0x67, 0xbd, 0x32, 0xb3, 0x32, 0xb3, 0xaa, - 0x06, 0x5a, 0x69, 0x32, 0xbc, 0x96, 0xa4, 0x71, 0x1e, 0xb3, 0xf9, 0x30, 0x4a, 0x93, 0x61, 0xff, - 0xe2, 0x38, 0x8e, 0xc7, 0x21, 0xdf, 0xf6, 0x93, 0x60, 0xdb, 0x8f, 0xa2, 0x38, 0xf7, 0xf3, 0x20, - 0x8e, 0x32, 0x41, 0xe4, 0x7e, 0x1b, 0xba, 0xf7, 0x79, 0xb4, 0xcf, 0xf9, 0xc8, 0xe3, 0x1f, 0x4d, - 0x79, 0x96, 0xb3, 0xff, 0x0f, 0x6b, 0x3e, 0xff, 0x98, 0xf3, 0xd1, 0x20, 0xf1, 0xb3, 0x2c, 0x39, - 0x4a, 0xfd, 0x8c, 0xf7, 0x9c, 0xcb, 0xce, 0xd5, 0x8e, 0xb7, 0x2a, 0x2a, 0xf6, 0x34, 0xce, 0xde, - 0x80, 0x4e, 0x86, 0xa4, 0x3c, 0xca, 0xd3, 0x38, 0x99, 0xf5, 0x1a, 0x44, 0xd7, 0x46, 0xec, 0xae, - 0x80, 0xdc, 0x10, 0x56, 0x74, 0x0b, 0x59, 0x12, 0x47, 0x19, 0x67, 0xd7, 0x61, 0x63, 0x18, 0x24, - 0x47, 0x3c, 0x1d, 0xd0, 0xc7, 0x93, 0x88, 0x4f, 0xe2, 0x28, 0x18, 0xf6, 0x9c, 0xcb, 0x73, 0x57, - 0x5b, 0x1e, 0x13, 0x75, 0xf8, 0xc5, 0x07, 0xb2, 0x86, 0x5d, 0x81, 0x15, 0x1e, 0x09, 0x9c, 0x8f, - 0xe8, 0x2b, 0xd9, 0x54, 0xb7, 0x80, 0xf1, 0x03, 0xf7, 0x4f, 0x1c, 0x58, 0x7b, 0x3f, 0x0a, 0xf2, - 0x27, 0x7e, 0x18, 0xf2, 0x5c, 0x8d, 0xe9, 0x0a, 0xac, 0x9c, 0x10, 0x40, 0x63, 0x3a, 0x89, 0xd3, - 0x91, 0x1c, 0x51, 0x57, 0xc0, 0x7b, 0x12, 0x3d, 0xb5, 0x67, 0x8d, 0x53, 0x7b, 0x56, 0x3b, 0x5d, - 0x73, 0xf5, 0xd3, 0xe5, 0x6e, 0x00, 0x33, 0x3b, 0x27, 0xa6, 0xc3, 0xfd, 0x12, 0xac, 0x3f, 0x8e, - 0xc2, 0x78, 0xf8, 0xf4, 0x27, 0xeb, 0xb4, 0xbb, 0x09, 0x1b, 0xf6, 0xf7, 0x92, 0xef, 0x77, 0x1b, - 0xd0, 0x7e, 0x94, 0xfa, 0x51, 0xe6, 0x0f, 0x71, 0xc9, 0x59, 0x0f, 0x16, 0xf3, 0x67, 0x83, 0x23, - 0x3f, 0x3b, 0x22, 0x46, 0x2d, 0x4f, 0x15, 0xd9, 0x26, 0x2c, 0xf8, 0x93, 0x78, 0x1a, 0xe5, 0x34, - 0xab, 0x73, 0x9e, 0x2c, 0xb1, 0xb7, 0x60, 0x2d, 0x9a, 0x4e, 0x06, 0xc3, 0x38, 0x3a, 0x0c, 0xd2, - 0x89, 0x10, 0x1c, 0x1a, 0xdc, 0xbc, 0x57, 0xad, 0x60, 0x97, 0x00, 0x0e, 0xb0, 0x1b, 0xa2, 0x89, - 0x26, 0x35, 0x61, 0x20, 0xcc, 0x85, 0x8e, 0x2c, 0xf1, 0x60, 0x7c, 0x94, 0xf7, 0xe6, 0x89, 0x91, - 0x85, 0x21, 0x8f, 0x3c, 0x98, 0xf0, 0x41, 0x96, 0xfb, 0x93, 0xa4, 0xb7, 0x40, 0xbd, 0x31, 0x10, - 0xaa, 0x8f, 0x73, 0x3f, 0x1c, 0x1c, 0x72, 0x9e, 0xf5, 0x16, 0x65, 0xbd, 0x46, 0xd8, 0x67, 0xa1, - 0x3b, 0xe2, 0x59, 0x3e, 0xf0, 0x47, 0xa3, 0x94, 0x67, 0x19, 0xcf, 0x7a, 0x4b, 0xb4, 0x74, 0x25, - 0xd4, 0xed, 0xc1, 0xe6, 0x7d, 0x9e, 0x1b, 0xb3, 0x93, 0xc9, 0x69, 0x77, 0x1f, 0x00, 0x33, 0xe0, - 0x3b, 0x3c, 0xf7, 0x83, 0x30, 0x63, 0xef, 0x40, 0x27, 0x37, 0x88, 0x49, 0x54, 0xdb, 0x3b, 0xec, - 0x1a, 0xe9, 0xd8, 0x35, 0xe3, 0x03, 0xcf, 0xa2, 0x73, 0xff, 0xcb, 0x81, 0xf6, 0x3e, 0x8f, 0xb4, - 0x76, 0x31, 0x68, 0x62, 0x4f, 0xe4, 0x4a, 0xd2, 0x6f, 0xf6, 0x3a, 0xb4, 0xa9, 0x77, 0x59, 0x9e, - 0x06, 0xd1, 0x98, 0x96, 0xa0, 0xe5, 0x01, 0x42, 0xfb, 0x84, 0xb0, 0x55, 0x98, 0xf3, 0x27, 0x39, - 0x4d, 0xfc, 0x9c, 0x87, 0x3f, 0x51, 0xef, 0x12, 0x7f, 0x36, 0xe1, 0x51, 0x5e, 0x4c, 0x76, 0xc7, - 0x6b, 0x4b, 0x6c, 0x17, 0x67, 0xfb, 0x1a, 0xac, 0x9b, 0x24, 0x8a, 0xfb, 0x3c, 0x71, 0x5f, 0x33, - 0x28, 0x65, 0x23, 0x57, 0x60, 0x45, 0xd1, 0xa7, 0xa2, 0xb3, 0x34, 0xfd, 0x2d, 0xaf, 0x2b, 0x61, - 0x35, 0x84, 0xab, 0xb0, 0x7a, 0x18, 0x44, 0x7e, 0x38, 0x18, 0x86, 0xf9, 0xf1, 0x60, 0xc4, 0xc3, - 0xdc, 0xa7, 0x85, 0x98, 0xf7, 0xba, 0x84, 0xdf, 0x0e, 0xf3, 0xe3, 0x3b, 0x88, 0xba, 0x7f, 0xe4, - 0x40, 0x47, 0x0c, 0x5e, 0x2a, 0xfe, 0x9b, 0xb0, 0xac, 0xda, 0xe0, 0x69, 0x1a, 0xa7, 0x52, 0x0e, - 0x6d, 0x90, 0x6d, 0xc1, 0xaa, 0x02, 0x92, 0x94, 0x07, 0x13, 0x7f, 0xcc, 0xa5, 0xb6, 0x57, 0x70, - 0xb6, 0x53, 0x70, 0x4c, 0xe3, 0x69, 0x2e, 0x54, 0xaf, 0xbd, 0xd3, 0x91, 0x0b, 0xe3, 0x21, 0xe6, - 0xd9, 0x24, 0xee, 0xf7, 0x1c, 0xe8, 0xdc, 0x3e, 0xf2, 0xa3, 0x88, 0x87, 0x7b, 0x71, 0x10, 0xe5, - 0xec, 0x3a, 0xb0, 0xc3, 0x69, 0x34, 0x0a, 0xa2, 0xf1, 0x20, 0x7f, 0x16, 0x8c, 0x06, 0x07, 0xb3, - 0x9c, 0x67, 0x62, 0x89, 0x76, 0xcf, 0x78, 0x35, 0x75, 0xec, 0x2d, 0x58, 0xb5, 0xd0, 0x2c, 0x4f, - 0xc5, 0xba, 0xed, 0x9e, 0xf1, 0x2a, 0x35, 0x28, 0xf8, 0xf1, 0x34, 0x4f, 0xa6, 0xf9, 0x20, 0x88, - 0x46, 0xfc, 0x19, 0xf5, 0x71, 0xd9, 0xb3, 0xb0, 0x5b, 0x5d, 0xe8, 0x98, 0xdf, 0xb9, 0x5f, 0x82, - 0xd5, 0x07, 0xa8, 0x11, 0x51, 0x10, 0x8d, 0x6f, 0x0a, 0xb1, 0x45, 0x35, 0x4d, 0xa6, 0x07, 0x4f, - 0xf9, 0x4c, 0xce, 0x9b, 0x2c, 0xa1, 0x50, 0x1d, 0xc5, 0x59, 0x2e, 0x25, 0x87, 0x7e, 0xbb, 0xff, - 0xe4, 0xc0, 0x0a, 0xce, 0xfd, 0x07, 0x7e, 0x34, 0x53, 0x2b, 0xf7, 0x00, 0x3a, 0xc8, 0xea, 0x51, - 0x7c, 0x53, 0x28, 0xbb, 0x10, 0xe2, 0xab, 0x72, 0xae, 0x4a, 0xd4, 0xd7, 0x4c, 0x52, 0x34, 0xe6, - 0x33, 0xcf, 0xfa, 0x1a, 0xc5, 0x36, 0xf7, 0xd3, 0x31, 0xcf, 0xc9, 0x0c, 0x48, 0xb3, 0x00, 0x02, - 0xba, 0x1d, 0x47, 0x87, 0xec, 0x32, 0x74, 0x32, 0x3f, 0x1f, 0x24, 0x3c, 0xa5, 0x59, 0x23, 0xd1, - 0x9b, 0xf3, 0x20, 0xf3, 0xf3, 0x3d, 0x9e, 0xde, 0x9a, 0xe5, 0xbc, 0xff, 0x65, 0x58, 0xab, 0xb4, - 0x82, 0xd2, 0x5e, 0x0c, 0x11, 0x7f, 0xb2, 0x0d, 0x98, 0x3f, 0xf6, 0xc3, 0x29, 0x97, 0xd6, 0x49, - 0x14, 0xde, 0x6b, 0xbc, 0xeb, 0xb8, 0x9f, 0x85, 0xd5, 0xa2, 0xdb, 0x52, 0xc8, 0x18, 0x34, 0x71, - 0x06, 0x25, 0x03, 0xfa, 0xed, 0xfe, 0x96, 0x23, 0x08, 0x6f, 0xc7, 0x81, 0xd6, 0x74, 0x24, 0x44, - 0x83, 0xa0, 0x08, 0xf1, 0xf7, 0xa9, 0x96, 0xf0, 0xa7, 0x1f, 0xac, 0x7b, 0x05, 0xd6, 0x8c, 0x2e, - 0xbc, 0xa0, 0xb3, 0xdf, 0x71, 0x60, 0xed, 0x21, 0x3f, 0x91, 0xab, 0xae, 0x7a, 0xfb, 0x2e, 0x34, - 0xf3, 0x59, 0x22, 0xb6, 0xe2, 0xee, 0xce, 0x9b, 0x72, 0xd1, 0x2a, 0x74, 0xd7, 0x64, 0xf1, 0xd1, - 0x2c, 0xe1, 0x1e, 0x7d, 0xe1, 0x7e, 0x09, 0xda, 0x06, 0xc8, 0xce, 0xc1, 0xfa, 0x93, 0xf7, 0x1f, - 0x3d, 0xbc, 0xbb, 0xbf, 0x3f, 0xd8, 0x7b, 0x7c, 0xeb, 0xab, 0x77, 0x7f, 0x65, 0xb0, 0x7b, 0x73, - 0x7f, 0x77, 0xf5, 0x0c, 0xdb, 0x04, 0xf6, 0xf0, 0xee, 0xfe, 0xa3, 0xbb, 0x77, 0x2c, 0xdc, 0x71, - 0xfb, 0xd0, 0x7b, 0xc8, 0x4f, 0x9e, 0x04, 0x79, 0xc4, 0xb3, 0xcc, 0x6e, 0xcd, 0xbd, 0x06, 0xcc, - 0xec, 0x82, 0x1c, 0x55, 0x0f, 0x16, 0xa5, 0xa9, 0x55, 0x3b, 0x8d, 0x2c, 0xba, 0x9f, 0x05, 0xb6, - 0x1f, 0x8c, 0xa3, 0x0f, 0x78, 0x96, 0xf9, 0x63, 0xae, 0xc6, 0xb6, 0x0a, 0x73, 0x93, 0x6c, 0x2c, - 0x8d, 0x22, 0xfe, 0x74, 0x3f, 0x07, 0xeb, 0x16, 0x9d, 0x64, 0x7c, 0x11, 0x5a, 0x59, 0x30, 0x8e, - 0xfc, 0x7c, 0x9a, 0x72, 0xc9, 0xba, 0x00, 0xdc, 0x7b, 0xb0, 0xf1, 0x0d, 0x9e, 0x06, 0x87, 0xb3, - 0x97, 0xb1, 0xb7, 0xf9, 0x34, 0xca, 0x7c, 0xee, 0xc2, 0xd9, 0x12, 0x1f, 0xd9, 0xbc, 0x10, 0x44, - 0xb9, 0x5c, 0x4b, 0x9e, 0x28, 0x18, 0x6a, 0xd9, 0x30, 0xd5, 0xd2, 0x7d, 0x0c, 0xec, 0x76, 0x1c, - 0x45, 0x7c, 0x98, 0xef, 0x71, 0x9e, 0x16, 0xfe, 0x55, 0x21, 0x75, 0xed, 0x9d, 0x73, 0x72, 0x1d, - 0xcb, 0xba, 0x2e, 0xc5, 0x91, 0x41, 0x33, 0xe1, 0xe9, 0x84, 0x18, 0x2f, 0x79, 0xf4, 0xdb, 0x3d, - 0x0b, 0xeb, 0x16, 0x5b, 0xb9, 0xdb, 0xbf, 0x0d, 0x67, 0xef, 0x04, 0xd9, 0xb0, 0xda, 0x60, 0x0f, - 0x16, 0x93, 0xe9, 0xc1, 0xa0, 0xd0, 0x29, 0x55, 0xc4, 0x4d, 0xb0, 0xfc, 0x89, 0x64, 0xf6, 0x7b, - 0x0e, 0x34, 0x77, 0x1f, 0x3d, 0xb8, 0xcd, 0xfa, 0xb0, 0x14, 0x44, 0xc3, 0x78, 0x82, 0x5b, 0x87, - 0x18, 0xb4, 0x2e, 0x9f, 0xaa, 0x2b, 0x17, 0xa1, 0x45, 0x3b, 0x0e, 0xee, 0xeb, 0xd2, 0x15, 0x2a, - 0x00, 0xf4, 0x29, 0xf8, 0xb3, 0x24, 0x48, 0xc9, 0x69, 0x50, 0xae, 0x40, 0x93, 0x2c, 0x62, 0xb5, - 0xc2, 0xfd, 0xef, 0x26, 0x2c, 0x4a, 0x5b, 0x4d, 0xed, 0x0d, 0xf3, 0xe0, 0x98, 0xcb, 0x9e, 0xc8, - 0x12, 0xee, 0x2a, 0x29, 0x9f, 0xc4, 0x39, 0x1f, 0x58, 0xcb, 0x60, 0x83, 0x48, 0x35, 0x14, 0x8c, - 0x06, 0x09, 0x5a, 0x7d, 0xea, 0x59, 0xcb, 0xb3, 0x41, 0x9c, 0x2c, 0x04, 0x06, 0xc1, 0x88, 0xfa, - 0xd4, 0xf4, 0x54, 0x11, 0x67, 0x62, 0xe8, 0x27, 0xfe, 0x30, 0xc8, 0x67, 0x52, 0xb9, 0x75, 0x19, - 0x79, 0x87, 0xf1, 0xd0, 0x0f, 0x07, 0x07, 0x7e, 0xe8, 0x47, 0x43, 0x2e, 0x1d, 0x17, 0x1b, 0x44, - 0xdf, 0x44, 0x76, 0x49, 0x91, 0x09, 0xff, 0xa5, 0x84, 0xa2, 0x8f, 0x33, 0x8c, 0x27, 0x93, 0x20, - 0x47, 0x97, 0xa6, 0xb7, 0x24, 0x0c, 0x49, 0x81, 0xd0, 0x48, 0x44, 0xe9, 0x44, 0xcc, 0x5e, 0x4b, - 0xb4, 0x66, 0x81, 0xc8, 0xe5, 0x90, 0x73, 0x32, 0x48, 0x4f, 0x4f, 0x7a, 0x20, 0xb8, 0x14, 0x08, - 0xae, 0xc3, 0x34, 0xca, 0x78, 0x9e, 0x87, 0x7c, 0xa4, 0x3b, 0xd4, 0x26, 0xb2, 0x6a, 0x05, 0xbb, - 0x0e, 0xeb, 0xc2, 0xcb, 0xca, 0xfc, 0x3c, 0xce, 0x8e, 0x82, 0x6c, 0x90, 0xf1, 0x28, 0xef, 0x75, - 0x88, 0xbe, 0xae, 0x8a, 0xbd, 0x0b, 0xe7, 0x4a, 0x70, 0xca, 0x87, 0x3c, 0x38, 0xe6, 0xa3, 0xde, - 0x32, 0x7d, 0x75, 0x5a, 0x35, 0xbb, 0x0c, 0x6d, 0x74, 0x2e, 0xa7, 0xc9, 0xc8, 0xc7, 0x7d, 0xb8, - 0x4b, 0xeb, 0x60, 0x42, 0xec, 0x6d, 0x58, 0x4e, 0xb8, 0xd8, 0x2c, 0x8f, 0xf2, 0x70, 0x98, 0xf5, - 0x56, 0x68, 0x27, 0x6b, 0x4b, 0x65, 0x42, 0xc9, 0xf5, 0x6c, 0x0a, 0x14, 0xca, 0x61, 0x46, 0xee, - 0x8a, 0x3f, 0xeb, 0xad, 0x92, 0xb8, 0x15, 0x00, 0xe9, 0x48, 0x1a, 0x1c, 0xfb, 0x39, 0xef, 0xad, - 0x91, 0x6c, 0xa9, 0xa2, 0xfb, 0x67, 0x0e, 0xac, 0x3f, 0x08, 0xb2, 0x5c, 0x0a, 0xa1, 0x36, 0xc7, - 0xaf, 0x43, 0x5b, 0x88, 0xdf, 0x20, 0x8e, 0xc2, 0x99, 0x94, 0x48, 0x10, 0xd0, 0xd7, 0xa2, 0x70, - 0xc6, 0x3e, 0x03, 0xcb, 0x41, 0x64, 0x92, 0x08, 0x1d, 0xee, 0x28, 0x90, 0x88, 0x5e, 0x87, 0x76, - 0x32, 0x3d, 0x08, 0x83, 0xa1, 0x20, 0x99, 0x13, 0x5c, 0x04, 0x44, 0x04, 0xe8, 0xe8, 0x89, 0x9e, - 0x08, 0x8a, 0x26, 0x51, 0xb4, 0x25, 0x86, 0x24, 0xee, 0x2d, 0xd8, 0xb0, 0x3b, 0x28, 0x8d, 0xd5, - 0x16, 0x2c, 0x49, 0xd9, 0xce, 0x7a, 0x6d, 0x9a, 0x9f, 0xae, 0x9c, 0x1f, 0x49, 0xea, 0xe9, 0x7a, - 0xf7, 0xdf, 0x1c, 0x68, 0xa2, 0x01, 0x38, 0xdd, 0x58, 0x98, 0x36, 0x7d, 0xce, 0xb2, 0xe9, 0xe4, - 0xf7, 0xa3, 0x57, 0x24, 0x44, 0x42, 0xa8, 0x8d, 0x81, 0x14, 0xf5, 0x29, 0x1f, 0x1e, 0x93, 0xee, - 0xe8, 0x7a, 0x44, 0x50, 0xb3, 0x70, 0xeb, 0xa4, 0xaf, 0x85, 0xe2, 0xe8, 0xb2, 0xaa, 0xa3, 0x2f, - 0x17, 0x8b, 0x3a, 0xfa, 0xae, 0x07, 0x8b, 0x41, 0x74, 0x10, 0x4f, 0xa3, 0x11, 0x29, 0xc9, 0x92, - 0xa7, 0x8a, 0xb8, 0xd8, 0x09, 0x79, 0x52, 0xc1, 0x84, 0x4b, 0xed, 0x28, 0x00, 0x97, 0xa1, 0x6b, - 0x95, 0x91, 0xc1, 0xd3, 0xfb, 0xd8, 0x3b, 0xb0, 0x66, 0x60, 0x72, 0x06, 0xdf, 0x80, 0xf9, 0x04, - 0x01, 0xe9, 0x28, 0x29, 0xf1, 0x22, 0x4b, 0x29, 0x6a, 0xdc, 0x55, 0x8c, 0x9f, 0xf3, 0xf7, 0xa3, - 0xc3, 0x58, 0x71, 0xfa, 0xe1, 0x1c, 0x06, 0xbc, 0x12, 0x92, 0x8c, 0xae, 0xc2, 0x4a, 0x30, 0xe2, - 0x51, 0x1e, 0xe4, 0xb3, 0x81, 0xe5, 0xc1, 0x95, 0x61, 0xdc, 0x61, 0xfc, 0x30, 0xf0, 0x33, 0x69, - 0xc3, 0x44, 0x81, 0xed, 0xc0, 0x06, 0x8a, 0xbf, 0x92, 0x68, 0xbd, 0xac, 0xc2, 0x91, 0xac, 0xad, - 0x43, 0x8d, 0x45, 0x5c, 0x4a, 0xa0, 0xfe, 0x44, 0x58, 0xda, 0xba, 0x2a, 0x9c, 0x35, 0xc1, 0x09, - 0x87, 0x3c, 0x2f, 0x54, 0x44, 0x03, 0x95, 0xe8, 0x6d, 0x41, 0x38, 0xb1, 0xe5, 0xe8, 0xcd, 0x88, - 0x00, 0x97, 0x2a, 0x11, 0xe0, 0x55, 0x58, 0xc9, 0x66, 0xd1, 0x90, 0x8f, 0x06, 0x79, 0x8c, 0xed, - 0x06, 0x11, 0xad, 0xce, 0x92, 0x57, 0x86, 0x29, 0x56, 0xe5, 0x59, 0x1e, 0xf1, 0x9c, 0x4c, 0xd7, - 0x92, 0xa7, 0x8a, 0xb8, 0x0b, 0x10, 0x89, 0x10, 0xea, 0x96, 0x27, 0x4b, 0xb8, 0x55, 0x4e, 0xd3, - 0x20, 0xeb, 0x75, 0x08, 0xa5, 0xdf, 0xec, 0xf3, 0x70, 0xf6, 0x00, 0x23, 0xab, 0x23, 0xee, 0x8f, - 0x78, 0x4a, 0xab, 0x2f, 0x02, 0x4b, 0x61, 0x81, 0xea, 0x2b, 0xb1, 0xed, 0x63, 0x9e, 0x66, 0x41, - 0x1c, 0x91, 0xed, 0x69, 0x79, 0xaa, 0xe8, 0x7e, 0x4c, 0x3b, 0xba, 0x0e, 0x79, 0x1f, 0x93, 0x39, - 0x62, 0x17, 0xa0, 0x25, 0xc6, 0x98, 0x1d, 0xf9, 0xd2, 0xc9, 0x58, 0x22, 0x60, 0xff, 0xc8, 0x47, - 0x05, 0xb6, 0xa6, 0xad, 0x41, 0x9e, 0x63, 0x9b, 0xb0, 0x5d, 0x31, 0x6b, 0x6f, 0x42, 0x57, 0x05, - 0xd3, 0xd9, 0x20, 0xe4, 0x87, 0xb9, 0x0a, 0x10, 0xa2, 0xe9, 0x04, 0x9b, 0xcb, 0x1e, 0xf0, 0xc3, - 0xdc, 0x7d, 0x08, 0x6b, 0x52, 0x6f, 0xbf, 0x96, 0x70, 0xd5, 0xf4, 0x17, 0xcb, 0x9b, 0x9a, 0xf0, - 0x2a, 0xd6, 0x6d, 0x45, 0xa7, 0x28, 0xa7, 0xb4, 0xd3, 0xb9, 0x1e, 0x30, 0x59, 0x7d, 0x3b, 0x8c, - 0x33, 0x2e, 0x19, 0xba, 0xd0, 0x19, 0x86, 0x71, 0xa6, 0xc2, 0x10, 0x39, 0x1c, 0x0b, 0xc3, 0xf9, - 0xc9, 0xa6, 0xc3, 0x21, 0x5a, 0x02, 0x61, 0xd3, 0x54, 0xd1, 0xfd, 0x73, 0x07, 0xd6, 0x89, 0x9b, - 0xb2, 0x30, 0xda, 0x77, 0x7d, 0xf5, 0x6e, 0x76, 0x86, 0x66, 0x68, 0xb6, 0x01, 0xf3, 0x87, 0x71, - 0x3a, 0xe4, 0xb2, 0x25, 0x51, 0xf8, 0xf1, 0xbd, 0xf1, 0x66, 0xc5, 0x1b, 0xff, 0xa1, 0x03, 0x6b, - 0xd4, 0xd5, 0xfd, 0xdc, 0xcf, 0xa7, 0x99, 0x1c, 0xfe, 0x2f, 0xc0, 0x32, 0x0e, 0x95, 0x2b, 0x75, - 0x92, 0x1d, 0xdd, 0xd0, 0x9a, 0x4f, 0xa8, 0x20, 0xde, 0x3d, 0xe3, 0xd9, 0xc4, 0xec, 0xcb, 0xd0, - 0x31, 0x33, 0x22, 0xd4, 0xe7, 0xf6, 0xce, 0x79, 0x35, 0xca, 0x8a, 0xe4, 0xec, 0x9e, 0xf1, 0xac, - 0x0f, 0xd8, 0x0d, 0x00, 0x72, 0x37, 0x88, 0xad, 0x0c, 0x65, 0xcf, 0xdb, 0x93, 0x64, 0x2c, 0xd6, - 0xee, 0x19, 0xcf, 0x20, 0xbf, 0xb5, 0x04, 0x0b, 0x62, 0x7f, 0x74, 0xef, 0xc3, 0xb2, 0xd5, 0x53, - 0x2b, 0xca, 0xe8, 0x88, 0x28, 0xa3, 0x12, 0x94, 0x36, 0xaa, 0x41, 0xa9, 0xfb, 0x2f, 0x0d, 0x60, - 0x28, 0x6d, 0xa5, 0xe5, 0xc4, 0x0d, 0x3a, 0x1e, 0x59, 0xee, 0x56, 0xc7, 0x33, 0x21, 0x76, 0x0d, - 0x98, 0x51, 0x54, 0xb9, 0x07, 0xb1, 0x6f, 0xd4, 0xd4, 0xa0, 0x81, 0x13, 0xbe, 0x92, 0x8a, 0x81, - 0xa5, 0x63, 0x29, 0xd6, 0xad, 0xb6, 0x0e, 0xb7, 0x86, 0x64, 0x9a, 0x1d, 0xa1, 0x03, 0xa1, 0x1c, - 0x32, 0x55, 0x2e, 0x0b, 0xc8, 0xc2, 0x4b, 0x05, 0x64, 0xb1, 0x2c, 0x20, 0xa6, 0x4b, 0xb0, 0x64, - 0xb9, 0x04, 0xe8, 0x7f, 0x4d, 0x82, 0x88, 0xfc, 0x8a, 0xc1, 0x04, 0x5b, 0x97, 0xfe, 0x97, 0x05, - 0xb2, 0x2d, 0x58, 0x95, 0x7e, 0x5d, 0xe1, 0x77, 0x00, 0xcd, 0x71, 0x05, 0x77, 0x3f, 0x75, 0x60, - 0x15, 0xe7, 0xd9, 0x92, 0xc5, 0xf7, 0x80, 0x54, 0xe1, 0x15, 0x45, 0xd1, 0xa2, 0xfd, 0xe9, 0x25, - 0xf1, 0x5d, 0x68, 0x11, 0xc3, 0x38, 0xe1, 0x91, 0x14, 0xc4, 0x9e, 0x2d, 0x88, 0x85, 0x15, 0xda, - 0x3d, 0xe3, 0x15, 0xc4, 0x86, 0x18, 0xfe, 0xbd, 0x03, 0x6d, 0xd9, 0xcd, 0x9f, 0x38, 0x96, 0xe8, - 0xc3, 0x12, 0x4a, 0xa4, 0xe1, 0xb0, 0xeb, 0x32, 0xee, 0x26, 0x13, 0x0c, 0xd8, 0x70, 0xfb, 0xb4, - 0xe2, 0x88, 0x32, 0x8c, 0x7b, 0x21, 0x19, 0xdc, 0x6c, 0x90, 0x07, 0xe1, 0x40, 0xd5, 0xca, 0x04, - 0x64, 0x5d, 0x15, 0xda, 0x9d, 0x2c, 0xf7, 0xc7, 0x5c, 0x6e, 0x73, 0xa2, 0x80, 0x01, 0x93, 0x1c, - 0x50, 0xc9, 0x1d, 0x74, 0xff, 0xa6, 0x03, 0xe7, 0x2a, 0x55, 0x3a, 0xdd, 0x2d, 0x1d, 0xe4, 0x30, - 0x98, 0x1c, 0xc4, 0xda, 0xd7, 0x76, 0x4c, 0xdf, 0xd9, 0xaa, 0x62, 0x63, 0x38, 0xab, 0xf6, 0x73, - 0x9c, 0xd3, 0x62, 0xf7, 0x6e, 0x90, 0x23, 0xf2, 0xb6, 0x2d, 0x03, 0xe5, 0x06, 0x15, 0x6e, 0x6a, - 0x6e, 0x3d, 0x3f, 0x76, 0x04, 0x3d, 0xed, 0x38, 0x48, 0x13, 0x6f, 0x38, 0x17, 0xd8, 0xd6, 0x5b, - 0x2f, 0x69, 0x8b, 0xec, 0xd1, 0x48, 0x35, 0x73, 0x2a, 0x37, 0x36, 0x83, 0x4b, 0xaa, 0x8e, 0x6c, - 0x78, 0xb5, 0xbd, 0xe6, 0x2b, 0x8d, 0xed, 0x1e, 0x7e, 0x6c, 0x37, 0xfa, 0x12, 0xc6, 0xec, 0x43, - 0xd8, 0x3c, 0xf1, 0x83, 0x5c, 0x75, 0xcb, 0x70, 0x86, 0xe6, 0xa9, 0xc9, 0x9d, 0x97, 0x34, 0xf9, - 0x44, 0x7c, 0x6c, 0x6d, 0x6c, 0xa7, 0x70, 0xec, 0xff, 0xad, 0x03, 0x5d, 0x9b, 0x0f, 0x8a, 0xa9, - 0x54, 0x78, 0x65, 0xf8, 0x94, 0xf3, 0x57, 0x82, 0xab, 0x21, 0x6a, 0xa3, 0x2e, 0x44, 0x35, 0x03, - 0xd1, 0xb9, 0x97, 0x05, 0xa2, 0xcd, 0x57, 0x0b, 0x44, 0xe7, 0xeb, 0x02, 0xd1, 0xfe, 0x7f, 0x3a, - 0xc0, 0xaa, 0xb2, 0xc4, 0xee, 0x8b, 0x18, 0x39, 0xe2, 0xa1, 0xb4, 0x49, 0x3f, 0xf7, 0x6a, 0xf2, - 0xa8, 0xe6, 0x4e, 0x7d, 0x8d, 0x8a, 0x61, 0x1a, 0x1d, 0xd3, 0x45, 0x5a, 0xf6, 0xea, 0xaa, 0x4a, - 0xa1, 0x71, 0xf3, 0xe5, 0xa1, 0xf1, 0xfc, 0xcb, 0x43, 0xe3, 0x85, 0x72, 0x68, 0xdc, 0xff, 0x5d, - 0x07, 0xd6, 0x6b, 0x16, 0xfd, 0x67, 0x37, 0x70, 0x5c, 0x26, 0xcb, 0x16, 0x34, 0xe4, 0x32, 0x99, - 0x60, 0xff, 0x37, 0x60, 0xd9, 0x12, 0xf4, 0x9f, 0x5d, 0xfb, 0x65, 0x2f, 0x4f, 0xc8, 0x99, 0x85, - 0xf5, 0x7f, 0xd4, 0x00, 0x56, 0x55, 0xb6, 0xff, 0xd3, 0x3e, 0x54, 0xe7, 0x69, 0xae, 0x66, 0x9e, - 0xfe, 0x57, 0xf7, 0x81, 0xb7, 0x60, 0x2d, 0xe5, 0xc3, 0xf8, 0x98, 0xce, 0x1d, 0xed, 0xec, 0x4e, - 0xb5, 0x02, 0xfd, 0x5c, 0x3b, 0x2f, 0xb1, 0x64, 0x1d, 0x13, 0x19, 0x9b, 0x61, 0x29, 0x3d, 0xe1, - 0x6e, 0xc2, 0x86, 0x38, 0xbd, 0xbb, 0x25, 0x58, 0xa9, 0x7d, 0xe5, 0x4f, 0x1d, 0x38, 0x5b, 0xaa, - 0x28, 0xce, 0x52, 0xc4, 0xd6, 0x61, 0xef, 0x27, 0x36, 0x88, 0xfd, 0x97, 0x7a, 0x64, 0xf4, 0x5f, - 0x48, 0x5b, 0xb5, 0x02, 0xe7, 0x67, 0x1a, 0x55, 0xe9, 0xc5, 0xac, 0xd7, 0x55, 0xb9, 0xe7, 0xe0, - 0xac, 0x5c, 0xd9, 0x52, 0xc7, 0x0f, 0x61, 0xb3, 0x5c, 0x51, 0x24, 0x87, 0xed, 0x2e, 0xab, 0x22, - 0x7a, 0x81, 0xd6, 0x36, 0x65, 0xf7, 0xb7, 0xb6, 0xce, 0xfd, 0x75, 0x60, 0x5f, 0x9f, 0xf2, 0x74, - 0x46, 0x27, 0x3d, 0x3a, 0x3b, 0x73, 0xae, 0x9c, 0xc6, 0x58, 0x48, 0xa6, 0x07, 0x5f, 0xe5, 0x33, - 0x75, 0x94, 0xd6, 0x28, 0x8e, 0xd2, 0x5e, 0x03, 0xc0, 0xe8, 0x8b, 0x8e, 0x86, 0xd4, 0xe1, 0x26, - 0x86, 0xbd, 0x82, 0xa1, 0x7b, 0x03, 0xd6, 0x2d, 0xfe, 0x7a, 0xf6, 0x17, 0xe4, 0x17, 0x22, 0x37, - 0x60, 0x1f, 0x38, 0xc9, 0x3a, 0xf7, 0xdf, 0x1d, 0x98, 0xdb, 0x8d, 0x13, 0x33, 0xab, 0xe8, 0xd8, - 0x59, 0x45, 0x69, 0xf2, 0x07, 0xda, 0xa2, 0x4b, 0x4b, 0x60, 0x81, 0x6c, 0x0b, 0xba, 0xfe, 0x24, - 0xc7, 0xe8, 0xf8, 0x30, 0x4e, 0x4f, 0xfc, 0x74, 0x24, 0x96, 0xe4, 0x56, 0xa3, 0xe7, 0x78, 0xa5, - 0x1a, 0xb6, 0x01, 0x73, 0xda, 0x36, 0x12, 0x01, 0x16, 0xd1, 0xbf, 0xa2, 0xe4, 0xea, 0x4c, 0x06, - 0xf6, 0xb2, 0x84, 0x2b, 0x6e, 0x7f, 0x2f, 0x3c, 0x5a, 0x21, 0xe1, 0x75, 0x55, 0xb8, 0xfd, 0xa0, - 0xa9, 0x24, 0x32, 0x99, 0x91, 0x51, 0x65, 0xf7, 0x5f, 0x1d, 0x98, 0xa7, 0x19, 0x40, 0x9d, 0x14, - 0x82, 0x48, 0x67, 0xb7, 0x94, 0x09, 0x76, 0x84, 0x4e, 0x96, 0x60, 0xe6, 0x5a, 0x27, 0xba, 0x0d, - 0xdd, 0x6d, 0xf3, 0x54, 0xf7, 0x32, 0xb4, 0x44, 0x49, 0x1f, 0x83, 0x12, 0x49, 0x01, 0xb2, 0x4b, - 0xd0, 0x3c, 0x8a, 0x13, 0xe5, 0x44, 0x80, 0x4a, 0x04, 0xc6, 0x89, 0x47, 0x78, 0xd1, 0x1f, 0xe4, - 0x27, 0x3a, 0x2f, 0xb6, 0x86, 0x32, 0x8c, 0x9b, 0xa3, 0x66, 0x6b, 0x4e, 0x46, 0x09, 0x75, 0xb7, - 0x60, 0xe5, 0x61, 0x3c, 0xe2, 0x46, 0xea, 0xe7, 0x54, 0xa9, 0x73, 0x7f, 0xd3, 0x81, 0x25, 0x45, - 0xcc, 0xae, 0x42, 0x13, 0x77, 0xfc, 0x92, 0x3f, 0xaf, 0x0f, 0x00, 0x90, 0xce, 0x23, 0x0a, 0x34, - 0x91, 0x94, 0x18, 0x28, 0xbc, 0x3f, 0x95, 0x16, 0x28, 0x9c, 0x1b, 0xdd, 0xdd, 0x92, 0x4f, 0x50, - 0x42, 0xdd, 0xbf, 0x70, 0x60, 0xd9, 0x6a, 0x03, 0xa3, 0xb8, 0xd0, 0xcf, 0x72, 0x99, 0x54, 0x95, - 0xcb, 0x63, 0x42, 0x66, 0x32, 0xb0, 0x61, 0x27, 0x03, 0x75, 0x9a, 0x6a, 0xce, 0x4c, 0x53, 0x5d, - 0x87, 0x56, 0x71, 0xee, 0xde, 0xb4, 0x4c, 0x1f, 0xb6, 0xa8, 0x8e, 0x36, 0x0a, 0x22, 0xe4, 0x33, - 0x8c, 0xc3, 0x38, 0x95, 0xc7, 0xd2, 0xa2, 0xe0, 0xde, 0x80, 0xb6, 0x41, 0x8f, 0xdd, 0x88, 0x78, - 0x7e, 0x12, 0xa7, 0x4f, 0x55, 0x4e, 0x52, 0x16, 0xf5, 0x09, 0x5e, 0xa3, 0x38, 0xc1, 0x73, 0xff, - 0xd2, 0x81, 0x65, 0x94, 0xc1, 0x20, 0x1a, 0xef, 0xc5, 0x61, 0x30, 0x9c, 0xd1, 0xda, 0x2b, 0x71, - 0x93, 0xe7, 0xd5, 0x4a, 0x16, 0x6d, 0x18, 0x65, 0x5b, 0x05, 0x71, 0x52, 0x11, 0x75, 0x19, 0x35, - 0x15, 0xe5, 0xfc, 0xc0, 0xcf, 0xa4, 0xf0, 0xcb, 0xbd, 0xc8, 0x02, 0x51, 0x9f, 0x10, 0x48, 0xfd, - 0x9c, 0x0f, 0x26, 0x41, 0x18, 0x06, 0x82, 0x56, 0x78, 0x2a, 0x75, 0x55, 0xee, 0x0f, 0x1a, 0xd0, - 0x96, 0x96, 0xf2, 0xee, 0x68, 0x2c, 0xb2, 0xff, 0xd2, 0xdf, 0xd3, 0xe6, 0xc2, 0x40, 0x54, 0xbd, - 0xe5, 0x21, 0x1a, 0x48, 0x79, 0x59, 0xe7, 0xaa, 0xcb, 0x7a, 0x11, 0x5a, 0x28, 0x5e, 0x6f, 0x93, - 0x2b, 0x2a, 0xae, 0x69, 0x14, 0x80, 0xaa, 0xdd, 0xa1, 0xda, 0xf9, 0xa2, 0x96, 0x00, 0xcb, 0xf9, - 0x5c, 0x28, 0x39, 0x9f, 0xef, 0x42, 0x47, 0xb2, 0xa1, 0x79, 0x27, 0xeb, 0x50, 0x08, 0xb8, 0xb5, - 0x26, 0x9e, 0x45, 0xa9, 0xbe, 0xdc, 0x51, 0x5f, 0x2e, 0xbd, 0xec, 0x4b, 0x45, 0x49, 0x87, 0x61, - 0x62, 0x6e, 0xee, 0xa7, 0x7e, 0x72, 0xa4, 0x76, 0x9f, 0x91, 0x3e, 0xe1, 0x27, 0x98, 0x6d, 0xc1, - 0x3c, 0x7e, 0xa6, 0xac, 0x75, 0xbd, 0xd2, 0x09, 0x12, 0x76, 0x15, 0xe6, 0xf9, 0x68, 0xcc, 0x55, - 0xb0, 0xc5, 0xec, 0xb0, 0x17, 0xd7, 0xc8, 0x13, 0x04, 0x68, 0x02, 0x10, 0x2d, 0x99, 0x00, 0xdb, - 0xd2, 0x2f, 0x60, 0xf1, 0xfd, 0x91, 0xbb, 0x01, 0xec, 0xa1, 0x90, 0x5a, 0x33, 0x59, 0xfc, 0x3b, - 0x73, 0xd0, 0x36, 0x60, 0xd4, 0xe6, 0x31, 0x76, 0x78, 0x30, 0x0a, 0xfc, 0x09, 0xcf, 0x79, 0x2a, - 0x25, 0xb5, 0x84, 0x22, 0x9d, 0x7f, 0x3c, 0x1e, 0xc4, 0xd3, 0x7c, 0x30, 0xe2, 0xe3, 0x94, 0x8b, - 0x3d, 0x12, 0x37, 0x03, 0x0b, 0x45, 0xba, 0x89, 0xff, 0xcc, 0xa4, 0x13, 0xf2, 0x50, 0x42, 0x55, - 0xea, 0x57, 0xcc, 0x51, 0xb3, 0x48, 0xfd, 0x8a, 0x19, 0x29, 0xdb, 0xa1, 0xf9, 0x1a, 0x3b, 0xf4, - 0x0e, 0x6c, 0x0a, 0x8b, 0x23, 0x75, 0x73, 0x50, 0x12, 0x93, 0x53, 0x6a, 0xd9, 0x16, 0xac, 0x62, - 0x9f, 0x95, 0x80, 0x67, 0xc1, 0xc7, 0x22, 0x19, 0xe3, 0x78, 0x15, 0x1c, 0x69, 0x51, 0x1d, 0x2d, - 0x5a, 0x71, 0x3c, 0x56, 0xc1, 0x89, 0xd6, 0x7f, 0x66, 0xd3, 0xb6, 0x24, 0x6d, 0x09, 0x77, 0x97, - 0xa1, 0xbd, 0x9f, 0xc7, 0x89, 0x5a, 0x94, 0x2e, 0x74, 0x44, 0x51, 0x1e, 0x86, 0x5e, 0x80, 0xf3, - 0x24, 0x45, 0x8f, 0xe2, 0x24, 0x0e, 0xe3, 0xf1, 0x6c, 0x7f, 0x7a, 0x90, 0x0d, 0xd3, 0x20, 0xc1, - 0xc0, 0xc4, 0xfd, 0x3b, 0x07, 0xd6, 0xad, 0x5a, 0x99, 0xbd, 0xf9, 0xbc, 0x10, 0x69, 0x7d, 0x8a, - 0x25, 0x04, 0x6f, 0xcd, 0x30, 0x87, 0x82, 0x50, 0xe4, 0xcd, 0x1e, 0xcb, 0x83, 0xad, 0x9b, 0xb0, - 0xa2, 0x7a, 0xa6, 0x3e, 0x14, 0x52, 0xd8, 0xab, 0x4a, 0xa1, 0xfc, 0xbe, 0x2b, 0x3f, 0x50, 0x2c, - 0x7e, 0x51, 0xf8, 0xd5, 0x7c, 0x44, 0x63, 0x54, 0x61, 0x7c, 0x5f, 0x7d, 0x6f, 0x3a, 0xf3, 0xaa, - 0x07, 0x43, 0x0d, 0x66, 0xee, 0xef, 0x3b, 0x00, 0x45, 0xef, 0x50, 0x30, 0x0a, 0x93, 0x2e, 0xee, - 0xe7, 0x19, 0xe6, 0xfb, 0x0d, 0xe8, 0xe8, 0x03, 0x8c, 0x62, 0x97, 0x68, 0x2b, 0x0c, 0x1d, 0xae, - 0x2b, 0xb0, 0x32, 0x0e, 0xe3, 0x03, 0xda, 0x62, 0xe9, 0x74, 0x3d, 0x93, 0x47, 0xc2, 0x5d, 0x01, - 0xdf, 0x93, 0x68, 0xb1, 0xa5, 0x34, 0x8d, 0x2d, 0xc5, 0xfd, 0x4e, 0x43, 0xa7, 0xbd, 0x8b, 0x31, - 0x9f, 0xaa, 0x65, 0x6c, 0xa7, 0x62, 0x1c, 0x4f, 0xc9, 0x32, 0x53, 0xc2, 0x6a, 0xef, 0xa5, 0xf1, - 0xf4, 0x0d, 0xe8, 0xa6, 0xc2, 0xfa, 0x28, 0xd3, 0xd4, 0x7c, 0x81, 0x69, 0x5a, 0x4e, 0xad, 0x7d, - 0xe7, 0xff, 0xc1, 0xaa, 0x3f, 0x3a, 0xe6, 0x69, 0x1e, 0x50, 0x44, 0x43, 0x9b, 0xbe, 0x30, 0xa8, - 0x2b, 0x06, 0x4e, 0x7b, 0xf1, 0x15, 0x58, 0x91, 0xc7, 0xf0, 0x9a, 0x52, 0x5e, 0xbe, 0x2a, 0x60, - 0x24, 0x74, 0xbf, 0xaf, 0x32, 0xec, 0xf6, 0x1a, 0x9e, 0x3e, 0x23, 0xe6, 0xe8, 0x1a, 0xa5, 0xd1, - 0x7d, 0x46, 0x66, 0xbb, 0x47, 0x2a, 0x6c, 0x92, 0xe7, 0x0e, 0x02, 0x94, 0xa7, 0x13, 0xf6, 0x94, - 0x36, 0x5f, 0x65, 0x4a, 0xdd, 0x4f, 0x1d, 0x58, 0xdc, 0x8d, 0x93, 0x5d, 0x79, 0xa2, 0x4e, 0x8a, - 0xa0, 0x2f, 0xb9, 0xa8, 0xa2, 0xe9, 0x15, 0x37, 0x2a, 0x5e, 0x71, 0x75, 0xaf, 0x5d, 0x2e, 0xef, - 0xb5, 0xbf, 0x04, 0x17, 0x28, 0x68, 0x4f, 0xe3, 0x24, 0x4e, 0x51, 0x19, 0xfd, 0x50, 0x6c, 0xac, - 0x71, 0x94, 0x1f, 0x29, 0x33, 0xf6, 0x22, 0x12, 0x8a, 0x8e, 0xc2, 0xfc, 0x78, 0x20, 0x9c, 0x61, - 0xe9, 0x1b, 0x08, 0xeb, 0x56, 0xad, 0x70, 0xbf, 0x08, 0x2d, 0x72, 0x6e, 0x69, 0x58, 0x6f, 0x41, - 0xeb, 0x28, 0x4e, 0x06, 0x47, 0x41, 0x94, 0x2b, 0xe5, 0xee, 0x16, 0x5e, 0xe7, 0x2e, 0x4d, 0x88, - 0x26, 0x70, 0x7f, 0x34, 0x07, 0x8b, 0xef, 0x47, 0xc7, 0x71, 0x30, 0xa4, 0x64, 0xfc, 0x84, 0x4f, - 0x62, 0x75, 0xe5, 0x07, 0x7f, 0xe3, 0x54, 0xd0, 0xf1, 0x77, 0x92, 0xcb, 0x6c, 0xba, 0x2a, 0xe2, - 0x76, 0x9f, 0x16, 0xd7, 0xe0, 0x84, 0xea, 0x18, 0x08, 0x3a, 0xf6, 0xa9, 0x79, 0x07, 0x50, 0x96, - 0x8a, 0x3b, 0x53, 0xf3, 0xc6, 0x9d, 0x29, 0x3a, 0xba, 0x11, 0x27, 0xfb, 0x24, 0x5f, 0x4b, 0x9e, - 0x2a, 0x52, 0x20, 0x92, 0x72, 0x91, 0x6c, 0x21, 0xc7, 0x61, 0x51, 0x06, 0x22, 0x26, 0x88, 0xce, - 0x85, 0xf8, 0x40, 0xd0, 0x08, 0xe3, 0x6b, 0x42, 0xe8, 0x6c, 0x95, 0xaf, 0x11, 0xb6, 0x84, 0xcc, - 0x97, 0x60, 0xb4, 0xd0, 0x23, 0xae, 0x0d, 0xa9, 0x18, 0x03, 0x88, 0x6b, 0x7e, 0x65, 0xdc, 0x08, - 0x5f, 0xc4, 0x0d, 0x05, 0x15, 0xbe, 0xa0, 0xa0, 0xf8, 0x61, 0x78, 0xe0, 0x0f, 0x9f, 0xd2, 0xe5, - 0x4e, 0xba, 0x90, 0xd0, 0xf2, 0x6c, 0x10, 0x7b, 0x6d, 0xac, 0x26, 0x1d, 0xfe, 0x35, 0x3d, 0x13, - 0x62, 0x3b, 0xd0, 0xa6, 0x90, 0x4d, 0xae, 0x67, 0x97, 0xd6, 0x73, 0xd5, 0x8c, 0xe9, 0x68, 0x45, - 0x4d, 0x22, 0xf3, 0x80, 0x60, 0xc5, 0xbe, 0x33, 0xf0, 0x0d, 0x60, 0x37, 0x47, 0x23, 0xb9, 0xde, - 0x3a, 0x64, 0x2c, 0x56, 0xca, 0xb1, 0x56, 0xaa, 0x66, 0xc6, 0x1a, 0xb5, 0x33, 0xe6, 0xde, 0x85, - 0xf6, 0x9e, 0x71, 0xc3, 0x93, 0x44, 0x43, 0xdd, 0xed, 0x94, 0xe2, 0x64, 0x20, 0x46, 0x83, 0x0d, - 0xb3, 0x41, 0xf7, 0xe7, 0x81, 0x3d, 0x08, 0xb2, 0x5c, 0xf7, 0x4f, 0x2c, 0xc7, 0x1b, 0xd0, 0xd1, - 0x01, 0x76, 0x71, 0xa3, 0xa1, 0x2d, 0x31, 0xba, 0x69, 0x70, 0x53, 0x5c, 0x85, 0x28, 0x0f, 0x6c, - 0x0b, 0x96, 0x02, 0x01, 0x95, 0x35, 0x41, 0x51, 0xea, 0x7a, 0xf4, 0xd7, 0x24, 0x68, 0xed, 0xa2, - 0x3f, 0x70, 0x60, 0x51, 0x0e, 0x0d, 0xbd, 0x0d, 0xeb, 0x6e, 0xab, 0x18, 0x98, 0x85, 0xd5, 0xdf, - 0x08, 0xac, 0xca, 0xf0, 0x5c, 0x9d, 0x0c, 0x33, 0x68, 0x26, 0x7e, 0x7e, 0x44, 0x01, 0x4a, 0xcb, - 0xa3, 0xdf, 0x6c, 0x55, 0x04, 0xcd, 0x42, 0x57, 0x28, 0x60, 0xae, 0xbb, 0x84, 0x2a, 0x4c, 0x72, - 0x05, 0xc7, 0x41, 0xd1, 0xe5, 0x01, 0x81, 0xeb, 0x33, 0x01, 0x79, 0x31, 0xa3, 0x80, 0x8b, 0xf9, - 0x92, 0x2c, 0xca, 0xf3, 0x25, 0x49, 0x3d, 0x5d, 0xef, 0xf6, 0xa1, 0x77, 0x87, 0x87, 0x3c, 0xe7, - 0x37, 0xc3, 0xb0, 0xcc, 0xff, 0x02, 0x9c, 0xaf, 0xa9, 0x93, 0x4e, 0xcb, 0x3d, 0x58, 0xbb, 0xc3, - 0x0f, 0xa6, 0xe3, 0x07, 0xfc, 0xb8, 0x38, 0xb8, 0x63, 0xd0, 0xcc, 0x8e, 0xe2, 0x13, 0xb9, 0xb6, - 0xf4, 0x9b, 0xbd, 0x06, 0x10, 0x22, 0xcd, 0x20, 0x4b, 0xf8, 0x50, 0xdd, 0x85, 0x23, 0x64, 0x3f, - 0xe1, 0x43, 0xf7, 0x1d, 0x60, 0x26, 0x1f, 0x39, 0x04, 0xb4, 0x03, 0xd3, 0x83, 0x41, 0x36, 0xcb, - 0x72, 0x3e, 0x51, 0x97, 0xfc, 0x4c, 0xc8, 0xbd, 0x02, 0x9d, 0x3d, 0x7f, 0xe6, 0xf1, 0x8f, 0xe4, - 0xf5, 0x62, 0x8c, 0x8d, 0xfd, 0x19, 0x8a, 0xb2, 0x8e, 0x8d, 0xa9, 0xda, 0xfd, 0x8f, 0x06, 0x2c, - 0x08, 0x4a, 0xe4, 0x3a, 0xe2, 0x59, 0x1e, 0x44, 0xe2, 0xd0, 0x4a, 0x72, 0x35, 0xa0, 0x8a, 0x6c, - 0x34, 0x6a, 0x64, 0x43, 0x7a, 0xab, 0xea, 0x5e, 0x91, 0x14, 0x02, 0x0b, 0x43, 0xb7, 0xa6, 0xb8, - 0x0c, 0x20, 0x82, 0xb3, 0x02, 0x28, 0x25, 0x4b, 0x0a, 0x6b, 0x23, 0xfa, 0xa7, 0x84, 0x56, 0x8a, - 0x83, 0x09, 0xd5, 0xda, 0xb4, 0x45, 0x21, 0x35, 0x15, 0x9b, 0x56, 0xb1, 0x5d, 0x4b, 0xaf, 0x60, - 0xbb, 0x84, 0x0b, 0xfb, 0x22, 0xdb, 0x05, 0xaf, 0x60, 0xbb, 0x5c, 0x06, 0xab, 0xf7, 0x38, 0xf7, - 0x38, 0xee, 0x8a, 0x4a, 0x9c, 0xbe, 0xeb, 0xc0, 0xaa, 0xdc, 0xd0, 0x75, 0x1d, 0x7b, 0xc3, 0xda, - 0xfd, 0x9d, 0xba, 0xf3, 0x88, 0x37, 0x61, 0x99, 0xf6, 0x64, 0x9d, 0x15, 0x92, 0x29, 0x2c, 0x0b, - 0xc4, 0x71, 0xa8, 0x0c, 0xfb, 0x24, 0x08, 0xe5, 0xa2, 0x98, 0x90, 0x4a, 0x2c, 0x61, 0x7c, 0x4c, - 0x4b, 0xe2, 0x78, 0xba, 0xec, 0xfe, 0xb5, 0x03, 0x6b, 0x46, 0x87, 0xa5, 0x14, 0xde, 0x00, 0x75, - 0x59, 0x40, 0x24, 0x8f, 0x84, 0x32, 0x9d, 0xb3, 0x9d, 0x93, 0xe2, 0x33, 0x8b, 0x98, 0x16, 0xd3, - 0x9f, 0x51, 0x07, 0xb3, 0xe9, 0x44, 0x7a, 0x20, 0x26, 0x84, 0x82, 0x74, 0xc2, 0xf9, 0x53, 0x4d, - 0x32, 0x47, 0x24, 0x16, 0x46, 0x67, 0xc1, 0xe8, 0x4b, 0x68, 0x22, 0x71, 0xfd, 0xc9, 0x06, 0xdd, - 0x7f, 0x70, 0x60, 0x5d, 0x38, 0x85, 0xd2, 0xe5, 0xd6, 0x57, 0x33, 0x17, 0x84, 0x17, 0x2c, 0x34, - 0x72, 0xf7, 0x8c, 0x27, 0xcb, 0xec, 0x0b, 0xaf, 0xe8, 0xc8, 0xea, 0x3b, 0x00, 0xa7, 0xac, 0xc5, - 0x5c, 0xdd, 0x5a, 0xbc, 0x60, 0xa6, 0xeb, 0x92, 0x25, 0xf3, 0xb5, 0xc9, 0x92, 0x5b, 0x8b, 0x30, - 0x9f, 0x0d, 0xe3, 0x84, 0xbb, 0x9b, 0xb0, 0x61, 0x0f, 0x4e, 0x9a, 0xa0, 0xef, 0x39, 0xd0, 0xbb, - 0x27, 0x52, 0x87, 0x41, 0x34, 0xde, 0x0d, 0xb2, 0x3c, 0x4e, 0xf5, 0x5d, 0xf4, 0x4b, 0x00, 0x59, - 0xee, 0xa7, 0xb9, 0xb8, 0xa3, 0x25, 0xd3, 0x1c, 0x05, 0x82, 0x7d, 0xe4, 0xd1, 0x48, 0xd4, 0x8a, - 0xb5, 0xd1, 0x65, 0x5c, 0x18, 0xba, 0x9f, 0x30, 0x88, 0x0f, 0x0f, 0x33, 0xae, 0xdd, 0x56, 0x13, - 0xc3, 0xc8, 0x17, 0x35, 0x1e, 0x63, 0x3d, 0x7e, 0x4c, 0xa6, 0x56, 0xf8, 0x83, 0x25, 0xd4, 0xfd, - 0x2b, 0x07, 0x56, 0x8a, 0x4e, 0xde, 0x45, 0xd0, 0xb6, 0x0e, 0xa2, 0x6b, 0x86, 0x75, 0x50, 0x09, - 0x98, 0x60, 0x34, 0x08, 0x22, 0xd9, 0x37, 0x03, 0x21, 0x8d, 0x95, 0xa5, 0x78, 0xaa, 0xee, 0xc3, - 0x99, 0x90, 0x38, 0xec, 0xce, 0xf1, 0x6b, 0x71, 0x19, 0x4e, 0x96, 0xe8, 0x8a, 0xdd, 0x24, 0xa7, - 0xaf, 0x16, 0x84, 0x43, 0x2c, 0x8b, 0x6a, 0x7f, 0x5a, 0x24, 0x14, 0x7f, 0xba, 0x7f, 0xe0, 0xc0, - 0xf9, 0x9a, 0xc9, 0x95, 0x9a, 0x71, 0x07, 0xd6, 0x0e, 0x75, 0xa5, 0x9a, 0x00, 0xa1, 0x1e, 0x9b, - 0x52, 0x8a, 0x4a, 0x83, 0xf6, 0xaa, 0x1f, 0xa0, 0x7b, 0x4c, 0x79, 0x23, 0x31, 0xa5, 0xd6, 0x3d, - 0x91, 0x6a, 0xc5, 0xce, 0xf7, 0x1b, 0xd0, 0x15, 0x47, 0x15, 0xe2, 0x35, 0x12, 0x4f, 0xd9, 0x07, - 0xb0, 0x28, 0xdf, 0x7e, 0xb1, 0xb3, 0xb2, 0x59, 0xfb, 0xb5, 0x59, 0x7f, 0xb3, 0x0c, 0x4b, 0xd9, - 0x59, 0xff, 0xed, 0x4f, 0xff, 0xf9, 0x0f, 0x1b, 0xcb, 0xac, 0xbd, 0x7d, 0xfc, 0xf6, 0xf6, 0x98, - 0x47, 0x19, 0xf2, 0xf8, 0x55, 0x80, 0xe2, 0xf9, 0x14, 0xeb, 0x69, 0x27, 0xa3, 0xf4, 0xdc, 0xab, - 0x7f, 0xbe, 0xa6, 0x46, 0xf2, 0x3d, 0x4f, 0x7c, 0xd7, 0xdd, 0x2e, 0xf2, 0x0d, 0xa2, 0x20, 0x17, - 0x6f, 0xa9, 0xde, 0x73, 0xb6, 0xd8, 0x08, 0x3a, 0xe6, 0x33, 0x2a, 0xa6, 0x42, 0xe6, 0x9a, 0xb7, - 0x59, 0xfd, 0x0b, 0xb5, 0x75, 0x2a, 0x5f, 0x40, 0x6d, 0x9c, 0x75, 0x57, 0xb1, 0x8d, 0x29, 0x51, - 0xe8, 0x56, 0x76, 0xfe, 0xf1, 0x02, 0xb4, 0x74, 0xda, 0x89, 0x7d, 0x08, 0xcb, 0xd6, 0xe9, 0x0e, - 0x53, 0x8c, 0xeb, 0x0e, 0x83, 0xfa, 0x17, 0xeb, 0x2b, 0x65, 0xb3, 0x97, 0xa8, 0xd9, 0x1e, 0xdb, - 0xc4, 0x66, 0xe5, 0xf1, 0xc8, 0x36, 0x9d, 0x69, 0x89, 0x2b, 0x75, 0x4f, 0xa1, 0x6b, 0x9f, 0xc8, - 0xb0, 0x8b, 0xb6, 0x41, 0x29, 0xb5, 0xf6, 0xda, 0x29, 0xb5, 0xb2, 0xb9, 0x8b, 0xd4, 0xdc, 0x26, - 0xdb, 0x30, 0x9b, 0xd3, 0xe9, 0x20, 0x4e, 0x97, 0x20, 0xcd, 0xf7, 0x55, 0xec, 0x35, 0xbd, 0xd4, - 0x75, 0xef, 0xae, 0xf4, 0xa2, 0x55, 0x1f, 0x5f, 0xb9, 0x3d, 0x6a, 0x8a, 0x31, 0x9a, 0x50, 0xf3, - 0x79, 0x15, 0xfb, 0x16, 0xb4, 0xf4, 0x9b, 0x0a, 0x76, 0xce, 0x78, 0xc8, 0x62, 0x3e, 0xf4, 0xe8, - 0xf7, 0xaa, 0x15, 0x75, 0x4b, 0x65, 0x72, 0x46, 0x81, 0x78, 0x00, 0x67, 0xa5, 0x93, 0x7a, 0xc0, - 0x7f, 0x9c, 0x91, 0xd4, 0xbc, 0x0a, 0xbb, 0xee, 0xb0, 0x1b, 0xb0, 0xa4, 0x9e, 0xaa, 0xb0, 0xcd, - 0xfa, 0x27, 0x37, 0xfd, 0x73, 0x15, 0x5c, 0xea, 0xf3, 0x4d, 0x80, 0xe2, 0x99, 0x85, 0x96, 0xfc, - 0xca, 0xe3, 0x0f, 0x3d, 0x89, 0x35, 0x6f, 0x32, 0xc6, 0xf4, 0xa8, 0xc4, 0x7e, 0xc5, 0xc1, 0x5e, - 0x2f, 0xe8, 0x6b, 0xdf, 0x77, 0xbc, 0x80, 0xa1, 0xbb, 0x49, 0x73, 0xb7, 0xca, 0x48, 0x95, 0x22, - 0x7e, 0xa2, 0xae, 0x03, 0xdf, 0x81, 0xb6, 0xf1, 0x74, 0x83, 0x29, 0x0e, 0xd5, 0x67, 0x1f, 0xfd, - 0x7e, 0x5d, 0x95, 0xec, 0xee, 0x57, 0x60, 0xd9, 0x7a, 0x83, 0xa1, 0x35, 0xa3, 0xee, 0x85, 0x87, - 0xd6, 0x8c, 0xfa, 0x67, 0x1b, 0xdf, 0x84, 0xb6, 0xf1, 0x62, 0x82, 0x19, 0xd7, 0xa0, 0x4a, 0x6f, - 0x25, 0x74, 0x8f, 0xea, 0x1e, 0x58, 0x6c, 0xd0, 0x78, 0xbb, 0x6e, 0x0b, 0xc7, 0x4b, 0x77, 0x62, - 0x51, 0x48, 0x3e, 0x84, 0xae, 0xfd, 0x86, 0x42, 0x6b, 0x55, 0xed, 0x6b, 0x0c, 0xad, 0x55, 0xa7, - 0x3c, 0xbc, 0x90, 0x02, 0xb9, 0xb5, 0xae, 0x1b, 0xd9, 0xfe, 0x44, 0x1e, 0xba, 0x3c, 0x67, 0x5f, - 0x47, 0xd3, 0x21, 0x2f, 0x29, 0xb3, 0xe2, 0xe5, 0x88, 0x7d, 0x95, 0x59, 0x4b, 0x7b, 0xe5, 0x3e, - 0xb3, 0xbb, 0x46, 0xcc, 0xdb, 0xac, 0x18, 0x81, 0xb0, 0xd0, 0x74, 0x59, 0xd9, 0xb0, 0xd0, 0xe6, - 0x7d, 0x66, 0xc3, 0x42, 0x5b, 0x77, 0x9a, 0xcb, 0x16, 0x3a, 0x0f, 0x90, 0x47, 0x04, 0x2b, 0xa5, - 0x7b, 0x00, 0x5a, 0x59, 0xea, 0x2f, 0x4e, 0xf5, 0x2f, 0xbd, 0xf8, 0xfa, 0x80, 0x6d, 0x66, 0x94, - 0x79, 0xd9, 0x56, 0xf7, 0xdc, 0x7e, 0x0d, 0x3a, 0xe6, 0xdd, 0x77, 0x6d, 0xb3, 0x6b, 0x6e, 0xec, - 0x6b, 0x9b, 0x5d, 0x77, 0x59, 0x5e, 0x2d, 0x2e, 0xeb, 0x98, 0xcd, 0xb0, 0x6f, 0xc2, 0x8a, 0x71, - 0xf1, 0x65, 0x7f, 0x16, 0x0d, 0xb5, 0xf0, 0x54, 0xaf, 0x45, 0xf6, 0xeb, 0xfc, 0x33, 0xf7, 0x1c, - 0x31, 0x5e, 0x73, 0x2d, 0xc6, 0x28, 0x38, 0xb7, 0xa1, 0x6d, 0x5e, 0xaa, 0x79, 0x01, 0xdf, 0x73, - 0x46, 0x95, 0x79, 0x43, 0xf0, 0xba, 0xc3, 0xfe, 0xd8, 0x81, 0x8e, 0x75, 0x45, 0xc5, 0xca, 0xf3, - 0x96, 0xf8, 0xf4, 0xcc, 0x3a, 0x93, 0x91, 0xeb, 0x51, 0x27, 0x1f, 0x6c, 0x7d, 0xc5, 0x9a, 0xe4, - 0x4f, 0x2c, 0x3f, 0xff, 0x5a, 0xf9, 0x59, 0xe3, 0xf3, 0x32, 0x81, 0x79, 0x75, 0xf4, 0xf9, 0x75, - 0x87, 0xbd, 0x27, 0x9e, 0xbe, 0xaa, 0xb8, 0x9e, 0x19, 0xc6, 0xad, 0x3c, 0x65, 0xe6, 0x2b, 0xd1, - 0xab, 0xce, 0x75, 0x87, 0x7d, 0x5b, 0xbc, 0x5e, 0x94, 0xdf, 0xd2, 0xcc, 0xbf, 0xea, 0xf7, 0xee, - 0x9b, 0x34, 0x9a, 0x4b, 0xee, 0x79, 0x6b, 0x34, 0x65, 0xeb, 0xbe, 0x07, 0x50, 0x24, 0x69, 0x58, - 0x29, 0x63, 0xa1, 0xed, 0x5e, 0x35, 0x8f, 0x63, 0xaf, 0xa8, 0x4a, 0x6c, 0x20, 0xc7, 0x6f, 0x09, - 0x61, 0x94, 0xf4, 0x99, 0x5e, 0xd2, 0x6a, 0xb2, 0xa5, 0xdf, 0xaf, 0xab, 0xaa, 0x13, 0x45, 0xc5, - 0x9f, 0x3d, 0x86, 0xe5, 0x07, 0x71, 0xfc, 0x74, 0x9a, 0xe8, 0x34, 0xa2, 0x9d, 0x33, 0xd8, 0xf5, - 0xb3, 0xa3, 0x7e, 0x69, 0x14, 0xee, 0x65, 0x62, 0xd5, 0x67, 0x3d, 0x83, 0xd5, 0xf6, 0x27, 0x45, - 0x8a, 0xe8, 0x39, 0xf3, 0x61, 0x4d, 0xef, 0x71, 0xba, 0xe3, 0x7d, 0x9b, 0x8d, 0x99, 0xa9, 0xa9, - 0x34, 0x61, 0x79, 0x1d, 0xaa, 0xb7, 0xdb, 0x99, 0xe2, 0x79, 0xdd, 0x61, 0x7b, 0xd0, 0xb9, 0xc3, - 0x87, 0xf1, 0x88, 0xcb, 0x28, 0x7f, 0xbd, 0xe8, 0xb8, 0x4e, 0x0f, 0xf4, 0x97, 0x2d, 0xd0, 0xd6, - 0xfa, 0xc4, 0x9f, 0xa5, 0xfc, 0xa3, 0xed, 0x4f, 0x64, 0xfe, 0xe0, 0xb9, 0xd2, 0x7a, 0x95, 0xf3, - 0xb0, 0xb4, 0xbe, 0x94, 0x24, 0xb1, 0xb4, 0xbe, 0x92, 0x24, 0xb1, 0xa6, 0x5a, 0xe5, 0x5c, 0x58, - 0x08, 0x6b, 0x95, 0xbc, 0x8a, 0xde, 0x29, 0x4f, 0xcb, 0xc6, 0xf4, 0x2f, 0x9f, 0x4e, 0x60, 0xb7, - 0xb6, 0x65, 0xb7, 0xb6, 0x0f, 0xcb, 0x77, 0xb8, 0x98, 0x2c, 0x71, 0x56, 0xd9, 0xb7, 0xcd, 0x88, - 0x79, 0xae, 0x59, 0x36, 0x31, 0x54, 0x67, 0x9b, 0x75, 0x3a, 0x28, 0x64, 0xdf, 0x82, 0xf6, 0x7d, - 0x9e, 0xab, 0xc3, 0x49, 0xed, 0x6f, 0x94, 0x4e, 0x2b, 0xfb, 0x35, 0x67, 0x9b, 0xb6, 0xcc, 0x10, - 0xb7, 0x6d, 0x3e, 0x1a, 0x73, 0xa1, 0xec, 0x83, 0x60, 0xf4, 0x9c, 0xfd, 0x32, 0x31, 0xd7, 0xf7, - 0x19, 0x36, 0x8d, 0x33, 0x2d, 0x93, 0xf9, 0x4a, 0x09, 0xaf, 0xe3, 0x1c, 0xc5, 0x23, 0x6e, 0x6c, - 0x70, 0x11, 0xb4, 0x8d, 0xcb, 0x36, 0x5a, 0x81, 0xaa, 0x17, 0x7c, 0xb4, 0x02, 0xd5, 0xdc, 0xcd, - 0x71, 0xaf, 0x52, 0x3b, 0x2e, 0xbb, 0x5c, 0xb4, 0x23, 0xee, 0xe3, 0x14, 0x2d, 0x6d, 0x7f, 0xe2, - 0x4f, 0xf2, 0xe7, 0xec, 0x09, 0xbd, 0xde, 0x31, 0x0f, 0x60, 0x0b, 0x7f, 0xa7, 0x7c, 0x56, 0xab, - 0x27, 0xcb, 0xa8, 0xb2, 0x7d, 0x20, 0xd1, 0x14, 0xed, 0x83, 0x5f, 0x00, 0xd8, 0xcf, 0xe3, 0xe4, - 0x8e, 0xcf, 0x27, 0x71, 0x54, 0x58, 0xae, 0xe2, 0x90, 0xb1, 0xb0, 0x5c, 0xc6, 0x49, 0x23, 0x7b, - 0x62, 0x78, 0x9c, 0xd6, 0xf9, 0xb5, 0x12, 0xae, 0x53, 0xcf, 0x21, 0xf5, 0x84, 0xd4, 0x9c, 0x45, - 0x5e, 0x77, 0xd0, 0x7f, 0x2c, 0xb2, 0x78, 0xda, 0x7f, 0xac, 0x24, 0x08, 0xb5, 0xd9, 0xab, 0x49, - 0xf9, 0xed, 0x41, 0xab, 0x48, 0x0b, 0xa9, 0x2d, 0xa9, 0x9c, 0x44, 0xd2, 0x7b, 0x4c, 0x25, 0x59, - 0xe3, 0xae, 0xd2, 0x54, 0x01, 0x5b, 0xc2, 0xa9, 0xa2, 0x0c, 0x4c, 0x00, 0xeb, 0xa2, 0x83, 0x7a, - 0xc3, 0xa4, 0x63, 0x33, 0x35, 0x92, 0x9a, 0x84, 0x89, 0xd6, 0xe6, 0xda, 0x7c, 0x83, 0x15, 0xdb, - 0xa1, 0xb4, 0x8a, 0x23, 0x3b, 0x34, 0xcd, 0x13, 0x58, 0xab, 0x04, 0xcb, 0x5a, 0xa5, 0x4f, 0xcb, - 0x51, 0x68, 0x95, 0x3e, 0x35, 0xce, 0x76, 0xcf, 0x52, 0x93, 0x2b, 0x2e, 0x60, 0x93, 0xd9, 0x49, - 0x90, 0x0f, 0x8f, 0xde, 0x73, 0xb6, 0x0e, 0x16, 0xe8, 0xcf, 0x55, 0x3e, 0xf7, 0x3f, 0x01, 0x00, - 0x00, 0xff, 0xff, 0x8f, 0xec, 0x5b, 0xef, 0x8e, 0x45, 0x00, 0x00, + // 5640 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x7c, 0x4d, 0x90, 0x1c, 0xc9, + 0x55, 0xbf, 0xaa, 0xa7, 0xe7, 0xa3, 0x5f, 0xf7, 0xf4, 0xcc, 0xe4, 0x8c, 0x46, 0xad, 0x96, 0x56, + 0xab, 0x2d, 0x6f, 0x58, 0xfa, 0xcf, 0x7f, 0xd1, 0x68, 0xc7, 0xf6, 0xb2, 0x5e, 0x81, 0x8d, 0xbe, + 0x67, 0x6d, 0xad, 0x3c, 0xae, 0x91, 0x2c, 0xb0, 0x81, 0x76, 0x4d, 0x77, 0x4e, 0x4f, 0xad, 0xaa, + 0xab, 0x6a, 0xab, 0xaa, 0x67, 0xd4, 0xbb, 0x28, 0x82, 0xaf, 0xe0, 0x84, 0x83, 0x03, 0x5c, 0x4c, + 0x04, 0x41, 0x84, 0x7d, 0x81, 0x03, 0x47, 0x4e, 0x86, 0x1b, 0x27, 0x22, 0x08, 0x0e, 0x7b, 0x72, + 0x70, 0xe3, 0xe3, 0x00, 0x0e, 0x2e, 0x44, 0x70, 0xe1, 0x40, 0x10, 0xef, 0xe5, 0x47, 0x65, 0x56, + 0xd5, 0x48, 0xf2, 0x07, 0xdc, 0x3a, 0x7f, 0xf9, 0xea, 0xe5, 0xd7, 0x7b, 0x2f, 0xdf, 0x7b, 0x99, + 0xd9, 0xd0, 0x4a, 0x93, 0xe1, 0xb5, 0x24, 0x8d, 0xf3, 0x98, 0xcd, 0x87, 0x51, 0x9a, 0x0c, 0xfb, + 0x17, 0xc7, 0x71, 0x3c, 0x0e, 0xf9, 0xb6, 0x9f, 0x04, 0xdb, 0x7e, 0x14, 0xc5, 0xb9, 0x9f, 0x07, + 0x71, 0x94, 0x09, 0x22, 0xf7, 0xdb, 0xd0, 0xbd, 0xcf, 0xa3, 0x7d, 0xce, 0x47, 0x1e, 0xff, 0x68, + 0xca, 0xb3, 0x9c, 0xfd, 0x7f, 0x58, 0xf3, 0xf9, 0xc7, 0x9c, 0x8f, 0x06, 0x89, 0x9f, 0x65, 0xc9, + 0x51, 0xea, 0x67, 0xbc, 0xe7, 0x5c, 0x76, 0xae, 0x76, 0xbc, 0x55, 0x51, 0xb1, 0xa7, 0x71, 0xf6, + 0x06, 0x74, 0x32, 0x24, 0xe5, 0x51, 0x9e, 0xc6, 0xc9, 0xac, 0xd7, 0x20, 0xba, 0x36, 0x62, 0x77, + 0x05, 0xe4, 0x86, 0xb0, 0xa2, 0x5b, 0xc8, 0x92, 0x38, 0xca, 0x38, 0xbb, 0x0e, 0x1b, 0xc3, 0x20, + 0x39, 0xe2, 0xe9, 0x80, 0x3e, 0x9e, 0x44, 0x7c, 0x12, 0x47, 0xc1, 0xb0, 0xe7, 0x5c, 0x9e, 0xbb, + 0xda, 0xf2, 0x98, 0xa8, 0xc3, 0x2f, 0x3e, 0x90, 0x35, 0xec, 0x0a, 0xac, 0xf0, 0x48, 0xe0, 0x7c, + 0x44, 0x5f, 0xc9, 0xa6, 0xba, 0x05, 0x8c, 0x1f, 0xb8, 0x7f, 0xe3, 0xc0, 0xda, 0xfb, 0x51, 0x90, + 0x3f, 0xf1, 0xc3, 0x90, 0xe7, 0x6a, 0x4c, 0x57, 0x60, 0xe5, 0x84, 0x00, 0x1a, 0xd3, 0x49, 0x9c, + 0x8e, 0xe4, 0x88, 0xba, 0x02, 0xde, 0x93, 0xe8, 0xa9, 0x3d, 0x6b, 0x9c, 0xda, 0xb3, 0xda, 0xe9, + 0x9a, 0x3b, 0x65, 0xba, 0xae, 0xc0, 0x4a, 0xca, 0x87, 0xf1, 0x31, 0x4f, 0x67, 0x83, 0x93, 0x20, + 0x1a, 0xc5, 0x27, 0xbd, 0xe6, 0x65, 0xe7, 0xea, 0xbc, 0xd7, 0x55, 0xf0, 0x13, 0x42, 0xdd, 0x0d, + 0x60, 0xe6, 0x28, 0xc4, 0xbc, 0xb9, 0x63, 0x58, 0x7f, 0x1c, 0x85, 0xf1, 0xf0, 0xe9, 0x4f, 0x38, + 0xba, 0x9a, 0xe6, 0x1b, 0xb5, 0xcd, 0x6f, 0xc2, 0x86, 0xdd, 0x90, 0xec, 0xc0, 0x77, 0x1b, 0xd0, + 0x7e, 0x94, 0xfa, 0x51, 0xe6, 0x0f, 0x51, 0x88, 0x58, 0x0f, 0x16, 0xf3, 0x67, 0x83, 0x23, 0x3f, + 0x3b, 0xa2, 0x16, 0x5b, 0x9e, 0x2a, 0xb2, 0x4d, 0x58, 0xf0, 0x27, 0xf1, 0x34, 0xca, 0xa9, 0x85, + 0x39, 0x4f, 0x96, 0xd8, 0x5b, 0xb0, 0x16, 0x4d, 0x27, 0x83, 0x61, 0x1c, 0x1d, 0x06, 0xe9, 0x44, + 0x88, 0x22, 0x4d, 0xd7, 0xbc, 0x57, 0xad, 0x60, 0x97, 0x00, 0x0e, 0xb0, 0x1b, 0xa2, 0x89, 0x26, + 0x35, 0x61, 0x20, 0xcc, 0x85, 0x8e, 0x2c, 0xf1, 0x60, 0x7c, 0x94, 0xf7, 0xe6, 0x89, 0x91, 0x85, + 0x21, 0x8f, 0x3c, 0x98, 0xf0, 0x41, 0x96, 0xfb, 0x93, 0xa4, 0xb7, 0x40, 0xbd, 0x31, 0x10, 0xaa, + 0x8f, 0x73, 0x3f, 0x1c, 0x1c, 0x72, 0x9e, 0xf5, 0x16, 0x65, 0xbd, 0x46, 0xd8, 0x67, 0xa1, 0x3b, + 0xe2, 0x59, 0x3e, 0xf0, 0x47, 0xa3, 0x94, 0x67, 0x19, 0xcf, 0x7a, 0x4b, 0x24, 0x0c, 0x25, 0xd4, + 0xed, 0xc1, 0xe6, 0x7d, 0x9e, 0x1b, 0xb3, 0x93, 0xc9, 0xf5, 0x71, 0x1f, 0x00, 0x33, 0xe0, 0x3b, + 0x3c, 0xf7, 0x83, 0x30, 0x63, 0xef, 0x40, 0x27, 0x37, 0x88, 0x49, 0xf8, 0xdb, 0x3b, 0xec, 0x1a, + 0x69, 0xed, 0x35, 0xe3, 0x03, 0xcf, 0xa2, 0x73, 0xff, 0xcb, 0x81, 0xf6, 0x3e, 0x8f, 0xb4, 0xbe, + 0x32, 0x68, 0x62, 0x4f, 0xe4, 0x92, 0xd3, 0x6f, 0xf6, 0x3a, 0xb4, 0xa9, 0x77, 0x59, 0x9e, 0x06, + 0xd1, 0x98, 0x96, 0xa0, 0xe5, 0x01, 0x42, 0xfb, 0x84, 0xb0, 0x55, 0x98, 0xf3, 0x27, 0x39, 0x4d, + 0xfc, 0x9c, 0x87, 0x3f, 0x51, 0x93, 0x13, 0x7f, 0x36, 0xe1, 0x51, 0x5e, 0x4c, 0x76, 0xc7, 0x6b, + 0x4b, 0x6c, 0x17, 0x67, 0xfb, 0x1a, 0xac, 0x9b, 0x24, 0x8a, 0xfb, 0x3c, 0x71, 0x5f, 0x33, 0x28, + 0x65, 0x23, 0x57, 0x60, 0x45, 0xd1, 0xa7, 0xa2, 0xb3, 0x34, 0xfd, 0x2d, 0xaf, 0x2b, 0x61, 0x35, + 0x84, 0xab, 0xb0, 0x7a, 0x18, 0x44, 0x7e, 0x38, 0x18, 0x86, 0xf9, 0xf1, 0x60, 0xc4, 0xc3, 0xdc, + 0xa7, 0x85, 0x98, 0xf7, 0xba, 0x84, 0xdf, 0x0e, 0xf3, 0xe3, 0x3b, 0x88, 0xba, 0x7f, 0xe4, 0x40, + 0x47, 0x0c, 0x5e, 0x9a, 0x92, 0x37, 0x61, 0x59, 0xb5, 0xc1, 0xd3, 0x34, 0x4e, 0xa5, 0x1c, 0xda, + 0x20, 0xdb, 0x82, 0x55, 0x05, 0x24, 0x29, 0x0f, 0x26, 0xfe, 0x98, 0x4b, 0xfb, 0x51, 0xc1, 0xd9, + 0x4e, 0xc1, 0x31, 0x8d, 0xa7, 0xb9, 0x50, 0xe6, 0xf6, 0x4e, 0x47, 0x2e, 0x8c, 0x87, 0x98, 0x67, + 0x93, 0xb8, 0xdf, 0x73, 0xa0, 0x73, 0xfb, 0xc8, 0x8f, 0x22, 0x1e, 0xee, 0xc5, 0x41, 0x94, 0xb3, + 0xeb, 0xc0, 0x0e, 0xa7, 0xd1, 0x28, 0x88, 0xc6, 0x83, 0xfc, 0x59, 0x30, 0x1a, 0x1c, 0xcc, 0x72, + 0x9e, 0x89, 0x25, 0xda, 0x3d, 0xe3, 0xd5, 0xd4, 0xb1, 0xb7, 0x60, 0xd5, 0x42, 0xb3, 0x3c, 0x15, + 0xeb, 0xb6, 0x7b, 0xc6, 0xab, 0xd4, 0xa0, 0xe0, 0xc7, 0xd3, 0x3c, 0x99, 0xe6, 0x83, 0x20, 0x1a, + 0xf1, 0x67, 0xd4, 0xc7, 0x65, 0xcf, 0xc2, 0x6e, 0x75, 0xa1, 0x63, 0x7e, 0xe7, 0x7e, 0x09, 0x56, + 0x1f, 0xa0, 0x46, 0x44, 0x41, 0x34, 0xbe, 0x29, 0xc4, 0x16, 0xd5, 0x34, 0x99, 0x1e, 0x3c, 0xe5, + 0x33, 0x39, 0x6f, 0xb2, 0x84, 0x42, 0x75, 0x14, 0x67, 0xb9, 0x94, 0x1c, 0xfa, 0xed, 0xfe, 0x93, + 0x03, 0x2b, 0x38, 0xf7, 0x1f, 0xf8, 0xd1, 0x4c, 0xad, 0xdc, 0x03, 0xe8, 0x20, 0xab, 0x47, 0xf1, + 0x4d, 0xa1, 0xec, 0x42, 0x88, 0xaf, 0xca, 0xb9, 0x2a, 0x51, 0x5f, 0x33, 0x49, 0x71, 0x7b, 0x98, + 0x79, 0xd6, 0xd7, 0x28, 0xb6, 0xb9, 0x9f, 0x8e, 0x79, 0x4e, 0x66, 0x40, 0x9a, 0x05, 0x10, 0xd0, + 0xed, 0x38, 0x3a, 0x64, 0x97, 0xa1, 0x93, 0xf9, 0xf9, 0x20, 0xe1, 0x29, 0xcd, 0x1a, 0x89, 0xde, + 0x9c, 0x07, 0x99, 0x9f, 0xef, 0xf1, 0xf4, 0xd6, 0x2c, 0xe7, 0xfd, 0x2f, 0xc3, 0x5a, 0xa5, 0x15, + 0x94, 0xf6, 0x62, 0x88, 0xf8, 0x93, 0x6d, 0xc0, 0xfc, 0xb1, 0x1f, 0x4e, 0xb9, 0xb4, 0x4e, 0xa2, + 0xf0, 0x5e, 0xe3, 0x5d, 0xc7, 0xfd, 0x2c, 0xac, 0x16, 0xdd, 0x96, 0x42, 0xc6, 0xa0, 0x89, 0x33, + 0x28, 0x19, 0xd0, 0x6f, 0xf7, 0xb7, 0x1c, 0x41, 0x78, 0x3b, 0x0e, 0xb4, 0xa6, 0x23, 0x21, 0x1a, + 0x04, 0x45, 0x88, 0xbf, 0x4f, 0xb5, 0x84, 0x3f, 0xfd, 0x60, 0xdd, 0x2b, 0xb0, 0x66, 0x74, 0xe1, + 0x05, 0x9d, 0xfd, 0x8e, 0x03, 0x6b, 0x0f, 0xf9, 0x89, 0x5c, 0x75, 0xd5, 0xdb, 0x77, 0xa1, 0x99, + 0xcf, 0x12, 0xb1, 0xb9, 0x77, 0x77, 0xde, 0x94, 0x8b, 0x56, 0xa1, 0xbb, 0x26, 0x8b, 0x8f, 0x66, + 0x09, 0xf7, 0xe8, 0x0b, 0xf7, 0x4b, 0xd0, 0x36, 0x40, 0x76, 0x0e, 0xd6, 0x9f, 0xbc, 0xff, 0xe8, + 0xe1, 0xdd, 0xfd, 0xfd, 0xc1, 0xde, 0xe3, 0x5b, 0x5f, 0xbd, 0xfb, 0x2b, 0x83, 0xdd, 0x9b, 0xfb, + 0xbb, 0xab, 0x67, 0xd8, 0x26, 0xb0, 0x87, 0x77, 0xf7, 0x1f, 0xdd, 0xbd, 0x63, 0xe1, 0x8e, 0xdb, + 0x87, 0xde, 0x43, 0x7e, 0xf2, 0x24, 0xc8, 0x23, 0x9e, 0x65, 0x76, 0x6b, 0xee, 0x35, 0x60, 0x66, + 0x17, 0xe4, 0xa8, 0x7a, 0xb0, 0x28, 0x4d, 0xad, 0xda, 0x69, 0x64, 0xd1, 0xfd, 0x2c, 0xb0, 0xfd, + 0x60, 0x1c, 0x7d, 0xc0, 0xb3, 0xcc, 0x1f, 0x73, 0x35, 0xb6, 0x55, 0x98, 0x9b, 0x64, 0x63, 0x69, + 0x14, 0xf1, 0xa7, 0xfb, 0x39, 0x58, 0xb7, 0xe8, 0x24, 0xe3, 0x8b, 0xd0, 0xca, 0x82, 0x71, 0xe4, + 0xe7, 0xd3, 0x94, 0x4b, 0xd6, 0x05, 0xe0, 0xde, 0x83, 0x8d, 0x6f, 0xf0, 0x34, 0x38, 0x9c, 0xbd, + 0x8c, 0xbd, 0xcd, 0xa7, 0x51, 0xe6, 0x73, 0x17, 0xce, 0x96, 0xf8, 0xc8, 0xe6, 0x85, 0x20, 0xca, + 0xe5, 0x5a, 0xf2, 0x44, 0xc1, 0x50, 0xcb, 0x86, 0xa9, 0x96, 0xee, 0x63, 0x60, 0xb7, 0xe3, 0x28, + 0xe2, 0xc3, 0x7c, 0x8f, 0xf3, 0xb4, 0xf0, 0xd8, 0x0a, 0xa9, 0x6b, 0xef, 0x9c, 0x93, 0xeb, 0x58, + 0xd6, 0x75, 0x29, 0x8e, 0x0c, 0x9a, 0x09, 0x4f, 0x27, 0xc4, 0x78, 0xc9, 0xa3, 0xdf, 0xee, 0x59, + 0x58, 0xb7, 0xd8, 0xca, 0xdd, 0xfe, 0x6d, 0x38, 0x7b, 0x27, 0xc8, 0x86, 0xd5, 0x06, 0x7b, 0xb0, + 0x98, 0x4c, 0x0f, 0x06, 0x85, 0x4e, 0xa9, 0x22, 0x6e, 0x82, 0xe5, 0x4f, 0x24, 0xb3, 0xdf, 0x73, + 0xa0, 0xb9, 0xfb, 0xe8, 0xc1, 0x6d, 0xd6, 0x87, 0xa5, 0x20, 0x1a, 0xc6, 0x13, 0xdc, 0x3a, 0xc4, + 0xa0, 0x75, 0xf9, 0x54, 0x5d, 0xb9, 0x08, 0x2d, 0xda, 0x71, 0x70, 0x5f, 0x97, 0xce, 0x55, 0x01, + 0xa0, 0x4f, 0xc1, 0x9f, 0x25, 0x41, 0x4a, 0x4e, 0x83, 0x72, 0x05, 0x9a, 0x64, 0x11, 0xab, 0x15, + 0xee, 0x7f, 0x37, 0x61, 0x51, 0xda, 0x6a, 0x6a, 0x6f, 0x98, 0x07, 0xc7, 0x5c, 0xf6, 0x44, 0x96, + 0x70, 0x57, 0x49, 0xf9, 0x24, 0xce, 0xf9, 0xc0, 0x5a, 0x06, 0x1b, 0x44, 0xaa, 0xa1, 0x60, 0x34, + 0x48, 0xd0, 0xea, 0x53, 0xcf, 0x5a, 0x9e, 0x0d, 0xe2, 0x64, 0x21, 0x30, 0x08, 0x46, 0xd4, 0xa7, + 0xa6, 0xa7, 0x8a, 0x38, 0x13, 0x43, 0x3f, 0xf1, 0x87, 0x41, 0x3e, 0x93, 0xca, 0xad, 0xcb, 0xc8, + 0x3b, 0x8c, 0x87, 0x7e, 0x38, 0x38, 0xf0, 0x43, 0x3f, 0x1a, 0x72, 0xe9, 0xb8, 0xd8, 0x20, 0xfa, + 0x26, 0xb2, 0x4b, 0x8a, 0x4c, 0xf8, 0x2f, 0x25, 0x14, 0x7d, 0x9c, 0x61, 0x3c, 0x99, 0x04, 0x39, + 0xba, 0x34, 0xbd, 0x25, 0x61, 0x48, 0x0a, 0x84, 0x46, 0x22, 0x4a, 0x27, 0x62, 0xf6, 0x5a, 0xa2, + 0x35, 0x0b, 0x44, 0x2e, 0x87, 0x9c, 0x93, 0x41, 0x7a, 0x7a, 0xd2, 0x03, 0xc1, 0xa5, 0x40, 0x70, + 0x1d, 0xa6, 0x51, 0xc6, 0xf3, 0x3c, 0xe4, 0x23, 0xdd, 0xa1, 0x36, 0x91, 0x55, 0x2b, 0xd8, 0x75, + 0x58, 0x17, 0x5e, 0x56, 0xe6, 0xe7, 0x71, 0x76, 0x14, 0x64, 0x83, 0x8c, 0x47, 0x79, 0xaf, 0x43, + 0xf4, 0x75, 0x55, 0xec, 0x5d, 0x38, 0x57, 0x82, 0x53, 0x3e, 0xe4, 0xc1, 0x31, 0x1f, 0xf5, 0x96, + 0xe9, 0xab, 0xd3, 0xaa, 0xd9, 0x65, 0x68, 0xa3, 0x73, 0x39, 0x4d, 0x46, 0x3e, 0xee, 0xc3, 0x5d, + 0x5a, 0x07, 0x13, 0x62, 0x6f, 0xc3, 0x72, 0xc2, 0xc5, 0x66, 0x79, 0x94, 0x87, 0xc3, 0xac, 0xb7, + 0x42, 0x3b, 0x59, 0x5b, 0x2a, 0x13, 0x4a, 0xae, 0x67, 0x53, 0xa0, 0x50, 0x0e, 0x33, 0x72, 0x57, + 0xfc, 0x59, 0x6f, 0x95, 0xc4, 0xad, 0x00, 0x48, 0x47, 0xd2, 0xe0, 0xd8, 0xcf, 0x79, 0x6f, 0x8d, + 0x64, 0x4b, 0x15, 0xdd, 0x3f, 0x75, 0x60, 0xfd, 0x41, 0x90, 0xe5, 0x52, 0x08, 0xb5, 0x39, 0x7e, + 0x1d, 0xda, 0x42, 0xfc, 0x06, 0x71, 0x14, 0xce, 0xa4, 0x44, 0x82, 0x80, 0xbe, 0x16, 0x85, 0x33, + 0xf6, 0x19, 0x58, 0x0e, 0x22, 0x93, 0x44, 0xe8, 0x70, 0x47, 0x81, 0x44, 0xf4, 0x3a, 0xb4, 0x93, + 0xe9, 0x41, 0x18, 0x0c, 0x05, 0xc9, 0x9c, 0xe0, 0x22, 0x20, 0x22, 0x40, 0x47, 0x4f, 0xf4, 0x44, + 0x50, 0x34, 0x89, 0xa2, 0x2d, 0x31, 0x24, 0x71, 0x6f, 0xc1, 0x86, 0xdd, 0x41, 0x69, 0xac, 0xb6, + 0x60, 0x49, 0xca, 0x76, 0xd6, 0x6b, 0xd3, 0xfc, 0x74, 0xe5, 0xfc, 0x48, 0x52, 0x4f, 0xd7, 0xbb, + 0xff, 0xe6, 0x40, 0x13, 0x0d, 0xc0, 0xe9, 0xc6, 0xc2, 0xb4, 0xe9, 0x73, 0x96, 0x4d, 0x27, 0xbf, + 0x1f, 0xbd, 0x22, 0x21, 0x12, 0x42, 0x6d, 0x0c, 0xa4, 0xa8, 0x4f, 0xf9, 0xf0, 0x98, 0x74, 0x47, + 0xd7, 0x23, 0x82, 0x9a, 0x85, 0x5b, 0x27, 0x7d, 0x2d, 0x14, 0x47, 0x97, 0x55, 0x1d, 0x7d, 0xb9, + 0x58, 0xd4, 0xd1, 0x77, 0x3d, 0x58, 0x0c, 0xa2, 0x83, 0x78, 0x1a, 0x8d, 0x48, 0x49, 0x96, 0x3c, + 0x55, 0xc4, 0xc5, 0x4e, 0xc8, 0x93, 0x0a, 0x26, 0x5c, 0x6a, 0x47, 0x01, 0xb8, 0x0c, 0x5d, 0xab, + 0x8c, 0x0c, 0x9e, 0xde, 0xc7, 0xde, 0x81, 0x35, 0x03, 0x93, 0x33, 0xf8, 0x06, 0xcc, 0x27, 0x08, + 0x48, 0x47, 0x49, 0x89, 0x17, 0x59, 0x4a, 0x51, 0xe3, 0xae, 0x62, 0x44, 0x9e, 0xbf, 0x1f, 0x1d, + 0xc6, 0x8a, 0xd3, 0x0f, 0xe7, 0x30, 0x84, 0x96, 0x90, 0x64, 0x74, 0x15, 0x56, 0x82, 0x11, 0x8f, + 0xf2, 0x20, 0x9f, 0x0d, 0x2c, 0x0f, 0xae, 0x0c, 0xe3, 0x0e, 0xe3, 0x87, 0x81, 0x9f, 0x49, 0x1b, + 0x26, 0x0a, 0x6c, 0x07, 0x36, 0x50, 0xfc, 0x95, 0x44, 0xeb, 0x65, 0x15, 0x8e, 0x64, 0x6d, 0x1d, + 0x6a, 0x2c, 0xe2, 0x52, 0x02, 0xf5, 0x27, 0xc2, 0xd2, 0xd6, 0x55, 0xe1, 0xac, 0x09, 0x4e, 0x38, + 0xe4, 0x79, 0xa1, 0x22, 0x1a, 0xa8, 0x44, 0x6f, 0x0b, 0xc2, 0x89, 0x2d, 0x47, 0x6f, 0x46, 0x04, + 0xb8, 0x54, 0x89, 0x00, 0xaf, 0xc2, 0x4a, 0x36, 0x8b, 0x86, 0x7c, 0x34, 0xc8, 0x63, 0x6c, 0x37, + 0x88, 0x68, 0x75, 0x96, 0xbc, 0x32, 0x4c, 0xb1, 0x2a, 0xcf, 0xf2, 0x88, 0xe7, 0x64, 0xba, 0x96, + 0x3c, 0x55, 0xc4, 0x5d, 0x80, 0x48, 0x84, 0x50, 0xb7, 0x3c, 0x59, 0xc2, 0xad, 0x72, 0x9a, 0x06, + 0x59, 0xaf, 0x43, 0x28, 0xfd, 0x66, 0x9f, 0x87, 0xb3, 0x07, 0x18, 0x59, 0x1d, 0x71, 0x7f, 0xc4, + 0x53, 0x5a, 0x7d, 0x11, 0x58, 0x0a, 0x0b, 0x54, 0x5f, 0x89, 0x6d, 0x1f, 0xf3, 0x34, 0x0b, 0xe2, + 0x88, 0x6c, 0x4f, 0xcb, 0x53, 0x45, 0xf7, 0x63, 0xda, 0xd1, 0x75, 0xc8, 0xfb, 0x98, 0xcc, 0x11, + 0xbb, 0x00, 0x2d, 0x31, 0xc6, 0xec, 0xc8, 0x97, 0x4e, 0xc6, 0x12, 0x01, 0xfb, 0x47, 0x3e, 0x2a, + 0xb0, 0x35, 0x6d, 0x22, 0x84, 0x6f, 0x13, 0xb6, 0x2b, 0x66, 0xed, 0x4d, 0xe8, 0xaa, 0x60, 0x3a, + 0x1b, 0x84, 0xfc, 0x30, 0x57, 0x01, 0x42, 0x34, 0x9d, 0x60, 0x73, 0xd9, 0x03, 0x7e, 0x98, 0xbb, + 0x0f, 0x61, 0x4d, 0xea, 0xed, 0xd7, 0x12, 0xae, 0x9a, 0xfe, 0x62, 0x79, 0x53, 0x13, 0x5e, 0xc5, + 0xba, 0xad, 0xe8, 0x14, 0xe5, 0x94, 0x76, 0x3a, 0xd7, 0x03, 0x26, 0xab, 0x6f, 0x87, 0x71, 0xc6, + 0x25, 0x43, 0x17, 0x3a, 0xc3, 0x30, 0xce, 0x54, 0x18, 0x22, 0x87, 0x63, 0x61, 0x38, 0x3f, 0xd9, + 0x74, 0x38, 0x44, 0x4b, 0x20, 0x6c, 0x9a, 0x2a, 0xba, 0x7f, 0xe6, 0xc0, 0x3a, 0x71, 0x53, 0x16, + 0x46, 0xfb, 0xae, 0xaf, 0xde, 0xcd, 0xce, 0xd0, 0x0c, 0xcd, 0x36, 0x60, 0xfe, 0x30, 0x4e, 0x87, + 0x5c, 0xb6, 0x24, 0x0a, 0x3f, 0xbe, 0x37, 0xde, 0xac, 0x78, 0xe3, 0x3f, 0x74, 0x60, 0x8d, 0xba, + 0xba, 0x9f, 0xfb, 0xf9, 0x34, 0x93, 0xc3, 0xff, 0x05, 0x58, 0xc6, 0xa1, 0x72, 0xa5, 0x4e, 0xb2, + 0xa3, 0x1b, 0x5a, 0xf3, 0x09, 0x15, 0xc4, 0xbb, 0x67, 0x3c, 0x9b, 0x98, 0x7d, 0x19, 0x3a, 0x66, + 0x46, 0x84, 0xfa, 0xdc, 0xde, 0x39, 0xaf, 0x46, 0x59, 0x91, 0x9c, 0xdd, 0x33, 0x9e, 0xf5, 0x01, + 0xbb, 0x01, 0x40, 0xee, 0x06, 0xb1, 0x95, 0xa1, 0xec, 0x79, 0x7b, 0x92, 0x8c, 0xc5, 0xda, 0x3d, + 0xe3, 0x19, 0xe4, 0xb7, 0x96, 0x60, 0x41, 0xec, 0x8f, 0xee, 0x7d, 0x58, 0xb6, 0x7a, 0x6a, 0x45, + 0x19, 0x1d, 0x11, 0x65, 0x54, 0x82, 0xd2, 0x46, 0x35, 0x28, 0x75, 0xff, 0xa5, 0x01, 0x0c, 0xa5, + 0xad, 0xb4, 0x9c, 0xb8, 0x41, 0xc7, 0x23, 0xcb, 0xdd, 0xea, 0x78, 0x26, 0xc4, 0xae, 0x01, 0x33, + 0x8a, 0x2a, 0xf7, 0x20, 0xf6, 0x8d, 0x9a, 0x1a, 0x34, 0x70, 0xc2, 0x57, 0x52, 0x31, 0xb0, 0x74, + 0x2c, 0xc5, 0xba, 0xd5, 0xd6, 0xe1, 0xd6, 0x90, 0x4c, 0xb3, 0x23, 0x74, 0x20, 0x94, 0x43, 0xa6, + 0xca, 0x65, 0x01, 0x59, 0x78, 0xa9, 0x80, 0x2c, 0x96, 0x05, 0xc4, 0x74, 0x09, 0x96, 0x2c, 0x97, + 0x00, 0xfd, 0xaf, 0x49, 0x10, 0x91, 0x5f, 0x31, 0x98, 0x60, 0xeb, 0xd2, 0xff, 0xb2, 0x40, 0xb6, + 0x05, 0xab, 0xd2, 0xaf, 0x2b, 0xfc, 0x0e, 0xa0, 0x39, 0xae, 0xe0, 0xee, 0xa7, 0x0e, 0xac, 0xe2, + 0x3c, 0x5b, 0xb2, 0xf8, 0x1e, 0x90, 0x2a, 0xbc, 0xa2, 0x28, 0x5a, 0xb4, 0x3f, 0xbd, 0x24, 0xbe, + 0x0b, 0x2d, 0x62, 0x18, 0x27, 0x3c, 0x92, 0x82, 0xd8, 0xb3, 0x05, 0xb1, 0xb0, 0x42, 0xbb, 0x67, + 0xbc, 0x82, 0xd8, 0x10, 0xc3, 0xbf, 0x77, 0xa0, 0x2d, 0xbb, 0xf9, 0x13, 0xc7, 0x12, 0x7d, 0x58, + 0x42, 0x89, 0x34, 0x1c, 0x76, 0x5d, 0xc6, 0xdd, 0x64, 0x82, 0x01, 0x1b, 0x6e, 0x9f, 0x56, 0x1c, + 0x51, 0x86, 0x71, 0x2f, 0x24, 0x83, 0x9b, 0x0d, 0xf2, 0x20, 0x1c, 0xa8, 0x5a, 0x99, 0x80, 0xac, + 0xab, 0x42, 0xbb, 0x93, 0xe5, 0xfe, 0x98, 0xcb, 0x6d, 0x4e, 0x14, 0x30, 0x60, 0x92, 0x03, 0x2a, + 0xb9, 0x83, 0xee, 0x5f, 0x77, 0xe0, 0x5c, 0xa5, 0x4a, 0x27, 0xd0, 0xa5, 0x83, 0x1c, 0x06, 0x93, + 0x83, 0x58, 0xfb, 0xda, 0x8e, 0xe9, 0x3b, 0x5b, 0x55, 0x6c, 0x0c, 0x67, 0xd5, 0x7e, 0x8e, 0x73, + 0x5a, 0xec, 0xde, 0x0d, 0x72, 0x44, 0xde, 0xb6, 0x65, 0xa0, 0xdc, 0xa0, 0xc2, 0x4d, 0xcd, 0xad, + 0xe7, 0xc7, 0x8e, 0xa0, 0xa7, 0x1d, 0x07, 0x69, 0xe2, 0x0d, 0xe7, 0x02, 0xdb, 0x7a, 0xeb, 0x25, + 0x6d, 0x91, 0x3d, 0x1a, 0xa9, 0x66, 0x4e, 0xe5, 0xc6, 0x66, 0x70, 0x49, 0xd5, 0x91, 0x0d, 0xaf, + 0xb6, 0xd7, 0x7c, 0xa5, 0xb1, 0xdd, 0xc3, 0x8f, 0xed, 0x46, 0x5f, 0xc2, 0x98, 0x7d, 0x08, 0x9b, + 0x27, 0x7e, 0x90, 0xab, 0x6e, 0x19, 0xce, 0xd0, 0x3c, 0x35, 0xb9, 0xf3, 0x92, 0x26, 0x9f, 0x88, + 0x8f, 0xad, 0x8d, 0xed, 0x14, 0x8e, 0xfd, 0xbf, 0x75, 0xa0, 0x6b, 0xf3, 0x41, 0x31, 0x95, 0x0a, + 0xaf, 0x0c, 0x9f, 0x72, 0xfe, 0x4a, 0x70, 0x35, 0x44, 0x6d, 0xd4, 0x85, 0xa8, 0x66, 0x20, 0x3a, + 0xf7, 0xb2, 0x40, 0xb4, 0xf9, 0x6a, 0x81, 0xe8, 0x7c, 0x5d, 0x20, 0xda, 0xff, 0x4f, 0x07, 0x58, + 0x55, 0x96, 0xd8, 0x7d, 0x11, 0x23, 0x47, 0x3c, 0x94, 0x36, 0xe9, 0xe7, 0x5e, 0x4d, 0x1e, 0xd5, + 0xdc, 0xa9, 0xaf, 0x51, 0x31, 0x4c, 0xa3, 0x63, 0xba, 0x48, 0xcb, 0x5e, 0x5d, 0x55, 0x29, 0x34, + 0x6e, 0xbe, 0x3c, 0x34, 0x9e, 0x7f, 0x79, 0x68, 0xbc, 0x50, 0x0e, 0x8d, 0xfb, 0xbf, 0xeb, 0xc0, + 0x7a, 0xcd, 0xa2, 0xff, 0xec, 0x06, 0x8e, 0xcb, 0x64, 0xd9, 0x82, 0x86, 0x5c, 0x26, 0x13, 0xec, + 0xff, 0x06, 0x2c, 0x5b, 0x82, 0xfe, 0xb3, 0x6b, 0xbf, 0xec, 0xe5, 0x09, 0x39, 0xb3, 0xb0, 0xfe, + 0x8f, 0x1a, 0xc0, 0xaa, 0xca, 0xf6, 0x7f, 0xda, 0x87, 0xea, 0x3c, 0xcd, 0xd5, 0xcc, 0xd3, 0xff, + 0xea, 0x3e, 0xf0, 0x16, 0xac, 0xc9, 0xd3, 0x36, 0x23, 0x4b, 0x22, 0x24, 0xa6, 0x5a, 0x81, 0x7e, + 0xae, 0x9d, 0x97, 0x58, 0xb2, 0x8e, 0x89, 0x8c, 0xcd, 0xb0, 0x94, 0x9e, 0x70, 0x37, 0x61, 0x43, + 0x9c, 0xde, 0xdd, 0x12, 0xac, 0xd4, 0xbe, 0xf2, 0x27, 0x0e, 0x9c, 0x2d, 0x55, 0x14, 0x67, 0x29, + 0x62, 0xeb, 0xb0, 0xf7, 0x13, 0x1b, 0xc4, 0xfe, 0x4b, 0x3d, 0x32, 0xfa, 0x2f, 0xa4, 0xad, 0x5a, + 0x81, 0xf3, 0x33, 0x8d, 0xaa, 0xf4, 0x62, 0xd6, 0xeb, 0xaa, 0xdc, 0x73, 0x70, 0x56, 0xae, 0x6c, + 0xa9, 0xe3, 0x87, 0xb0, 0x59, 0xae, 0x28, 0x92, 0xc3, 0x76, 0x97, 0x55, 0x11, 0xbd, 0x40, 0x6b, + 0x9b, 0xb2, 0xfb, 0x5b, 0x5b, 0xe7, 0xfe, 0x3a, 0xb0, 0xaf, 0x4f, 0x79, 0x3a, 0xa3, 0x93, 0x1e, + 0x9d, 0x9d, 0x39, 0x57, 0x4e, 0x63, 0x2c, 0x24, 0xd3, 0x83, 0xaf, 0xf2, 0x99, 0x3a, 0x4a, 0x6b, + 0x14, 0x47, 0x69, 0xaf, 0x01, 0x60, 0xf4, 0x45, 0x47, 0x43, 0xea, 0x70, 0x13, 0xc3, 0x5e, 0xc1, + 0xd0, 0xbd, 0x01, 0xeb, 0x16, 0x7f, 0x3d, 0xfb, 0x0b, 0xf2, 0x0b, 0x91, 0x1b, 0xb0, 0x0f, 0x9c, + 0x64, 0x9d, 0xfb, 0xef, 0x0e, 0xcc, 0xed, 0xc6, 0x89, 0x99, 0x55, 0x74, 0xec, 0xac, 0xa2, 0x34, + 0xf9, 0x03, 0x6d, 0xd1, 0xa5, 0x25, 0xb0, 0x40, 0xb6, 0x05, 0x5d, 0x7f, 0x92, 0x63, 0x74, 0x7c, + 0x18, 0xa7, 0x27, 0x7e, 0x3a, 0x12, 0x4b, 0x72, 0xab, 0xd1, 0x73, 0xbc, 0x52, 0x0d, 0xdb, 0x80, + 0x39, 0x6d, 0x1b, 0x89, 0x00, 0x8b, 0xe8, 0x5f, 0x51, 0x72, 0x75, 0x26, 0x03, 0x7b, 0x59, 0xc2, + 0x15, 0xb7, 0xbf, 0x17, 0x1e, 0xad, 0x90, 0xf0, 0xba, 0x2a, 0xdc, 0x7e, 0xd0, 0x54, 0x12, 0x99, + 0xcc, 0xc8, 0xa8, 0xb2, 0xfb, 0xaf, 0x0e, 0xcc, 0xd3, 0x0c, 0xa0, 0x4e, 0x0a, 0x41, 0xa4, 0xb3, + 0x5b, 0xca, 0x04, 0x3b, 0x42, 0x27, 0x4b, 0x30, 0x73, 0xad, 0x13, 0xdd, 0x86, 0xee, 0xb6, 0x79, + 0xaa, 0x7b, 0x19, 0x5a, 0xa2, 0xa4, 0x8f, 0x41, 0x89, 0xa4, 0x00, 0xd9, 0x25, 0x68, 0x1e, 0xc5, + 0x89, 0x72, 0x22, 0x40, 0x25, 0x02, 0xe3, 0xc4, 0x23, 0xbc, 0xe8, 0x0f, 0xf2, 0x13, 0x9d, 0x17, + 0x5b, 0x43, 0x19, 0xc6, 0xcd, 0x51, 0xb3, 0x35, 0x27, 0xa3, 0x84, 0xba, 0x5b, 0xb0, 0xf2, 0x30, + 0x1e, 0x71, 0x23, 0xf5, 0x73, 0xaa, 0xd4, 0xb9, 0xbf, 0xe9, 0xc0, 0x92, 0x22, 0x66, 0x57, 0xa1, + 0x89, 0x3b, 0x7e, 0xc9, 0x9f, 0xd7, 0x07, 0x00, 0x48, 0xe7, 0x11, 0x05, 0x9a, 0x48, 0x4a, 0x0c, + 0x14, 0xde, 0x9f, 0x4a, 0x0b, 0x14, 0xce, 0x8d, 0xee, 0x6e, 0xc9, 0x27, 0x28, 0xa1, 0xee, 0x9f, + 0x3b, 0xb0, 0x6c, 0xb5, 0x81, 0x51, 0x5c, 0xe8, 0x67, 0xb9, 0x4c, 0xaa, 0xca, 0xe5, 0x31, 0x21, + 0x33, 0x19, 0xd8, 0xb0, 0x93, 0x81, 0x3a, 0x4d, 0x35, 0x67, 0xa6, 0xa9, 0xae, 0x43, 0xab, 0x38, + 0x77, 0x6f, 0x5a, 0xa6, 0x0f, 0x5b, 0x54, 0x47, 0x1b, 0x05, 0x11, 0xf2, 0x19, 0xc6, 0x61, 0x9c, + 0xca, 0x63, 0x69, 0x51, 0x70, 0x6f, 0x40, 0xdb, 0xa0, 0xc7, 0x6e, 0x44, 0x3c, 0x3f, 0x89, 0xd3, + 0xa7, 0x2a, 0x27, 0x29, 0x8b, 0xfa, 0x04, 0xaf, 0x51, 0x9c, 0xe0, 0xb9, 0x7f, 0xe1, 0xc0, 0x32, + 0xca, 0x60, 0x10, 0x8d, 0xf7, 0xe2, 0x30, 0x18, 0xce, 0x68, 0xed, 0x95, 0xb8, 0xc9, 0xf3, 0x6a, + 0x25, 0x8b, 0x36, 0x8c, 0xb2, 0xad, 0x82, 0x38, 0xa9, 0x88, 0xba, 0x8c, 0x9a, 0x8a, 0x72, 0x7e, + 0xe0, 0x67, 0x52, 0xf8, 0xe5, 0x5e, 0x64, 0x81, 0xa8, 0x4f, 0x08, 0xa4, 0x7e, 0xce, 0x07, 0x93, + 0x20, 0x0c, 0x03, 0x41, 0x2b, 0x3c, 0x95, 0xba, 0x2a, 0xf7, 0x07, 0x0d, 0x68, 0x4b, 0x4b, 0x79, + 0x77, 0x34, 0x16, 0xd9, 0x7f, 0xe9, 0xef, 0x69, 0x73, 0x61, 0x20, 0xaa, 0xde, 0xf2, 0x10, 0x0d, + 0xa4, 0xbc, 0xac, 0x73, 0xd5, 0x65, 0xbd, 0x08, 0x2d, 0x14, 0xaf, 0xb7, 0xc9, 0x15, 0x15, 0xd7, + 0x34, 0x0a, 0x40, 0xd5, 0xee, 0x50, 0xed, 0x7c, 0x51, 0x4b, 0x80, 0xe5, 0x7c, 0x2e, 0x94, 0x9c, + 0xcf, 0x77, 0xa1, 0x23, 0xd9, 0xd0, 0xbc, 0x93, 0x75, 0x28, 0x04, 0xdc, 0x5a, 0x13, 0xcf, 0xa2, + 0x54, 0x5f, 0xee, 0xa8, 0x2f, 0x97, 0x5e, 0xf6, 0xa5, 0xa2, 0xa4, 0xc3, 0x30, 0x31, 0x37, 0xf7, + 0x53, 0x3f, 0x39, 0x52, 0xbb, 0xcf, 0x48, 0x9f, 0xf0, 0x13, 0xcc, 0xb6, 0x60, 0x1e, 0x3f, 0x53, + 0xd6, 0xba, 0x5e, 0xe9, 0x04, 0x09, 0xbb, 0x0a, 0xf3, 0x7c, 0x34, 0xe6, 0x2a, 0xd8, 0x62, 0x76, + 0xd8, 0x8b, 0x6b, 0xe4, 0x09, 0x02, 0x34, 0x01, 0x88, 0x96, 0x4c, 0x80, 0x6d, 0xe9, 0x17, 0xb0, + 0xf8, 0xfe, 0xc8, 0xdd, 0x00, 0xf6, 0x50, 0x48, 0xad, 0x99, 0x2c, 0xfe, 0x9d, 0x39, 0x68, 0x1b, + 0x30, 0x6a, 0xf3, 0x18, 0x3b, 0x3c, 0x18, 0x05, 0xfe, 0x84, 0xe7, 0x3c, 0x95, 0x92, 0x5a, 0x42, + 0x91, 0xce, 0x3f, 0x1e, 0x0f, 0xe2, 0x69, 0x3e, 0x18, 0xf1, 0x71, 0xca, 0xc5, 0x1e, 0x89, 0x9b, + 0x81, 0x85, 0x22, 0xdd, 0xc4, 0x7f, 0x66, 0xd2, 0x09, 0x79, 0x28, 0xa1, 0x2a, 0xf5, 0x2b, 0xe6, + 0xa8, 0x59, 0xa4, 0x7e, 0xc5, 0x8c, 0x94, 0xed, 0xd0, 0x7c, 0x8d, 0x1d, 0x7a, 0x07, 0x36, 0x85, + 0xc5, 0x91, 0xba, 0x39, 0x28, 0x89, 0xc9, 0x29, 0xb5, 0x6c, 0x0b, 0x56, 0xb1, 0xcf, 0x4a, 0xc0, + 0xb3, 0xe0, 0x63, 0x91, 0x8c, 0x71, 0xbc, 0x0a, 0x8e, 0xb4, 0xa8, 0x8e, 0x16, 0xad, 0x38, 0x1e, + 0xab, 0xe0, 0x44, 0xeb, 0x3f, 0xb3, 0x69, 0x5b, 0x92, 0xb6, 0x84, 0xbb, 0xcb, 0xd0, 0xde, 0xcf, + 0xe3, 0x44, 0x2d, 0x4a, 0x17, 0x3a, 0xa2, 0x28, 0x0f, 0x43, 0x2f, 0xc0, 0x79, 0x92, 0xa2, 0x47, + 0x71, 0x12, 0x87, 0xf1, 0x78, 0xb6, 0x3f, 0x3d, 0xc8, 0x86, 0x69, 0x90, 0x60, 0x60, 0xe2, 0xfe, + 0x9d, 0x03, 0xeb, 0x56, 0xad, 0xcc, 0xde, 0x7c, 0x5e, 0x88, 0xb4, 0x3e, 0xc5, 0x12, 0x82, 0xb7, + 0x66, 0x98, 0x43, 0x41, 0x28, 0xf2, 0x66, 0x8f, 0xe5, 0xc1, 0xd6, 0x4d, 0x58, 0x51, 0x3d, 0x53, + 0x1f, 0x0a, 0x29, 0xec, 0x55, 0xa5, 0x50, 0x7e, 0xdf, 0x95, 0x1f, 0x28, 0x16, 0xbf, 0x28, 0xfc, + 0x6a, 0x3e, 0xa2, 0x31, 0xaa, 0x30, 0xbe, 0xaf, 0xbe, 0x37, 0x9d, 0x79, 0xd5, 0x83, 0xa1, 0x06, + 0x33, 0xf7, 0xf7, 0x1d, 0x80, 0xa2, 0x77, 0x28, 0x18, 0x85, 0x49, 0x17, 0x37, 0xfe, 0x0c, 0xf3, + 0xfd, 0x06, 0x74, 0xf4, 0x01, 0x46, 0xb1, 0x4b, 0xb4, 0x15, 0x86, 0x0e, 0xd7, 0x15, 0x58, 0x19, + 0x87, 0xf1, 0x01, 0x6d, 0xb1, 0x74, 0xba, 0x9e, 0xc9, 0x23, 0xe1, 0xae, 0x80, 0xef, 0x49, 0xb4, + 0xd8, 0x52, 0x9a, 0xc6, 0x96, 0xe2, 0x7e, 0xa7, 0xa1, 0xd3, 0xde, 0xc5, 0x98, 0x4f, 0xd5, 0x32, + 0xb6, 0x53, 0x31, 0x8e, 0xa7, 0x64, 0x99, 0x29, 0x61, 0xb5, 0xf7, 0xd2, 0x78, 0xfa, 0x06, 0x74, + 0x53, 0x61, 0x7d, 0x94, 0x69, 0x6a, 0xbe, 0xc0, 0x34, 0x2d, 0xa7, 0xd6, 0xbe, 0xf3, 0xff, 0x60, + 0xd5, 0x1f, 0x1d, 0xf3, 0x34, 0x0f, 0x28, 0xa2, 0xa1, 0x4d, 0x5f, 0x18, 0xd4, 0x15, 0x03, 0xa7, + 0xbd, 0xf8, 0x0a, 0xac, 0xc8, 0x63, 0x78, 0x4d, 0x29, 0x2f, 0x5f, 0x15, 0x30, 0x12, 0xba, 0xdf, + 0x57, 0x19, 0x76, 0x7b, 0x0d, 0x4f, 0x9f, 0x11, 0x73, 0x74, 0x8d, 0xd2, 0xe8, 0x3e, 0x23, 0xb3, + 0xdd, 0x23, 0x15, 0x36, 0xc9, 0x73, 0x07, 0x01, 0xca, 0xd3, 0x09, 0x7b, 0x4a, 0x9b, 0xaf, 0x32, + 0xa5, 0xee, 0xa7, 0x0e, 0x2c, 0xee, 0xc6, 0xc9, 0xae, 0x3c, 0x51, 0x27, 0x45, 0xd0, 0x97, 0x5c, + 0x54, 0xd1, 0xf4, 0x8a, 0x1b, 0x15, 0xaf, 0xb8, 0xba, 0xd7, 0x2e, 0x97, 0xf7, 0xda, 0x5f, 0x82, + 0x0b, 0x14, 0xb4, 0xa7, 0x71, 0x12, 0xa7, 0xa8, 0x8c, 0x7e, 0x28, 0x36, 0xd6, 0x38, 0xca, 0x8f, + 0x94, 0x19, 0x7b, 0x11, 0x09, 0x45, 0x47, 0x61, 0x7e, 0x3c, 0x10, 0xce, 0xb0, 0xf4, 0x0d, 0x84, + 0x75, 0xab, 0x56, 0xb8, 0x5f, 0x84, 0x16, 0x39, 0xb7, 0x34, 0xac, 0xb7, 0xa0, 0x75, 0x14, 0x27, + 0x83, 0xa3, 0x20, 0xca, 0x95, 0x72, 0x77, 0x0b, 0xaf, 0x73, 0x97, 0x26, 0x44, 0x13, 0xb8, 0x3f, + 0x9a, 0x83, 0xc5, 0xf7, 0xa3, 0xe3, 0x38, 0x18, 0x52, 0x32, 0x7e, 0xc2, 0x27, 0xb1, 0xba, 0xf2, + 0x83, 0xbf, 0x71, 0x2a, 0xe8, 0xf8, 0x3b, 0xc9, 0x65, 0x36, 0x5d, 0x15, 0x71, 0xbb, 0x4f, 0x8b, + 0x6b, 0x70, 0x42, 0x75, 0x0c, 0x04, 0x1d, 0xfb, 0xd4, 0xbc, 0x03, 0x28, 0x4b, 0xc5, 0x9d, 0xa9, + 0x79, 0xe3, 0xce, 0x14, 0x1d, 0xdd, 0x88, 0x93, 0x7d, 0x92, 0xaf, 0x25, 0x4f, 0x15, 0x29, 0x10, + 0x49, 0xb9, 0x48, 0xb6, 0x90, 0xe3, 0xb0, 0x28, 0x03, 0x11, 0x13, 0x44, 0xe7, 0x42, 0x7c, 0x20, + 0x68, 0x84, 0xf1, 0x35, 0x21, 0x74, 0xb6, 0xca, 0xd7, 0x08, 0x5b, 0x42, 0xe6, 0x4b, 0x30, 0x5a, + 0xe8, 0x11, 0xd7, 0x86, 0x54, 0x8c, 0x01, 0xc4, 0x35, 0xbf, 0x32, 0x6e, 0x84, 0x2f, 0xe2, 0x86, + 0x82, 0x0a, 0x5f, 0x50, 0x50, 0xfc, 0x30, 0x3c, 0xf0, 0x87, 0x4f, 0xe9, 0x72, 0x27, 0x5d, 0x48, + 0x68, 0x79, 0x36, 0x88, 0xbd, 0x36, 0x56, 0x93, 0x0e, 0xff, 0x9a, 0x9e, 0x09, 0xb1, 0x1d, 0x68, + 0x53, 0xc8, 0x26, 0xd7, 0xb3, 0x4b, 0xeb, 0xb9, 0x6a, 0xc6, 0x74, 0xb4, 0xa2, 0x26, 0x91, 0x79, + 0x40, 0xb0, 0x62, 0xdf, 0x19, 0xf8, 0x06, 0xb0, 0x9b, 0xa3, 0x91, 0x5c, 0x6f, 0x1d, 0x32, 0x16, + 0x2b, 0xe5, 0x58, 0x2b, 0x55, 0x33, 0x63, 0x8d, 0xda, 0x19, 0x73, 0xef, 0x42, 0x7b, 0xcf, 0xb8, + 0xe1, 0x49, 0xa2, 0xa1, 0xee, 0x76, 0x4a, 0x71, 0x32, 0x10, 0xa3, 0xc1, 0x86, 0xd9, 0xa0, 0xfb, + 0xf3, 0xc0, 0x1e, 0x04, 0x59, 0xae, 0xfb, 0x27, 0x96, 0xe3, 0x0d, 0xe8, 0xe8, 0x00, 0xbb, 0xb8, + 0xd1, 0xd0, 0x96, 0x18, 0xdd, 0x34, 0xb8, 0x29, 0xae, 0x42, 0x94, 0x07, 0xb6, 0x05, 0x4b, 0x81, + 0x80, 0xca, 0x9a, 0xa0, 0x28, 0x75, 0x3d, 0xfa, 0x6b, 0x12, 0xb4, 0x76, 0xd1, 0x1f, 0x38, 0xb0, + 0x28, 0x87, 0x86, 0xde, 0x86, 0x75, 0xb7, 0x55, 0x0c, 0xcc, 0xc2, 0xea, 0x6f, 0x04, 0x56, 0x65, + 0x78, 0xae, 0x4e, 0x86, 0x19, 0x34, 0x13, 0x3f, 0x3f, 0xa2, 0x00, 0xa5, 0xe5, 0xd1, 0x6f, 0xb6, + 0x2a, 0x82, 0x66, 0xa1, 0x2b, 0x14, 0x30, 0xd7, 0x5d, 0x42, 0x15, 0x26, 0xb9, 0x82, 0xe3, 0xa0, + 0xe8, 0xf2, 0x80, 0xc0, 0xf5, 0x99, 0x80, 0xbc, 0x98, 0x51, 0xc0, 0xc5, 0x7c, 0x49, 0x16, 0xe5, + 0xf9, 0x92, 0xa4, 0x9e, 0xae, 0x77, 0xfb, 0xd0, 0xbb, 0xc3, 0x43, 0x9e, 0xf3, 0x9b, 0x61, 0x58, + 0xe6, 0x7f, 0x01, 0xce, 0xd7, 0xd4, 0x49, 0xa7, 0xe5, 0x1e, 0xac, 0xdd, 0xe1, 0x07, 0xd3, 0xf1, + 0x03, 0x7e, 0x5c, 0x1c, 0xdc, 0x31, 0x68, 0x66, 0x47, 0xf1, 0x89, 0x5c, 0x5b, 0xfa, 0xcd, 0x5e, + 0x03, 0x08, 0x91, 0x66, 0x90, 0x25, 0x7c, 0xa8, 0xee, 0xc2, 0x11, 0xb2, 0x9f, 0xf0, 0xa1, 0xfb, + 0x0e, 0x30, 0x93, 0x8f, 0x1c, 0x02, 0xda, 0x81, 0xe9, 0xc1, 0x20, 0x9b, 0x65, 0x39, 0x9f, 0xa8, + 0x4b, 0x7e, 0x26, 0xe4, 0x5e, 0x81, 0xce, 0x9e, 0x3f, 0xf3, 0xf8, 0x47, 0xf2, 0x7a, 0x31, 0xc6, + 0xc6, 0xfe, 0x0c, 0x45, 0x59, 0xc7, 0xc6, 0x54, 0xed, 0xfe, 0x47, 0x03, 0x16, 0x04, 0x25, 0x72, + 0x1d, 0xf1, 0x2c, 0x0f, 0x22, 0x71, 0x68, 0x25, 0xb9, 0x1a, 0x50, 0x45, 0x36, 0x1a, 0x35, 0xb2, + 0x21, 0xbd, 0x55, 0x75, 0xaf, 0x48, 0x0a, 0x81, 0x85, 0xa1, 0x5b, 0x53, 0x5c, 0x06, 0x10, 0xc1, + 0x59, 0x01, 0x94, 0x92, 0x25, 0x85, 0xb5, 0x11, 0xfd, 0x53, 0x42, 0x2b, 0xc5, 0xc1, 0x84, 0x6a, + 0x6d, 0xda, 0xa2, 0x90, 0x9a, 0x8a, 0x4d, 0xab, 0xd8, 0xae, 0xa5, 0x57, 0xb0, 0x5d, 0xc2, 0x85, + 0x7d, 0x91, 0xed, 0x82, 0x57, 0xb0, 0x5d, 0x2e, 0x83, 0xd5, 0x7b, 0x9c, 0x7b, 0x1c, 0x77, 0x45, + 0x25, 0x4e, 0xdf, 0x75, 0x60, 0x55, 0x6e, 0xe8, 0xba, 0x8e, 0xbd, 0x61, 0xed, 0xfe, 0x4e, 0xdd, + 0x79, 0xc4, 0x9b, 0xb0, 0x4c, 0x7b, 0xb2, 0xce, 0x0a, 0xc9, 0x14, 0x96, 0x05, 0xe2, 0x38, 0x54, + 0x86, 0x7d, 0x12, 0x84, 0x72, 0x51, 0x4c, 0x48, 0x25, 0x96, 0x30, 0x3e, 0xa6, 0x25, 0x71, 0x3c, + 0x5d, 0x76, 0xff, 0xca, 0x81, 0x35, 0xa3, 0xc3, 0x52, 0x0a, 0x6f, 0x80, 0xba, 0x2c, 0x20, 0x92, + 0x47, 0x42, 0x99, 0xce, 0xd9, 0xce, 0x49, 0xf1, 0x99, 0x45, 0x4c, 0x8b, 0xe9, 0xcf, 0xa8, 0x83, + 0xd9, 0x74, 0x22, 0x3d, 0x10, 0x13, 0x42, 0x41, 0x3a, 0xe1, 0xfc, 0xa9, 0x26, 0x99, 0x23, 0x12, + 0x0b, 0xa3, 0xb3, 0x60, 0xf4, 0x25, 0x34, 0x91, 0xb8, 0xfe, 0x64, 0x83, 0xee, 0x3f, 0x38, 0xb0, + 0x2e, 0x9c, 0x42, 0xe9, 0x72, 0xeb, 0xab, 0x99, 0x0b, 0xc2, 0x0b, 0x16, 0x1a, 0xb9, 0x7b, 0xc6, + 0x93, 0x65, 0xf6, 0x85, 0x57, 0x74, 0x64, 0xf5, 0x1d, 0x80, 0x53, 0xd6, 0x62, 0xae, 0x6e, 0x2d, + 0x5e, 0x30, 0xd3, 0x75, 0xc9, 0x92, 0xf9, 0xda, 0x64, 0xc9, 0xad, 0x45, 0x98, 0xcf, 0x86, 0x71, + 0xc2, 0xdd, 0x4d, 0xd8, 0xb0, 0x07, 0x27, 0x4d, 0xd0, 0xf7, 0x1c, 0xe8, 0xdd, 0x13, 0xa9, 0xc3, + 0x20, 0x1a, 0xef, 0x06, 0x59, 0x1e, 0xa7, 0xfa, 0x2e, 0xfa, 0x25, 0x80, 0x2c, 0xf7, 0xd3, 0x5c, + 0xdc, 0xd1, 0x92, 0x69, 0x8e, 0x02, 0xc1, 0x3e, 0xf2, 0x68, 0x24, 0x6a, 0xc5, 0xda, 0xe8, 0x32, + 0x2e, 0x0c, 0xdd, 0x4f, 0x18, 0xc4, 0x87, 0x87, 0x19, 0xd7, 0x6e, 0xab, 0x89, 0x61, 0xe4, 0x8b, + 0x1a, 0x8f, 0xb1, 0x1e, 0x3f, 0x26, 0x53, 0x2b, 0xfc, 0xc1, 0x12, 0xea, 0xfe, 0xa5, 0x03, 0x2b, + 0x45, 0x27, 0xef, 0x22, 0x68, 0x5b, 0x07, 0xd1, 0x35, 0xc3, 0x3a, 0xa8, 0x04, 0x4c, 0x30, 0x1a, + 0x04, 0x91, 0xec, 0x9b, 0x81, 0x90, 0xc6, 0xca, 0x52, 0x3c, 0x55, 0xf7, 0xe1, 0x4c, 0x48, 0x1c, + 0x76, 0xe7, 0xf8, 0xb5, 0xb8, 0x0c, 0x27, 0x4b, 0x74, 0xc5, 0x6e, 0x92, 0xd3, 0x57, 0x0b, 0xc2, + 0x21, 0x96, 0x45, 0xb5, 0x3f, 0x2d, 0x12, 0x8a, 0x3f, 0xdd, 0x3f, 0x70, 0xe0, 0x7c, 0xcd, 0xe4, + 0x4a, 0xcd, 0xb8, 0x03, 0x6b, 0x87, 0xba, 0x52, 0x4d, 0x80, 0x50, 0x8f, 0x4d, 0x29, 0x45, 0xa5, + 0x41, 0x7b, 0xd5, 0x0f, 0xd0, 0x3d, 0xa6, 0xbc, 0x91, 0x98, 0x52, 0xeb, 0x9e, 0x48, 0xb5, 0x62, + 0xe7, 0xfb, 0x0d, 0xe8, 0x8a, 0xa3, 0x0a, 0xf1, 0x1a, 0x89, 0xa7, 0xec, 0x03, 0x58, 0x94, 0xaf, + 0xc9, 0xd8, 0x59, 0xd9, 0xac, 0xfd, 0x7e, 0xad, 0xbf, 0x59, 0x86, 0xa5, 0xec, 0xac, 0xff, 0xf6, + 0xa7, 0xff, 0xfc, 0x87, 0x8d, 0x65, 0xd6, 0xde, 0x3e, 0x7e, 0x7b, 0x7b, 0xcc, 0xa3, 0x0c, 0x79, + 0xfc, 0x2a, 0x40, 0xf1, 0xce, 0x8a, 0xf5, 0xb4, 0x93, 0x51, 0x7a, 0x40, 0xd6, 0x3f, 0x5f, 0x53, + 0x23, 0xf9, 0x9e, 0x27, 0xbe, 0xeb, 0x6e, 0x17, 0xf9, 0x06, 0x51, 0x90, 0x8b, 0x47, 0x57, 0xef, + 0x39, 0x5b, 0x6c, 0x04, 0x1d, 0xf3, 0x19, 0x15, 0x53, 0x21, 0x73, 0xcd, 0x23, 0xae, 0xfe, 0x85, + 0xda, 0x3a, 0x95, 0x2f, 0xa0, 0x36, 0xce, 0xba, 0xab, 0xd8, 0xc6, 0x94, 0x28, 0x74, 0x2b, 0x3b, + 0xff, 0x78, 0x01, 0x5a, 0x3a, 0xed, 0xc4, 0x3e, 0x84, 0x65, 0xeb, 0x74, 0x87, 0x29, 0xc6, 0x75, + 0x87, 0x41, 0xfd, 0x8b, 0xf5, 0x95, 0xb2, 0xd9, 0x4b, 0xd4, 0x6c, 0x8f, 0x6d, 0x62, 0xb3, 0xf2, + 0x78, 0x64, 0x9b, 0xce, 0xb4, 0xc4, 0x95, 0xba, 0xa7, 0xd0, 0xb5, 0x4f, 0x64, 0xd8, 0x45, 0xdb, + 0xa0, 0x94, 0x5a, 0x7b, 0xed, 0x94, 0x5a, 0xd9, 0xdc, 0x45, 0x6a, 0x6e, 0x93, 0x6d, 0x98, 0xcd, + 0xe9, 0x74, 0x10, 0xa7, 0x4b, 0x90, 0xe6, 0xfb, 0x2a, 0xf6, 0x9a, 0x5e, 0xea, 0xba, 0x77, 0x57, + 0x7a, 0xd1, 0xaa, 0x8f, 0xaf, 0xdc, 0x1e, 0x35, 0xc5, 0x18, 0x4d, 0xa8, 0xf9, 0xbc, 0x8a, 0x7d, + 0x0b, 0x5a, 0xfa, 0x4d, 0x05, 0x3b, 0x67, 0x3c, 0x64, 0x31, 0x1f, 0x7a, 0xf4, 0x7b, 0xd5, 0x8a, + 0xba, 0xa5, 0x32, 0x39, 0xa3, 0x40, 0x3c, 0x80, 0xb3, 0xd2, 0x49, 0x3d, 0xe0, 0x3f, 0xce, 0x48, + 0x6a, 0x5e, 0x85, 0x5d, 0x77, 0xd8, 0x0d, 0x58, 0x52, 0x4f, 0x55, 0xd8, 0x66, 0xfd, 0x93, 0x9b, + 0xfe, 0xb9, 0x0a, 0x2e, 0xf5, 0xf9, 0x26, 0x40, 0xf1, 0xcc, 0x42, 0x4b, 0x7e, 0xe5, 0xf1, 0x87, + 0x9e, 0xc4, 0x9a, 0x37, 0x19, 0x63, 0x7a, 0x54, 0x62, 0xbf, 0xe2, 0x60, 0xaf, 0x17, 0xf4, 0xb5, + 0xef, 0x3b, 0x5e, 0xc0, 0xd0, 0xdd, 0xa4, 0xb9, 0x5b, 0x65, 0xa4, 0x4a, 0x11, 0x3f, 0x51, 0xd7, + 0x81, 0xef, 0x40, 0xdb, 0x78, 0xba, 0xc1, 0x14, 0x87, 0xea, 0xb3, 0x8f, 0x7e, 0xbf, 0xae, 0x4a, + 0x76, 0xf7, 0x2b, 0xb0, 0x6c, 0xbd, 0xc1, 0xd0, 0x9a, 0x51, 0xf7, 0xc2, 0x43, 0x6b, 0x46, 0xfd, + 0xb3, 0x8d, 0x6f, 0x42, 0xdb, 0x78, 0x31, 0xc1, 0x8c, 0x6b, 0x50, 0xa5, 0xb7, 0x12, 0xba, 0x47, + 0x75, 0x0f, 0x2c, 0x36, 0x68, 0xbc, 0x5d, 0xb7, 0x85, 0xe3, 0xa5, 0x3b, 0xb1, 0x28, 0x24, 0x1f, + 0x42, 0xd7, 0x7e, 0x43, 0xa1, 0xb5, 0xaa, 0xf6, 0x35, 0x86, 0xd6, 0xaa, 0x53, 0x1e, 0x5e, 0x48, + 0x81, 0xdc, 0x5a, 0xd7, 0x8d, 0x6c, 0x7f, 0x22, 0x0f, 0x5d, 0x9e, 0xb3, 0xaf, 0xa3, 0xe9, 0x90, + 0x97, 0x94, 0x59, 0xf1, 0x72, 0xc4, 0xbe, 0xca, 0xac, 0xa5, 0xbd, 0x72, 0x9f, 0xd9, 0x5d, 0x23, + 0xe6, 0x6d, 0x56, 0x8c, 0x40, 0x58, 0x68, 0xba, 0xac, 0x6c, 0x58, 0x68, 0xf3, 0x3e, 0xb3, 0x61, + 0xa1, 0xad, 0x3b, 0xcd, 0x65, 0x0b, 0x9d, 0x07, 0xc8, 0x23, 0x82, 0x95, 0xd2, 0x3d, 0x00, 0xad, + 0x2c, 0xf5, 0x17, 0xa7, 0xfa, 0x97, 0x5e, 0x7c, 0x7d, 0xc0, 0x36, 0x33, 0xca, 0xbc, 0x6c, 0xab, + 0x7b, 0x6e, 0xbf, 0x06, 0x1d, 0xf3, 0xee, 0xbb, 0xb6, 0xd9, 0x35, 0x37, 0xf6, 0xb5, 0xcd, 0xae, + 0xbb, 0x2c, 0xaf, 0x16, 0x97, 0x75, 0xcc, 0x66, 0xd8, 0x37, 0x61, 0xc5, 0xb8, 0xf8, 0xb2, 0x3f, + 0x8b, 0x86, 0x5a, 0x78, 0xaa, 0xd7, 0x22, 0xfb, 0x75, 0xfe, 0x99, 0x7b, 0x8e, 0x18, 0xaf, 0xb9, + 0x16, 0x63, 0x14, 0x9c, 0xdb, 0xd0, 0x36, 0x2f, 0xd5, 0xbc, 0x80, 0xef, 0x39, 0xa3, 0xca, 0xbc, + 0x21, 0x78, 0xdd, 0x61, 0x7f, 0xec, 0x40, 0xc7, 0xba, 0xa2, 0x62, 0xe5, 0x79, 0x4b, 0x7c, 0x7a, + 0x66, 0x9d, 0xc9, 0xc8, 0xf5, 0xa8, 0x93, 0x0f, 0xb6, 0xbe, 0x62, 0x4d, 0xf2, 0x27, 0x96, 0x9f, + 0x7f, 0xad, 0xfc, 0xac, 0xf1, 0x79, 0x99, 0xc0, 0xbc, 0x3a, 0xfa, 0xfc, 0xba, 0xc3, 0xde, 0x13, + 0x4f, 0x5f, 0x55, 0x5c, 0xcf, 0x0c, 0xe3, 0x56, 0x9e, 0x32, 0xf3, 0x95, 0xe8, 0x55, 0xe7, 0xba, + 0xc3, 0xbe, 0x2d, 0x5e, 0x2f, 0xca, 0x6f, 0x69, 0xe6, 0x5f, 0xf5, 0x7b, 0xf7, 0x4d, 0x1a, 0xcd, + 0x25, 0xf7, 0xbc, 0x35, 0x9a, 0xb2, 0x75, 0xdf, 0x03, 0x28, 0x92, 0x34, 0xac, 0x94, 0xb1, 0xd0, + 0x76, 0xaf, 0x9a, 0xc7, 0xb1, 0x57, 0x54, 0x25, 0x36, 0x90, 0xe3, 0xb7, 0x84, 0x30, 0x4a, 0xfa, + 0x4c, 0x2f, 0x69, 0x35, 0xd9, 0xd2, 0xef, 0xd7, 0x55, 0xd5, 0x89, 0xa2, 0xe2, 0xcf, 0x1e, 0xc3, + 0xf2, 0x83, 0x38, 0x7e, 0x3a, 0x4d, 0x74, 0x1a, 0xd1, 0xce, 0x19, 0xec, 0xfa, 0xd9, 0x51, 0xbf, + 0x34, 0x0a, 0xf7, 0x32, 0xb1, 0xea, 0xb3, 0x9e, 0xc1, 0x6a, 0xfb, 0x93, 0x22, 0x45, 0xf4, 0x9c, + 0xf9, 0xb0, 0xa6, 0xf7, 0x38, 0xdd, 0xf1, 0xbe, 0xcd, 0xc6, 0xcc, 0xd4, 0x54, 0x9a, 0xb0, 0xbc, + 0x0e, 0xd5, 0xdb, 0xed, 0x4c, 0xf1, 0xbc, 0xee, 0xb0, 0x3d, 0xe8, 0xdc, 0xe1, 0xc3, 0x78, 0xc4, + 0x65, 0x94, 0xbf, 0x5e, 0x74, 0x5c, 0xa7, 0x07, 0xfa, 0xcb, 0x16, 0x68, 0x6b, 0x7d, 0xe2, 0xcf, + 0x52, 0xfe, 0xd1, 0xf6, 0x27, 0x32, 0x7f, 0xf0, 0x5c, 0x69, 0xbd, 0xca, 0x79, 0x58, 0x5a, 0x5f, + 0x4a, 0x92, 0x58, 0x5a, 0x5f, 0x49, 0x92, 0x58, 0x53, 0xad, 0x72, 0x2e, 0x2c, 0x84, 0xb5, 0x4a, + 0x5e, 0x45, 0xef, 0x94, 0xa7, 0x65, 0x63, 0xfa, 0x97, 0x4f, 0x27, 0xb0, 0x5b, 0xdb, 0xb2, 0x5b, + 0xdb, 0x87, 0xe5, 0x3b, 0x5c, 0x4c, 0x96, 0x38, 0xab, 0xec, 0xdb, 0x66, 0xc4, 0x3c, 0xd7, 0x2c, + 0x9b, 0x18, 0xaa, 0xb3, 0xcd, 0x3a, 0x1d, 0x14, 0xb2, 0x6f, 0x41, 0xfb, 0x3e, 0xcf, 0xd5, 0xe1, + 0xa4, 0xf6, 0x37, 0x4a, 0xa7, 0x95, 0xfd, 0x9a, 0xb3, 0x4d, 0x5b, 0x66, 0x88, 0xdb, 0x36, 0x1f, + 0x8d, 0xb9, 0x50, 0xf6, 0x41, 0x30, 0x7a, 0xce, 0x7e, 0x99, 0x98, 0xeb, 0xfb, 0x0c, 0x9b, 0xc6, + 0x99, 0x96, 0xc9, 0x7c, 0xa5, 0x84, 0xd7, 0x71, 0x8e, 0xe2, 0x11, 0x37, 0x36, 0xb8, 0x08, 0xda, + 0xc6, 0x65, 0x1b, 0xad, 0x40, 0xd5, 0x0b, 0x3e, 0x5a, 0x81, 0x6a, 0xee, 0xe6, 0xb8, 0x57, 0xa9, + 0x1d, 0x97, 0x5d, 0x2e, 0xda, 0x11, 0xf7, 0x71, 0x8a, 0x96, 0xb6, 0x3f, 0xf1, 0x27, 0xf9, 0x73, + 0xf6, 0x84, 0x5e, 0xef, 0x98, 0x07, 0xb0, 0x85, 0xbf, 0x53, 0x3e, 0xab, 0xd5, 0x93, 0x65, 0x54, + 0xd9, 0x3e, 0x90, 0x68, 0x8a, 0xf6, 0xc1, 0x2f, 0x00, 0xec, 0xe7, 0x71, 0x72, 0xc7, 0xe7, 0x93, + 0x38, 0x2a, 0x2c, 0x57, 0x71, 0xc8, 0x58, 0x58, 0x2e, 0xe3, 0xa4, 0x91, 0x3d, 0x31, 0x3c, 0x4e, + 0xeb, 0xfc, 0x5a, 0x09, 0xd7, 0xa9, 0xe7, 0x90, 0x7a, 0x42, 0x6a, 0xce, 0x22, 0xaf, 0x3b, 0xe8, + 0x3f, 0x16, 0x59, 0x3c, 0xed, 0x3f, 0x56, 0x12, 0x84, 0xda, 0xec, 0xd5, 0xa4, 0xfc, 0xf6, 0xa0, + 0x55, 0xa4, 0x85, 0xd4, 0x96, 0x54, 0x4e, 0x22, 0xe9, 0x3d, 0xa6, 0x92, 0xac, 0x71, 0x57, 0x69, + 0xaa, 0x80, 0x2d, 0xe1, 0x54, 0x51, 0x06, 0x26, 0x80, 0x75, 0xd1, 0x41, 0xbd, 0x61, 0xd2, 0xb1, + 0x99, 0x1a, 0x49, 0x4d, 0xc2, 0x44, 0x6b, 0x73, 0x6d, 0xbe, 0xc1, 0x8a, 0xed, 0x50, 0x5a, 0xc5, + 0x91, 0x1d, 0x9a, 0xe6, 0x09, 0xac, 0x55, 0x82, 0x65, 0xad, 0xd2, 0xa7, 0xe5, 0x28, 0xb4, 0x4a, + 0x9f, 0x1a, 0x67, 0xbb, 0x67, 0xa9, 0xc9, 0x15, 0x17, 0xb0, 0xc9, 0xec, 0x24, 0xc8, 0x87, 0x47, + 0xef, 0x39, 0x5b, 0x07, 0x0b, 0xf4, 0x77, 0x2d, 0x9f, 0xfb, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x5c, 0x78, 0xf8, 0x82, 0xe0, 0x45, 0x00, 0x00, } diff --git a/lnrpc/rpc.pb.gw.go b/lnrpc/rpc.pb.gw.go index 0453e1c86..9ec87c485 100644 --- a/lnrpc/rpc.pb.gw.go +++ b/lnrpc/rpc.pb.gw.go @@ -592,7 +592,15 @@ func RegisterWalletUnlockerHandlerFromEndpoint(ctx context.Context, mux *runtime // RegisterWalletUnlockerHandler registers the http handlers for service WalletUnlocker to "mux". // The handlers forward requests to the grpc endpoint over "conn". func RegisterWalletUnlockerHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - client := NewWalletUnlockerClient(conn) + return RegisterWalletUnlockerHandlerClient(ctx, mux, NewWalletUnlockerClient(conn)) +} + +// RegisterWalletUnlockerHandler registers the http handlers for service WalletUnlocker to "mux". +// The handlers forward requests to the grpc endpoint over the given implementation of "WalletUnlockerClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "WalletUnlockerClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "WalletUnlockerClient" to call the correct interceptors. +func RegisterWalletUnlockerHandlerClient(ctx context.Context, mux *runtime.ServeMux, client WalletUnlockerClient) error { mux.Handle("GET", pattern_WalletUnlocker_GenSeed_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(ctx) @@ -728,7 +736,15 @@ func RegisterLightningHandlerFromEndpoint(ctx context.Context, mux *runtime.Serv // RegisterLightningHandler registers the http handlers for service Lightning to "mux". // The handlers forward requests to the grpc endpoint over "conn". func RegisterLightningHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - client := NewLightningClient(conn) + return RegisterLightningHandlerClient(ctx, mux, NewLightningClient(conn)) +} + +// RegisterLightningHandler registers the http handlers for service Lightning to "mux". +// The handlers forward requests to the grpc endpoint over the given implementation of "LightningClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "LightningClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "LightningClient" to call the correct interceptors. +func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux, client LightningClient) error { mux.Handle("GET", pattern_Lightning_WalletBalance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(ctx) diff --git a/lnrpc/rpc.proto b/lnrpc/rpc.proto index 4f6760f12..6a6f4bda0 100644 --- a/lnrpc/rpc.proto +++ b/lnrpc/rpc.proto @@ -127,6 +127,15 @@ message InitWalletRequest { to encrypt the generated aezeed cipher seed. */ bytes aezeed_passphrase = 3; + + /** + recovery_window is an optional argument specifying the address lookahead + when restoring a wallet seed. The recovery window applies to each + invdividual branch of the BIP44 derivation paths. Supplying a recovery + window of zero indicates that no addresses should be recovered, such after + the first initialization of the wallet. + */ + int32 recovery_window = 4; } message InitWalletResponse { } @@ -138,6 +147,15 @@ message UnlockWalletRequest { function properly. */ bytes wallet_password = 1; + + /** + recovery_window is an optional argument specifying the address lookahead + when restoring a wallet seed. The recovery window applies to each + invdividual branch of the BIP44 derivation paths. Supplying a recovery + window of zero indicates that no addresses should be recovered, such after + the first initialization of the wallet. + */ + int32 recovery_window = 2; } message UnlockWalletResponse {} diff --git a/lnrpc/rpc.swagger.json b/lnrpc/rpc.swagger.json index 417a78ec3..23dde7375 100644 --- a/lnrpc/rpc.swagger.json +++ b/lnrpc/rpc.swagger.json @@ -1569,6 +1569,11 @@ "type": "string", "format": "byte", "description": "*\naezeed_passphrase is an optional user provided passphrase that will be used\nto encrypt the generated aezeed cipher seed." + }, + "recovery_window": { + "type": "integer", + "format": "int32", + "description": "*\nrecovery_window is an optional argument specifying the address lookahead\nwhen restoring a wallet seed. The recovery window applies to each\ninvdividual branch of the BIP44 derivation paths. Supplying a recovery\nwindow of zero indicates that no addresses should be recovered, such after\nthe first initialization of the wallet." } } }, @@ -2390,6 +2395,11 @@ "type": "string", "format": "byte", "description": "*\nwallet_password should be the current valid passphrase for the daemon. This\nwill be required to decrypt on-disk material that the daemon requires to\nfunction properly." + }, + "recovery_window": { + "type": "integer", + "format": "int32", + "description": "*\nrecovery_window is an optional argument specifying the address lookahead\nwhen restoring a wallet seed. The recovery window applies to each\ninvdividual branch of the BIP44 derivation paths. Supplying a recovery\nwindow of zero indicates that no addresses should be recovered, such after\nthe first initialization of the wallet." } } }, From 1972a795e5a3057af740282917c140ecdcf4ddf8 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:10:29 -0700 Subject: [PATCH 05/15] chainregistry: initialize wallet w/ recovery window --- chainregistry.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/chainregistry.go b/chainregistry.go index a9bed51d6..005aa106f 100644 --- a/chainregistry.go +++ b/chainregistry.go @@ -112,7 +112,8 @@ type chainControl struct { // branches of chainControl instances exist: one backed by a running btcd // full-node, and the other backed by a running neutrino light client instance. func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB, - privateWalletPw, publicWalletPw []byte) (*chainControl, func(), error) { + privateWalletPw, publicWalletPw []byte, birthday time.Time, + recoveryWindow uint32) (*chainControl, func(), error) { // Set the RPC config from the "home" chain. Multi-chain isn't yet // active, so we'll restrict usage to a particular chain for now. @@ -152,12 +153,14 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB, } walletConfig := &btcwallet.Config{ - PrivatePass: privateWalletPw, - PublicPass: publicWalletPw, - DataDir: homeChainConfig.ChainDir, - NetParams: activeNetParams.Params, - FeeEstimator: cc.feeEstimator, - CoinType: activeNetParams.CoinType, + PrivatePass: privateWalletPw, + PublicPass: publicWalletPw, + Birthday: birthday, + RecoveryWindow: recoveryWindow, + DataDir: homeChainConfig.ChainDir, + NetParams: activeNetParams.Params, + FeeEstimator: cc.feeEstimator, + CoinType: activeNetParams.CoinType, } var ( @@ -243,7 +246,9 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB, // Finally, we'll set the chain source for btcwallet, and // create our clean up function which simply closes the // database. - walletConfig.ChainSource = chain.NewNeutrinoClient(svc) + walletConfig.ChainSource = chain.NewNeutrinoClient( + activeNetParams.Params, svc, + ) cleanUp = func() { svc.Stop() nodeDatabase.Close() From b9df5e75f7937b3d9e86944627042e30dc9a0999 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:11:40 -0700 Subject: [PATCH 06/15] keychain/interface_test: init test wallet w/o recovery window --- keychain/interface_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/keychain/interface_test.go b/keychain/interface_test.go index 57f56a1bc..f3b6b1e3b 100644 --- a/keychain/interface_test.go +++ b/keychain/interface_test.go @@ -6,6 +6,7 @@ import ( "math/rand" "os" "testing" + "time" "github.com/roasbeef/btcd/chaincfg" "github.com/roasbeef/btcd/chaincfg/chainhash" @@ -42,11 +43,13 @@ func createTestBtcWallet(coinType uint32) (func(), *wallet.Wallet, error) { if err != nil { return nil, nil, err } - loader := wallet.NewLoader(&chaincfg.SimNetParams, tempDir) + loader := wallet.NewLoader(&chaincfg.SimNetParams, tempDir, 0) pass := []byte("test") - baseWallet, err := loader.CreateNewWallet(pass, pass, testHDSeed[:]) + baseWallet, err := loader.CreateNewWallet( + pass, pass, testHDSeed[:], time.Time{}, + ) if err != nil { return nil, nil, err } From 603228ce7909133f23b30e92ab4d040850b60397 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:12:17 -0700 Subject: [PATCH 07/15] lnd: threads recovery window param from walletunlocker --- lnd.go | 98 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 25 deletions(-) diff --git a/lnd.go b/lnd.go index 2afcc7275..4e1e2dc1e 100644 --- a/lnd.go +++ b/lnd.go @@ -207,19 +207,35 @@ func lndMain() error { defer macaroonService.Close() } + var ( + privateWalletPw = []byte("hello") + publicWalletPw = []byte("public") + birthday time.Time + recoveryWindow uint32 + ) + // We wait until the user provides a password over RPC. In case lnd is // started with the --noencryptwallet flag, we use the default password // "hello" for wallet encryption. - privateWalletPw := []byte("hello") - publicWalletPw := []byte("public") if !cfg.NoEncryptWallet { - privateWalletPw, publicWalletPw, err = waitForWalletPassword( - cfg.RPCListeners, cfg.RESTListeners, serverOpts, proxyOpts, - tlsConf, macaroonService, + walletInitParams, err := waitForWalletPassword( + cfg.RPCListeners, cfg.RESTListeners, serverOpts, + proxyOpts, tlsConf, macaroonService, ) if err != nil { return err } + + privateWalletPw = walletInitParams.Password + publicWalletPw = walletInitParams.Password + birthday = walletInitParams.Birthday + recoveryWindow = walletInitParams.RecoveryWindow + + if recoveryWindow > 0 { + ltndLog.Infof("Wallet recovery mode enabled with "+ + "address lookahead of %d addresses", + recoveryWindow) + } } if !cfg.NoMacaroons { @@ -251,8 +267,10 @@ func lndMain() error { // With the information parsed from the configuration, create valid // instances of the pertinent interfaces required to operate the // Lightning Network Daemon. - activeChainControl, chainCleanUp, err := newChainControlFromConfig(cfg, - chanDB, privateWalletPw, publicWalletPw) + activeChainControl, chainCleanUp, err := newChainControlFromConfig( + cfg, chanDB, privateWalletPw, publicWalletPw, birthday, + recoveryWindow, + ) if err != nil { fmt.Printf("unable to create chain control: %v\n", err) return err @@ -827,12 +845,30 @@ func genMacaroons(ctx context.Context, svc *macaroons.Service, return nil } +// WalletUnlockParams holds the variables used to parameterize the unlocking of +// lnd's wallet after it has already been created. +type WalletUnlockParams struct { + // Password is the public and private wallet passphrase. + Password []byte + + // Birthday specifies the approximate time that this wallet was created. + // This is used to bound any rescans on startup. + Birthday time.Time + + // RecoveryWindow specifies the address lookahead when entering recovery + // mode. A recovery will be attempted if this value is non-zero. + RecoveryWindow uint32 +} + // waitForWalletPassword will spin up gRPC and REST endpoints for the // WalletUnlocker server, and block until a password is provided by // the user to this RPC server. -func waitForWalletPassword(grpcEndpoints, restEndpoints []string, - serverOpts []grpc.ServerOption, proxyOpts []grpc.DialOption, - tlsConf *tls.Config, macaroonService *macaroons.Service) ([]byte, []byte, error) { +func waitForWalletPassword( + grpcEndpoints, restEndpoints []string, + serverOpts []grpc.ServerOption, + proxyOpts []grpc.DialOption, + tlsConf *tls.Config, + macaroonService *macaroons.Service) (*WalletUnlockParams, error) { // Set up a new PasswordService, which will listen // for passwords provided over RPC. @@ -857,7 +893,7 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []string, if err != nil { ltndLog.Errorf("password RPC server unable to listen on %s", grpcEndpoint) - return nil, nil, err + return nil, err } defer lis.Close() @@ -879,7 +915,7 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []string, err := lnrpc.RegisterWalletUnlockerHandlerFromEndpoint(ctx, mux, grpcEndpoints[0], proxyOpts) if err != nil { - return nil, nil, err + return nil, err } srv := &http.Server{Handler: mux} @@ -889,7 +925,7 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []string, if err != nil { ltndLog.Errorf("password gRPC proxy unable to listen on %s", restEndpoint) - return nil, nil, err + return nil, err } defer lis.Close() @@ -920,14 +956,15 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []string, case initMsg := <-pwService.InitMsgs: password := initMsg.Passphrase cipherSeed := initMsg.WalletSeed + recoveryWindow := initMsg.RecoveryWindow // Before we proceed, we'll check the internal version of the // seed. If it's greater than the current key derivation // version, then we'll return an error as we don't understand // this. if cipherSeed.InternalVersion != keychain.KeyDerivationVersion { - return nil, nil, fmt.Errorf("invalid internal seed "+ - "version %v, current version is %v", + return nil, fmt.Errorf("invalid internal seed version "+ + "%v, current version is %v", cipherSeed.InternalVersion, keychain.KeyDerivationVersion) } @@ -935,31 +972,42 @@ func waitForWalletPassword(grpcEndpoints, restEndpoints []string, netDir := btcwallet.NetworkDir( chainConfig.ChainDir, activeNetParams.Params, ) - loader := wallet.NewLoader(activeNetParams.Params, netDir) + loader := wallet.NewLoader( + activeNetParams.Params, netDir, uint32(recoveryWindow), + ) // With the seed, we can now use the wallet loader to create // the wallet, then unload it so it can be opened shortly - // after. - // TODO(roasbeef): extend loader to also accept birthday + birthday := cipherSeed.BirthdayTime() _, err = loader.CreateNewWallet( - password, password, cipherSeed.Entropy[:], + password, password, cipherSeed.Entropy[:], birthday, ) if err != nil { - return nil, nil, err + return nil, err } if err := loader.UnloadWallet(); err != nil { - return nil, nil, err + return nil, err } - return password, password, nil + walletInitParams := &WalletUnlockParams{ + Password: password, + Birthday: birthday, + RecoveryWindow: recoveryWindow, + } + + return walletInitParams, nil // The wallet has already been created in the past, and is simply being // unlocked. So we'll just return these passphrases. - case walletPw := <-pwService.UnlockPasswords: - return walletPw, walletPw, nil + case unlockMsg := <-pwService.UnlockMsgs: + walletInitParams := &WalletUnlockParams{ + Password: unlockMsg.Passphrase, + RecoveryWindow: unlockMsg.RecoveryWindow, + } + return walletInitParams, nil case <-shutdownChannel: - return nil, nil, fmt.Errorf("shutting down") + return nil, fmt.Errorf("shutting down") } } From ae604061bf9d2d61885e10063469c87a6ed4a6c7 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:13:31 -0700 Subject: [PATCH 08/15] lnwallet/btcwallet/btcwallet: pass recovery window to CreateNewWallet --- lnwallet/btcwallet/btcwallet.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnwallet/btcwallet/btcwallet.go b/lnwallet/btcwallet/btcwallet.go index a34111f02..5ce00533c 100644 --- a/lnwallet/btcwallet/btcwallet.go +++ b/lnwallet/btcwallet/btcwallet.go @@ -88,7 +88,7 @@ func New(cfg Config) (*BtcWallet, error) { pubPass = cfg.PublicPass } - loader := base.NewLoader(cfg.NetParams, netDir) + loader := base.NewLoader(cfg.NetParams, netDir, cfg.RecoveryWindow) walletExists, err := loader.WalletExists() if err != nil { return nil, err @@ -98,7 +98,7 @@ func New(cfg Config) (*BtcWallet, error) { if !walletExists { // Wallet has never been created, perform initial set up. wallet, err = loader.CreateNewWallet( - pubPass, cfg.PrivatePass, cfg.HdSeed, + pubPass, cfg.PrivatePass, cfg.HdSeed, cfg.Birthday, ) if err != nil { return nil, err From 06a53aa5cc18fe6bc267a132a2501582b738a78f Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:14:11 -0700 Subject: [PATCH 09/15] lnwallet/btcwallet/config: add recovery window and bday --- lnwallet/btcwallet/config.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lnwallet/btcwallet/config.go b/lnwallet/btcwallet/config.go index 6096c7742..b0ac59021 100644 --- a/lnwallet/btcwallet/config.go +++ b/lnwallet/btcwallet/config.go @@ -2,6 +2,7 @@ package btcwallet import ( "path/filepath" + "time" "github.com/lightningnetwork/lnd/lnwallet" "github.com/roasbeef/btcd/chaincfg" @@ -63,6 +64,15 @@ type Config struct { // unspecified, a new seed will be generated. HdSeed []byte + // Birthday specifies the time at which this wallet was initially + // created. It is used to bound rescans for used addresses. + Birthday time.Time + + // RecoveryWindow specifies the address look-ahead for which to scan + // when restoring a wallet. The recovery window will apply to all + // default BIP44 derivation paths. + RecoveryWindow uint32 + // ChainSource is the primary chain interface. This is used to operate // the wallet and do things such as rescanning, sending transactions, // notifications for received funds, etc. From a2fdd8593dda0d8dfab8a6cedd6d75d79edf6d17 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:14:47 -0700 Subject: [PATCH 10/15] lnwallet/interfaace_test: init neutrino with chain params --- lnwallet/interface_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lnwallet/interface_test.go b/lnwallet/interface_test.go index f01fd1f19..3bd5f8e35 100644 --- a/lnwallet/interface_test.go +++ b/lnwallet/interface_test.go @@ -2083,7 +2083,9 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver, } aliceChain.Start() defer aliceChain.Stop() - aliceClient = chain.NewNeutrinoClient(aliceChain) + aliceClient = chain.NewNeutrinoClient( + netParams, aliceChain, + ) // Start Bob - open a database, start a neutrino // instance, and initialize a btcwallet driver for it. @@ -2108,7 +2110,9 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver, } bobChain.Start() defer bobChain.Stop() - bobClient = chain.NewNeutrinoClient(bobChain) + bobClient = chain.NewNeutrinoClient( + netParams, bobChain, + ) case "bitcoind": feeEstimator, err = lnwallet.NewBitcoindFeeEstimator( From 92a2ba163e3399a171488182804abf013aeab110 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:15:04 -0700 Subject: [PATCH 11/15] cmd/lncli/commands: ask for recovery window after restore seed --- cmd/lncli/commands.go | 64 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/cmd/lncli/commands.go b/cmd/lncli/commands.go index 4a1f32975..53abbc7cb 100644 --- a/cmd/lncli/commands.go +++ b/cmd/lncli/commands.go @@ -35,6 +35,8 @@ import ( // TODO(roasbeef): expose all fee conf targets +const defaultRecoveryWindow int32 = 250 + func printJSON(resp interface{}) { b, err := json.Marshal(resp) if err != nil { @@ -1132,6 +1134,7 @@ mnemonicCheck: var ( cipherSeedMnemonic []string aezeedPass []byte + recoveryWindow int32 ) if hasMnemonic { // We'll now prompt the user to enter in their 24-word @@ -1170,7 +1173,37 @@ mnemonicCheck: aezeedPass = []byte(passphrase) - fmt.Println() + for { + fmt.Println() + fmt.Printf("Input an optional address look-ahead "+ + "used to scan for used keys (default %d): ", + defaultRecoveryWindow) + + reader := bufio.NewReader(os.Stdin) + answer, err := reader.ReadString('\n') + if err != nil { + return err + } + + fmt.Println() + + answer = strings.TrimSpace(answer) + + if len(answer) == 0 { + recoveryWindow = defaultRecoveryWindow + break + } + + lookAhead, err := strconv.Atoi(answer) + if err != nil { + fmt.Println("Unable to parse recovery "+ + "window: %v", err) + continue + } + + recoveryWindow = int32(lookAhead) + break + } } else { // Otherwise, if the user doesn't have a mnemonic that they // want to use, we'll generate a fresh one with the GenSeed @@ -1247,6 +1280,7 @@ mnemonicCheck: WalletPassword: pw1, CipherSeedMnemonic: cipherSeedMnemonic, AezeedPassphrase: aezeedPass, + RecoveryWindow: recoveryWindow, } if _, err := client.InitWallet(ctxb, req); err != nil { return err @@ -1265,6 +1299,16 @@ var unlockCommand = cli.Command{ able to carry out its duties. An exception is if a user is running with --noencryptwallet, then a default passphrase will be used. `, + Flags: []cli.Flag{ + cli.IntFlag{ + Name: "recovery_window", + Usage: "address lookahead to resume recovery rescan, " + + "value should be non-zero -- To recover all " + + "funds, this should be greater than the " + + "maximum number of consecutive, unused " + + "addresses ever generated by the wallet.", + }, + }, Action: actionDecorator(unlock), } @@ -1280,8 +1324,26 @@ func unlock(ctx *cli.Context) error { } fmt.Println() + args := ctx.Args() + + // Parse the optional recovery window if it is specified. By default, + // the recovery window will be 0, indicating no lookahead should be + // used. + var recoveryWindow int32 + switch { + case ctx.IsSet("recovery_window"): + recoveryWindow = int32(ctx.Int64("recovery_window")) + case args.Present(): + window, err := strconv.ParseInt(args.First(), 10, 64) + if err != nil { + return err + } + recoveryWindow = int32(window) + } + req := &lnrpc.UnlockWalletRequest{ WalletPassword: pw, + RecoveryWindow: recoveryWindow, } _, err = client.UnlockWallet(ctxb, req) if err != nil { From 329793d06b585de685281261c58418944190952c Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 2 Apr 2018 16:57:04 -0700 Subject: [PATCH 12/15] lntest/harness: add NewNodeWithSeed and RestoreNodeWithSeed --- lntest/harness.go | 133 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 4 deletions(-) diff --git a/lntest/harness.go b/lntest/harness.go index e6e68580f..c16547ad3 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -238,7 +238,97 @@ func (n *NetworkHarness) TearDownAll() error { // current instance of the network harness. The created node is running, but // not yet connected to other nodes within the network. func (n *NetworkHarness) NewNode(extraArgs []string) (*HarnessNode, error) { + return n.newNode(extraArgs, false) +} + +// NewNodeWithSeed fully initializes a new HarnessNode after creating a fresh +// aezeed. The provided password is used as both the aezeed password and the +// wallet password. The generated mnemonic is returned along with the +// initialized harness node. +func (n *NetworkHarness) NewNodeWithSeed(extraArgs []string, + password []byte) (*HarnessNode, []string, error) { + + node, err := n.newNode(extraArgs, true) + if err != nil { + return nil, nil, err + } + + timeout := time.Duration(time.Second * 15) + ctxb := context.Background() + + // Create a request to generate a new aezeed. The new seed will have the + // same password as the internal wallet. + genSeedReq := &lnrpc.GenSeedRequest{ + AezeedPassphrase: password, + } + + ctxt, _ := context.WithTimeout(ctxb, timeout) + genSeedResp, err := node.GenSeed(ctxt, genSeedReq) + if err != nil { + return nil, nil, err + } + + // With the seed created, construct the init request to the node, + // including the newly generated seed. + initReq := &lnrpc.InitWalletRequest{ + WalletPassword: password, + CipherSeedMnemonic: genSeedResp.CipherSeedMnemonic, + AezeedPassphrase: password, + } + + // Pass the init request via rpc to finish unlocking the node. This will + // also initialize the macaroon-authenticated LightningClient. + err = node.Init(ctxb, initReq) + if err != nil { + return nil, nil, err + } + + // With the node started, we can now record its public key within the + // global mapping. + n.RegisterNode(node) + + return node, genSeedResp.CipherSeedMnemonic, nil +} + +// RestoreNodeWithSeed fully initializes a HarnessNode using a chosen mnemonic, +// password, and recovery window. After providing the initialization request to +// unlock the node, this method will finish initializing the LightningClient +// such that the HarnessNode can be used for regular rpc operations. +func (n *NetworkHarness) RestoreNodeWithSeed(extraArgs []string, + password []byte, mnemonic []string, + recoveryWindow int32) (*HarnessNode, error) { + + node, err := n.newNode(extraArgs, true) + if err != nil { + return nil, err + } + + initReq := &lnrpc.InitWalletRequest{ + WalletPassword: password, + CipherSeedMnemonic: mnemonic, + AezeedPassphrase: password, + RecoveryWindow: recoveryWindow, + } + + err = node.Init(context.Background(), initReq) + if err != nil { + return nil, err + } + + // With the node started, we can now record its public key within the + // global mapping. + n.RegisterNode(node) + + return node, nil +} + +// newNode initializes a new HarnessNode, supporting the ability to initialize a +// wallet with or without a seed. If hasSeed is false, the returned harness node +// can be used immediately. Otherwise, the node will require an additional +// initialization phase where the wallet is either created or restored. +func (n *NetworkHarness) newNode(extraArgs []string, hasSeed bool) (*HarnessNode, error) { node, err := newNode(nodeConfig{ + HasSeed: hasSeed, RPCConfig: &n.rpcConfig, NetParams: n.netParams, ExtraArgs: extraArgs, @@ -257,13 +347,27 @@ func (n *NetworkHarness) NewNode(extraArgs []string) (*HarnessNode, error) { return nil, err } + // If this node is to have a seed, it will need to be unlocked or + // initialized via rpc. Delay registering it with the network until it + // can be driven via an unlocked rpc connection. + if node.cfg.HasSeed { + return node, nil + } + // With the node started, we can now record its public key within the // global mapping. + n.RegisterNode(node) + + return node, nil +} + +// RegisterNode records a new HarnessNode in the NetworkHarnesses map of known +// nodes. This method should only be called with nodes that have successfully +// retrieved their public keys via FetchNodeInfo. +func (n *NetworkHarness) RegisterNode(node *HarnessNode) { n.mtx.Lock() n.nodesByPub[node.PubKeyStr] = node n.mtx.Unlock() - - return node, nil } // EnsureConnected will try to connect to two nodes, returning no error if they @@ -986,10 +1090,31 @@ func (n *NetworkHarness) DumpLogs(node *HarnessNode) (string, error) { } // SendCoins attempts to send amt satoshis from the internal mining node to the -// targeted lightning node. +// targeted lightning node using a P2WKH address. func (n *NetworkHarness) SendCoins(ctx context.Context, amt btcutil.Amount, target *HarnessNode) error { + return n.sendCoins( + ctx, amt, target, lnrpc.NewAddressRequest_WITNESS_PUBKEY_HASH, + ) +} + +// SendCoinsNP2WKH attempts to send amt satoshis from the internal mining node +// to the targeted lightning node using a NP2WKH address. +func (n *NetworkHarness) SendCoinsNP2WKH(ctx context.Context, + amt btcutil.Amount, target *HarnessNode) error { + + return n.sendCoins( + ctx, amt, target, lnrpc.NewAddressRequest_NESTED_PUBKEY_HASH, + ) +} + +// sendCoins attempts to send amt satoshis from the internal mining node to the +// targeted lightning node. +func (n *NetworkHarness) sendCoins(ctx context.Context, amt btcutil.Amount, + target *HarnessNode, + addrType lnrpc.NewAddressRequest_AddressType) error { + balReq := &lnrpc.WalletBalanceRequest{} initialBalance, err := target.WalletBalance(ctx, balReq) if err != nil { @@ -1000,7 +1125,7 @@ func (n *NetworkHarness) SendCoins(ctx context.Context, amt btcutil.Amount, // to receive a p2wkh address s.t the output can immediately be used as // an input to a funding transaction. addrReq := &lnrpc.NewAddressRequest{ - Type: lnrpc.NewAddressRequest_WITNESS_PUBKEY_HASH, + Type: addrType, } resp, err := target.NewAddress(ctx, addrReq) if err != nil { From c977ebb8bd9d60edcca444842cf23d2f8f3fee1d Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 2 Apr 2018 16:57:25 -0700 Subject: [PATCH 13/15] lntest/node: add ability to unlock/init HarnessNode --- lntest/node.go | 124 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 18 deletions(-) diff --git a/lntest/node.go b/lntest/node.go index c41897e2f..5c54a3e61 100644 --- a/lntest/node.go +++ b/lntest/node.go @@ -98,6 +98,8 @@ type nodeConfig struct { ReadMacPath string InvoiceMacPath string + HasSeed bool + P2PPort int RPCPort int RESTPort int @@ -136,7 +138,6 @@ func (cfg nodeConfig) genArgs() []string { encodedCert := hex.EncodeToString(cfg.RPCConfig.Certificates) args = append(args, "--bitcoin.active") args = append(args, "--nobootstrap") - args = append(args, "--noencryptwallet") args = append(args, "--debuglevel=debug") args = append(args, "--bitcoin.defaultchanconfs=1") args = append(args, "--bitcoin.defaultremotedelay=4") @@ -159,6 +160,10 @@ func (cfg nodeConfig) genArgs() []string { args = append(args, fmt.Sprintf("--externalip=%s", cfg.P2PAddr())) args = append(args, fmt.Sprintf("--trickledelay=%v", trickleDelay)) + if !cfg.HasSeed { + args = append(args, "--noencryptwallet") + } + if cfg.ExtraArgs != nil { args = append(args, cfg.ExtraArgs...) } @@ -195,10 +200,13 @@ type HarnessNode struct { wg sync.WaitGroup lnrpc.LightningClient + + lnrpc.WalletUnlockerClient } // Assert *HarnessNode implements the lnrpc.LightningClient interface. var _ lnrpc.LightningClient = (*HarnessNode)(nil) +var _ lnrpc.WalletUnlockerClient = (*HarnessNode)(nil) // newNode creates a new test lightning node instance from the passed config. func newNode(cfg nodeConfig) (*HarnessNode, error) { @@ -301,13 +309,78 @@ func (hn *HarnessNode) start(lndError chan<- error) error { // Since Stop uses the LightningClient to stop the node, if we fail to get a // connected client, we have to kill the process. - conn, err := hn.connectRPC() + useMacaroons := !hn.cfg.HasSeed + conn, err := hn.ConnectRPC(useMacaroons) if err != nil { hn.cmd.Process.Kill() return err } + + // If the node was created with a seed, we will need to perform an + // additional step to unlock the wallet. The connection returned will + // only use the TLS certs, and can only perform operations necessary to + // unlock the daemon. + if hn.cfg.HasSeed { + hn.WalletUnlockerClient = lnrpc.NewWalletUnlockerClient(conn) + return nil + } + + return hn.initLightningClient(conn) +} + +// Init initializes a harness node by passing the init request via rpc. After +// the request is submitted, this method will block until an +// macaroon-authenticated rpc connection can be established to the harness node. +// Once established, the new connection is used to initialize the +// LightningClient and subscribes the HarnessNode to topology changes. +func (hn *HarnessNode) Init(ctx context.Context, + initReq *lnrpc.InitWalletRequest) error { + + timeout := time.Duration(time.Second * 15) + ctxt, _ := context.WithTimeout(ctx, timeout) + _, err := hn.InitWallet(ctxt, initReq) + if err != nil { + return err + } + + // Wait for the wallet to finish unlocking, such that we can connect to + // it via a macaroon-authenticated rpc connection. + var conn *grpc.ClientConn + if err = WaitPredicate(func() bool { + conn, err = hn.ConnectRPC(true) + return err == nil + }, 5*time.Second); err != nil { + return err + } + + return hn.initLightningClient(conn) +} + +// initLightningClient constructs the grpc LightningClient from the given client +// connection and subscribes the harness node to graph topology updates. +func (hn *HarnessNode) initLightningClient(conn *grpc.ClientConn) error { + // Construct the LightningClient that will allow us to use the + // HarnessNode directly for normal rpc operations. hn.LightningClient = lnrpc.NewLightningClient(conn) + // Set the harness node's pubkey to what the node claims in GetInfo. + err := hn.FetchNodeInfo() + if err != nil { + return err + } + + // Launch the watcher that will hook into graph related topology change + // from the PoV of this node. + hn.wg.Add(1) + go hn.lightningNetworkWatcher() + + return nil +} + +// FetchNodeInfo queries an unlocked node to retrieve its public key. This +// method also spawns a lightning network watcher for this node, which watches +// for topology changes. +func (hn *HarnessNode) FetchNodeInfo() error { // Obtain the lnid of this node for quick identification purposes. ctxb := context.Background() info, err := hn.GetInfo(ctxb, &lnrpc.GetInfoRequest{}) @@ -323,11 +396,6 @@ func (hn *HarnessNode) start(lndError chan<- error) error { } copy(hn.PubKey[:], pubkey) - // Launch the watcher that will hook into graph related topology change - // from the PoV of this node. - hn.wg.Add(1) - go hn.lightningNetworkWatcher() - return nil } @@ -365,24 +433,45 @@ func (hn *HarnessNode) writePidFile() error { // connectRPC uses the TLS certificate and admin macaroon files written by the // lnd node to create a gRPC client connection. -func (hn *HarnessNode) connectRPC() (*grpc.ClientConn, error) { +func (hn *HarnessNode) ConnectRPC(useMacs bool) (*grpc.ClientConn, error) { // Wait until TLS certificate and admin macaroon are created before // using them, up to 20 sec. tlsTimeout := time.After(30 * time.Second) - for !fileExists(hn.cfg.TLSCertPath) || !fileExists(hn.cfg.AdminMacPath) { + for !fileExists(hn.cfg.TLSCertPath) { select { case <-tlsTimeout: - return nil, fmt.Errorf("timeout waiting for TLS cert file " + - "and admin macaroon file to be created after " + - "20 seconds") + return nil, fmt.Errorf("timeout waiting for TLS cert " + + "file to be created after 30 seconds") case <-time.After(100 * time.Millisecond): } } + opts := []grpc.DialOption{ + grpc.WithBlock(), + grpc.WithTimeout(time.Second * 20), + } + tlsCreds, err := credentials.NewClientTLSFromFile(hn.cfg.TLSCertPath, "") if err != nil { return nil, err } + + opts = append(opts, grpc.WithTransportCredentials(tlsCreds)) + + if !useMacs { + return grpc.Dial(hn.cfg.RPCAddr(), opts...) + } + + macTimeout := time.After(30 * time.Second) + for !fileExists(hn.cfg.AdminMacPath) { + select { + case <-macTimeout: + return nil, fmt.Errorf("timeout waiting for admin " + + "macaroon file to be created after 30 seconds") + case <-time.After(100 * time.Millisecond): + } + } + macBytes, err := ioutil.ReadFile(hn.cfg.AdminMacPath) if err != nil { return nil, err @@ -391,12 +480,10 @@ func (hn *HarnessNode) connectRPC() (*grpc.ClientConn, error) { if err = mac.UnmarshalBinary(macBytes); err != nil { return nil, err } - opts := []grpc.DialOption{ - grpc.WithTransportCredentials(tlsCreds), - grpc.WithPerRPCCredentials(macaroons.NewMacaroonCredential(mac)), - grpc.WithBlock(), - grpc.WithTimeout(time.Second * 20), - } + + macCred := macaroons.NewMacaroonCredential(mac) + opts = append(opts, grpc.WithPerRPCCredentials(macCred)) + return grpc.Dial(hn.cfg.RPCAddr(), opts...) } @@ -441,6 +528,7 @@ func (hn *HarnessNode) stop() error { hn.quit = nil hn.processExit = nil hn.LightningClient = nil + hn.WalletUnlockerClient = nil return nil } From 5049d3956b5de298133b8a8fe5b908299ba4145d Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 2 Apr 2018 16:57:58 -0700 Subject: [PATCH 14/15] lnd_test: adds wallet recovery test --- lnd_test.go | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/lnd_test.go b/lnd_test.go index af09964b2..143f100fb 100644 --- a/lnd_test.go +++ b/lnd_test.go @@ -440,6 +440,180 @@ func completePaymentRequests(ctx context.Context, client lnrpc.LightningClient, return nil } +const ( + AddrTypeWitnessPubkeyHash = lnrpc.NewAddressRequest_WITNESS_PUBKEY_HASH + AddrTypeNestedPubkeyHash = lnrpc.NewAddressRequest_NESTED_PUBKEY_HASH +) + +// testOnchainFundRecovery checks lnd's ability to rescan for onchain outputs +// when providing a valid aezeed that owns outputs on the chain. This test +// performs multiple restorations using the same seed and various recovery +// windows to ensure we detect funds properly. +func testOnchainFundRecovery(net *lntest.NetworkHarness, t *harnessTest) { + timeout := time.Duration(time.Second * 15) + ctxb := context.Background() + + // First, create a new node with strong passphrase and grab the mnemonic + // used for key derivation. This will bring up Carol with an empty + // wallet, and such that she is synced up. + password := []byte("The Magic Words are Squeamish Ossifrage") + carol, mnemonic, err := net.NewNodeWithSeed(nil, password) + if err != nil { + t.Fatalf("unable to create node with seed; %v", err) + } + + err = net.ShutdownNode(carol) + if err != nil { + t.Fatalf("unable to shutdown carol: %v", err) + } + + // Create a closure for testing the recovery of Carol's wallet. This + // method takes the expected value of Carol's balance when using the + // given recovery window. Additionally, the caller can specify an action + // to perform on the restored node before the node is shutdown. + restoreCheckBalance := func(expAmount int64, recoveryWindow int32, + fn func(*lntest.HarnessNode)) { + + // Restore Carol, passing in the password, mnemonic, and + // desired recovery window. + node, err := net.RestoreNodeWithSeed( + nil, password, mnemonic, recoveryWindow, + ) + if err != nil { + t.Fatalf("unable to restore node: %v", err) + } + + // Query carol for her current wallet balance. + var currBalance int64 + err = lntest.WaitPredicate(func() bool { + req := &lnrpc.WalletBalanceRequest{} + ctxt, _ := context.WithTimeout(ctxb, timeout) + resp, err := node.WalletBalance(ctxt, req) + if err != nil { + t.Fatalf("unable to query wallet balance: %v", + err) + } + + // Verify that Carol's balance matches our expected + // amount. + currBalance = resp.ConfirmedBalance + if expAmount != currBalance { + return false + } + + return true + }, 15*time.Second) + if err != nil { + t.Fatalf("expected restored node to have %d satoshis, "+ + "instead has %d satoshis", expAmount, + currBalance) + } + + // If the user provided a callback, execute the commands against + // the restored Carol. + if fn != nil { + fn(node) + } + + // Lastly, shutdown this Carol so we can move on to the next + // restoration. + err = net.ShutdownNode(node) + if err != nil { + t.Fatalf("unable to shutdown node: %v", err) + } + } + + // Create a closure-factory for building closures that can generate and + // skip a configurable number of addresses, before finally sending coins + // to a next generated address. The returned closure will apply the same + // behavior to both default P2WKH and NP2WKH scopes. + skipAndSend := func(nskip int) func(*lntest.HarnessNode) { + return func(node *lntest.HarnessNode) { + newP2WKHAddrReq := &lnrpc.NewAddressRequest{ + Type: AddrTypeWitnessPubkeyHash, + } + + newNP2WKHAddrReq := &lnrpc.NewAddressRequest{ + Type: AddrTypeNestedPubkeyHash, + } + + // Generate and skip the number of addresses requested. + for i := 0; i < nskip; i++ { + ctxt, _ := context.WithTimeout(ctxb, timeout) + _, err = node.NewAddress(ctxt, newP2WKHAddrReq) + if err != nil { + t.Fatalf("unable to generate new "+ + "p2wkh address: %v", err) + } + + ctxt, _ = context.WithTimeout(ctxb, timeout) + _, err = node.NewAddress(ctxt, newNP2WKHAddrReq) + if err != nil { + t.Fatalf("unable to generate new "+ + "np2wkh address: %v", err) + } + } + + // Send one BTC to the next P2WKH address. + ctxt, _ := context.WithTimeout(ctxb, timeout) + err = net.SendCoins( + ctxt, btcutil.SatoshiPerBitcoin, node, + ) + if err != nil { + t.Fatalf("unable to send coins to node: %v", + err) + } + + // And another to the next NP2WKH address. + ctxt, _ = context.WithTimeout(ctxb, timeout) + err = net.SendCoinsNP2WKH( + ctxt, btcutil.SatoshiPerBitcoin, node, + ) + if err != nil { + t.Fatalf("unable to send coins to node: %v", + err) + } + } + } + + // Restore Carol with a recovery window of 0. Since no coins have been + // sent, her balance should be zero. + // + // After, one BTC is sent to both her first external P2WKH and NP2WKH + // addresses. + restoreCheckBalance(0, 0, skipAndSend(0)) + + // Check that restoring without a look-ahead results in having no funds + // in the wallet, even though they exist on-chain. + restoreCheckBalance(0, 0, nil) + + // Now, check that using a look-ahead of 1 recovers the balance from the + // two transactions above. + // + // After, we will generate and skip 9 P2WKH and NP2WKH addresses, and + // send another BTC to the subsequent 10th address in each derivation + // path. + restoreCheckBalance(2*btcutil.SatoshiPerBitcoin, 1, skipAndSend(9)) + + // Check that using a recovery window of 9 does not find the two most + // recent txns. + restoreCheckBalance(2*btcutil.SatoshiPerBitcoin, 9, nil) + + // Extending our recovery window to 10 should find the most recent + // transactions, leaving the wallet with 4 BTC total. + // + // After, we will skip 19 more addrs, sending to the 20th address past + // our last found address, and repeat the same checks. + restoreCheckBalance(4*btcutil.SatoshiPerBitcoin, 10, skipAndSend(19)) + + // Check that recovering with a recovery window of 19 fails to find the + // most recent transactions. + restoreCheckBalance(4*btcutil.SatoshiPerBitcoin, 19, nil) + + // Ensure that using a recovery window of 20 succeeds. + restoreCheckBalance(6*btcutil.SatoshiPerBitcoin, 20, nil) +} + // testBasicChannelFunding performs a test exercising expected behavior from a // basic funding workflow. The test creates a new channel between Alice and // Bob, then immediately closes the channel after asserting some expected post @@ -8808,6 +8982,10 @@ type testCase struct { } var testsCases = []*testCase{ + { + name: "onchain fund recovery", + test: testOnchainFundRecovery, + }, { name: "basic funding flow", test: testBasicChannelFunding, From 1ae3d4f11899b11b69ecd7d1858ce8e1e4f37580 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Mon, 26 Mar 2018 14:02:15 -0700 Subject: [PATCH 15/15] dep: update btcwallet w/ wallet recovery --- Gopkg.lock | 4 ++-- Gopkg.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index d486ed71d..06650edab 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -225,7 +225,7 @@ "walletdb/bdb", "wtxmgr" ] - revision = "41f0e0145c5a4d1b90105dcccf0cbe5d22372eed" + revision = "ccd48bb4720f2baeaa795cac81264f6ced2da4c7" [[projects]] branch = "master" @@ -359,6 +359,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "25f631ecffcdb9df5a8675cd1fee102ee89a39a64dd8a467667a257d35f816e0" + inputs-digest = "7edcc418d8e2f483001838e05dc77e3fe613273418f8ddf7efd5cee6df68c6a8" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 66c079061..8fe9087fc 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -64,7 +64,7 @@ [[constraint]] name = "github.com/roasbeef/btcwallet" - revision = "41f0e0145c5a4d1b90105dcccf0cbe5d22372eed" + revision = "ccd48bb4720f2baeaa795cac81264f6ced2da4c7" [[constraint]] name = "github.com/tv42/zbase32"