diff --git a/bchain/coins/blockchain.go b/bchain/coins/blockchain.go index ddfa1a80..26a5347e 100644 --- a/bchain/coins/blockchain.go +++ b/bchain/coins/blockchain.go @@ -36,6 +36,7 @@ import ( type blockChainFactory func(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) +// BlockChainFactories is a map of constructors of coin RPC interfaces var BlockChainFactories = make(map[string]blockChainFactory) func init() { diff --git a/bchain/coins/btc/bitcoinrpc.go b/bchain/coins/btc/bitcoinrpc.go index b4a748b6..a2fc0f11 100644 --- a/bchain/coins/btc/bitcoinrpc.go +++ b/bchain/coins/btc/bitcoinrpc.go @@ -857,6 +857,7 @@ func safeDecodeResponse(body io.ReadCloser, res interface{}) (err error) { return json.Unmarshal(data, &res) } +// Call calls Backend RPC interface, using RPCMarshaler interface to marshall the request func (b *BitcoinRPC) Call(req interface{}, res interface{}) error { httpData, err := b.RPCMarshaler.Marshal(req) if err != nil { diff --git a/bchain/coins/btc/codec.go b/bchain/coins/btc/codec.go index 21284a9e..10cff649 100644 --- a/bchain/coins/btc/codec.go +++ b/bchain/coins/btc/codec.go @@ -6,12 +6,15 @@ import ( "reflect" ) +// RPCMarshaler is used for marshalling requests to Bitcoin Type RPC interfaces type RPCMarshaler interface { Marshal(v interface{}) ([]byte, error) } +// JSONMarshalerV2 is used for marshalling requests to newer Bitcoin Type RPC interfaces type JSONMarshalerV2 struct{} +// Marshal converts struct passed by parameter to JSON func (JSONMarshalerV2) Marshal(v interface{}) ([]byte, error) { d, err := json.Marshal(v) if err != nil { @@ -20,10 +23,13 @@ func (JSONMarshalerV2) Marshal(v interface{}) ([]byte, error) { return d, nil } -var InvalidValue = errors.New("Invalid value to marshal") +// ErrInvalidValue is error returned by JSONMarshalerV1.Marshal if the passed structure contains invalid value +var ErrInvalidValue = errors.New("Invalid value to marshal") +// JSONMarshalerV1 is used for marshalling requests to legacy Bitcoin Type RPC interfaces type JSONMarshalerV1 struct{} +// Marshal converts struct passed by parameter to JSON func (JSONMarshalerV1) Marshal(v interface{}) ([]byte, error) { u := cmdUntypedParams{} @@ -50,7 +56,7 @@ func (JSONMarshalerV1) Marshal(v interface{}) ([]byte, error) { f := v.FieldByName("Method") if !f.IsValid() || f.Kind() != reflect.String { - return nil, InvalidValue + return nil, ErrInvalidValue } u.Method = f.String() @@ -69,7 +75,7 @@ func (JSONMarshalerV1) Marshal(v interface{}) ([]byte, error) { arr[i] = f.Field(i).Interface() } default: - return nil, InvalidValue + return nil, ErrInvalidValue } u.Params = arr } diff --git a/bchain/coins/btg/bgoldparser_test.go b/bchain/coins/btg/bgoldparser_test.go index cff75f78..4f316137 100644 --- a/bchain/coins/btg/bgoldparser_test.go +++ b/bchain/coins/btg/bgoldparser_test.go @@ -28,7 +28,7 @@ type testBlock struct { } var testParseBlockTxs = map[int]testBlock{ - 104000: testBlock{ + 104000: { size: 15776, time: 1295705889, txs: []string{ @@ -81,7 +81,7 @@ var testParseBlockTxs = map[int]testBlock{ "33ad36d79d63b575c7532c516f16b19541f5c637caf7073beb7ddf604c3f39cc", }, }, - 532144: testBlock{ + 532144: { size: 12198, time: 1528372417, txs: []string{ diff --git a/bchain/coins/dogecoin/dogecoinparser_test.go b/bchain/coins/dogecoin/dogecoinparser_test.go index bf7f08e1..5738290a 100644 --- a/bchain/coins/dogecoin/dogecoinparser_test.go +++ b/bchain/coins/dogecoin/dogecoinparser_test.go @@ -276,7 +276,7 @@ type testBlock struct { var testParseBlockTxs = map[int]testBlock{ // block without auxpow - 12345: testBlock{ + 12345: { size: 8582, time: 1387104223, txs: []string{ @@ -314,7 +314,7 @@ var testParseBlockTxs = map[int]testBlock{ }, }, // 1st block with auxpow - 371337: testBlock{ + 371337: { size: 1704, time: 1410464577, txs: []string{ @@ -327,7 +327,7 @@ var testParseBlockTxs = map[int]testBlock{ }, }, // block with auxpow - 567890: testBlock{ + 567890: { size: 3833, time: 1422855443, txs: []string{ @@ -343,7 +343,7 @@ var testParseBlockTxs = map[int]testBlock{ }, }, // recent block - 2264125: testBlock{ + 2264125: { size: 8531, time: 1529099968, txs: []string{ diff --git a/bchain/coins/eth/erc20_test.go b/bchain/coins/eth/erc20_test.go index 60e19f9b..324ec3c3 100644 --- a/bchain/coins/eth/erc20_test.go +++ b/bchain/coins/eth/erc20_test.go @@ -21,7 +21,7 @@ func TestErc20_erc20GetTransfersFromLog(t *testing.T) { { name: "1", args: []*rpcLog{ - &rpcLog{ + { Address: "0x76a45e8976499ab9ae223cc584019341d5a84e96", Topics: []string{ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", @@ -43,7 +43,7 @@ func TestErc20_erc20GetTransfersFromLog(t *testing.T) { { name: "2", args: []*rpcLog{ - &rpcLog{ // Transfer + { // Transfer Address: "0x0d0f936ee4c93e25944694d6c121de94d9760f11", Topics: []string{ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", @@ -52,7 +52,7 @@ func TestErc20_erc20GetTransfersFromLog(t *testing.T) { }, Data: "0x0000000000000000000000000000000000000000000000006a8313d60b1f606b", }, - &rpcLog{ // Transfer + { // Transfer Address: "0xc778417e063141139fce010982780140aa0cd5ab", Topics: []string{ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", @@ -61,7 +61,7 @@ func TestErc20_erc20GetTransfersFromLog(t *testing.T) { }, Data: "0x000000000000000000000000000000000000000000000000000308fd0e798ac0", }, - &rpcLog{ // not Transfer + { // not Transfer Address: "0x479cc461fecd078f766ecc58533d6f69580cf3ac", Topics: []string{ "0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3", @@ -71,7 +71,7 @@ func TestErc20_erc20GetTransfersFromLog(t *testing.T) { }, Data: "0x0000000000000000000000004bda106325c335df99eab7fe363cac8a0ba2a24d0000000000000", }, - &rpcLog{ // not Transfer + { // not Transfer Address: "0x0d0f936ee4c93e25944694d6c121de94d9760f11", Topics: []string{ "0x0d0b9391970d9a25552f37d436d2aae2925e2bfe1b2a923754bada030c498cb3", diff --git a/bchain/coins/eth/ethparser_test.go b/bchain/coins/eth/ethparser_test.go index 7012d061..c23cd78b 100644 --- a/bchain/coins/eth/ethparser_test.go +++ b/bchain/coins/eth/ethparser_test.go @@ -142,7 +142,7 @@ func init() { GasUsed: "0xcb39", Status: "0x1", Logs: []*rpcLog{ - &rpcLog{ + { Address: "0x4af4114f73d1c1c903ac9e0361b379d1291808a2", Data: "0x00000000000000000000000000000000000000000000021e19e0c9bab2400000", Topics: []string{ diff --git a/bchain/coins/eth/ethrpc.go b/bchain/coins/eth/ethrpc.go index e33f2ab2..2a34c077 100644 --- a/bchain/coins/eth/ethrpc.go +++ b/bchain/coins/eth/ethrpc.go @@ -507,6 +507,9 @@ func (b *EthereumRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) { return nil, err } bch, err := b.ethHeaderToBlockHeader(&head) + if err != nil { + return nil, err + } return &bchain.BlockInfo{ BlockHeader: *bch, Difficulty: json.Number(head.Difficulty), diff --git a/bchain/coins/koto/kotoparser_test.go b/bchain/coins/koto/kotoparser_test.go index 45caae2a..d71075da 100644 --- a/bchain/coins/koto/kotoparser_test.go +++ b/bchain/coins/koto/kotoparser_test.go @@ -29,8 +29,7 @@ func init() { Time: 1525189571, Txid: "97f944e3558cc784f4013b3753ce9570fe4707893eda724b12eb4c69686113a6", LockTime: 0, - Vin: []bchain.Vin{ - }, + Vin: []bchain.Vin{}, Vout: []bchain.Vout{ { ValueSat: *big.NewInt(9800018691), diff --git a/bchain/coins/namecoin/namecoinparser_test.go b/bchain/coins/namecoin/namecoinparser_test.go index b46a0173..60e22652 100644 --- a/bchain/coins/namecoin/namecoinparser_test.go +++ b/bchain/coins/namecoin/namecoinparser_test.go @@ -69,7 +69,7 @@ type testBlock struct { } var testParseBlockTxs = map[int]testBlock{ - 40000: testBlock{ + 40000: { size: 1385, time: 1327728573, txs: []string{ diff --git a/bchain/coins/pivx/pivxparser.go b/bchain/coins/pivx/pivxparser.go index 2cf12055..1ac00be5 100644 --- a/bchain/coins/pivx/pivxparser.go +++ b/bchain/coins/pivx/pivxparser.go @@ -11,11 +11,12 @@ import ( "encoding/json" "math/big" + "github.com/martinboehm/btcd/blockchain" + "github.com/juju/errors" "github.com/martinboehm/btcd/wire" "github.com/martinboehm/btcutil/chaincfg" - "github.com/juju/errors" ) const ( @@ -37,7 +38,7 @@ func init() { // PivXParser handle type PivXParser struct { *btc.BitcoinParser - baseparser *bchain.BaseParser + baseparser *bchain.BaseParser BitcoinOutputScriptToAddressesFunc btc.OutputScriptToAddressesFunc } @@ -73,9 +74,9 @@ func (p *PivXParser) ParseBlock(b []byte) (*bchain.Block, error) { return nil, errors.Annotatef(err, "Deserialize") } - if (h.Version > 3) { + if h.Version > 3 { // Skip past AccumulatorCheckpoint which was added in pivx block version 4 - _, err = r.Seek(32, io.SeekCurrent) + r.Seek(32, io.SeekCurrent) } err = utils.DecodeTransactions(r, 0, wire.WitnessEncoding, &w) @@ -125,7 +126,7 @@ func (p *PivXParser) TxFromMsgTx(t *wire.MsgTx, parseAddresses bool) bchain.Tx { for i, in := range t.TxIn { // extra check to not confuse Tx with single OP_ZEROCOINSPEND input as a coinbase Tx - if (!isZeroCoinSpendScript(in.SignatureScript) && blockchain.IsCoinBaseTx(t)) { + if !isZeroCoinSpendScript(in.SignatureScript) && blockchain.IsCoinBaseTx(t) { vin[i] = bchain.Vin{ Coinbase: hex.EncodeToString(in.SignatureScript), Sequence: in.Sequence, @@ -198,7 +199,7 @@ func (p *PivXParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) { } vout.JsonValue = "" - if(vout.ScriptPubKey.Addresses == nil) { + if vout.ScriptPubKey.Addresses == nil { vout.ScriptPubKey.Addresses = []string{} } } @@ -206,16 +207,15 @@ func (p *PivXParser) ParseTxFromJson(msg json.RawMessage) (*bchain.Tx, error) { return &tx, nil } - // outputScriptToAddresses converts ScriptPubKey to bitcoin addresses func (p *PivXParser) outputScriptToAddresses(script []byte) ([]string, bool, error) { - if (isZeroCoinSpendScript(script) || isZeroCoinMintScript(script)) { + if isZeroCoinSpendScript(script) || isZeroCoinMintScript(script) { hexScript := hex.EncodeToString(script) anonAddr := "Anonymous " + hexScript return []string{anonAddr}, false, nil } - rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script) + rv, s, _ := p.BitcoinOutputScriptToAddressesFunc(script) return rv, s, nil } @@ -223,7 +223,7 @@ func (p *PivXParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain if len(tx.Vin) > input { scriptHex := tx.Vin[input].ScriptSig.Hex - if(scriptHex != "") { + if scriptHex != "" { script, _ := hex.DecodeString(scriptHex) return script } @@ -237,7 +237,7 @@ func (p *PivXParser) GetAddrDescForUnknownInput(tx *bchain.Tx, input int) bchain func isZeroCoinMintScript(signatureScript []byte) bool { OP_ZEROCOINMINT := byte(0xc1) - if (len(signatureScript) > 1 && signatureScript[0] == OP_ZEROCOINMINT) { + if len(signatureScript) > 1 && signatureScript[0] == OP_ZEROCOINMINT { return true } @@ -248,7 +248,7 @@ func isZeroCoinMintScript(signatureScript []byte) bool { func isZeroCoinSpendScript(signatureScript []byte) bool { OP_ZEROCOINSPEND := byte(0xc2) - if (len(signatureScript) >= 100 && signatureScript[0] == OP_ZEROCOINSPEND) { + if len(signatureScript) >= 100 && signatureScript[0] == OP_ZEROCOINSPEND { return true } diff --git a/bchain/coins/pivx/pivxparser_test.go b/bchain/coins/pivx/pivxparser_test.go index 896e8819..ac7c767f 100644 --- a/bchain/coins/pivx/pivxparser_test.go +++ b/bchain/coins/pivx/pivxparser_test.go @@ -5,15 +5,15 @@ package pivx import ( "blockbook/bchain" "blockbook/bchain/coins/btc" + "bytes" "encoding/hex" + "fmt" + "io/ioutil" "math/big" "os" + "path/filepath" "reflect" "testing" - "path/filepath" - "fmt" - "bytes" - "io/ioutil" "github.com/martinboehm/btcutil/chaincfg" ) @@ -135,9 +135,9 @@ var ( func init() { testTx1 = bchain.Tx{ - Hex: "010000000188557c816acd0a61579b701278c7dde85ea25d57877f9dbc65d3b2df2feacc42320000006b483045022100f5d0e98d064d5256852e420a4a3779527fb182c5edbfecf6143fc70eeba8eeef02202f0b2445185fbf846cca07c56c317733a9a4e46f960615f541da7aa27c33cfa201210251c5555ff3c684aebfca92f5329e2f660da54856299da067060a1bcf5e8fae73ffffffff03000000000000000000f06832fa0100000023210251c5555ff3c684aebfca92f5329e2f660da54856299da067060a1bcf5e8fae73aca038370e000000001976a914b4aa56c103b398f875bb8d15c3bb4136aa62725f88ac00000000", - Txid: "52b116d26f7c8b633c284f8998a431e106d837c0c5888f9ea5273d36c4556bec", - LockTime: 0, + Hex: "010000000188557c816acd0a61579b701278c7dde85ea25d57877f9dbc65d3b2df2feacc42320000006b483045022100f5d0e98d064d5256852e420a4a3779527fb182c5edbfecf6143fc70eeba8eeef02202f0b2445185fbf846cca07c56c317733a9a4e46f960615f541da7aa27c33cfa201210251c5555ff3c684aebfca92f5329e2f660da54856299da067060a1bcf5e8fae73ffffffff03000000000000000000f06832fa0100000023210251c5555ff3c684aebfca92f5329e2f660da54856299da067060a1bcf5e8fae73aca038370e000000001976a914b4aa56c103b398f875bb8d15c3bb4136aa62725f88ac00000000", + Txid: "52b116d26f7c8b633c284f8998a431e106d837c0c5888f9ea5273d36c4556bec", + LockTime: 0, Vin: []bchain.Vin{ { ScriptSig: bchain.ScriptSig{ @@ -178,13 +178,13 @@ func init() { }, }, Blocktime: 1504351235, - Time: 1504351235, + Time: 1504351235, } testTx2 = bchain.Tx{ - Hex: "0100000001b56a0fe242a8de7dcbb58ae1009e44e7f2ec25a65eeb8b815cf53393309741ca0100000049483045022100cc208a59341dca98207ec8a4a42c014d435192694a77c69d40e51467800c0a0802205ac1782d4ecefa260b33340d92c2ab2396b43c1073a67b4180aa8ef2aede8af801ffffffff0200e876481700000087c10281004c816f5ce1eeda911203319a256e8560c8dbfd47b569ff32c27559bda78854e63e49718ce43036e5120dce357b5630afd745d399f91e675a921adbb45224a6661656217fcfe32396fb25609b724646759116326964f2f1f7ddb7c340dc24be2b75a0a9dc05ca2fdf805c03c7a04d972456beb82a51de73d8842b39a553919dfa5d8e003e98dab7210000001976a914dda91c0396050d660f9c0e38f78064486bbfcb2c88ac00000000", - Txid: "599d5d797a4575eb25e1c291c0e7630bd6fdc0e6ec5fa9b14147f929a4e41bf2", - LockTime: 0, + Hex: "0100000001b56a0fe242a8de7dcbb58ae1009e44e7f2ec25a65eeb8b815cf53393309741ca0100000049483045022100cc208a59341dca98207ec8a4a42c014d435192694a77c69d40e51467800c0a0802205ac1782d4ecefa260b33340d92c2ab2396b43c1073a67b4180aa8ef2aede8af801ffffffff0200e876481700000087c10281004c816f5ce1eeda911203319a256e8560c8dbfd47b569ff32c27559bda78854e63e49718ce43036e5120dce357b5630afd745d399f91e675a921adbb45224a6661656217fcfe32396fb25609b724646759116326964f2f1f7ddb7c340dc24be2b75a0a9dc05ca2fdf805c03c7a04d972456beb82a51de73d8842b39a553919dfa5d8e003e98dab7210000001976a914dda91c0396050d660f9c0e38f78064486bbfcb2c88ac00000000", + Txid: "599d5d797a4575eb25e1c291c0e7630bd6fdc0e6ec5fa9b14147f929a4e41bf2", + LockTime: 0, Vin: []bchain.Vin{ { ScriptSig: bchain.ScriptSig{ @@ -215,13 +215,13 @@ func init() { }, }, Blocktime: 1508218269, - Time: 1508218269, + Time: 1508218269, } testTx3 = bchain.Tx{ - Hex: "01000000010000000000000000000000000000000000000000000000000000000000000000fffffffffd8a55c2028655e8030000dc8ce67bfe1851477371a9ac40b6ae0cb8571f6e2d5285855288f6079f1ce7239ee8c85f465b1820058b79554f41af297e9caf95ce0084b7c35dea0b95e15a2fb9f8e62c5427c1c36120cbc1fc11ff344909079335209c6b84b45a9211cac960f64e9432ba5eb6e4ecb2068223dfe3d85b345da17bf374f9140c9577c148bcc431c9ec3c7d13bd2363dba821381ed9fa0614416261e88330b3e74c40e6561310eab3f26f092e72f3cab761f373d02680dfb52937bd9515be242f6573754f8f665523cce3bd606c8ad190954f8181577fd0efe7cc64b711d03774958df4a5211e44870302056557777951d7ff8c002161a6a59e979f05469cb31770bd484be6525625359979220eb7e9912e835065fb00fd000216aefbae3525166510814d1636b76b0d48ea3cd54a3a17b136a84340989d75f74ff952966830e4c0d59daa006d5a7190978270ee9475a0778afaf002cdce7efdbfad630f72838b5c4a3b538ba61b94bbd9e353437a50725af5f16fbcbf36bb34e7da54e5c24dfc90b545f95c973877bfadc2703ee10585a1fc1c97d7377bf41c9cbcd5a313849a3c826e7c1301083694e6dc05f46899a901ab4a8d7f6b3600df280157fbef6eca4c28fc610957a42a9acf7c4d7f9846ab6b9b04fa6abb5fefc168d45f10078b97d4d6a39638588a1c19e1bfc472657861a902c2d52cd32fb0463746f649ae88bc0602dbf35816fbccf91dc249be809160cbc7f8b6702d6cc5b81fdebd283231f40758afc899f6fecedc51dc4e5d09cb8961092220541f75ddad45680ea92b4ee78c29f58c197a68420bbb25b450c72d02d7249f7facf9927378620eb36fbf9b4ccbcb55627eb9cf905b4a4c65fcb77a537f642f10901b6e94afa37e4afb0d6d91194454a9c2dd8ef8fe4316f8594c7822a7d58cab09657cf501da5be5a44f947bb957b71e4291a7fc60cd5cef9f0676f7c89123c7ff1ae2e6dc001b6f19785534e207fed2bade8597541b13714284f67d6986bc616ef1b0adbe415242fee85acbf482a6a48b3f142ef7ddb5dd1c97a4b0c53c6ac7aceb8c042d9c9ada1bc986b8c276d07fbf8512a3dae6a357fc02b167eb85000040e8693e45fd000200e23abd27b258f9827ed58545a507bd465e255e1156610da314bf7df68b6b55129df84c7b19e362751ebb9beba10790c9c26c5ddc7f087258d81b006c0d2e92be0178bf5edf6e78e89f73cd97746afbb2551dbc97eafe32ae62e7f9ebcd14ad69faf74d2011d16f2c50775f4f499c87c3c50d9d5d486394c2a7f462675d2a4885493332e0610a78fc0c8b08eda42e4bfe93b8c7f80a911a7992a1deb7cca2e40933e1559815688d4e5ae5e58d706bc513e5108449a8393928b5b77ae73cb03fe212c6375b6c5e61fce9db16360a147e7f7fcd49e05a99711d4d5799be77f7e39d9d1397388d6680d4931b48798ce013256a586781ba80168bae63bed4d150b64a73f7d0ab0c9ebb42f5d4db40eeee303783249af4bbf334c660f8c084ed9a2e5fff8be230940a4a08b59418676ef005192365e4e67757288791ce4992b903a31537596cf6dad0be2af2418a6b9cc2c33e99d874168f6a29df189a869b16eb5d24400ab30e4eca9274114d646aaaa8bad45832b6c0ded2bfa698939a8af9d0af380d2afc58966afe0f45483ecad0f114b904cc2fafcf470dd4fb8f193795e8afc3243b4c946d5eac82babac6feaf4ff10bf53acdf8347fb9fb7a5ac4efcf160f0a7ef3576f439404a3078ea092f46f408a955c965344023d847fad7374cf145cadbc8348eeb2c5aa999ebeeb8a5548bb14e0092b184caee354020c19d66cb213fd0002729bdb186c4c494e17fd6effe29cbe7fbc539caca738d54f9ffc6e52a35a27da134192e2f7f4ee2a86af281b78670e662677e97a1ef008f10f42349fa83bf7841d88b1a457d38164a383ae9c6b974137d58216f22d135d30b9d6e7a74952a7e905f385141f4df088415d704cc3b03b2cd600cb5507f8ea1b53fc0e73031a3946c0d6269f020c9c26a3be3bfdcd37f8d3b9fd42538ebd72029fa0bd8eb57a4fe6769e1b43b5d5d7be311e12e52ee9dad67aa988dedc80ad616d7540381993d9de91a7fac6d08e4414254b9d1d72940fec032833a6b1a5605f4b62c47a86d70dbec5ec913d0a613d438cad385fedf24566bf79edd17238e55421520b95772224623f145100e663b2ba20161784f688afcf07a900ade1d48060d21be9ba9297697891c2584cb99a44868efbdf65178592ecfbadc92f4883662d6b21b7f266eb21815c7401b8e7da061e3258dd685f8cf65f2c2e407c913f85d053b05f6f92ed1299186632ddcf175ccbbc933044bdac5e10916917dea1146f77a8ba4b4fc8ce260b5deed395ecae9b81baa6b385fecca5d2982041c131ce02a1dec517ad2d459434aa3a514e7a4c6c1362401b1ab62b4c89bd7705d5072e0be5250c60c2fdd946bc73050d3b8bcfaa73165eee3660063f279e824d1e15f87307a40bc9e1ccc0f7d7087ba84fe9275742455241b61d3687d23eb9d7a9cc18072ed8be1492db46a454464090750eb0a393499a73d23f4c552ec6ae425a77f97d4285a7f287066b2198bfaa99073da6f4009755e59838e48cd5fe692962b87da3ea7e14b34b352fb2a4673eaaaa594a094610bd0cc566acafc21891b7b0c2470bbb338f579231e01c064f275c5ac9c2748cc50e7f2e36f2768d2a59c22d14b6b9a431f7772e716731c55ccbf086187fb15bd07a5af3040d468d4088ba9e6383f1df6dead9384758f2da81ee96370d9055ce5a0db56bbdccb57ab490f42a01e083b61c5157b3c00e2011dda865c7294cdfd2be5c03a1a36a4deda9cf03b500fd0101b3c97046a717a2f38fe2265185f4411cc68cce6cf9885a7a8fe6292eb9e3eca69fb6249774a8c82b888d22d5fcdd549846c3ebcf054c6bf07aa4d6b1c0d4d9bd8e16501f65373ceda249e9c760848fc86ea92fae7142d211c8bb4a287c91eb08cef7678ef1f445f76f81d464eb1d29ce5c6d6286d73d49cd0ef03b65376eb146a3ff69a487ec90b53c11cce613a586f22cd56fd34df6f7ad64fa3c68a6ae5c9dad99d4a3d2b0974ea1f627be4f0153c7b5fe472d0c562556c4d8d1c7c592bea45bb7886b74f8639f9487b2f6aebf4848b5718f2ce65b8f5a4efcf140e2857bc9c503f0058f9b6af16e75f2d530fbba8979f81569e6cc0bc04a54e30de4e03a9300fd00019b881d73a78b86771d41c0c2a9ebdb3899727f33d2d4d81dd27b6a00b4c7db265999b8442800750abde7cd97be0c691ed06b5d40da115546d90d4803e82c61d43eb5e2bc684adcf180be47660870921fdedb2ce43f33564541fc0debe175c6c49bdfb51378902dc709594b9b7d34d0af70b67c3c608aeb5185e78c1c39cc3080b71a36115f623a07a4e1a3e1f3e17b6f9f695f1a1acd9dd1319d0a0d67b337e64f720e5168c09196244bc71b083f302e042be19b6aa1f8ad61755f4883c3a1ae615252b884ca3cca5e18a023ad6725f08f9e0ffd60e7a73ccd29afc910d60dc99c06f5953c3e398ef615fca45f6a83f8a0be653d31a7e1a1666cc7334d9cad51fd00016f7efa38c8f9f478a6ea1217d8be9b7f0b01c5d1fa483c26e403eb3a4875aeebbd0e7eb8aab8472a5bd80e8be38df13526042952f813b71f8aeb4a2281bfe5e5d9ba70f7e4c9f477706da922899f505dd172e260ce5f008b59c0590d498ac50810e9a38d35f1a2ea4e9ce8f77e46d0b5604dbf94629cfb8b65453a0295eeca9d992365309b7956481a8c5080510a09183bd3358fb26933e15c83fe2ca6d186e631d72889a09464f5dafdc8a93dd100329071e52beb522bef1af0fbae0516ad3b02011e19a2b2924791b3f22679b78039c8356c0e6676e2451487f056d0cff064f55a992afba08f59af7606a809394772ff85c4c40673dd54eb30020c6a5cde3cfd0001ecbc47845e4a1f3c05c4e9d0a47e5e8996326f48d7ee1bd0e432c5f33fecf8a94feaf03f2da65525bbcb119c7928456c28f31c183a21af1acfcd9615669cf47a077f861f694bfc1831f1a71ab66540906c62b85274f63abcc53a37e3fccdc8563ca2153818b6b796473848d765d1c81d4e6f78ef8fce804184e04664c5c6af7c3abe4d92aac3f6ea99b84a3e53a7bf7679c26dc96804ac9e1443b054e3c55fe89315106a14646d06b84122861ac0ac27fe64fbee3c9807b0264a90eb9602187f4df2cc0c62b025ba70bbb30a7e43d533f32546d2e6f97537bc2d623a7f545676a37cb511614037d77fe21a35ce4a2275e7ea1d85b7bc19e477c61033f5effe7fa5d8ff48e2873845157b7a29718e6692704a9d864301fa254798555172c6277cce4ed5aebdff9c27a1bb37071677c16da15d6c1547c5b708e1988eba68befff1f1743342ad7cb89ec8731b567198953d965ef6e395d38b410a326ef3e262937c763179f22a076d17f848dc4e36be38d838d5788f121d771f23209a0d50fb3d016c5cbc47cec31069f7d22bd78691662d8b609932b9533bf828e213e5ed4e61f2b80f05acbc00fda0017bdc59c8a6a23d261cdf1dd10e91523503c3375a803755c29b6a84bac626708b7db937ed39f4053b5c6376b3988fc9388cc64dc07466c67704a32b703d5dd86d8fb8597cc2ff7ca190044c66638028855f29fdf2a0943c64125e3ad2487de6928bc34088957eb32d843613e6b588a91cbfd8c37c24ba655739cefdb203bc3061ff93498160c7e949823b0947c68b6c51dcdf038c538f50413266680ee23817ed9cb840e0094f6fd2277012aa2c6f82b086242e6332a4e00bb9c12c153dfea9340e681e63d72551f8830b2bb2587e5937685252928894bf90bfa174f62bf7ccd43415a094bb4142fcfe639c62f6eda0e4d7ee033f49f51eaa6a35b0f7f400992d8367a275e9d018a547430083c41a35ef543bb92e159efad39c5b84d127bc68dd581c308afd5f81654ffcdb3317dd6e21d5251916214e873c83b6ac197dbac6c1b93d79b9dd5da090be204b9765fdcf662c9296295610e42a0570a1503dd67c44e17936946f3a6ce61f82b13cf00a0b47d06f2cd28651b6af32ffc58304593d5ce81159ccc952ed980f93182fb468ebccadae4dab4565d64a5bcb3aec7a09d681fd24016a4905a3a143e4d61b16898fddbb0f9d7602ce865716b62ae4f9a37e2f6ab89de930e066db6f4a8667ccc4e79e7ac760642c33e5f24266540c9b4fbadda4c0aa1b6a74d02bdf2324ebf9598d8ba918438de1e3343be0b057925bdd52304581ef621fd085dc55cf8b45d605cb0b60047bfa935c2968d554753a615e75f24086b4e40508ecdeb411ed26c007a1110f3e73f504d7fdefb275cbb59cf9cd68bf4784b8845467fac90275f3bbcc2c14a87fbbd7d111441d6ba0833b9045db43975317aee170242b291f8b07254d395472bd4b67db7576bcf2460bf0c182f745a6cbbec3f680b7c6e0a85308bc3af8af3302355757a77a2fe3f98350e4ea1b3074e37a638c630d529141843583ba4b802e089e0a7ecaeeeb42079e072e64fa5251782cbc67ba9d46e4c7f502d44a06e5212d09f4dc5bef1f1dfc376d4a042f608b860971c44caeb3735cd57e19401314af06a73180918af7693ec5204b3f858806e6919af05a1a8c6daea2ee3f08fd2401c082f09f7042a7a0b6b484287050a15f5d8c1011c200d42eb51aff5a484fe1de9feaa264ed3022b6f5b1b54a4a316d3d7e2635210ad83e2d3c497bed46f417ed22804682529b034925dc785a2d74361d1db395d1681d71bc1b0635908ec3e92f850577f35912fe5c173402e6e2ed8003c64a57bb65a2013014a3ce14ccc725f733a50457a696396cac0a551cdda03a2ec81597031feaddd801a9bceaeb5f862a4cdb3eda06dc317a96b29c27d78dd977cc6f25d62bb967814fd1d7e87c675042522c904fadf1cff80289374de8f98df511de975011d877058aa7ea9cdf186ccfa5cfa5258e581ee7ee73e16dcfaa82f079a16c95e6ca4f49c037b2423c12006b549a0b80c5dc9b93685fd2a4bda99e5aea74eafe9d28149e94adc538198d459c7a9a45a1fd24011c69aaa26aa94954fb7dfae2d63eac286b4979e7d513eac8144a7bccc34fb298b7c556a82e7450bf590f1ae658c474ac7c12b3fccaec877b6bdd11fd9655a27b7b69b922b1629a24a8d7f81a6827dd22cbab62d121f5cf96d59be904022360c5bf04d2435c52541ea4d7f932e19fc471a0afb38f2e84668d974c57c963346d790a670a699ff53b5557def1ce9650a8624bb2065f9ce99d6b5361a1b39629040fc897a5d0a07816618840f86601508e90198de64d7091a8bda406009948fa9ebbf2f56adc66e057ab23152504438062867c4237ce2b99c020add16bf66a0c06a072c4fabd9b9fd1146b73366535d934328188798ccc18ad37d30e06a39b8e14468d32820d912359323b7d474dbf507e894a448a4e921f70d1fb4d4ac03b178ae157814004fda0015c202cbc492bde212955236761fcad7de9ec8932946b5352f6c35a242d39b354a1f96a706bcb84174a5b11a7e51cf0adeec9c1e5c88a3f8f32ca81977db668650734398e6feb45cbe0ed5c5d8f77cfa67b78f8c7c856629e6731321126d12ebe70603fe28d4281f5c9165e60749bc8688d7ff3cd509d958dcd1ac7b068a3548af0a3e20b984bf4406a6c6d55c674bc83240757e3a0515bbb626b6b6b863fa7029c5043d67ebcd531601d39b8b6b7e507a176216a264fb80f574d7a6a587d5ebba7c355007630fc49127368f6b672bd12fba956db75f189bd438f5034badc04d396b04a021608a7888434eefffd082efb0c3196698d1b015b42eb6f5a2123c085d37841c0cd6c7a1d77c55d61d76426758cdadcad3d7b1037b5d94c29962d4fe218c9f98c89ecdd9a50a48bc534bc167d536e11906bf594876aea01683269255701b705ac454b250abd45d10f4f8b881c6f4a360014b450132d750099100e15c70ef65ab0eeea340604f3c7b3eb3c51292036a6cc2843989ea418631fb595ca9d7e23a88a3a7d0a8dd5ec1212fc786dcf7107214d5c4d3f2cffffe2b1fbef09816033fdb616b9318b80b32f045ec1bec678dd1500480154ccdd87365d602f0126b57015784abee6fdb9b7f22ba135cb882dfa738baa17233fa53c68d35e4102f185c07a1310b710ff2d63db7238d36487ab504e64e239d0641137cd75cb282e831621f101663efb2f9de2520049c0d08a7c965477fef9d575ba31e101faaea20f96e40046132cd3aa981e8f360cb6a9bac68844d07c7d1741e56b104f634fa1a0c31d64ca4526de4f1754effc40aa04b9dfdb6f53ef77540d66fc9d0a4058fb46518433a1467a71873a03600b47c81e0d452cc44728e3a625235c84f7f62d753faf91fdfa1aea056925168616516e5c4357a7e82c94127fe8a4626c868bb7bcc13a0422e15e31c82935a4e1b9cac496bb456d1318e2e3e704627f1dbe646f5f1590283833193cb03f28e00f5020fbd43c5fdc39fd35498cf4fb7471417e814974331500d8e4ec8af34af39b457d20843d897d0e015456600325ef702c1bdfa7bbb3f2e7a74dcd8fd77beb3df4022320108d0f48a7a9b2a32e1587eb01094e20cb7c002d3de08f481a1d7cdc6b3f9c7c20185bc7ee65a12aa6003a58b83aa90d90baef64c7d324c662ea5138fbb4bd063720f8f9111e20def54a90755537e44fd506737cf1fcc4d0b320bef16eedbd750f8b2002e3af2f477e9d2912e50e4f03e43742c19e6e94c1ccf84ab04f0eff342bfc1020a544d7e745fa08a740418aa6da398bf10870a860427dcdbb857b6b41cec8e1342059eabb84637e61530039918cca60b860ef24c0df9e586b7ee9ce89336d5f1f7a210f0385ce2ad9f83a8534ab0325a42495a9cc4cd4774c9e8910bbf4e7192c2e98001fc3aae0957bc822f2aca9be874e1493a0dbad2ceaf959996060a2bc1781c23520cd178b0cfdcaa92929b9daef0c4dc752225792454327bc351b63765208972820203954fb6c5f5fa020f757c1bac415fec7e1bad3b7c19a93ba5ba53dc12f5ffc6720e7572f4709fdb74cdf2dbbf50a7bec9c10ee302cc2c5dd878bd109d1c87bfe3e20883ea4bb25deffe4bed0029e066230311cd71a4beafa608d43d615652cf9c146204c98a01cfce1f0ab321105b2f2659d375f691e2f6cd9eb821adc512718acdd6120d5f64f7950ad04508b36baeadb52228ed3a1139512125834c1f449b2a9613d67204550d2bb9a9333d567b6c2ab154f1fb4bde51d4b5c50307989ed07100095485720109b0b89090c8a2fb0c51f3f9ca1eab0e36b4d9200396e7958523e57b705d11b209195a60cb9f034fced26b3336b0c49872fa13d56cc410f59463e4f312c93423d20f52bbd6ff9d724752b5ecdb148a47e86c1378111d76e77a2f4434816e325c62920510cf87382f2a4c1417203c4e17511170ac616fca2caa49b521dd721a8183f1120ee7ab5b0de3332ec1fb81c2d5baaf0509eda6de26147b081866c2a9aaa3435882011ce790ec01637ff533a68dfd8fa22733bd7e4fefe18a5796e9bfaf996adf54b20509ea869f679c1ae8b074619487fedad28874cf9c93d01003e9dd0df2f45b66b20380577ba031eb78adb2c71bedc8154056b157ae0d01203c19d7df420a424f71521d04f8ed62e7175b7e70d7f92dafff586e5a60be02901f9f67e97374bcecfe7830020c6be51acd068843922b23415a1c7b39f4846da7584a496483a36612dc295968c204e43611bdc897913427fae390deb145024077c5808238d960f93c62a62f70e6520e2f6ace6ca1e8b6b73dc2fc3c43f3d1e740f1c663e3e0ff9415b2d282e1d377420bf6b145630d553e8c6e40d84626f01964e3d6befc33ac284263ee2c35d76003721a9d895ebe788be0a6988027ae6b33a26bee33016d8f4b64255f320d34deba4900020c8bbe181b5482c9352b9d607eed48dde4a2759d765bc2da53cbc1c03d68da30a20818a0a41e03fcaf75f38766bfa81738f0c8ec2fabed7142e998e7b55e014300120b61bcde758db04bc126bc67a1c87b9fb4f8eb2c3958b9e4106306508e2b22c5220cec0548ab3977bd4bbc802483f0c2ce3b1d6dae43bc0f8c79167e4a76ee6f7522007f74fab71a89f6b94bdc8b5128de93ef2be214d04fbb8ac8c2832e1f2ea6371213c26fe406e69b2060b60c6d0eb7759fe85f19cb2288344239f2a398f04b2b8900020689efa2cc2baa15ce24852b1f71d08200fb1f2ab8e10be0c4db8c8263a85032220b1f2737db4e6e55370ce004319e7c5e137f3567bc4d5603e4ed1f5c636db6a6b206dc3dc994eb2ed126f1a76892117b18b24028dce73ab6d35924ec69df9bc361121fb6e92175d959528d8326cafddb4ee94fb9ffc2d9c8a413898f14cec99d4299a0020349eb2d5c10d69df3bfc41f99d6cafff21ce69323637565e1cefa60173ad0d78201818225053a5e2d51745c5002281935d4dca8ad82ff76c5ca2dee6be84fb767021e8d31f169295ce6052584692ed9e4da87e637ca0b52455f216d5036c55d45c85002100c51c6bcf08c0a3926b2be93b47d0ed8955386d369ab8d6849957efb23904a20020b4b64e35cfcbde2461db3ce57292361aa30d136b0e7bbc766f4aa3ab4a72b66821e802f9eb8168e002b64b2b7ccdaba46e73e5c422dda18311788b19eec7af5782002062e41e97d6c8f4c6ac4c0f978f6f8488c92a51eb5793ad109abee4d6c009256920009f7f1755459578897b027bc2b282466aa1d3b9b0983fe4cdf51c9090548d5120760bc9a32ab7facf7f3c1d1aea1b6cab28bb65276e269472cb24ded949256c0121ea8ed0306eb39aeefdd4f57e98d25cef9ee6288a915cc96207ddff402bc2fe81002138caf88bb834204209e39e6c9430ceda0294f1253f8be81917370a34eb28149200203aa2e1582961cbf9b22333ed51aa4512dddeb3cef2e4fdc3644dfa5145366618203a0ac51cf2e1a98ea343e9ca5fbead275516bc20e9bc421e967be939026677682164c2810712d79c82e75116a7e173af1208478e8ab6763c7ee58551b4f323f78200209943e959b9228e61e5def9b2ea18de1688565a2c49dd98f1c0a7d43e81a6800820c4ab26007fa076e1ecd22f104a860f10b22b1ce2ad1229eaa2cf204815f7246e204090f4ac3d42b2793d83aa79103e0d0488ae1297109a6f47bcb29d8c8b6d383d2058ceed8e9f61bca997b4fef220feba451f5401ff7186d1348aab81d7951b5e1d2014994a638981db8c53c2a364c744009050975bfc23fe7bcfc5c8c36b3df0bc2120e26863332f579b931156f0559025f7f96a4d72a9fd108fbfd5c29a71b13df72520e84680238c100c359efc6bfbb7e97d3ddd4d1d24ef3fe8a5208a714580e9aa552108c2aed76de2cc32cfd4d0fa02eea4be069e74da620ba09461e63b5127cf9d8e0020626acd1bbc9c821f30e5ad5b682272cc4b87a9e05323357a367e170ebdae283c20ff8a87793a1dd9996598d50333ace7856916b2add797fb4cd7cb7fdf24245a642165e43a1aa272317475fddbb370cb547766ee44842ab25d83cef370304213eb8b002121565e2ca6c09a263cfcd17fed20fb6aa06e1e798276a5f0ca8cc16dfc5c309600203e8034276a6f2379f8374e8fbc709a692b2dfdf271c0726c4f890282a40eec2920fa335f7d0543267026ecca4424d15cd07755568dc93c6557f850031098fa55572036cea7284ab1abcbe3c7a83ea779392fec2fd8c1524f95c5bb481c67e300600521444c7d18c458aa1e62e5efc656b27d6396c2fc9299befe67e3eef807711f948c0020829cf5a6319d4467027f9057dfa46e1de952a01233e068f7fd18cdadf9a3534820b622a3b592686cde240a056840080c5116582bf166f4655ace84b34145a78b0520fddc9480245d4ac36034ada99a182ada449373ea0fe16557c3c6d9d55b21942720e59aec0bc8b52c1ea0179ef1bece2bf3275164c8b14ef9528a1335dbe13def6620af95305f745778a84f8405956a82816f366957d31e74af5509ff0b7f7dee737221424e7838cbff036afc7e59ba67c6add560e242a1772ff069a31e5e320c08428e0020f4855f5217b4a20c250b75c69d494ec450321911f9d7841e489d43b3739eca792010f35a5fc740eccaa7fa007f33b028089dbb8bf539f560df19627d5bdba6fe3f213c35de64e6b2d64bdb6ba246a5c9b6a91047e35240db65c383a1be9210b7838c0050fd000184213201216f3c4d446f38e3733348efdc4a4dfd79febf41f03567e0ec2b5a8acb93639951dc506d8649ca6d1926a25b4f19549d2b3700cff07c100c47c456ae23df2e60e27f8822c427e2de12038e00293de92621bc4a27d104803e48d076e3ffcf8c31f549fe9f95c6b9233be396cbd3c557efdfca11fdd91397e52f35d6b3a2130fd46ae505dc66bc987d8e93689d41be09a1df024af243b843e18f298de218ab87e557c782bd20648dc4fd4a5e654f1e9fa59626663adb179f51fec2f5534f2f4929ceaccd34d6928ca3d42fcc5efa32490428abc3296147147eabffda85ec2be06be4512448aabe1829d0219902fe1e9cd2bef29a8f89ed8eb1966b89bffd00015e46cc825850532b9bd9d584441772b3963c554af1424ffa9ccc7d7de55dbef9456a3fbf7b4be985d185eb898e166ba646daa12cca359ea77bb7a59e45e8a6cf2708c16b5ccacb708839eef2ee4b5b6597ba3c5899c9f5214bdace3a521fe36cd39b77952d1bcc81f9e5edfae34f1cce40369b7ee492701351d34e231af8a3768cc158a796e900d0cac462f5204da5cde3abcf561ad60f91fc8951e4fb37166ce37261649f840aa51e6ff9be749d72f1f5b5ae3349f14d572860dcf36aa4655788b8cf5108dff7a4e231d2e2a3bec0a159a1e16c9bb38c4052439f2b6b1a62addf739772a1d51057c89751f7518a3b1cd7b37c4ff7d621a54bca5b3936b137c3fd0001b4a09bfe02e11668f8f6204cb9ffa9817ec412c820b6b394ce2cc3a12546ebc5052ec1c74876f3de8fa22e19158198cd04c1336a792ea47e63c2bf4e85dbe7460501606c97409a906dae4e7ad84517a7955793365ca4f49b5f6829efe61f52069fa19cb30ce0a74d415898e7e134ed8c4106cc9d6be32577e9a024b9dfd8129cb5efb1ef282802fe0066aa41e587ac9ee20d6416010e1b0772a44b6d6d1eb4ddb32b80b288952b26323bbec16614c227e4599cf721484443f56571c7b048e58fe48b1786c44e4979e105196eb9b5803795b8aa3d3e3a8f85e10abeb0f7b43b9a62dbd0905af620309ef74f281f39b241c4b4c109ca7e0ec55b13eef8ee0544c820b833fcfd65b4a897458cb9aa376c6bdccf1032e099598452130bd38d28096322fd0001b6c9b1d3d60a49cdf61f9031694f9f790a4e0118ae39cce789df472c13bba207d101410af89ba4b2a88cff5eb09e53593bfdc69a4e2706633a45c77a6d8f4baff22c7e5e6b32278dbfe97100271b1fd1e64463fa6a757c4cf4b19954d1d363494664750fcde0f0b6e35f9e0f08f4fb1e438669f78b10e800943840b15541a31c3090437364159681974adba314bcac37e6cb3ec97c3d8e0cd52241a4c162787c199a256599b97e488b8a75a46d2c3d8af1951ddac43b0d338e739deed1ba26a8616f04d124244f365573b602697aab0b427a8f26f1a22de77c563cda13fc03a030817a837c497732c6108eac62102641176f62d5b8e73d0e27e17586d6e2c2c3fd0001ca7e381637425fa77d95f92b8b491ea1398f53d763a6ce32a2b2ff972ab74bd377723dde5302c487fcf7eac93b089457761ca341f143b7c5aeb51b33cf103f2f4ce4c282bc5bb8c7290c2a9dcc82fce3dcd9669f660872f602de46e869fccdd99c85c06d1d7bc9af4e93502e4ffc385b9641df8f21a25a14b8e4cf99cca023da529f8689d86418c37dbe3d4116e08069f3d08b9c952f4e2164dada9e62908d57cc68b264df8fcbfe449c21cae576adb8169a97294a6bbd369a58654cd182c8403080b3a5a916c107d7271311a291841f3e35e065d48f6023ec4118a3a88d417507ae86b6c74e6ced02c768e0f879844e22862c357a9fe22574e30c179e2243e62192455f24a5c214eba9746d2a8f6a47625b53e5e62bcecade179907fccb08e4b200218a8694fa7fa94c9c174c8e1525bb14dd946981e66b1c02178cde818615e3b6910021fca3cbe539842d405545a71cdacd7a795b6f6fd1c1095497ee8ee215d5cb8eca002039f76b8f7067cd9cf8bde783c8ea6edee7638113ec6729093749c2cc0c15d13c2091ecd1eb4b171326a6a26d764e72e09160ff2112e577149bc7c24e6c0907324421cdebc7f780b73aef4358c6f7e5c9a78ee95dce81c4c1bbbf570cde3c43ff5ca00021c6955241d2f09d2e90e33601fc139d0603919a1011ea7ee89f0e5d53727c45a3002037be468901ac92d7c3481ad63d364a93e2daa023bbcfaf4f6fa40cc54974de19209178cde568ebc660a7698cdd7f83d5932364eb8ac144e62cdc045a00ccda5201fd0001a3347a2cd4b1f5337653554be5fea273a5bf0292c0fd60908c6e699802079912372435166baf2f71b35ec0e00a714e9f7c10096d0f39a65f66f220057f369ce7c8221dddd00e90604f9de897ebf9f06afd41814b57350ca2d7ff7e08f60c94dc1aa087b7975936832a7050ae4a14b47b1986e70d61223cdc37dfeabc5e4212a869d953450202c9c12db23f8819faad59252173ac11c54020fd7324b4d39673befd2b585437affe9398e7967772d408c6db860ec512f94d02b0cbe9c9d414bb4be4b08c3a420a549efaedaa6f0aed7c74044785b611b2d65abfa33374748adb690a54c8719131e9dda9d46afc9dd09c8abc498d6de657920642d3d47a55f17fd3fd000189cc7f3247c6ede0becf1ec89f5d92142d25a713e037454409ccd146dc18c58319550275149342c690f00b1e060db34bf6ea34473c661ff9f32a40214a4715bbcea59a9ad6ff976e43b325135ca16377be53be39255f9e45ab4b3652d629a30500f9e37671d56952b215628ef42c1e49046476e9a760041003742751b158aa85c4e95f70e267d2631491c60cf09a174816890a2dcc2f8a38f296389c3ea66a6d577301297c242a6b9ca7465d8282f2e72e7673f9e1f1c8f470949c970854134de397c08c06d5d21fc487b2b9529c901c052e838a087f15b802d081e869cbb311efed66ba31c17c73cce1e0fc32d58d35e54bc5524776ee3f45d7b8f81fdad4d621b95f023b2202f5d7c814aa89c27b5e0bf5cd64b444c711c2e1c4b805af4fd58300208214f56ae87b268fd16d6df77efaa715fccd1fb1e6298c1c4f7a4f18d39c2f75fd00013fddc975fb72a66d5a7f3ba6df9c1ff55c7abb5a8f08317c6b346875e850223d87d72d71d9b17c11bdbe6eca34b521fe98dc8d31bef6fcfacec74e5c4a6c5f00ac769363df4720e17c3b687a42f29e8edbc20184dc9274d8546368e3fd2408bb68dd224b73a1487c10f4e29b0d8b9823f7c73db26ed16baa4c5d75b162cb5a97caff3cc8957072902538e0e698fad2e90b471777c5e8d90e5cd313933c2f3b30e49b6cf7ae7dcc09ab2e5e464601f093973d99c0815c3ea587d1803b4ca1d9bcc2ac20cb818f95d9239fbbe62c3356ba41f7dc9d2232f6221447fc4858bbf11ee382bfc639d9101943d958a59ff9b81007508c0879c4bf16885bcd6eb2383898fd00018ef6741f57def1a55a42b565ebe0451f0208762da626acaf0cbaac6d9bcec14e22c15660c2a0c5a23b27c445ad968a7e6b2daab11463040eb50799858b7a5063965f947234beb0d42fe1c2dc7bdce7fcda3de1bae384b62e798995eba4836dbee41a8a4de269c026018a22687ad77985d049bda1d39b79528b320ad3d22d893c547b4dc4acb57fac4e0603468beafdf54408ddb7d4c5db0cf14162d0d735b3fad10888f0048035481e5713b846761838504a36c1f956b072b46f11c7c6fc86c766c36fc7dfd5068855335b96162d8b299e3cd21060fed730310d7748c3d16f228b0eea1f37f5eee5453e3a19ebe1e60e4f2834d3338bf1887969de57ef02a1bbfd0001b50e09d8212707f0035a46513208bdba63a5d1fd7a7ea88e181d7a3de81b8afb4ea4b0428eff67c04b27372d73896fd9df443aa9b2a42cdb8665271bb1c54833454504dbc80645bc02366dc998d334b2723bbf5ee1e139265c107db84774b4884f26b57818d39d05b47d5bdab25778965a0627a96ec303c743ba57c0d32d0337a6d3dbe982284109eb0a7976221816cf3fa7f2e3cf739f30be83f253564af7f411358d9c5340fa5578120c48b617c088d9a3d0811a575bb1e96b746e25312ff6d87b9705c04a10123c7606b4c5d6658244121310ce3f1d062250b57ee51e35e0d7b787d38206fd9d26c70ef94f337cc7108ae8ffddf5fa314e6c4e5e1538fbb0fd000192fa78c12fea8a45902ac86e2878e8327b5f4c2ad9bec7d6167bc5590df49cbddda4d4d652f6f087f2ddc7a2813aa5b33048adc5f900eb4acd983bc86ea7b89f630b647a9ef42ab1bb6484ebc20989603144912ffd80158aff7e7d40a1a76489afb21f5f711ecc3ba613868a7aac4f28f2cd5440dfd064c4874d4e398a4718e10de8f7055e452271f01b27544af7035aed32259796962035d7bc37ef843cdccfacf969a1659e354ec27efda8756b09c0bf855f4fbf7598273154b3f517303b6169bdbe4ede890a90d3b34c917311027afeaca7dcd27158b04886dfd81803594292cdb3dbb77ad3a8df97df63095fd28c275b956cc61faddf770608b898d74ca9fd000138b1c34ee04d01368d9cd8ec4d70b97633951ada508c031470cb4cfb15a62426276c7442e7679f926e93325e287ab9ed87446c144be02e559dd076c9c5e1d6a6a7de45438076b1bd7b9ff5a821070877c1d9626925c1f47838e56bb6982b54fb9e131741bab5ea38aabbe4003538c454980dc3be9a436283edc32a3de0321f114ad32cf34e860ca36f18d476980910e564af57da498cd16d08af8b4d4696a9962adeb298d7af4c8c4ad9cb911d80a2115e833f0856833232f92f94cc9c3a6a14270f4c30ada671bacc9aa35bcd3c945dacbb01f4556ebac4e52adf8790dd49fa799584d227ab95afd2da9e67e5642a90e54fc8b693a07384577d04cc40861cc9fd00012c7977632367de82810aecc22a1a802a1aeb6ac54a4a79d8e61606a6eb72effe1abd74a0a18ef83709355e77cef5666f16d94c0d710f5ae3973bb26d07c0a436aebca4d156d42952cc8cedca94162225b5b4780cf47a6426757758957dcf2f638ead2312e67e140ee8c380949c0885c68b396517ba122d90a0ed184564bbe67bf1d0115c77857fbb29945ea00d8e809c295295494dc8cca091d900837b60b31a79bacfae59fe638ee8a2208942e27f605c452be3a4a43cf21e8e0f78e7cc20ffd2c546a0bbcc404b415e4eae2c7b9c2f9121bc741a6f8c5c28c9df3e0169cd86809f5e235ce17fb625f913f94b75b360f9097b625a5305040c55a4057dc4a68efd0001d594cafd37d880576656265ebb737602d6f3b9d0feb3147d8c1f6e1514ca64e3ee046bea5e6892d8db9c094198fb3f697ae6fc880075bbd461e9aab7425ac3a7fad84071b170739e7815d0c76d2ae7fefb718ec132b32a842c58cde33605488043aad9c5df6e58401994a38dc50779e348cd18582ca74aaadcce6df39b221d4235a88000eb2e3efed6744abd0b68836d56ff5d9ec973be549d52a195195725caf3b8cb683da9b96868d35727bf4b74dcbee838d9c39a33d15609fde1c2b345974a93c030952f52da7ac20b8c26b340fd9c08f56b97ccce21004af28ebe4946a91682f9738085cdd9a53e160346cfcf396cfb59465d114c600d9571634aa3c880fd00016c714ccc93e995491adb6718e9ef69fb2cc36044d9e6b73130606b9c845dfdc56e9518a120237f58fb6f2546bec6f47ea6a11f3d898baa47682fe3f537542fe9f6d3679398064a48a3ef8abc92e89eea84c6d8ca956b3c40e9b82b2a496bb1230f8789fc7b0befc061468049d416aca3fb41d4272304a728322684f9ca6125b91dea97bbbba8c83045b5ce8b3110d429d65998b3aed570ecfedd176e98a91eb3410cd501ba52d176bd2c8d05e94acc8f352b3cbe12adefb82d34e174765ef1197f8a93fd4e03c98967ddd0332733e5aa0ce87f63aff78a2b44d10ac63c1549d9a9c6808b743e6f785173924d736bc0890f2e68c1df72b0fb1632bd4679e87690fd0001e736a64f64d58af8d43f0980d29ba57dccea56ff13040270c926a2703401b83859a94d6cbf4cd62109053c9e6ddd1cc61ac649ebb1243037adec455891642de8f43b57afe96cb63736e3e7d735bbeec8d1dc2c698f37f0bcd85bd84cc6b7e25eab500c03f1c62ec730c24208e2df2830d32842277d9e5c9416a91217cbdad60d6a77a7127b09e7463354266a1130d1f04de9041f0f83d41246766027700fa9a02d10d2b0fcb0bd534d22ed38278ce177bbc1c429c09030f105a67db70011d3eb24754bbb31f8a6a98bde215f635409e4cb8c3d769efdd7f1561976bd29876c8a11a130cbb8e3fdf15fd9ad0329852dffd794f499345c3fee09eee21997a5c8a021b993d7cea74a8935b42df2d55606a8841b1a4a8fc0321701d5de9bce1dd1bee100fd00016e510cf2b787c67956990655ca7ba97aaea25163317e7ebfbcf2681b29b0b821aedb8f9b2e309d37f660ac7169dc8234a7e7e4d01e79164eb75f28d284c52ea3d7edff718aa96db6b0b6781366ab985d202823130ca53c2a8e5186fc18862348952e967b1a3e3636517c3e3c48d8fe5e4ef1d5e230ab584964c888c61393ee3d6e34c50446b86e68ebfd048ac86065f9a9c4bbfc2474027b612dcafbbb0416f12d3d856a96557529d1144a852ade77f50f600ecf3c0e00296576eb49a0b211baaa815cea78e1b7a56a1c698ff58488378722f58fdb1ab8bb0063654a8de8344041fddd04be1b4b2b1944ce9d1ebda667caf9ca00e5c2de892a9063a449edd8c1fd00017140014f19e2474e1cc4b40a5a8033f3ddfd960ef33c7e35432deabd85a5b2c18a27b85477c9e6fbb2d8a5e6c686078009b1f7868768fbb5f569ae3429fd64e49cb3a62f32fada09059982a03a20494bd2fd2caa75a01b3ecdbc32acbbd648905d56cd2aefc714af1c24bd6e8f06b1ddbb85e9882ddf8f0e67c654402bfe2e0d9ba404bb3da2d58305184949ce513b3784c3234b39d25e0c6df741683750cb46d7856e67a0d45f4839b5305f9965808d41cbcfb2ad3ad18cdba6744eab0148dd0c1d5e687b6e76bdb9408766b57297be6fdbcf9d7e3e6918c194ef32bb776b5ab85f3a6a164baf866d93ecc3acaefbac43a9fa267bc623cc136ad712b00d788efd00016d3db1d97d5d429249f5cd6dc35f61d0b1b44f1e433cd5e01d28afa6cd6718fc1432b77e8eb6418b0a4b6fcc6707cd3d5c6661cf57b3b73b78feae7c89e25eff2ec1d465be91a18b2f3bc4311919f410cfafe8ae8a06b4b947f9b6fd8ac17453c2f558dfd67f71829be66250d40c3aad6e3ff52d1c0c455e7a4f646445405cf1ad45ba65392bb622a770ab0f5a57e73d32d98ee49d73ac7dde7dad9b9c8e1da9d1e6aef0f9cd120bc1d2cbc5ad819190b758be385f2b0dd736184382af8aa419ac7d734881ab4728ea927b6655b7d3faa4a1e14caf6d38cc706a940bff9c9021e4b6c3ce516d0257deda35d2ac4e0423f01ac849b19b919b773a58f34a06c6b1fd0001464885fd950d292d5aaa6155164216521d2113d795d9aff389771e8f39ff3d96afb5e2359fc52aa6d6cbc3921a7a21e6f3fab62e748337e2cd212456e2b2f52dcb352a75902ac6fdcce93dcf027138be788aad5e09490bbce637751cfd5bda9ec540d7daa92eed7b27ff1bf66585fbe3b39db3de9dd386ecd7671f2395522c1c9006908afd04fe68d88194cbbc3216377cfc27c4fce55c8e558ebc4943cbb477a1172aa8b344c08d6fb853e64ff0f986b7f3e7cc3b2c3d8b2abbc43e08eff15787bfd6a9a8f98b207d8e2530c0c37a37ffcec2fecbd726b4b845ff48a44c1ec7031e4e663ec0042663ff81b9a7fe7d599695737511a685148fce0c3eb01513bb20ffe083f86d11f3c552efeba225a93eb8ea756f45c2e49a4dd08467b79a14000220fd4b0ae4d4c5a165ab75af08922366e89721ba7ee52751e0b3e64017787b9445fd0001d0a8ddbc130bbf7bcd20bdbc8728e812a45cdbe602dcea5826f753b94e1220cf698c1212464a17ed846b29db82b1cf5373241d4117b07a8b7d279d4e8511d22c47be22291e9ab56454becf533b771e5e602542d07828952d5ef900e2548739d57cbb6254c667bc50a0f97c11b7f3dc1624111f9d32cb0d85ac4106b41cd6d82db7aea1135334220163c190744b6daefa456f69c331facf9083af360db6f2a2c80c423357c8fd1bc28fcfd42db69d733efa9ecdff9df079bde1b73a63ee74e5af5c75b67a4824a72466e17b501f6057a68efc19627d115f19fbcb48c0e0889857f0d9191db5875ad6d336adfbf7f09989b2aecfe868c2efc2cc64af46d07c44b9fd000151620fcd4091a3d3e78e8a1f1b5ac9ae8bdd3760320ed9bea2e1b237110d7747e9894704336b958fc92eb200f06507cb56a12f202a8b098bcec5b7b6941dccc18d2bd968538185dbfdbb6ea61eaee22aa8ad24d73df0adfcfafaec181fda3626479710bc19835a5aa7a3b9afd8166b89f5aee8d52589059eda61f19f6319335dfac7765a9a9e22cce0fb3236eeba6ce250ea0b7cfc4a021ca3c88859f556dc1137349a7ad5a628bc47267ad91ff86174a2fe74e3ab298ae8917d6a57a916f00b16bc0f3584b12b0d63141a20b1ed54c6551c6dfa5647783dd9acc68ed75044faf6745161c1ee4abcd9969ff9e01f14791de7d0c8e44e77a5b249e2da833ad3bbfd000119884821e74482b639ec1f8484eb6199a01d6e0a3606e25527d7a9fdbdabaad9f378a9aab04a153b1003d520d03f25a9e41c82504ad6de9fa6cda30a3ee1128c35f49d469a79b3c190ab0fab92d9977478c7ddabb6a66f291b58756e040892f44ebf6c8d0ba3cdf5d9335c8b05b0d34a8f4e832c54979274f5d4554af2d05aec3d51a3cbe03282c9c104f664fc39863c3a23396e762a5a8b5ba18b3c84f0f49f8b7cb6f627905a4fec65e5ab41e868561dba5cc8bcaa8c201d613eb678342aaba5e5d44f7ad7a58810129aaea2e6bb9850ef022e54a50b18e5fbbb76b93f050c31d279e66cd51a29c42591b18db05e88283e52070e6eeffd8fa447bce2f22eb921b2e3f53f38bb201511b9e1d5bbf22bf9e23be137543e34d81a0b194f373dbaa600fd00010ef2d9c59966c760260612842d16526b4352a5f05de655fd0bf50546be1d893d90f4b8264488467880be2c4d7f3c577e6b68335f1e0764fdb16d6fc44fc5bc2c1660798e6b31bdcafbd33a9edb44e48dc37306abe9ea761cd2077e977a6d5b92aff3cdc33f644f47d90fa9a4b172faf29e264c9d55d27cc4e7b7e5e891adb566d172207406ac400348c386e74716a518cfde36169e4cbd8d3093c8d85b99e54474fb7c7ebec5a3beb18b664b953f4d9037041c45738e87c53d55eb92fe862a78627a8f4f3f8f3ef01102b8df05c9c1d81da85e36bff90943e0dd93efc00edbec664fe16f03c8e79d3e105803c50a606f9812d3717921477e224efc9c38604e932116d048938c5e50af925d722ada7f78de5fb1020ef09d45e001364d0ac87ea4b800fd00015a2d2be1965546e9ffe759719faf9960648c9183812a7db83a24b0ea52bc26e3774ac36fcef82756ad386332d49551a147e87ca68fedb289b965a4088b3de6506378af1f858c1c995313e189684bbd3e484499dd7a26097ee6e89ff1d0b6d4c6c03917c53a95d9fd1b6f9a8e59e1687506a5499adea9c1bbf2f63b14207daebf64c8bd5742bec97f6364560cb3d687f8a1ce12a197e87df8b23eff607c97849672fcd5803b43bc8b6dc2090d7b99299248007a3207621c0b40e6fcecc3f68b2888f5abc842a44e6f019391449a7356f9e2637c77612b342fe61e76b307ffb780f529c6c84a6e6ad8d7553021070499e85542cd288a543bb0d318b7abca62c48721047951dd48307113449db6a3f997999f421c62b4524e5baebffef1ed21a6a1a800fd0001c4594030b3c64f25c491e6a5ab25b959438c11265e0fb2e5b2c58e3d59c86d642aff89f4e5137f08ee4871df4098a5748795d596baeadd2db0b006e02822ae2c5f6a93c5281b82a7d60f8c390a264d293f1769d55a5b1f78f0f65f7694477ca79ec16677993d5b6606298171df85a7a8c9bc74a2438618d2aeb384de706b797758dd418b2b5d59dff089f7d4f7f21a8390a3a707c08ea4a238682670a0d80297ba68febea9c4c5afccc241d9f95aa77366880ccf891174b33d95f462839d2820451611e8453d981a703595e8fc73df0a4963c1baab591b7f3dbbbf62b50dc7bbfeb05ec2ecdb1a63d06ec20c4311451b4129a08b94049263e180411ce7b8b7b120a96a6184af4c9ac706b2fb01d6389d94cc4e3930925a5b2bdac9e96dbfa42a78fd0001cb6e8b1c0da834c4fc0d797fc3521eda3ddacade8a4ecfeb518a2e2e8a234d2f6901a7eb4d117404328c70a5c24f36236e88eb1dd19a7e9cf4ec7582f472da053e283dc193d70bc71867d2a348521a860fccebe0b45958f1b5919cb833d79802640b7665b7ec45135b24108eac8a882121b6e6734dcd327b506a434cea9298e6067c36457858e3c18d88a320ce33cc3861f5329bc1f9a8f4af57caf2c134051b12dbb58e309d7bfe9028c3b9b4179759095fa531cf20bdf18134c517ceddfb38b4d94849c3d7eae9b46c353bc43d2f8345e345f818e328875c1bdcd754b706258779c7c30592d0a4c4b5cb557eaad484d1cef2bd4d98d12e70b8fda33f3a5e8320486c47e0fc0d0e679b413041e800ed28ca862ceec23c1a937954131b960fdb3320a3e4a1a7ded3a425d38b144b090d9fb0aeb9ba631622041a702626583d41142520f6fded7e7b2408e70ac4ab0b4d23bc2571cfb9048b0bc738dfd0d6507549a451fd0001656bbe84db36e12bf3c78c07ba3f561d2c2687aaeeef2e2da17cb00f060e025a993c12551c12bd4d75c4c116d18951515f42c5628b0858d85b8afe5deb0aa14a2e33d147eb62b9a52bd4769b6a97382d6c39e5f70e727ee0c9a4684fcf9a03e7232394b4ecc6a2d32e27fe2b436b1081bcb4f3c8bc844e9cb1cf9b828bfc155a2467d506be2f89c9a36bfe2d19125fb21666ed4625cf881ffba75e67d209fde2742d5a46634019cf1f96c1e649a9dd58edbc374b9d6220bccf20055104e8ae8917537fd07f69e12e0b8200af3d924997ee33a7d1e9eb3ebba741f0edd1b59f05e1f279d0c4f7106276968fac8055088bd5f57840438a2776bb21693d9587d188fd00011ae402863053cdeb79711a4c4e7472a1559d86f89bc4daaa6865eced1126197f3c43d78ba16fb2d6508632ab4712b13c3f45d674064a51867bcba96a71b7683fa69ad337fd0c50e7927b913f025fcc47adddf1376a053280cd0fc45bbf29767b4555bbc4054a824c11dc93c3648b3e1c2ca42a5dc5f536eca084370ef65c5a6229bcac295c3fa578fc22eab793205cdc8d37fe3cbf7dc6e1a7c53ff3c7e4d226f0a0d4667bad282c625695d4a1ad88931ca894d4931b19b09c56d2f72e72f62600c97348ed8814f0841baea716d1e0d90f26f8c3932a1e66dd1e8c8e039d3e891ab7be0a887c16ea9fbf3dd7f2c7200587ef56cd0e75e8e828aedcef6198e6d6fd0001a265b258bad27b42d12a12e43a25bf566f2b77f6f0924e8e0c32f294768fd6d9f92e5a15dcc94a2067c71a1f9740700ee0e7f626d35fad2c441b176a077fe681515cb0c8613b0b43c708895c9ca5a41745ca87cc5e8d02e272a484be75cd9afc7478b98bd4c030c3dd4885c5214efbe70cf9a1f8a2616e2eadc150f979e1ca8c389b6fa288889464886bbdaee7539c6bba71ad0927e455d45db2c7371a5b15ccd8c7e7e91592e9bd057d85a18a9a9d1165a84329a6c7beab031f2819cf36a26aeaa4cbef4e7871c472b9b363a1a5d597005cb98e6828a7b6b7ae81cbd036f8d8afbc6289efacedbe51c10f27462c81525b18d119ab4527d9c6db52cde19cfdddfd000143a024d1136d92c3d0de09ce4a3837fff20ce4c4307fca87b1a09acdba6a1df122cc69dca4ec3ca89118ade730ec8959d0dd84db0eff5ab2ff71793af68a2d6bf3a301edce9cf1088046b3177c18d90f6318e2bea3a071469873d1a320d5036a6ea1375ce17113721f01852e1c436745536bba80365d2ee1060a73098f99983d18511059ecac21b84131d845bddfc589a1a4c195ee1d89ba9845c09d681a87c3fe2322cdf571b4a31756d2de38276b97ecef325f4ada73b747d78899c3f84aeec26fc9732ef5843f8b2d7af0fee0f04e01f85731eb9fde3f0a69c4c0aad09f51db5cd03db3627cce5d2a1dfe9910817efc2e53ebf9f79afaf09521a3f14980cd20d6c0a0d48152ef8efbf7a58b809f5c28186addc9690ba0857cbf2c96e395e92afd0001781c2002615bfb1b7d35b2e208a1df0bd8f95f2d639422c213683828227885660bb231058546848fd01763a1ae99e0a7a1040a0f398d8171b45ffc4a58a4439a5addbad802fe79c71a4a27fea8ed229c51d6cb26c3e21127aeccd2f0e31ff1c7d38987c95b917d4c86439a7a0d54b3985ccc3072727c654bea4d473676a45f13ac693de273581cd6f864fba7ff00f3e61cabfb689689c49849419ca1cf489cf9db2138f65c1445b74a0e0cc83e8368e6e79149e699b6e64c77c70ac5156bfa98794cd0c561732fc7e3623673e1f0ebc09de026d9745c4986d498762be6799cf99143fca5d69d04283b504c8d8e325c8811853d467b72e204417c7e35064ce7bcfd0001e42f7a528e3e1de18bdde6e2d9888886aea8ab8eb149299c32c68f6c93a19889efc05e641037687a091933cc83bfbdfac77d48a2828bac6b0625260d4b9da29b0d215d403c6d3aaaf33addeeac4d46875cbc4e3edc1a865d6fe0b6a588631188897cfd131672a8c5d098c0ff8ec5b17bcaecac1d78f83b5296408c994c1e81f93021da25ca403ab6694fb3e82ed260e88067e3edcd8cd0e70ce4c79b49962096eeb1eeb2b17be69033a338ebfadaaa1293f7fe17fb7ddce051d9eb82c84d639bab4a415353ae82dfed2996a26d184189ff1f25d3196c67f34ae50a39bdc2f711ed6468b364d1f0ea8eb29f486dc6c2f6dc59a24acf4772bd542557e9ef4b5b93fd00015ea90490404b84482136f214f4497c09a0ca87dcebecc03ac3152ae1c3e87b945f721137c7a309e1036d0e5d94c6cce38c36b1645a62c7160ca45abcfb5c165eb696154ae38684002a150ab45f1b8f1bb69b28757e2503967a1432090b6c90ce7e3671860e40e95200f8a1ac1ad927b49bdc0a66472eac7123c383ba28578b149f121ad8b1ead1e1908858a640ebebd2e1b8a4f787e5f41d573168493115448edb0de580a8c281b783afe2b62ac6ea243d021187367df9fd28f97e2ca7c8856d89c64a4c3c5e2147aea8120b4bc8b2d0b8ec5b7edeed35d24a800760e82ab19cb7363c7b2fcde6200b8e63e2b698489e9dc0bc4c8f1ba9ff68b59a7277038eb920fe94cb66b60142227c026662ddbc3dc29b373c5c805c365b245c2f69152f1e2b2007e3634d06ba18b973add33bf3e23a7175729a9442fc4213adcb0e5a52e2cc272096af7547b4220ef6335cf5fe47c75896ef2d27e58acb6d7b444b3645ad1a9370fd0001f3642f6dab0eedbdf04e554106719fde491a9bfe00e8228f250e0035f5a95782bef5680a15e6148467d4c7db9e22d9a4bc766ba884940645845b25ace95d405744929adc2c63e41e4c807e33a0d514919c09e855c9d77690be00720d83dcf2b2276e157d39b7acb3ae262e65a8a09ff49478fcd67765dd03b545d7e83bf194ee6b0c5f83c41f7c470e0a1c3f1014a7afc2b7149c01b3f1181eeee4ce8a9be47f0f7f897a05683629d6164fb882e1b67765e7560e7f5c6be76ad9902a755c6af0c455156b93f14e618f533feb9d351bb956da352b7a9d63cc5082d6f9768d80f1bb703c84be2bd75b848f06925f47e226c424c0ae8ad4293b0e9c330cdb16bbddfd000158cc2778c31d0436228349fd19e0428de5916401bbed1f3668014cc51cc6b42381c32e5a7d5ec4d194037b0544284c52e151b652e2733b17065b2a98fc1f5ff30a8acf5dc7522b64eb94a8a71526e2aff0acba058b541fa412bb5344eaae4945ace66b4f9251e842e4b52feae5ad89ae1ce3617debbb551c09c87c6e6e69b7942f1178db84dd758fcb3f63d658e3f48c1a47b725cd2e003a59b8e318950a45fd908c6c4d53d706dfcc2041c046324e3925c9ca032f62cc825f0c11c9fff3fed99f616837244c7d71b3a8d79a8d5bba3284280b59ca1d0ed044801b7d4d6148f014c8c04e8859d9c3d074a7ad77b86ea0ae39fde03fb33eda53fe5c1728cf2daafd0001991691f21883d17fbf12b24e86f0f639967240dcf120c01713ad612ce32a7b8a9c911248414d8a2b836e82c827270f60f154d5de0efb7aec5b3db3f8b9cedbcda84aedea5fd0988ed0069871fda9db5ec2a1ba0f04592048f0040599023ac01e758886daa3fdd9190bb1c8ea29898cdc711e8e8e6c4497ae95ee2e5a6730bd8388d8fa812b21c9b97af84a7cc9f790139b0005dc86efe16436e63982fe8d8ca6bc5bea86b2297a0726dab7704fdcc8a3f6c273eb0f8aa008ad1e6c4a985d7cefe05d3b24cfd195d2fae5392a48be5bd50386244fa9002f95ce18efe97be356a3c5b3990172f812987d0fa10d7fdf9afcd20e165697e3e8f1fa564d1f03010f8f20d53cbea6789dd88800af410af54c3c346483fa085c6e02c088092372ce828e2afd0001f903226d53becf91fe3ee0e556a7ddd652e179dc3c2de5d7af38f380c9916791a37e149ec620429b47e5e0c016b898ee1dc45db857c93a718daeab3167c3c336b22692da51bbf7ef1bc42cba25af0b1fa89df2adcf41535803ad6e80ff1e1f57c80514f1d091040aec55e87c4810ea31ba22e4f93a101d71e324cfb2d84e381f1a59a601ea97907013e119a24a468b27558b68de170690e71bc3c2d7361ca7f77d116b642516d9cb128a70d6bfba83b2c22420059e8c22c9f794f2e144a3a065c942d3276253013efaa88a80e3d7f3c32dc249347a6df656df62d4f9482cc8470bd1bebda925d47c5cd9a54ce81d7bda23c2d0434a98a1f73911c6172facb08a21cb1b1935a2667416f5cb810c787fac55fe8e14146721452870f27b1d5a14fcce0021600ca51450ca3b29e9ff6b388f4df5286db585d027f68fbbd1d4a95fd756318700fd0001b941fa0b95cbce10d49d29c80ac6c45bb624fbcef94b9bcc75d3593a5e11ed85488b6332f9d059e0123d5df6486dd2f57a9239d137d46f3b9c0120d391d1f06cd48c13a0b847020d0832b15162461811662eadcaa2757e2b6b2240d478e7411c7e807e09ef824ecfb3681b49aa72a3319dd310d8efd930ffa7751a222e73f198032f2dfa00e978c9542dc476ca44b161fe470a5f63759de5086a18fc92aa375c608841c6ea41ebc6fb86dea22a8987f7d9abac948d5e67a173eee3b9b90c323c4f2624f53fcaaadd79427a36f560ce6cbd99872d8119acd2173935b0331217e33ceb4a0ef314e45c1a90ad06a46948a38a00feac8f58d8780e6d15ff6e013dbe214cc25d39b2def7e68e2d5c7afd69c5d629265f750b683dd660040dd3220a2ad600209901a1f845f602ecd4f341e7b68c6787561b4f18d7819c8b319dba6836a42517216578b022ea0911e03a47f0814046cea045fa63bb506730b0b491614417df91f900fd0001ab0bc038363d54f8e9e8ebed6a498b0f989c8ee56c81720bd66f71d0d97477d0db56d4481cc0e57c2316f4bd3a6843f86e5b28152436ba23f377dac267c7bb6501666efefb705be623d0491dd42a1a5397f45b6be6ceb1e0499842914f56296a34f304320f5b623ae7e16379d89394b7057d1b92de4c913265ba231d81dbf9e4b586704803baf1cf0fd474a721bd65206df02888dd77df03c831f8433f3b2c7cf7e1211c7c85a975d129f33734fcf77c09aaf68b681da7c506e8c89ac5394589d185117b722b757e307ccf31e9ddc1b9131633bd684ad458fdef09d346566eb4df920801ec4ac019081feda518cafe1ff9f9197b1473ddb18d3349652db870e0fd00014168b6756041ac27a58e4160cdc78c2cca30e144cfac7c58d40b5521c76ae171399e4e22bd3eb5a59d0a44666cbd8d38c4983f8e2bac6fa5ee84c86adbf9679bf8631dec545667463df5fbfdd5ff2d0f6f9021a4a03510e291253bd133520d5366e3c272bf8ec41a14b15aea97c420ff263bb52dacb3c3962359312e5a4690483434ba5f592057dc449727f03768f3756c24c85814e1204d2d90cad6e656d39e7dd7b9c4bfcd103dac62415b0d64901b01278602553c149f6d64342f16757b5ca1033494395404fe1ac7ae33d796be12b0d4f986de23186ecdbdc8477a742fdc973b34b312f5984b74faa42f5f62dd4938f76f5d7ec141249902825d81ab2d88fd000193a2f7ea915b7e506459b8484c43d305deca93a84b3c313a6cea7286d485395158806c3d7f3155f3ddadbfc913cbd7673193a951b356ae208319ecf406172cfbbad940f9fb6accde0c73ea5a19037d5d8644b4de22db968851a303717f473c491465712da34aba4e5dbc31361163ae1492bb3435779569598639943640b6e14233d8888aefa72580e22091b6848592d5b2273cd2df009d614da03d0c0803b4320800094dcbaaa337fd210820e07a8deabbd595d2b59b3bee5c7a27e585a1cef44e532de83f08f3df43d68f5934ca69776b8ee8ddc42969970d64145c093d4e989cf32ba71f750cd03b5c818c33462d05c6477ec1f0ec81c48e4b119d05d31cd5fd00010b1cbcbad09df7edcebe79a913033895c66686f078402893059e4a986fb76d28e89324f5b04ead2c2aa0a05786faa1e8f66fbaf66b7ca94bf52123e6afe4dab54bc33e5860e8766031dd256edf40b294f55062e613cafac04f77e284f5097e88cd7aaf46fd28f4fc24ef1ec1aa0bebbb3da5b504e4dca8dfc13ed99e4371dea6f3bc0f78cdf6ff47548e5a426c92095da045e5ccf45f446116e2c9567ed01d62c1fd3a78c62aa359118f77705174db6a4faacaa0b6d49b4da38e42b20e9cd2ed7979a0f6da28964e0b3fb755046f0a5477dda7465e00d13c8751c36255b7f922dbfe108a14e359257ad607dd7e1c9ccf330779135714b01746a25ddd11e565c821713c8702e50956f6f6ed9c283cfdd08938c8ccf08ada04309e47fe9ddf5cf5dc00fd0001f5e2772a310c56c1343104f8f618a6408dbdd5e421e31856f271fb33329d5055c4c73e06870feb8f7b298cb9b403dd6c4e87dd2137ac84df583c58ffd627b0c52996bea39da5959ccce7968455d3b4ac512c3d552cf63f2da74d6de8e8f037eca47a715d0d9398502b287e5f1034e536a84839bac21ae9958da81fe54c67165fc650f19679c9a628b74fb40c65257dc5b50f690263f9c1eaf41c3365c0e23f91aa7ade32a352c8b88b40b2d7acabbd085185f7737be6f5a7c342e2c908e8a4f997ec949e4bfd6ca7b3da894fd4581c81141cbfc01afc3eb86bc91c304c18c1dccde49d8b61e41d922fcb02162e444dd4931a076bb072ee3a6d5cebbe8683e992fd0001197c654987867c3fa8c71ce3718a70756063be0179e55bf302daafbbdfdd5669ec38e140e3204b260b1d54373f84657101147e672120d735c179fe2dc5fdf7dbb8aadee63b867e31d9d1242e45bd23ed510dc7a6d44ea7806159895a2293c0898bfa6d0018d9864f584a59003a8d4e3a38eae3ec7c9e35d1e5985acd544547ccc1e31024f05bfd5dc07ccbf535b2e0a0a703548e355eb9d1acd8a59684ba0fb674075011c7be7cc899c30ea6c1df0dc34c9366f47743aa12991192cc836db7fd5a3b0306d6905a82e13b729038c70fd3bea01def02b93cd2e71439a9fdd5fb93da6a72436ce9f5b431b7e18c76d8173964d5a02e24195e761d888a6a2532d785fd000177fcd4e94194a3c34efea9f8f04faccbdeae9f0eb8662b0195db08e2b41a08fed52ab7060465ecebdb2eeed7a768c4f65ed7b5193151a56c752cdf97cd4c6be8daf95c16c6703ec95b6cb541506c715983be6384031685d48190e611ddbded6fa377affb759a1f289523e56761857afb3c33b68f743c59a6bf2098a2f5bf3c1c8a3d41224dd12ef247874ff5ab6257cc3e29a65a1c16f3ecc26108142d1899a340be3db55556258a348f51ef61e8e73fa9db743f08df3d31919f2d9484603f0281422c2cfbd66959dc138c2176d6e242a5a04d5b1cbd8c39ed051486869f8b0f3ecdaf42498be6016dc9d49ae52220612a32f50259fb9a8be0cab88deafd56b12024a02c37de6161be5eee8cf63c3b0d16d0bdca07ad59fa0532678b864c13bc20c87f061046d5218e768801c69818dadd24e62aa4625d5a2af09b08f9eba8efb5e29fc2977184990fcd81a0a3f896691051da425d7b99292d8ad7a3bbae5ed9503c5b761907097dd6457a5444b9c85ccc829d5901d46cd917ead52a3316f96588a7b508501be9f69c73d97e0db9d615f20e50712f377663f6c47f42d005db72b225048abeb8d6e3a60afbe21cd13d4539b7d39806952d745a7c49a552175135d840a3f9b9e9ef6ba3c46e9f4bd42f9bbde0d5d5abda8cf06538d3492aa856d8708285c0aa99567adaf6e0d4b28feec0a55e49879ac8ee966e4520e5eeae3e6b4473cb710b4213973850ea6ff0331b04ccffab2c2c3f55ff28b8bdf644e4c19982916d01e28d745302b079066c61fc0e8e1c90931f122893f7f5eb86e9111f98cf36e719129668dcc4718c52d0c4c6a1a941b939e5e744d61aa9fb1aed6eca5fe062cd109b15abfc5851ff77c026e9ba7023b298d40acb1ae9884671ff1776aedabd859f2a481eb18b963afae2e2ec41e3f3671e9dfaeab234d6aaf97249f4702e706437d8e36f517b3b227bae68b79064a3fbe999bc2d75912d970826908dc17b815ec0f030e20b24f17c527557e36695abd05f67c60475a0c74aff42b5e7fd13efc3b1c3bf5ae6e3251731ffaad110c4210c9d6d78d69d6f68cc31ca99fe783a12fca506af01e28234f01e1b30dcdccdfbe696bd5703ddbf0554c8c4863edb0f252e2a9daa54d4900d8fd6aef61b8a8f1e165eea79a3f20663b08722762f2c548e0cd10cf0d2d8e8b9239b638d02c49749d55b721a6c81d2554b51b49191518150664b7e4dbde3ae02b36ab3ec9250290c8cee6b7371e0d3c7ad64d267cf463c4c82cc5a325aa72461345c4f45c8753de23bc148527b0e982511bed9e4bcd4cc37e1e3b5089373fcbfbef9a111c96cc79e9f37d619c0d68598541f2a37ea0fd614ca310c915c0d412d2eeee8f7d71e4a250bcc60d68ab3f296a5f75d75d627e5913aedf3646f733701218878049c420ce0089ded11b087f16111e397d0f2e354f1df0a858aaf07eeb8e80002210305cf1786fa950ae9b553390d6d62e2b285ebaeb978822439e0922403f9cc7dbc473045022100b807fa7bc196a7b2d7a3000e5e1870e2ff488bfd6e2850aeaefb3c606f28379e022009c3cec446550e5cb04483404a677c4b8406d85c62cb4d714e5ca3a50aa02f2600e80300000100e87648170000001976a914dbe6d470fa9fe4d037043533eff4f80aeef0c8d288ac00000000", - Txid: "b65181decb00e684fef238776a0a129db4e1ffdfc454f6ef323e5f7a8deae6a8", - LockTime: 0, + Hex: "01000000010000000000000000000000000000000000000000000000000000000000000000fffffffffd8a55c2028655e8030000dc8ce67bfe1851477371a9ac40b6ae0cb8571f6e2d5285855288f6079f1ce7239ee8c85f465b1820058b79554f41af297e9caf95ce0084b7c35dea0b95e15a2fb9f8e62c5427c1c36120cbc1fc11ff344909079335209c6b84b45a9211cac960f64e9432ba5eb6e4ecb2068223dfe3d85b345da17bf374f9140c9577c148bcc431c9ec3c7d13bd2363dba821381ed9fa0614416261e88330b3e74c40e6561310eab3f26f092e72f3cab761f373d02680dfb52937bd9515be242f6573754f8f665523cce3bd606c8ad190954f8181577fd0efe7cc64b711d03774958df4a5211e44870302056557777951d7ff8c002161a6a59e979f05469cb31770bd484be6525625359979220eb7e9912e835065fb00fd000216aefbae3525166510814d1636b76b0d48ea3cd54a3a17b136a84340989d75f74ff952966830e4c0d59daa006d5a7190978270ee9475a0778afaf002cdce7efdbfad630f72838b5c4a3b538ba61b94bbd9e353437a50725af5f16fbcbf36bb34e7da54e5c24dfc90b545f95c973877bfadc2703ee10585a1fc1c97d7377bf41c9cbcd5a313849a3c826e7c1301083694e6dc05f46899a901ab4a8d7f6b3600df280157fbef6eca4c28fc610957a42a9acf7c4d7f9846ab6b9b04fa6abb5fefc168d45f10078b97d4d6a39638588a1c19e1bfc472657861a902c2d52cd32fb0463746f649ae88bc0602dbf35816fbccf91dc249be809160cbc7f8b6702d6cc5b81fdebd283231f40758afc899f6fecedc51dc4e5d09cb8961092220541f75ddad45680ea92b4ee78c29f58c197a68420bbb25b450c72d02d7249f7facf9927378620eb36fbf9b4ccbcb55627eb9cf905b4a4c65fcb77a537f642f10901b6e94afa37e4afb0d6d91194454a9c2dd8ef8fe4316f8594c7822a7d58cab09657cf501da5be5a44f947bb957b71e4291a7fc60cd5cef9f0676f7c89123c7ff1ae2e6dc001b6f19785534e207fed2bade8597541b13714284f67d6986bc616ef1b0adbe415242fee85acbf482a6a48b3f142ef7ddb5dd1c97a4b0c53c6ac7aceb8c042d9c9ada1bc986b8c276d07fbf8512a3dae6a357fc02b167eb85000040e8693e45fd000200e23abd27b258f9827ed58545a507bd465e255e1156610da314bf7df68b6b55129df84c7b19e362751ebb9beba10790c9c26c5ddc7f087258d81b006c0d2e92be0178bf5edf6e78e89f73cd97746afbb2551dbc97eafe32ae62e7f9ebcd14ad69faf74d2011d16f2c50775f4f499c87c3c50d9d5d486394c2a7f462675d2a4885493332e0610a78fc0c8b08eda42e4bfe93b8c7f80a911a7992a1deb7cca2e40933e1559815688d4e5ae5e58d706bc513e5108449a8393928b5b77ae73cb03fe212c6375b6c5e61fce9db16360a147e7f7fcd49e05a99711d4d5799be77f7e39d9d1397388d6680d4931b48798ce013256a586781ba80168bae63bed4d150b64a73f7d0ab0c9ebb42f5d4db40eeee303783249af4bbf334c660f8c084ed9a2e5fff8be230940a4a08b59418676ef005192365e4e67757288791ce4992b903a31537596cf6dad0be2af2418a6b9cc2c33e99d874168f6a29df189a869b16eb5d24400ab30e4eca9274114d646aaaa8bad45832b6c0ded2bfa698939a8af9d0af380d2afc58966afe0f45483ecad0f114b904cc2fafcf470dd4fb8f193795e8afc3243b4c946d5eac82babac6feaf4ff10bf53acdf8347fb9fb7a5ac4efcf160f0a7ef3576f439404a3078ea092f46f408a955c965344023d847fad7374cf145cadbc8348eeb2c5aa999ebeeb8a5548bb14e0092b184caee354020c19d66cb213fd0002729bdb186c4c494e17fd6effe29cbe7fbc539caca738d54f9ffc6e52a35a27da134192e2f7f4ee2a86af281b78670e662677e97a1ef008f10f42349fa83bf7841d88b1a457d38164a383ae9c6b974137d58216f22d135d30b9d6e7a74952a7e905f385141f4df088415d704cc3b03b2cd600cb5507f8ea1b53fc0e73031a3946c0d6269f020c9c26a3be3bfdcd37f8d3b9fd42538ebd72029fa0bd8eb57a4fe6769e1b43b5d5d7be311e12e52ee9dad67aa988dedc80ad616d7540381993d9de91a7fac6d08e4414254b9d1d72940fec032833a6b1a5605f4b62c47a86d70dbec5ec913d0a613d438cad385fedf24566bf79edd17238e55421520b95772224623f145100e663b2ba20161784f688afcf07a900ade1d48060d21be9ba9297697891c2584cb99a44868efbdf65178592ecfbadc92f4883662d6b21b7f266eb21815c7401b8e7da061e3258dd685f8cf65f2c2e407c913f85d053b05f6f92ed1299186632ddcf175ccbbc933044bdac5e10916917dea1146f77a8ba4b4fc8ce260b5deed395ecae9b81baa6b385fecca5d2982041c131ce02a1dec517ad2d459434aa3a514e7a4c6c1362401b1ab62b4c89bd7705d5072e0be5250c60c2fdd946bc73050d3b8bcfaa73165eee3660063f279e824d1e15f87307a40bc9e1ccc0f7d7087ba84fe9275742455241b61d3687d23eb9d7a9cc18072ed8be1492db46a454464090750eb0a393499a73d23f4c552ec6ae425a77f97d4285a7f287066b2198bfaa99073da6f4009755e59838e48cd5fe692962b87da3ea7e14b34b352fb2a4673eaaaa594a094610bd0cc566acafc21891b7b0c2470bbb338f579231e01c064f275c5ac9c2748cc50e7f2e36f2768d2a59c22d14b6b9a431f7772e716731c55ccbf086187fb15bd07a5af3040d468d4088ba9e6383f1df6dead9384758f2da81ee96370d9055ce5a0db56bbdccb57ab490f42a01e083b61c5157b3c00e2011dda865c7294cdfd2be5c03a1a36a4deda9cf03b500fd0101b3c97046a717a2f38fe2265185f4411cc68cce6cf9885a7a8fe6292eb9e3eca69fb6249774a8c82b888d22d5fcdd549846c3ebcf054c6bf07aa4d6b1c0d4d9bd8e16501f65373ceda249e9c760848fc86ea92fae7142d211c8bb4a287c91eb08cef7678ef1f445f76f81d464eb1d29ce5c6d6286d73d49cd0ef03b65376eb146a3ff69a487ec90b53c11cce613a586f22cd56fd34df6f7ad64fa3c68a6ae5c9dad99d4a3d2b0974ea1f627be4f0153c7b5fe472d0c562556c4d8d1c7c592bea45bb7886b74f8639f9487b2f6aebf4848b5718f2ce65b8f5a4efcf140e2857bc9c503f0058f9b6af16e75f2d530fbba8979f81569e6cc0bc04a54e30de4e03a9300fd00019b881d73a78b86771d41c0c2a9ebdb3899727f33d2d4d81dd27b6a00b4c7db265999b8442800750abde7cd97be0c691ed06b5d40da115546d90d4803e82c61d43eb5e2bc684adcf180be47660870921fdedb2ce43f33564541fc0debe175c6c49bdfb51378902dc709594b9b7d34d0af70b67c3c608aeb5185e78c1c39cc3080b71a36115f623a07a4e1a3e1f3e17b6f9f695f1a1acd9dd1319d0a0d67b337e64f720e5168c09196244bc71b083f302e042be19b6aa1f8ad61755f4883c3a1ae615252b884ca3cca5e18a023ad6725f08f9e0ffd60e7a73ccd29afc910d60dc99c06f5953c3e398ef615fca45f6a83f8a0be653d31a7e1a1666cc7334d9cad51fd00016f7efa38c8f9f478a6ea1217d8be9b7f0b01c5d1fa483c26e403eb3a4875aeebbd0e7eb8aab8472a5bd80e8be38df13526042952f813b71f8aeb4a2281bfe5e5d9ba70f7e4c9f477706da922899f505dd172e260ce5f008b59c0590d498ac50810e9a38d35f1a2ea4e9ce8f77e46d0b5604dbf94629cfb8b65453a0295eeca9d992365309b7956481a8c5080510a09183bd3358fb26933e15c83fe2ca6d186e631d72889a09464f5dafdc8a93dd100329071e52beb522bef1af0fbae0516ad3b02011e19a2b2924791b3f22679b78039c8356c0e6676e2451487f056d0cff064f55a992afba08f59af7606a809394772ff85c4c40673dd54eb30020c6a5cde3cfd0001ecbc47845e4a1f3c05c4e9d0a47e5e8996326f48d7ee1bd0e432c5f33fecf8a94feaf03f2da65525bbcb119c7928456c28f31c183a21af1acfcd9615669cf47a077f861f694bfc1831f1a71ab66540906c62b85274f63abcc53a37e3fccdc8563ca2153818b6b796473848d765d1c81d4e6f78ef8fce804184e04664c5c6af7c3abe4d92aac3f6ea99b84a3e53a7bf7679c26dc96804ac9e1443b054e3c55fe89315106a14646d06b84122861ac0ac27fe64fbee3c9807b0264a90eb9602187f4df2cc0c62b025ba70bbb30a7e43d533f32546d2e6f97537bc2d623a7f545676a37cb511614037d77fe21a35ce4a2275e7ea1d85b7bc19e477c61033f5effe7fa5d8ff48e2873845157b7a29718e6692704a9d864301fa254798555172c6277cce4ed5aebdff9c27a1bb37071677c16da15d6c1547c5b708e1988eba68befff1f1743342ad7cb89ec8731b567198953d965ef6e395d38b410a326ef3e262937c763179f22a076d17f848dc4e36be38d838d5788f121d771f23209a0d50fb3d016c5cbc47cec31069f7d22bd78691662d8b609932b9533bf828e213e5ed4e61f2b80f05acbc00fda0017bdc59c8a6a23d261cdf1dd10e91523503c3375a803755c29b6a84bac626708b7db937ed39f4053b5c6376b3988fc9388cc64dc07466c67704a32b703d5dd86d8fb8597cc2ff7ca190044c66638028855f29fdf2a0943c64125e3ad2487de6928bc34088957eb32d843613e6b588a91cbfd8c37c24ba655739cefdb203bc3061ff93498160c7e949823b0947c68b6c51dcdf038c538f50413266680ee23817ed9cb840e0094f6fd2277012aa2c6f82b086242e6332a4e00bb9c12c153dfea9340e681e63d72551f8830b2bb2587e5937685252928894bf90bfa174f62bf7ccd43415a094bb4142fcfe639c62f6eda0e4d7ee033f49f51eaa6a35b0f7f400992d8367a275e9d018a547430083c41a35ef543bb92e159efad39c5b84d127bc68dd581c308afd5f81654ffcdb3317dd6e21d5251916214e873c83b6ac197dbac6c1b93d79b9dd5da090be204b9765fdcf662c9296295610e42a0570a1503dd67c44e17936946f3a6ce61f82b13cf00a0b47d06f2cd28651b6af32ffc58304593d5ce81159ccc952ed980f93182fb468ebccadae4dab4565d64a5bcb3aec7a09d681fd24016a4905a3a143e4d61b16898fddbb0f9d7602ce865716b62ae4f9a37e2f6ab89de930e066db6f4a8667ccc4e79e7ac760642c33e5f24266540c9b4fbadda4c0aa1b6a74d02bdf2324ebf9598d8ba918438de1e3343be0b057925bdd52304581ef621fd085dc55cf8b45d605cb0b60047bfa935c2968d554753a615e75f24086b4e40508ecdeb411ed26c007a1110f3e73f504d7fdefb275cbb59cf9cd68bf4784b8845467fac90275f3bbcc2c14a87fbbd7d111441d6ba0833b9045db43975317aee170242b291f8b07254d395472bd4b67db7576bcf2460bf0c182f745a6cbbec3f680b7c6e0a85308bc3af8af3302355757a77a2fe3f98350e4ea1b3074e37a638c630d529141843583ba4b802e089e0a7ecaeeeb42079e072e64fa5251782cbc67ba9d46e4c7f502d44a06e5212d09f4dc5bef1f1dfc376d4a042f608b860971c44caeb3735cd57e19401314af06a73180918af7693ec5204b3f858806e6919af05a1a8c6daea2ee3f08fd2401c082f09f7042a7a0b6b484287050a15f5d8c1011c200d42eb51aff5a484fe1de9feaa264ed3022b6f5b1b54a4a316d3d7e2635210ad83e2d3c497bed46f417ed22804682529b034925dc785a2d74361d1db395d1681d71bc1b0635908ec3e92f850577f35912fe5c173402e6e2ed8003c64a57bb65a2013014a3ce14ccc725f733a50457a696396cac0a551cdda03a2ec81597031feaddd801a9bceaeb5f862a4cdb3eda06dc317a96b29c27d78dd977cc6f25d62bb967814fd1d7e87c675042522c904fadf1cff80289374de8f98df511de975011d877058aa7ea9cdf186ccfa5cfa5258e581ee7ee73e16dcfaa82f079a16c95e6ca4f49c037b2423c12006b549a0b80c5dc9b93685fd2a4bda99e5aea74eafe9d28149e94adc538198d459c7a9a45a1fd24011c69aaa26aa94954fb7dfae2d63eac286b4979e7d513eac8144a7bccc34fb298b7c556a82e7450bf590f1ae658c474ac7c12b3fccaec877b6bdd11fd9655a27b7b69b922b1629a24a8d7f81a6827dd22cbab62d121f5cf96d59be904022360c5bf04d2435c52541ea4d7f932e19fc471a0afb38f2e84668d974c57c963346d790a670a699ff53b5557def1ce9650a8624bb2065f9ce99d6b5361a1b39629040fc897a5d0a07816618840f86601508e90198de64d7091a8bda406009948fa9ebbf2f56adc66e057ab23152504438062867c4237ce2b99c020add16bf66a0c06a072c4fabd9b9fd1146b73366535d934328188798ccc18ad37d30e06a39b8e14468d32820d912359323b7d474dbf507e894a448a4e921f70d1fb4d4ac03b178ae157814004fda0015c202cbc492bde212955236761fcad7de9ec8932946b5352f6c35a242d39b354a1f96a706bcb84174a5b11a7e51cf0adeec9c1e5c88a3f8f32ca81977db668650734398e6feb45cbe0ed5c5d8f77cfa67b78f8c7c856629e6731321126d12ebe70603fe28d4281f5c9165e60749bc8688d7ff3cd509d958dcd1ac7b068a3548af0a3e20b984bf4406a6c6d55c674bc83240757e3a0515bbb626b6b6b863fa7029c5043d67ebcd531601d39b8b6b7e507a176216a264fb80f574d7a6a587d5ebba7c355007630fc49127368f6b672bd12fba956db75f189bd438f5034badc04d396b04a021608a7888434eefffd082efb0c3196698d1b015b42eb6f5a2123c085d37841c0cd6c7a1d77c55d61d76426758cdadcad3d7b1037b5d94c29962d4fe218c9f98c89ecdd9a50a48bc534bc167d536e11906bf594876aea01683269255701b705ac454b250abd45d10f4f8b881c6f4a360014b450132d750099100e15c70ef65ab0eeea340604f3c7b3eb3c51292036a6cc2843989ea418631fb595ca9d7e23a88a3a7d0a8dd5ec1212fc786dcf7107214d5c4d3f2cffffe2b1fbef09816033fdb616b9318b80b32f045ec1bec678dd1500480154ccdd87365d602f0126b57015784abee6fdb9b7f22ba135cb882dfa738baa17233fa53c68d35e4102f185c07a1310b710ff2d63db7238d36487ab504e64e239d0641137cd75cb282e831621f101663efb2f9de2520049c0d08a7c965477fef9d575ba31e101faaea20f96e40046132cd3aa981e8f360cb6a9bac68844d07c7d1741e56b104f634fa1a0c31d64ca4526de4f1754effc40aa04b9dfdb6f53ef77540d66fc9d0a4058fb46518433a1467a71873a03600b47c81e0d452cc44728e3a625235c84f7f62d753faf91fdfa1aea056925168616516e5c4357a7e82c94127fe8a4626c868bb7bcc13a0422e15e31c82935a4e1b9cac496bb456d1318e2e3e704627f1dbe646f5f1590283833193cb03f28e00f5020fbd43c5fdc39fd35498cf4fb7471417e814974331500d8e4ec8af34af39b457d20843d897d0e015456600325ef702c1bdfa7bbb3f2e7a74dcd8fd77beb3df4022320108d0f48a7a9b2a32e1587eb01094e20cb7c002d3de08f481a1d7cdc6b3f9c7c20185bc7ee65a12aa6003a58b83aa90d90baef64c7d324c662ea5138fbb4bd063720f8f9111e20def54a90755537e44fd506737cf1fcc4d0b320bef16eedbd750f8b2002e3af2f477e9d2912e50e4f03e43742c19e6e94c1ccf84ab04f0eff342bfc1020a544d7e745fa08a740418aa6da398bf10870a860427dcdbb857b6b41cec8e1342059eabb84637e61530039918cca60b860ef24c0df9e586b7ee9ce89336d5f1f7a210f0385ce2ad9f83a8534ab0325a42495a9cc4cd4774c9e8910bbf4e7192c2e98001fc3aae0957bc822f2aca9be874e1493a0dbad2ceaf959996060a2bc1781c23520cd178b0cfdcaa92929b9daef0c4dc752225792454327bc351b63765208972820203954fb6c5f5fa020f757c1bac415fec7e1bad3b7c19a93ba5ba53dc12f5ffc6720e7572f4709fdb74cdf2dbbf50a7bec9c10ee302cc2c5dd878bd109d1c87bfe3e20883ea4bb25deffe4bed0029e066230311cd71a4beafa608d43d615652cf9c146204c98a01cfce1f0ab321105b2f2659d375f691e2f6cd9eb821adc512718acdd6120d5f64f7950ad04508b36baeadb52228ed3a1139512125834c1f449b2a9613d67204550d2bb9a9333d567b6c2ab154f1fb4bde51d4b5c50307989ed07100095485720109b0b89090c8a2fb0c51f3f9ca1eab0e36b4d9200396e7958523e57b705d11b209195a60cb9f034fced26b3336b0c49872fa13d56cc410f59463e4f312c93423d20f52bbd6ff9d724752b5ecdb148a47e86c1378111d76e77a2f4434816e325c62920510cf87382f2a4c1417203c4e17511170ac616fca2caa49b521dd721a8183f1120ee7ab5b0de3332ec1fb81c2d5baaf0509eda6de26147b081866c2a9aaa3435882011ce790ec01637ff533a68dfd8fa22733bd7e4fefe18a5796e9bfaf996adf54b20509ea869f679c1ae8b074619487fedad28874cf9c93d01003e9dd0df2f45b66b20380577ba031eb78adb2c71bedc8154056b157ae0d01203c19d7df420a424f71521d04f8ed62e7175b7e70d7f92dafff586e5a60be02901f9f67e97374bcecfe7830020c6be51acd068843922b23415a1c7b39f4846da7584a496483a36612dc295968c204e43611bdc897913427fae390deb145024077c5808238d960f93c62a62f70e6520e2f6ace6ca1e8b6b73dc2fc3c43f3d1e740f1c663e3e0ff9415b2d282e1d377420bf6b145630d553e8c6e40d84626f01964e3d6befc33ac284263ee2c35d76003721a9d895ebe788be0a6988027ae6b33a26bee33016d8f4b64255f320d34deba4900020c8bbe181b5482c9352b9d607eed48dde4a2759d765bc2da53cbc1c03d68da30a20818a0a41e03fcaf75f38766bfa81738f0c8ec2fabed7142e998e7b55e014300120b61bcde758db04bc126bc67a1c87b9fb4f8eb2c3958b9e4106306508e2b22c5220cec0548ab3977bd4bbc802483f0c2ce3b1d6dae43bc0f8c79167e4a76ee6f7522007f74fab71a89f6b94bdc8b5128de93ef2be214d04fbb8ac8c2832e1f2ea6371213c26fe406e69b2060b60c6d0eb7759fe85f19cb2288344239f2a398f04b2b8900020689efa2cc2baa15ce24852b1f71d08200fb1f2ab8e10be0c4db8c8263a85032220b1f2737db4e6e55370ce004319e7c5e137f3567bc4d5603e4ed1f5c636db6a6b206dc3dc994eb2ed126f1a76892117b18b24028dce73ab6d35924ec69df9bc361121fb6e92175d959528d8326cafddb4ee94fb9ffc2d9c8a413898f14cec99d4299a0020349eb2d5c10d69df3bfc41f99d6cafff21ce69323637565e1cefa60173ad0d78201818225053a5e2d51745c5002281935d4dca8ad82ff76c5ca2dee6be84fb767021e8d31f169295ce6052584692ed9e4da87e637ca0b52455f216d5036c55d45c85002100c51c6bcf08c0a3926b2be93b47d0ed8955386d369ab8d6849957efb23904a20020b4b64e35cfcbde2461db3ce57292361aa30d136b0e7bbc766f4aa3ab4a72b66821e802f9eb8168e002b64b2b7ccdaba46e73e5c422dda18311788b19eec7af5782002062e41e97d6c8f4c6ac4c0f978f6f8488c92a51eb5793ad109abee4d6c009256920009f7f1755459578897b027bc2b282466aa1d3b9b0983fe4cdf51c9090548d5120760bc9a32ab7facf7f3c1d1aea1b6cab28bb65276e269472cb24ded949256c0121ea8ed0306eb39aeefdd4f57e98d25cef9ee6288a915cc96207ddff402bc2fe81002138caf88bb834204209e39e6c9430ceda0294f1253f8be81917370a34eb28149200203aa2e1582961cbf9b22333ed51aa4512dddeb3cef2e4fdc3644dfa5145366618203a0ac51cf2e1a98ea343e9ca5fbead275516bc20e9bc421e967be939026677682164c2810712d79c82e75116a7e173af1208478e8ab6763c7ee58551b4f323f78200209943e959b9228e61e5def9b2ea18de1688565a2c49dd98f1c0a7d43e81a6800820c4ab26007fa076e1ecd22f104a860f10b22b1ce2ad1229eaa2cf204815f7246e204090f4ac3d42b2793d83aa79103e0d0488ae1297109a6f47bcb29d8c8b6d383d2058ceed8e9f61bca997b4fef220feba451f5401ff7186d1348aab81d7951b5e1d2014994a638981db8c53c2a364c744009050975bfc23fe7bcfc5c8c36b3df0bc2120e26863332f579b931156f0559025f7f96a4d72a9fd108fbfd5c29a71b13df72520e84680238c100c359efc6bfbb7e97d3ddd4d1d24ef3fe8a5208a714580e9aa552108c2aed76de2cc32cfd4d0fa02eea4be069e74da620ba09461e63b5127cf9d8e0020626acd1bbc9c821f30e5ad5b682272cc4b87a9e05323357a367e170ebdae283c20ff8a87793a1dd9996598d50333ace7856916b2add797fb4cd7cb7fdf24245a642165e43a1aa272317475fddbb370cb547766ee44842ab25d83cef370304213eb8b002121565e2ca6c09a263cfcd17fed20fb6aa06e1e798276a5f0ca8cc16dfc5c309600203e8034276a6f2379f8374e8fbc709a692b2dfdf271c0726c4f890282a40eec2920fa335f7d0543267026ecca4424d15cd07755568dc93c6557f850031098fa55572036cea7284ab1abcbe3c7a83ea779392fec2fd8c1524f95c5bb481c67e300600521444c7d18c458aa1e62e5efc656b27d6396c2fc9299befe67e3eef807711f948c0020829cf5a6319d4467027f9057dfa46e1de952a01233e068f7fd18cdadf9a3534820b622a3b592686cde240a056840080c5116582bf166f4655ace84b34145a78b0520fddc9480245d4ac36034ada99a182ada449373ea0fe16557c3c6d9d55b21942720e59aec0bc8b52c1ea0179ef1bece2bf3275164c8b14ef9528a1335dbe13def6620af95305f745778a84f8405956a82816f366957d31e74af5509ff0b7f7dee737221424e7838cbff036afc7e59ba67c6add560e242a1772ff069a31e5e320c08428e0020f4855f5217b4a20c250b75c69d494ec450321911f9d7841e489d43b3739eca792010f35a5fc740eccaa7fa007f33b028089dbb8bf539f560df19627d5bdba6fe3f213c35de64e6b2d64bdb6ba246a5c9b6a91047e35240db65c383a1be9210b7838c0050fd000184213201216f3c4d446f38e3733348efdc4a4dfd79febf41f03567e0ec2b5a8acb93639951dc506d8649ca6d1926a25b4f19549d2b3700cff07c100c47c456ae23df2e60e27f8822c427e2de12038e00293de92621bc4a27d104803e48d076e3ffcf8c31f549fe9f95c6b9233be396cbd3c557efdfca11fdd91397e52f35d6b3a2130fd46ae505dc66bc987d8e93689d41be09a1df024af243b843e18f298de218ab87e557c782bd20648dc4fd4a5e654f1e9fa59626663adb179f51fec2f5534f2f4929ceaccd34d6928ca3d42fcc5efa32490428abc3296147147eabffda85ec2be06be4512448aabe1829d0219902fe1e9cd2bef29a8f89ed8eb1966b89bffd00015e46cc825850532b9bd9d584441772b3963c554af1424ffa9ccc7d7de55dbef9456a3fbf7b4be985d185eb898e166ba646daa12cca359ea77bb7a59e45e8a6cf2708c16b5ccacb708839eef2ee4b5b6597ba3c5899c9f5214bdace3a521fe36cd39b77952d1bcc81f9e5edfae34f1cce40369b7ee492701351d34e231af8a3768cc158a796e900d0cac462f5204da5cde3abcf561ad60f91fc8951e4fb37166ce37261649f840aa51e6ff9be749d72f1f5b5ae3349f14d572860dcf36aa4655788b8cf5108dff7a4e231d2e2a3bec0a159a1e16c9bb38c4052439f2b6b1a62addf739772a1d51057c89751f7518a3b1cd7b37c4ff7d621a54bca5b3936b137c3fd0001b4a09bfe02e11668f8f6204cb9ffa9817ec412c820b6b394ce2cc3a12546ebc5052ec1c74876f3de8fa22e19158198cd04c1336a792ea47e63c2bf4e85dbe7460501606c97409a906dae4e7ad84517a7955793365ca4f49b5f6829efe61f52069fa19cb30ce0a74d415898e7e134ed8c4106cc9d6be32577e9a024b9dfd8129cb5efb1ef282802fe0066aa41e587ac9ee20d6416010e1b0772a44b6d6d1eb4ddb32b80b288952b26323bbec16614c227e4599cf721484443f56571c7b048e58fe48b1786c44e4979e105196eb9b5803795b8aa3d3e3a8f85e10abeb0f7b43b9a62dbd0905af620309ef74f281f39b241c4b4c109ca7e0ec55b13eef8ee0544c820b833fcfd65b4a897458cb9aa376c6bdccf1032e099598452130bd38d28096322fd0001b6c9b1d3d60a49cdf61f9031694f9f790a4e0118ae39cce789df472c13bba207d101410af89ba4b2a88cff5eb09e53593bfdc69a4e2706633a45c77a6d8f4baff22c7e5e6b32278dbfe97100271b1fd1e64463fa6a757c4cf4b19954d1d363494664750fcde0f0b6e35f9e0f08f4fb1e438669f78b10e800943840b15541a31c3090437364159681974adba314bcac37e6cb3ec97c3d8e0cd52241a4c162787c199a256599b97e488b8a75a46d2c3d8af1951ddac43b0d338e739deed1ba26a8616f04d124244f365573b602697aab0b427a8f26f1a22de77c563cda13fc03a030817a837c497732c6108eac62102641176f62d5b8e73d0e27e17586d6e2c2c3fd0001ca7e381637425fa77d95f92b8b491ea1398f53d763a6ce32a2b2ff972ab74bd377723dde5302c487fcf7eac93b089457761ca341f143b7c5aeb51b33cf103f2f4ce4c282bc5bb8c7290c2a9dcc82fce3dcd9669f660872f602de46e869fccdd99c85c06d1d7bc9af4e93502e4ffc385b9641df8f21a25a14b8e4cf99cca023da529f8689d86418c37dbe3d4116e08069f3d08b9c952f4e2164dada9e62908d57cc68b264df8fcbfe449c21cae576adb8169a97294a6bbd369a58654cd182c8403080b3a5a916c107d7271311a291841f3e35e065d48f6023ec4118a3a88d417507ae86b6c74e6ced02c768e0f879844e22862c357a9fe22574e30c179e2243e62192455f24a5c214eba9746d2a8f6a47625b53e5e62bcecade179907fccb08e4b200218a8694fa7fa94c9c174c8e1525bb14dd946981e66b1c02178cde818615e3b6910021fca3cbe539842d405545a71cdacd7a795b6f6fd1c1095497ee8ee215d5cb8eca002039f76b8f7067cd9cf8bde783c8ea6edee7638113ec6729093749c2cc0c15d13c2091ecd1eb4b171326a6a26d764e72e09160ff2112e577149bc7c24e6c0907324421cdebc7f780b73aef4358c6f7e5c9a78ee95dce81c4c1bbbf570cde3c43ff5ca00021c6955241d2f09d2e90e33601fc139d0603919a1011ea7ee89f0e5d53727c45a3002037be468901ac92d7c3481ad63d364a93e2daa023bbcfaf4f6fa40cc54974de19209178cde568ebc660a7698cdd7f83d5932364eb8ac144e62cdc045a00ccda5201fd0001a3347a2cd4b1f5337653554be5fea273a5bf0292c0fd60908c6e699802079912372435166baf2f71b35ec0e00a714e9f7c10096d0f39a65f66f220057f369ce7c8221dddd00e90604f9de897ebf9f06afd41814b57350ca2d7ff7e08f60c94dc1aa087b7975936832a7050ae4a14b47b1986e70d61223cdc37dfeabc5e4212a869d953450202c9c12db23f8819faad59252173ac11c54020fd7324b4d39673befd2b585437affe9398e7967772d408c6db860ec512f94d02b0cbe9c9d414bb4be4b08c3a420a549efaedaa6f0aed7c74044785b611b2d65abfa33374748adb690a54c8719131e9dda9d46afc9dd09c8abc498d6de657920642d3d47a55f17fd3fd000189cc7f3247c6ede0becf1ec89f5d92142d25a713e037454409ccd146dc18c58319550275149342c690f00b1e060db34bf6ea34473c661ff9f32a40214a4715bbcea59a9ad6ff976e43b325135ca16377be53be39255f9e45ab4b3652d629a30500f9e37671d56952b215628ef42c1e49046476e9a760041003742751b158aa85c4e95f70e267d2631491c60cf09a174816890a2dcc2f8a38f296389c3ea66a6d577301297c242a6b9ca7465d8282f2e72e7673f9e1f1c8f470949c970854134de397c08c06d5d21fc487b2b9529c901c052e838a087f15b802d081e869cbb311efed66ba31c17c73cce1e0fc32d58d35e54bc5524776ee3f45d7b8f81fdad4d621b95f023b2202f5d7c814aa89c27b5e0bf5cd64b444c711c2e1c4b805af4fd58300208214f56ae87b268fd16d6df77efaa715fccd1fb1e6298c1c4f7a4f18d39c2f75fd00013fddc975fb72a66d5a7f3ba6df9c1ff55c7abb5a8f08317c6b346875e850223d87d72d71d9b17c11bdbe6eca34b521fe98dc8d31bef6fcfacec74e5c4a6c5f00ac769363df4720e17c3b687a42f29e8edbc20184dc9274d8546368e3fd2408bb68dd224b73a1487c10f4e29b0d8b9823f7c73db26ed16baa4c5d75b162cb5a97caff3cc8957072902538e0e698fad2e90b471777c5e8d90e5cd313933c2f3b30e49b6cf7ae7dcc09ab2e5e464601f093973d99c0815c3ea587d1803b4ca1d9bcc2ac20cb818f95d9239fbbe62c3356ba41f7dc9d2232f6221447fc4858bbf11ee382bfc639d9101943d958a59ff9b81007508c0879c4bf16885bcd6eb2383898fd00018ef6741f57def1a55a42b565ebe0451f0208762da626acaf0cbaac6d9bcec14e22c15660c2a0c5a23b27c445ad968a7e6b2daab11463040eb50799858b7a5063965f947234beb0d42fe1c2dc7bdce7fcda3de1bae384b62e798995eba4836dbee41a8a4de269c026018a22687ad77985d049bda1d39b79528b320ad3d22d893c547b4dc4acb57fac4e0603468beafdf54408ddb7d4c5db0cf14162d0d735b3fad10888f0048035481e5713b846761838504a36c1f956b072b46f11c7c6fc86c766c36fc7dfd5068855335b96162d8b299e3cd21060fed730310d7748c3d16f228b0eea1f37f5eee5453e3a19ebe1e60e4f2834d3338bf1887969de57ef02a1bbfd0001b50e09d8212707f0035a46513208bdba63a5d1fd7a7ea88e181d7a3de81b8afb4ea4b0428eff67c04b27372d73896fd9df443aa9b2a42cdb8665271bb1c54833454504dbc80645bc02366dc998d334b2723bbf5ee1e139265c107db84774b4884f26b57818d39d05b47d5bdab25778965a0627a96ec303c743ba57c0d32d0337a6d3dbe982284109eb0a7976221816cf3fa7f2e3cf739f30be83f253564af7f411358d9c5340fa5578120c48b617c088d9a3d0811a575bb1e96b746e25312ff6d87b9705c04a10123c7606b4c5d6658244121310ce3f1d062250b57ee51e35e0d7b787d38206fd9d26c70ef94f337cc7108ae8ffddf5fa314e6c4e5e1538fbb0fd000192fa78c12fea8a45902ac86e2878e8327b5f4c2ad9bec7d6167bc5590df49cbddda4d4d652f6f087f2ddc7a2813aa5b33048adc5f900eb4acd983bc86ea7b89f630b647a9ef42ab1bb6484ebc20989603144912ffd80158aff7e7d40a1a76489afb21f5f711ecc3ba613868a7aac4f28f2cd5440dfd064c4874d4e398a4718e10de8f7055e452271f01b27544af7035aed32259796962035d7bc37ef843cdccfacf969a1659e354ec27efda8756b09c0bf855f4fbf7598273154b3f517303b6169bdbe4ede890a90d3b34c917311027afeaca7dcd27158b04886dfd81803594292cdb3dbb77ad3a8df97df63095fd28c275b956cc61faddf770608b898d74ca9fd000138b1c34ee04d01368d9cd8ec4d70b97633951ada508c031470cb4cfb15a62426276c7442e7679f926e93325e287ab9ed87446c144be02e559dd076c9c5e1d6a6a7de45438076b1bd7b9ff5a821070877c1d9626925c1f47838e56bb6982b54fb9e131741bab5ea38aabbe4003538c454980dc3be9a436283edc32a3de0321f114ad32cf34e860ca36f18d476980910e564af57da498cd16d08af8b4d4696a9962adeb298d7af4c8c4ad9cb911d80a2115e833f0856833232f92f94cc9c3a6a14270f4c30ada671bacc9aa35bcd3c945dacbb01f4556ebac4e52adf8790dd49fa799584d227ab95afd2da9e67e5642a90e54fc8b693a07384577d04cc40861cc9fd00012c7977632367de82810aecc22a1a802a1aeb6ac54a4a79d8e61606a6eb72effe1abd74a0a18ef83709355e77cef5666f16d94c0d710f5ae3973bb26d07c0a436aebca4d156d42952cc8cedca94162225b5b4780cf47a6426757758957dcf2f638ead2312e67e140ee8c380949c0885c68b396517ba122d90a0ed184564bbe67bf1d0115c77857fbb29945ea00d8e809c295295494dc8cca091d900837b60b31a79bacfae59fe638ee8a2208942e27f605c452be3a4a43cf21e8e0f78e7cc20ffd2c546a0bbcc404b415e4eae2c7b9c2f9121bc741a6f8c5c28c9df3e0169cd86809f5e235ce17fb625f913f94b75b360f9097b625a5305040c55a4057dc4a68efd0001d594cafd37d880576656265ebb737602d6f3b9d0feb3147d8c1f6e1514ca64e3ee046bea5e6892d8db9c094198fb3f697ae6fc880075bbd461e9aab7425ac3a7fad84071b170739e7815d0c76d2ae7fefb718ec132b32a842c58cde33605488043aad9c5df6e58401994a38dc50779e348cd18582ca74aaadcce6df39b221d4235a88000eb2e3efed6744abd0b68836d56ff5d9ec973be549d52a195195725caf3b8cb683da9b96868d35727bf4b74dcbee838d9c39a33d15609fde1c2b345974a93c030952f52da7ac20b8c26b340fd9c08f56b97ccce21004af28ebe4946a91682f9738085cdd9a53e160346cfcf396cfb59465d114c600d9571634aa3c880fd00016c714ccc93e995491adb6718e9ef69fb2cc36044d9e6b73130606b9c845dfdc56e9518a120237f58fb6f2546bec6f47ea6a11f3d898baa47682fe3f537542fe9f6d3679398064a48a3ef8abc92e89eea84c6d8ca956b3c40e9b82b2a496bb1230f8789fc7b0befc061468049d416aca3fb41d4272304a728322684f9ca6125b91dea97bbbba8c83045b5ce8b3110d429d65998b3aed570ecfedd176e98a91eb3410cd501ba52d176bd2c8d05e94acc8f352b3cbe12adefb82d34e174765ef1197f8a93fd4e03c98967ddd0332733e5aa0ce87f63aff78a2b44d10ac63c1549d9a9c6808b743e6f785173924d736bc0890f2e68c1df72b0fb1632bd4679e87690fd0001e736a64f64d58af8d43f0980d29ba57dccea56ff13040270c926a2703401b83859a94d6cbf4cd62109053c9e6ddd1cc61ac649ebb1243037adec455891642de8f43b57afe96cb63736e3e7d735bbeec8d1dc2c698f37f0bcd85bd84cc6b7e25eab500c03f1c62ec730c24208e2df2830d32842277d9e5c9416a91217cbdad60d6a77a7127b09e7463354266a1130d1f04de9041f0f83d41246766027700fa9a02d10d2b0fcb0bd534d22ed38278ce177bbc1c429c09030f105a67db70011d3eb24754bbb31f8a6a98bde215f635409e4cb8c3d769efdd7f1561976bd29876c8a11a130cbb8e3fdf15fd9ad0329852dffd794f499345c3fee09eee21997a5c8a021b993d7cea74a8935b42df2d55606a8841b1a4a8fc0321701d5de9bce1dd1bee100fd00016e510cf2b787c67956990655ca7ba97aaea25163317e7ebfbcf2681b29b0b821aedb8f9b2e309d37f660ac7169dc8234a7e7e4d01e79164eb75f28d284c52ea3d7edff718aa96db6b0b6781366ab985d202823130ca53c2a8e5186fc18862348952e967b1a3e3636517c3e3c48d8fe5e4ef1d5e230ab584964c888c61393ee3d6e34c50446b86e68ebfd048ac86065f9a9c4bbfc2474027b612dcafbbb0416f12d3d856a96557529d1144a852ade77f50f600ecf3c0e00296576eb49a0b211baaa815cea78e1b7a56a1c698ff58488378722f58fdb1ab8bb0063654a8de8344041fddd04be1b4b2b1944ce9d1ebda667caf9ca00e5c2de892a9063a449edd8c1fd00017140014f19e2474e1cc4b40a5a8033f3ddfd960ef33c7e35432deabd85a5b2c18a27b85477c9e6fbb2d8a5e6c686078009b1f7868768fbb5f569ae3429fd64e49cb3a62f32fada09059982a03a20494bd2fd2caa75a01b3ecdbc32acbbd648905d56cd2aefc714af1c24bd6e8f06b1ddbb85e9882ddf8f0e67c654402bfe2e0d9ba404bb3da2d58305184949ce513b3784c3234b39d25e0c6df741683750cb46d7856e67a0d45f4839b5305f9965808d41cbcfb2ad3ad18cdba6744eab0148dd0c1d5e687b6e76bdb9408766b57297be6fdbcf9d7e3e6918c194ef32bb776b5ab85f3a6a164baf866d93ecc3acaefbac43a9fa267bc623cc136ad712b00d788efd00016d3db1d97d5d429249f5cd6dc35f61d0b1b44f1e433cd5e01d28afa6cd6718fc1432b77e8eb6418b0a4b6fcc6707cd3d5c6661cf57b3b73b78feae7c89e25eff2ec1d465be91a18b2f3bc4311919f410cfafe8ae8a06b4b947f9b6fd8ac17453c2f558dfd67f71829be66250d40c3aad6e3ff52d1c0c455e7a4f646445405cf1ad45ba65392bb622a770ab0f5a57e73d32d98ee49d73ac7dde7dad9b9c8e1da9d1e6aef0f9cd120bc1d2cbc5ad819190b758be385f2b0dd736184382af8aa419ac7d734881ab4728ea927b6655b7d3faa4a1e14caf6d38cc706a940bff9c9021e4b6c3ce516d0257deda35d2ac4e0423f01ac849b19b919b773a58f34a06c6b1fd0001464885fd950d292d5aaa6155164216521d2113d795d9aff389771e8f39ff3d96afb5e2359fc52aa6d6cbc3921a7a21e6f3fab62e748337e2cd212456e2b2f52dcb352a75902ac6fdcce93dcf027138be788aad5e09490bbce637751cfd5bda9ec540d7daa92eed7b27ff1bf66585fbe3b39db3de9dd386ecd7671f2395522c1c9006908afd04fe68d88194cbbc3216377cfc27c4fce55c8e558ebc4943cbb477a1172aa8b344c08d6fb853e64ff0f986b7f3e7cc3b2c3d8b2abbc43e08eff15787bfd6a9a8f98b207d8e2530c0c37a37ffcec2fecbd726b4b845ff48a44c1ec7031e4e663ec0042663ff81b9a7fe7d599695737511a685148fce0c3eb01513bb20ffe083f86d11f3c552efeba225a93eb8ea756f45c2e49a4dd08467b79a14000220fd4b0ae4d4c5a165ab75af08922366e89721ba7ee52751e0b3e64017787b9445fd0001d0a8ddbc130bbf7bcd20bdbc8728e812a45cdbe602dcea5826f753b94e1220cf698c1212464a17ed846b29db82b1cf5373241d4117b07a8b7d279d4e8511d22c47be22291e9ab56454becf533b771e5e602542d07828952d5ef900e2548739d57cbb6254c667bc50a0f97c11b7f3dc1624111f9d32cb0d85ac4106b41cd6d82db7aea1135334220163c190744b6daefa456f69c331facf9083af360db6f2a2c80c423357c8fd1bc28fcfd42db69d733efa9ecdff9df079bde1b73a63ee74e5af5c75b67a4824a72466e17b501f6057a68efc19627d115f19fbcb48c0e0889857f0d9191db5875ad6d336adfbf7f09989b2aecfe868c2efc2cc64af46d07c44b9fd000151620fcd4091a3d3e78e8a1f1b5ac9ae8bdd3760320ed9bea2e1b237110d7747e9894704336b958fc92eb200f06507cb56a12f202a8b098bcec5b7b6941dccc18d2bd968538185dbfdbb6ea61eaee22aa8ad24d73df0adfcfafaec181fda3626479710bc19835a5aa7a3b9afd8166b89f5aee8d52589059eda61f19f6319335dfac7765a9a9e22cce0fb3236eeba6ce250ea0b7cfc4a021ca3c88859f556dc1137349a7ad5a628bc47267ad91ff86174a2fe74e3ab298ae8917d6a57a916f00b16bc0f3584b12b0d63141a20b1ed54c6551c6dfa5647783dd9acc68ed75044faf6745161c1ee4abcd9969ff9e01f14791de7d0c8e44e77a5b249e2da833ad3bbfd000119884821e74482b639ec1f8484eb6199a01d6e0a3606e25527d7a9fdbdabaad9f378a9aab04a153b1003d520d03f25a9e41c82504ad6de9fa6cda30a3ee1128c35f49d469a79b3c190ab0fab92d9977478c7ddabb6a66f291b58756e040892f44ebf6c8d0ba3cdf5d9335c8b05b0d34a8f4e832c54979274f5d4554af2d05aec3d51a3cbe03282c9c104f664fc39863c3a23396e762a5a8b5ba18b3c84f0f49f8b7cb6f627905a4fec65e5ab41e868561dba5cc8bcaa8c201d613eb678342aaba5e5d44f7ad7a58810129aaea2e6bb9850ef022e54a50b18e5fbbb76b93f050c31d279e66cd51a29c42591b18db05e88283e52070e6eeffd8fa447bce2f22eb921b2e3f53f38bb201511b9e1d5bbf22bf9e23be137543e34d81a0b194f373dbaa600fd00010ef2d9c59966c760260612842d16526b4352a5f05de655fd0bf50546be1d893d90f4b8264488467880be2c4d7f3c577e6b68335f1e0764fdb16d6fc44fc5bc2c1660798e6b31bdcafbd33a9edb44e48dc37306abe9ea761cd2077e977a6d5b92aff3cdc33f644f47d90fa9a4b172faf29e264c9d55d27cc4e7b7e5e891adb566d172207406ac400348c386e74716a518cfde36169e4cbd8d3093c8d85b99e54474fb7c7ebec5a3beb18b664b953f4d9037041c45738e87c53d55eb92fe862a78627a8f4f3f8f3ef01102b8df05c9c1d81da85e36bff90943e0dd93efc00edbec664fe16f03c8e79d3e105803c50a606f9812d3717921477e224efc9c38604e932116d048938c5e50af925d722ada7f78de5fb1020ef09d45e001364d0ac87ea4b800fd00015a2d2be1965546e9ffe759719faf9960648c9183812a7db83a24b0ea52bc26e3774ac36fcef82756ad386332d49551a147e87ca68fedb289b965a4088b3de6506378af1f858c1c995313e189684bbd3e484499dd7a26097ee6e89ff1d0b6d4c6c03917c53a95d9fd1b6f9a8e59e1687506a5499adea9c1bbf2f63b14207daebf64c8bd5742bec97f6364560cb3d687f8a1ce12a197e87df8b23eff607c97849672fcd5803b43bc8b6dc2090d7b99299248007a3207621c0b40e6fcecc3f68b2888f5abc842a44e6f019391449a7356f9e2637c77612b342fe61e76b307ffb780f529c6c84a6e6ad8d7553021070499e85542cd288a543bb0d318b7abca62c48721047951dd48307113449db6a3f997999f421c62b4524e5baebffef1ed21a6a1a800fd0001c4594030b3c64f25c491e6a5ab25b959438c11265e0fb2e5b2c58e3d59c86d642aff89f4e5137f08ee4871df4098a5748795d596baeadd2db0b006e02822ae2c5f6a93c5281b82a7d60f8c390a264d293f1769d55a5b1f78f0f65f7694477ca79ec16677993d5b6606298171df85a7a8c9bc74a2438618d2aeb384de706b797758dd418b2b5d59dff089f7d4f7f21a8390a3a707c08ea4a238682670a0d80297ba68febea9c4c5afccc241d9f95aa77366880ccf891174b33d95f462839d2820451611e8453d981a703595e8fc73df0a4963c1baab591b7f3dbbbf62b50dc7bbfeb05ec2ecdb1a63d06ec20c4311451b4129a08b94049263e180411ce7b8b7b120a96a6184af4c9ac706b2fb01d6389d94cc4e3930925a5b2bdac9e96dbfa42a78fd0001cb6e8b1c0da834c4fc0d797fc3521eda3ddacade8a4ecfeb518a2e2e8a234d2f6901a7eb4d117404328c70a5c24f36236e88eb1dd19a7e9cf4ec7582f472da053e283dc193d70bc71867d2a348521a860fccebe0b45958f1b5919cb833d79802640b7665b7ec45135b24108eac8a882121b6e6734dcd327b506a434cea9298e6067c36457858e3c18d88a320ce33cc3861f5329bc1f9a8f4af57caf2c134051b12dbb58e309d7bfe9028c3b9b4179759095fa531cf20bdf18134c517ceddfb38b4d94849c3d7eae9b46c353bc43d2f8345e345f818e328875c1bdcd754b706258779c7c30592d0a4c4b5cb557eaad484d1cef2bd4d98d12e70b8fda33f3a5e8320486c47e0fc0d0e679b413041e800ed28ca862ceec23c1a937954131b960fdb3320a3e4a1a7ded3a425d38b144b090d9fb0aeb9ba631622041a702626583d41142520f6fded7e7b2408e70ac4ab0b4d23bc2571cfb9048b0bc738dfd0d6507549a451fd0001656bbe84db36e12bf3c78c07ba3f561d2c2687aaeeef2e2da17cb00f060e025a993c12551c12bd4d75c4c116d18951515f42c5628b0858d85b8afe5deb0aa14a2e33d147eb62b9a52bd4769b6a97382d6c39e5f70e727ee0c9a4684fcf9a03e7232394b4ecc6a2d32e27fe2b436b1081bcb4f3c8bc844e9cb1cf9b828bfc155a2467d506be2f89c9a36bfe2d19125fb21666ed4625cf881ffba75e67d209fde2742d5a46634019cf1f96c1e649a9dd58edbc374b9d6220bccf20055104e8ae8917537fd07f69e12e0b8200af3d924997ee33a7d1e9eb3ebba741f0edd1b59f05e1f279d0c4f7106276968fac8055088bd5f57840438a2776bb21693d9587d188fd00011ae402863053cdeb79711a4c4e7472a1559d86f89bc4daaa6865eced1126197f3c43d78ba16fb2d6508632ab4712b13c3f45d674064a51867bcba96a71b7683fa69ad337fd0c50e7927b913f025fcc47adddf1376a053280cd0fc45bbf29767b4555bbc4054a824c11dc93c3648b3e1c2ca42a5dc5f536eca084370ef65c5a6229bcac295c3fa578fc22eab793205cdc8d37fe3cbf7dc6e1a7c53ff3c7e4d226f0a0d4667bad282c625695d4a1ad88931ca894d4931b19b09c56d2f72e72f62600c97348ed8814f0841baea716d1e0d90f26f8c3932a1e66dd1e8c8e039d3e891ab7be0a887c16ea9fbf3dd7f2c7200587ef56cd0e75e8e828aedcef6198e6d6fd0001a265b258bad27b42d12a12e43a25bf566f2b77f6f0924e8e0c32f294768fd6d9f92e5a15dcc94a2067c71a1f9740700ee0e7f626d35fad2c441b176a077fe681515cb0c8613b0b43c708895c9ca5a41745ca87cc5e8d02e272a484be75cd9afc7478b98bd4c030c3dd4885c5214efbe70cf9a1f8a2616e2eadc150f979e1ca8c389b6fa288889464886bbdaee7539c6bba71ad0927e455d45db2c7371a5b15ccd8c7e7e91592e9bd057d85a18a9a9d1165a84329a6c7beab031f2819cf36a26aeaa4cbef4e7871c472b9b363a1a5d597005cb98e6828a7b6b7ae81cbd036f8d8afbc6289efacedbe51c10f27462c81525b18d119ab4527d9c6db52cde19cfdddfd000143a024d1136d92c3d0de09ce4a3837fff20ce4c4307fca87b1a09acdba6a1df122cc69dca4ec3ca89118ade730ec8959d0dd84db0eff5ab2ff71793af68a2d6bf3a301edce9cf1088046b3177c18d90f6318e2bea3a071469873d1a320d5036a6ea1375ce17113721f01852e1c436745536bba80365d2ee1060a73098f99983d18511059ecac21b84131d845bddfc589a1a4c195ee1d89ba9845c09d681a87c3fe2322cdf571b4a31756d2de38276b97ecef325f4ada73b747d78899c3f84aeec26fc9732ef5843f8b2d7af0fee0f04e01f85731eb9fde3f0a69c4c0aad09f51db5cd03db3627cce5d2a1dfe9910817efc2e53ebf9f79afaf09521a3f14980cd20d6c0a0d48152ef8efbf7a58b809f5c28186addc9690ba0857cbf2c96e395e92afd0001781c2002615bfb1b7d35b2e208a1df0bd8f95f2d639422c213683828227885660bb231058546848fd01763a1ae99e0a7a1040a0f398d8171b45ffc4a58a4439a5addbad802fe79c71a4a27fea8ed229c51d6cb26c3e21127aeccd2f0e31ff1c7d38987c95b917d4c86439a7a0d54b3985ccc3072727c654bea4d473676a45f13ac693de273581cd6f864fba7ff00f3e61cabfb689689c49849419ca1cf489cf9db2138f65c1445b74a0e0cc83e8368e6e79149e699b6e64c77c70ac5156bfa98794cd0c561732fc7e3623673e1f0ebc09de026d9745c4986d498762be6799cf99143fca5d69d04283b504c8d8e325c8811853d467b72e204417c7e35064ce7bcfd0001e42f7a528e3e1de18bdde6e2d9888886aea8ab8eb149299c32c68f6c93a19889efc05e641037687a091933cc83bfbdfac77d48a2828bac6b0625260d4b9da29b0d215d403c6d3aaaf33addeeac4d46875cbc4e3edc1a865d6fe0b6a588631188897cfd131672a8c5d098c0ff8ec5b17bcaecac1d78f83b5296408c994c1e81f93021da25ca403ab6694fb3e82ed260e88067e3edcd8cd0e70ce4c79b49962096eeb1eeb2b17be69033a338ebfadaaa1293f7fe17fb7ddce051d9eb82c84d639bab4a415353ae82dfed2996a26d184189ff1f25d3196c67f34ae50a39bdc2f711ed6468b364d1f0ea8eb29f486dc6c2f6dc59a24acf4772bd542557e9ef4b5b93fd00015ea90490404b84482136f214f4497c09a0ca87dcebecc03ac3152ae1c3e87b945f721137c7a309e1036d0e5d94c6cce38c36b1645a62c7160ca45abcfb5c165eb696154ae38684002a150ab45f1b8f1bb69b28757e2503967a1432090b6c90ce7e3671860e40e95200f8a1ac1ad927b49bdc0a66472eac7123c383ba28578b149f121ad8b1ead1e1908858a640ebebd2e1b8a4f787e5f41d573168493115448edb0de580a8c281b783afe2b62ac6ea243d021187367df9fd28f97e2ca7c8856d89c64a4c3c5e2147aea8120b4bc8b2d0b8ec5b7edeed35d24a800760e82ab19cb7363c7b2fcde6200b8e63e2b698489e9dc0bc4c8f1ba9ff68b59a7277038eb920fe94cb66b60142227c026662ddbc3dc29b373c5c805c365b245c2f69152f1e2b2007e3634d06ba18b973add33bf3e23a7175729a9442fc4213adcb0e5a52e2cc272096af7547b4220ef6335cf5fe47c75896ef2d27e58acb6d7b444b3645ad1a9370fd0001f3642f6dab0eedbdf04e554106719fde491a9bfe00e8228f250e0035f5a95782bef5680a15e6148467d4c7db9e22d9a4bc766ba884940645845b25ace95d405744929adc2c63e41e4c807e33a0d514919c09e855c9d77690be00720d83dcf2b2276e157d39b7acb3ae262e65a8a09ff49478fcd67765dd03b545d7e83bf194ee6b0c5f83c41f7c470e0a1c3f1014a7afc2b7149c01b3f1181eeee4ce8a9be47f0f7f897a05683629d6164fb882e1b67765e7560e7f5c6be76ad9902a755c6af0c455156b93f14e618f533feb9d351bb956da352b7a9d63cc5082d6f9768d80f1bb703c84be2bd75b848f06925f47e226c424c0ae8ad4293b0e9c330cdb16bbddfd000158cc2778c31d0436228349fd19e0428de5916401bbed1f3668014cc51cc6b42381c32e5a7d5ec4d194037b0544284c52e151b652e2733b17065b2a98fc1f5ff30a8acf5dc7522b64eb94a8a71526e2aff0acba058b541fa412bb5344eaae4945ace66b4f9251e842e4b52feae5ad89ae1ce3617debbb551c09c87c6e6e69b7942f1178db84dd758fcb3f63d658e3f48c1a47b725cd2e003a59b8e318950a45fd908c6c4d53d706dfcc2041c046324e3925c9ca032f62cc825f0c11c9fff3fed99f616837244c7d71b3a8d79a8d5bba3284280b59ca1d0ed044801b7d4d6148f014c8c04e8859d9c3d074a7ad77b86ea0ae39fde03fb33eda53fe5c1728cf2daafd0001991691f21883d17fbf12b24e86f0f639967240dcf120c01713ad612ce32a7b8a9c911248414d8a2b836e82c827270f60f154d5de0efb7aec5b3db3f8b9cedbcda84aedea5fd0988ed0069871fda9db5ec2a1ba0f04592048f0040599023ac01e758886daa3fdd9190bb1c8ea29898cdc711e8e8e6c4497ae95ee2e5a6730bd8388d8fa812b21c9b97af84a7cc9f790139b0005dc86efe16436e63982fe8d8ca6bc5bea86b2297a0726dab7704fdcc8a3f6c273eb0f8aa008ad1e6c4a985d7cefe05d3b24cfd195d2fae5392a48be5bd50386244fa9002f95ce18efe97be356a3c5b3990172f812987d0fa10d7fdf9afcd20e165697e3e8f1fa564d1f03010f8f20d53cbea6789dd88800af410af54c3c346483fa085c6e02c088092372ce828e2afd0001f903226d53becf91fe3ee0e556a7ddd652e179dc3c2de5d7af38f380c9916791a37e149ec620429b47e5e0c016b898ee1dc45db857c93a718daeab3167c3c336b22692da51bbf7ef1bc42cba25af0b1fa89df2adcf41535803ad6e80ff1e1f57c80514f1d091040aec55e87c4810ea31ba22e4f93a101d71e324cfb2d84e381f1a59a601ea97907013e119a24a468b27558b68de170690e71bc3c2d7361ca7f77d116b642516d9cb128a70d6bfba83b2c22420059e8c22c9f794f2e144a3a065c942d3276253013efaa88a80e3d7f3c32dc249347a6df656df62d4f9482cc8470bd1bebda925d47c5cd9a54ce81d7bda23c2d0434a98a1f73911c6172facb08a21cb1b1935a2667416f5cb810c787fac55fe8e14146721452870f27b1d5a14fcce0021600ca51450ca3b29e9ff6b388f4df5286db585d027f68fbbd1d4a95fd756318700fd0001b941fa0b95cbce10d49d29c80ac6c45bb624fbcef94b9bcc75d3593a5e11ed85488b6332f9d059e0123d5df6486dd2f57a9239d137d46f3b9c0120d391d1f06cd48c13a0b847020d0832b15162461811662eadcaa2757e2b6b2240d478e7411c7e807e09ef824ecfb3681b49aa72a3319dd310d8efd930ffa7751a222e73f198032f2dfa00e978c9542dc476ca44b161fe470a5f63759de5086a18fc92aa375c608841c6ea41ebc6fb86dea22a8987f7d9abac948d5e67a173eee3b9b90c323c4f2624f53fcaaadd79427a36f560ce6cbd99872d8119acd2173935b0331217e33ceb4a0ef314e45c1a90ad06a46948a38a00feac8f58d8780e6d15ff6e013dbe214cc25d39b2def7e68e2d5c7afd69c5d629265f750b683dd660040dd3220a2ad600209901a1f845f602ecd4f341e7b68c6787561b4f18d7819c8b319dba6836a42517216578b022ea0911e03a47f0814046cea045fa63bb506730b0b491614417df91f900fd0001ab0bc038363d54f8e9e8ebed6a498b0f989c8ee56c81720bd66f71d0d97477d0db56d4481cc0e57c2316f4bd3a6843f86e5b28152436ba23f377dac267c7bb6501666efefb705be623d0491dd42a1a5397f45b6be6ceb1e0499842914f56296a34f304320f5b623ae7e16379d89394b7057d1b92de4c913265ba231d81dbf9e4b586704803baf1cf0fd474a721bd65206df02888dd77df03c831f8433f3b2c7cf7e1211c7c85a975d129f33734fcf77c09aaf68b681da7c506e8c89ac5394589d185117b722b757e307ccf31e9ddc1b9131633bd684ad458fdef09d346566eb4df920801ec4ac019081feda518cafe1ff9f9197b1473ddb18d3349652db870e0fd00014168b6756041ac27a58e4160cdc78c2cca30e144cfac7c58d40b5521c76ae171399e4e22bd3eb5a59d0a44666cbd8d38c4983f8e2bac6fa5ee84c86adbf9679bf8631dec545667463df5fbfdd5ff2d0f6f9021a4a03510e291253bd133520d5366e3c272bf8ec41a14b15aea97c420ff263bb52dacb3c3962359312e5a4690483434ba5f592057dc449727f03768f3756c24c85814e1204d2d90cad6e656d39e7dd7b9c4bfcd103dac62415b0d64901b01278602553c149f6d64342f16757b5ca1033494395404fe1ac7ae33d796be12b0d4f986de23186ecdbdc8477a742fdc973b34b312f5984b74faa42f5f62dd4938f76f5d7ec141249902825d81ab2d88fd000193a2f7ea915b7e506459b8484c43d305deca93a84b3c313a6cea7286d485395158806c3d7f3155f3ddadbfc913cbd7673193a951b356ae208319ecf406172cfbbad940f9fb6accde0c73ea5a19037d5d8644b4de22db968851a303717f473c491465712da34aba4e5dbc31361163ae1492bb3435779569598639943640b6e14233d8888aefa72580e22091b6848592d5b2273cd2df009d614da03d0c0803b4320800094dcbaaa337fd210820e07a8deabbd595d2b59b3bee5c7a27e585a1cef44e532de83f08f3df43d68f5934ca69776b8ee8ddc42969970d64145c093d4e989cf32ba71f750cd03b5c818c33462d05c6477ec1f0ec81c48e4b119d05d31cd5fd00010b1cbcbad09df7edcebe79a913033895c66686f078402893059e4a986fb76d28e89324f5b04ead2c2aa0a05786faa1e8f66fbaf66b7ca94bf52123e6afe4dab54bc33e5860e8766031dd256edf40b294f55062e613cafac04f77e284f5097e88cd7aaf46fd28f4fc24ef1ec1aa0bebbb3da5b504e4dca8dfc13ed99e4371dea6f3bc0f78cdf6ff47548e5a426c92095da045e5ccf45f446116e2c9567ed01d62c1fd3a78c62aa359118f77705174db6a4faacaa0b6d49b4da38e42b20e9cd2ed7979a0f6da28964e0b3fb755046f0a5477dda7465e00d13c8751c36255b7f922dbfe108a14e359257ad607dd7e1c9ccf330779135714b01746a25ddd11e565c821713c8702e50956f6f6ed9c283cfdd08938c8ccf08ada04309e47fe9ddf5cf5dc00fd0001f5e2772a310c56c1343104f8f618a6408dbdd5e421e31856f271fb33329d5055c4c73e06870feb8f7b298cb9b403dd6c4e87dd2137ac84df583c58ffd627b0c52996bea39da5959ccce7968455d3b4ac512c3d552cf63f2da74d6de8e8f037eca47a715d0d9398502b287e5f1034e536a84839bac21ae9958da81fe54c67165fc650f19679c9a628b74fb40c65257dc5b50f690263f9c1eaf41c3365c0e23f91aa7ade32a352c8b88b40b2d7acabbd085185f7737be6f5a7c342e2c908e8a4f997ec949e4bfd6ca7b3da894fd4581c81141cbfc01afc3eb86bc91c304c18c1dccde49d8b61e41d922fcb02162e444dd4931a076bb072ee3a6d5cebbe8683e992fd0001197c654987867c3fa8c71ce3718a70756063be0179e55bf302daafbbdfdd5669ec38e140e3204b260b1d54373f84657101147e672120d735c179fe2dc5fdf7dbb8aadee63b867e31d9d1242e45bd23ed510dc7a6d44ea7806159895a2293c0898bfa6d0018d9864f584a59003a8d4e3a38eae3ec7c9e35d1e5985acd544547ccc1e31024f05bfd5dc07ccbf535b2e0a0a703548e355eb9d1acd8a59684ba0fb674075011c7be7cc899c30ea6c1df0dc34c9366f47743aa12991192cc836db7fd5a3b0306d6905a82e13b729038c70fd3bea01def02b93cd2e71439a9fdd5fb93da6a72436ce9f5b431b7e18c76d8173964d5a02e24195e761d888a6a2532d785fd000177fcd4e94194a3c34efea9f8f04faccbdeae9f0eb8662b0195db08e2b41a08fed52ab7060465ecebdb2eeed7a768c4f65ed7b5193151a56c752cdf97cd4c6be8daf95c16c6703ec95b6cb541506c715983be6384031685d48190e611ddbded6fa377affb759a1f289523e56761857afb3c33b68f743c59a6bf2098a2f5bf3c1c8a3d41224dd12ef247874ff5ab6257cc3e29a65a1c16f3ecc26108142d1899a340be3db55556258a348f51ef61e8e73fa9db743f08df3d31919f2d9484603f0281422c2cfbd66959dc138c2176d6e242a5a04d5b1cbd8c39ed051486869f8b0f3ecdaf42498be6016dc9d49ae52220612a32f50259fb9a8be0cab88deafd56b12024a02c37de6161be5eee8cf63c3b0d16d0bdca07ad59fa0532678b864c13bc20c87f061046d5218e768801c69818dadd24e62aa4625d5a2af09b08f9eba8efb5e29fc2977184990fcd81a0a3f896691051da425d7b99292d8ad7a3bbae5ed9503c5b761907097dd6457a5444b9c85ccc829d5901d46cd917ead52a3316f96588a7b508501be9f69c73d97e0db9d615f20e50712f377663f6c47f42d005db72b225048abeb8d6e3a60afbe21cd13d4539b7d39806952d745a7c49a552175135d840a3f9b9e9ef6ba3c46e9f4bd42f9bbde0d5d5abda8cf06538d3492aa856d8708285c0aa99567adaf6e0d4b28feec0a55e49879ac8ee966e4520e5eeae3e6b4473cb710b4213973850ea6ff0331b04ccffab2c2c3f55ff28b8bdf644e4c19982916d01e28d745302b079066c61fc0e8e1c90931f122893f7f5eb86e9111f98cf36e719129668dcc4718c52d0c4c6a1a941b939e5e744d61aa9fb1aed6eca5fe062cd109b15abfc5851ff77c026e9ba7023b298d40acb1ae9884671ff1776aedabd859f2a481eb18b963afae2e2ec41e3f3671e9dfaeab234d6aaf97249f4702e706437d8e36f517b3b227bae68b79064a3fbe999bc2d75912d970826908dc17b815ec0f030e20b24f17c527557e36695abd05f67c60475a0c74aff42b5e7fd13efc3b1c3bf5ae6e3251731ffaad110c4210c9d6d78d69d6f68cc31ca99fe783a12fca506af01e28234f01e1b30dcdccdfbe696bd5703ddbf0554c8c4863edb0f252e2a9daa54d4900d8fd6aef61b8a8f1e165eea79a3f20663b08722762f2c548e0cd10cf0d2d8e8b9239b638d02c49749d55b721a6c81d2554b51b49191518150664b7e4dbde3ae02b36ab3ec9250290c8cee6b7371e0d3c7ad64d267cf463c4c82cc5a325aa72461345c4f45c8753de23bc148527b0e982511bed9e4bcd4cc37e1e3b5089373fcbfbef9a111c96cc79e9f37d619c0d68598541f2a37ea0fd614ca310c915c0d412d2eeee8f7d71e4a250bcc60d68ab3f296a5f75d75d627e5913aedf3646f733701218878049c420ce0089ded11b087f16111e397d0f2e354f1df0a858aaf07eeb8e80002210305cf1786fa950ae9b553390d6d62e2b285ebaeb978822439e0922403f9cc7dbc473045022100b807fa7bc196a7b2d7a3000e5e1870e2ff488bfd6e2850aeaefb3c606f28379e022009c3cec446550e5cb04483404a677c4b8406d85c62cb4d714e5ca3a50aa02f2600e80300000100e87648170000001976a914dbe6d470fa9fe4d037043533eff4f80aeef0c8d288ac00000000", + Txid: "b65181decb00e684fef238776a0a129db4e1ffdfc454f6ef323e5f7a8deae6a8", + LockTime: 0, Vin: []bchain.Vin{ { ScriptSig: bchain.ScriptSig{ @@ -245,7 +245,7 @@ func init() { }, }, Blocktime: 1534045750, - Time: 1534045750, + Time: 1534045750, } } @@ -363,7 +363,7 @@ func Test_UnpackTx(t *testing.T) { return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("unpackTx() got = %v, want %v", got, tt.want) + t.Errorf("unpackTx() got = %v, want %v", got, tt.want) } if got1 != tt.want1 { t.Errorf("unpackTx() got1 = %v, want %v", got1, tt.want1) @@ -379,7 +379,7 @@ type testBlock struct { } var testParseBlockTxs = map[int]testBlock{ - 800000: testBlock{ + 800000: { size: 463, time: 1504351235, txs: []string{ @@ -387,31 +387,31 @@ var testParseBlockTxs = map[int]testBlock{ "52b116d26f7c8b633c284f8998a431e106d837c0c5888f9ea5273d36c4556bec", }, }, - 864611: testBlock{ + 864611: { size: 460, time: 1508265763, txs: []string{ "3e68db3117021178bfd56eceed2fcfcc8210d1198372412de713f953ce01db5c", - "f773cd0f042a264c31c8e0b70485e2c85097b66d3d67bac055d620505de29ce2", + "f773cd0f042a264c31c8e0b70485e2c85097b66d3d67bac055d620505de29ce2", }, }, - 1300002: testBlock{ + 1300002: { size: 43673, time: 1534045750, txs: []string{ "21cfc7b58e666c393431619393526fd736d8d6bf2d8699e2acbedbf5d3c60b85", - "afdc7e28ca02ff6a71fc662072bf7590bac6ec3bd93148d0c9f9d1a820c6b1ed", - "b65181decb00e684fef238776a0a129db4e1ffdfc454f6ef323e5f7a8deae6a8", - "10bc6050c6eb19dd81bede01e974f46740a94049902ced66f10b6dd3d5d31da5", + "afdc7e28ca02ff6a71fc662072bf7590bac6ec3bd93148d0c9f9d1a820c6b1ed", + "b65181decb00e684fef238776a0a129db4e1ffdfc454f6ef323e5f7a8deae6a8", + "10bc6050c6eb19dd81bede01e974f46740a94049902ced66f10b6dd3d5d31da5", }, }, - 1299975: testBlock{ + 1299975: { size: 42801, time: 1534044012, txs: []string{ "a99f5fa0b4bf464d57ddd10ae56db27edb054830a2b95b9a23509d217b871a6a", - "fccaee46b6f01e42c24ee3f7bbfe5a3f2732b2486af0423473446fbc50a1e48c", - "baab318237b55f2dbb1ede2c65f7da9bf2c51c0e9a63903b3376f559fe999960", + "fccaee46b6f01e42c24ee3f7bbfe5a3f2732b2486af0423473446fbc50a1e48c", + "baab318237b55f2dbb1ede2c65f7da9bf2c51c0e9a63903b3376f559fe999960", }, }, } diff --git a/common/metrics.go b/common/metrics.go index 6f92b14b..3516640a 100644 --- a/common/metrics.go +++ b/common/metrics.go @@ -6,6 +6,7 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +// Metrics holds prometheus collectors for various metrics collected by Blockbook type Metrics struct { SocketIORequests *prometheus.CounterVec SocketIOSubscribes *prometheus.CounterVec @@ -28,8 +29,10 @@ type Metrics struct { BlockbookAppInfo *prometheus.GaugeVec } +// Labels represents a collection of label name -> value mappings. type Labels = prometheus.Labels +// GetMetrics returns struct holding prometheus collectors for various metrics collected by Blockbook func GetMetrics(coin string) (*Metrics, error) { metrics := Metrics{} diff --git a/common/version.go b/common/version.go index 43a96e2f..f81004c5 100644 --- a/common/version.go +++ b/common/version.go @@ -8,6 +8,7 @@ var ( buildtime = "unknown" ) +// VersionInfo holds information about the running Blockbook instance type VersionInfo struct { Version string `json:"version"` GitCommit string `json:"gitcommit"` @@ -16,6 +17,7 @@ type VersionInfo struct { OSArch string `json:"os/arch"` } +// GetVersionInfo returns VersionInfo of the running Blockbook instance func GetVersionInfo() VersionInfo { return VersionInfo{ Version: version, diff --git a/db/rocksdb_ethereumtype_test.go b/db/rocksdb_ethereumtype_test.go index 8b66cc0d..c40e6ad4 100644 --- a/db/rocksdb_ethereumtype_test.go +++ b/db/rocksdb_ethereumtype_test.go @@ -22,7 +22,7 @@ func ethereumTestnetParser() *eth.EthereumParser { func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool) { if err := checkColumn(d, cfHeight, []keyPair{ - keyPair{ + { "0041eee8", "c7b98df95acfd11c51ba25611a39e004fe56c8fdfc1582af99354fcd09c17b11" + uintToHex(1534858022) + varuintToHex(2) + varuintToHex(31839), nil, @@ -33,10 +33,10 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo } } if err := checkColumn(d, cfAddresses, []keyPair{ - keyPair{addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^1}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0}), nil}, + {addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil}, + {addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil}, + {addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^1}), nil}, + {addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0}), nil}, }); err != nil { { t.Fatal(err) @@ -44,10 +44,10 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo } if err := checkColumn(d, cfAddressContracts, []keyPair{ - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "0101", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "0201" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "0101", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "0101", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "0201" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "0101", nil}, }); err != nil { { t.Fatal(err) @@ -59,7 +59,7 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo blockTxsKp = []keyPair{} } else { blockTxsKp = []keyPair{ - keyPair{ + { "0041eee8", dbtestdata.EthTxidB1T1 + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + "00" + @@ -81,12 +81,12 @@ func verifyAfterEthereumTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect boo func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) { if err := checkColumn(d, cfHeight, []keyPair{ - keyPair{ + { "0041eee8", "c7b98df95acfd11c51ba25611a39e004fe56c8fdfc1582af99354fcd09c17b11" + uintToHex(1534858022) + varuintToHex(2) + varuintToHex(31839), nil, }, - keyPair{ + { "0041eee9", "2b57e15e93a0ed197417a34c2498b7187df79099572c04a6b6e6ff418f74e6ee" + uintToHex(1534859988) + varuintToHex(2) + varuintToHex(2345678), nil, @@ -97,15 +97,15 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) { } } if err := checkColumn(d, cfAddresses, []keyPair{ - keyPair{addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^1}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddr55, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^2, 1}) + txIndexesHex(dbtestdata.EthTxidB2T1, []int32{^0}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddr9f, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T1, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddr4b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^0, 1, ^2, 2, ^1}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddr7b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^1, 2}), nil}, - keyPair{addressKeyHex(dbtestdata.EthAddrContract47, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{0}), nil}, + {addressKeyHex(dbtestdata.EthAddr3e, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T1, []int32{^0}), nil}, + {addressKeyHex(dbtestdata.EthAddr55, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{1}) + txIndexesHex(dbtestdata.EthTxidB1T1, []int32{0}), nil}, + {addressKeyHex(dbtestdata.EthAddr20, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{^0, ^1}), nil}, + {addressKeyHex(dbtestdata.EthAddrContract4a, 4321000, d), txIndexesHex(dbtestdata.EthTxidB1T2, []int32{0}), nil}, + {addressKeyHex(dbtestdata.EthAddr55, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^2, 1}) + txIndexesHex(dbtestdata.EthTxidB2T1, []int32{^0}), nil}, + {addressKeyHex(dbtestdata.EthAddr9f, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T1, []int32{0}), nil}, + {addressKeyHex(dbtestdata.EthAddr4b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^0, 1, ^2, 2, ^1}), nil}, + {addressKeyHex(dbtestdata.EthAddr7b, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{^1, 2}), nil}, + {addressKeyHex(dbtestdata.EthAddrContract47, 4321001, d), txIndexesHex(dbtestdata.EthTxidB2T2, []int32{0}), nil}, }); err != nil { { t.Fatal(err) @@ -113,14 +113,14 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) { } if err := checkColumn(d, cfAddressContracts, []keyPair{ - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "0101", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "0402" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "0101", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "0101", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser), "0100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser), "0101", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr3e, d.chainParser), "0101", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser), "0402" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr20, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser), "0101", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser), "0101", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr4b, d.chainParser), "0101" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "02" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "02", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr7b, d.chainParser), "0100" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract4a, d.chainParser) + "01" + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract0d, d.chainParser) + "01", nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddrContract47, d.chainParser), "0101", nil}, }); err != nil { { t.Fatal(err) @@ -128,7 +128,7 @@ func verifyAfterEthereumTypeBlock2(t *testing.T, d *RocksDB) { } if err := checkColumn(d, cfBlockTxs, []keyPair{ - keyPair{ + { "0041eee9", dbtestdata.EthTxidB2T1 + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr55, d.chainParser) + dbtestdata.AddressToPubKeyHex(dbtestdata.EthAddr9f, d.chainParser) + "00" + @@ -249,7 +249,7 @@ func TestRocksDB_Index_EthereumType(t *testing.T) { // check that there is only the last tx in the cache packedTx, err := d.chainParser.PackTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime) if err := checkColumn(d, cfTransactions, []keyPair{ - keyPair{dbtestdata.EthTxidB2T2, hex.EncodeToString(packedTx), nil}, + {dbtestdata.EthTxidB2T2, hex.EncodeToString(packedTx), nil}, }); err != nil { { t.Fatal(err) diff --git a/db/rocksdb_test.go b/db/rocksdb_test.go index a4da7f52..068a86ed 100644 --- a/db/rocksdb_test.go +++ b/db/rocksdb_test.go @@ -173,7 +173,7 @@ func checkColumn(d *RocksDB, col int, kp []keyPair) error { func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool) { if err := checkColumn(d, cfHeight, []keyPair{ - keyPair{ + { "000370d5", "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997" + uintToHex(1534858021) + varuintToHex(2) + varuintToHex(1234567), nil, @@ -185,18 +185,18 @@ func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool } // the vout is encoded as signed varint, i.e. value * 2 for non negative values if err := checkColumn(d, cfAddresses, []keyPair{ - keyPair{addressKeyHex(dbtestdata.Addr1, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr2, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{1}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr3, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr4, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{1}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr5, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{2}), nil}, + {addressKeyHex(dbtestdata.Addr1, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{0}), nil}, + {addressKeyHex(dbtestdata.Addr2, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{1}), nil}, + {addressKeyHex(dbtestdata.Addr3, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{0}), nil}, + {addressKeyHex(dbtestdata.Addr4, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{1}), nil}, + {addressKeyHex(dbtestdata.Addr5, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{2}), nil}, }); err != nil { { t.Fatal(err) } } if err := checkColumn(d, cfTxAddresses, []keyPair{ - keyPair{ + { dbtestdata.TxidB1T1, varuintToHex(225493) + "00" + @@ -205,7 +205,7 @@ func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool addressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2), nil, }, - keyPair{ + { dbtestdata.TxidB1T2, varuintToHex(225493) + "00" + @@ -221,11 +221,11 @@ func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool } } if err := checkColumn(d, cfAddressBalance, []keyPair{ - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A1), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A2), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A3), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A4), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A5), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A1), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A2), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A3), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A4), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T2A5), nil}, }); err != nil { { t.Fatal(err) @@ -237,7 +237,7 @@ func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool blockTxsKp = []keyPair{} } else { blockTxsKp = []keyPair{ - keyPair{ + { "000370d5", dbtestdata.TxidB1T1 + "00" + dbtestdata.TxidB1T2 + "00", nil, @@ -254,12 +254,12 @@ func verifyAfterBitcoinTypeBlock1(t *testing.T, d *RocksDB, afterDisconnect bool func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { if err := checkColumn(d, cfHeight, []keyPair{ - keyPair{ + { "000370d5", "0000000076fbbed90fd75b0e18856aa35baa984e9c9d444cf746ad85e94e2997" + uintToHex(1534858021) + varuintToHex(2) + varuintToHex(1234567), nil, }, - keyPair{ + { "000370d6", "00000000eb0443fd7dc4a1ed5c686a8e995057805f9a161d9a5a77a95e72b7b6" + uintToHex(1534859123) + varuintToHex(4) + varuintToHex(2345678), nil, @@ -270,27 +270,27 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { } } if err := checkColumn(d, cfAddresses, []keyPair{ - keyPair{addressKeyHex(dbtestdata.Addr1, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr2, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{1}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr3, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr4, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{1}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr5, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{2}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr6, 225494, d), txIndexesHex(dbtestdata.TxidB2T2, []int32{^0}) + txIndexesHex(dbtestdata.TxidB2T1, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr7, 225494, d), txIndexesHex(dbtestdata.TxidB2T1, []int32{1}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr8, 225494, d), txIndexesHex(dbtestdata.TxidB2T2, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr9, 225494, d), txIndexesHex(dbtestdata.TxidB2T2, []int32{1}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr3, 225494, d), txIndexesHex(dbtestdata.TxidB2T1, []int32{^0}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr2, 225494, d), txIndexesHex(dbtestdata.TxidB2T1, []int32{^1}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr5, 225494, d), txIndexesHex(dbtestdata.TxidB2T3, []int32{0, ^0}), nil}, - keyPair{addressKeyHex(dbtestdata.AddrA, 225494, d), txIndexesHex(dbtestdata.TxidB2T4, []int32{0}), nil}, - keyPair{addressKeyHex(dbtestdata.Addr4, 225494, d), txIndexesHex(dbtestdata.TxidB2T2, []int32{^1}), nil}, + {addressKeyHex(dbtestdata.Addr1, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{0}), nil}, + {addressKeyHex(dbtestdata.Addr2, 225493, d), txIndexesHex(dbtestdata.TxidB1T1, []int32{1}), nil}, + {addressKeyHex(dbtestdata.Addr3, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{0}), nil}, + {addressKeyHex(dbtestdata.Addr4, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{1}), nil}, + {addressKeyHex(dbtestdata.Addr5, 225493, d), txIndexesHex(dbtestdata.TxidB1T2, []int32{2}), nil}, + {addressKeyHex(dbtestdata.Addr6, 225494, d), txIndexesHex(dbtestdata.TxidB2T2, []int32{^0}) + txIndexesHex(dbtestdata.TxidB2T1, []int32{0}), nil}, + {addressKeyHex(dbtestdata.Addr7, 225494, d), txIndexesHex(dbtestdata.TxidB2T1, []int32{1}), nil}, + {addressKeyHex(dbtestdata.Addr8, 225494, d), txIndexesHex(dbtestdata.TxidB2T2, []int32{0}), nil}, + {addressKeyHex(dbtestdata.Addr9, 225494, d), txIndexesHex(dbtestdata.TxidB2T2, []int32{1}), nil}, + {addressKeyHex(dbtestdata.Addr3, 225494, d), txIndexesHex(dbtestdata.TxidB2T1, []int32{^0}), nil}, + {addressKeyHex(dbtestdata.Addr2, 225494, d), txIndexesHex(dbtestdata.TxidB2T1, []int32{^1}), nil}, + {addressKeyHex(dbtestdata.Addr5, 225494, d), txIndexesHex(dbtestdata.TxidB2T3, []int32{0, ^0}), nil}, + {addressKeyHex(dbtestdata.AddrA, 225494, d), txIndexesHex(dbtestdata.TxidB2T4, []int32{0}), nil}, + {addressKeyHex(dbtestdata.Addr4, 225494, d), txIndexesHex(dbtestdata.TxidB2T2, []int32{^1}), nil}, }); err != nil { { t.Fatal(err) } } if err := checkColumn(d, cfTxAddresses, []keyPair{ - keyPair{ + { dbtestdata.TxidB1T1, varuintToHex(225493) + "00" + @@ -299,7 +299,7 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { spentAddressToPubKeyHexWithLength(dbtestdata.Addr2, t, d) + bigintToHex(dbtestdata.SatB1T1A2), nil, }, - keyPair{ + { dbtestdata.TxidB1T2, varuintToHex(225493) + "00" + @@ -309,7 +309,7 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { spentAddressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB1T2A5), nil, }, - keyPair{ + { dbtestdata.TxidB2T1, varuintToHex(225494) + "02" + @@ -320,7 +320,7 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { addressToPubKeyHexWithLength(dbtestdata.Addr7, t, d) + bigintToHex(dbtestdata.SatB2T1A7), nil, }, - keyPair{ + { dbtestdata.TxidB2T2, varuintToHex(225494) + "02" + @@ -331,7 +331,7 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { addressToPubKeyHexWithLength(dbtestdata.Addr9, t, d) + bigintToHex(dbtestdata.SatB2T2A9), nil, }, - keyPair{ + { dbtestdata.TxidB2T3, varuintToHex(225494) + "01" + @@ -340,7 +340,7 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { addressToPubKeyHexWithLength(dbtestdata.Addr5, t, d) + bigintToHex(dbtestdata.SatB2T3A5), nil, }, - keyPair{ + { dbtestdata.TxidB2T4, varuintToHex(225494) + "01" + inputAddressToPubKeyHexWithLength("", t, d) + bigintToHex(dbtestdata.SatZero) + @@ -355,23 +355,23 @@ func verifyAfterBitcoinTypeBlock2(t *testing.T, d *RocksDB) { } } if err := checkColumn(d, cfAddressBalance, []keyPair{ - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A1), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T1A2) + bigintToHex(dbtestdata.SatZero), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A3) + bigintToHex(dbtestdata.SatZero), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A4) + bigintToHex(dbtestdata.SatZero), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A5) + bigintToHex(dbtestdata.SatB2T3A5), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr6, d.chainParser), "02" + bigintToHex(dbtestdata.SatB2T1A6) + bigintToHex(dbtestdata.SatZero), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr7, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T1A7), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr8, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T2A8), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.Addr9, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T2A9), nil}, - keyPair{dbtestdata.AddressToPubKeyHex(dbtestdata.AddrA, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T4AA), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr1, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB1T1A1), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr2, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T1A2) + bigintToHex(dbtestdata.SatZero), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr3, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A3) + bigintToHex(dbtestdata.SatZero), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr4, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A4) + bigintToHex(dbtestdata.SatZero), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr5, d.chainParser), "02" + bigintToHex(dbtestdata.SatB1T2A5) + bigintToHex(dbtestdata.SatB2T3A5), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr6, d.chainParser), "02" + bigintToHex(dbtestdata.SatB2T1A6) + bigintToHex(dbtestdata.SatZero), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr7, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T1A7), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr8, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T2A8), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.Addr9, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T2A9), nil}, + {dbtestdata.AddressToPubKeyHex(dbtestdata.AddrA, d.chainParser), "01" + bigintToHex(dbtestdata.SatZero) + bigintToHex(dbtestdata.SatB2T4AA), nil}, }); err != nil { { t.Fatal(err) } } if err := checkColumn(d, cfBlockTxs, []keyPair{ - keyPair{ + { "000370d6", dbtestdata.TxidB2T1 + "02" + dbtestdata.TxidB1T2 + "00" + dbtestdata.TxidB1T1 + "02" + dbtestdata.TxidB2T2 + "02" + dbtestdata.TxidB2T1 + "00" + dbtestdata.TxidB1T2 + "02" + @@ -541,7 +541,7 @@ func TestRocksDB_Index_BitcoinType(t *testing.T) { // check that there is only the last tx in the cache packedTx, err := d.chainParser.PackTx(&block2.Txs[1], block2.Height, block2.Txs[1].Blocktime) if err := checkColumn(d, cfTransactions, []keyPair{ - keyPair{block2.Txs[1].Txid, hex.EncodeToString(packedTx), nil}, + {block2.Txs[1].Txid, hex.EncodeToString(packedTx), nil}, }); err != nil { { t.Fatal(err) diff --git a/tests/dbtestdata/dbtestdata.go b/tests/dbtestdata/dbtestdata.go index c485129f..36a55c9b 100644 --- a/tests/dbtestdata/dbtestdata.go +++ b/tests/dbtestdata/dbtestdata.go @@ -64,18 +64,18 @@ func GetTestBitcoinTypeBlock1(parser bchain.BlockChainParser) *bchain.Block { Confirmations: 2, }, Txs: []bchain.Tx{ - bchain.Tx{ + { Txid: TxidB1T1, Vin: []bchain.Vin{}, Vout: []bchain.Vout{ - bchain.Vout{ + { N: 0, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr1, parser), }, ValueSat: *SatB1T1A1, }, - bchain.Vout{ + { N: 1, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr2, parser), @@ -87,24 +87,24 @@ func GetTestBitcoinTypeBlock1(parser bchain.BlockChainParser) *bchain.Block { Time: 22549300000, Confirmations: 2, }, - bchain.Tx{ + { Txid: TxidB1T2, Vout: []bchain.Vout{ - bchain.Vout{ + { N: 0, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr3, parser), }, ValueSat: *SatB1T2A3, }, - bchain.Vout{ + { N: 1, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr4, parser), }, ValueSat: *SatB1T2A4, }, - bchain.Vout{ + { N: 2, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr5, parser), @@ -130,29 +130,29 @@ func GetTestBitcoinTypeBlock2(parser bchain.BlockChainParser) *bchain.Block { Confirmations: 1, }, Txs: []bchain.Tx{ - bchain.Tx{ + { Txid: TxidB2T1, Vin: []bchain.Vin{ // addr3 - bchain.Vin{ + { Txid: TxidB1T2, Vout: 0, }, // addr2 - bchain.Vin{ + { Txid: TxidB1T1, Vout: 1, }, }, Vout: []bchain.Vout{ - bchain.Vout{ + { N: 0, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr6, parser), }, ValueSat: *SatB2T1A6, }, - bchain.Vout{ + { N: 1, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr7, parser), @@ -164,29 +164,29 @@ func GetTestBitcoinTypeBlock2(parser bchain.BlockChainParser) *bchain.Block { Time: 22549400000, Confirmations: 1, }, - bchain.Tx{ + { Txid: TxidB2T2, Vin: []bchain.Vin{ // spending an output in the same block - addr6 - bchain.Vin{ + { Txid: TxidB2T1, Vout: 0, }, // spending an output in the previous block - addr4 - bchain.Vin{ + { Txid: TxidB1T2, Vout: 1, }, }, Vout: []bchain.Vout{ - bchain.Vout{ + { N: 0, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr8, parser), }, ValueSat: *SatB2T2A8, }, - bchain.Vout{ + { N: 1, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr9, parser), @@ -199,17 +199,17 @@ func GetTestBitcoinTypeBlock2(parser bchain.BlockChainParser) *bchain.Block { Confirmations: 1, }, // transaction from the same address in the previous block - bchain.Tx{ + { Txid: TxidB2T3, Vin: []bchain.Vin{ // addr5 - bchain.Vin{ + { Txid: TxidB1T2, Vout: 2, }, }, Vout: []bchain.Vout{ - bchain.Vout{ + { N: 0, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(Addr5, parser), @@ -222,22 +222,22 @@ func GetTestBitcoinTypeBlock2(parser bchain.BlockChainParser) *bchain.Block { Confirmations: 1, }, // mining transaction - bchain.Tx{ + { Txid: TxidB2T4, Vin: []bchain.Vin{ - bchain.Vin{ + { Coinbase: "03bf1e1504aede765b726567696f6e312f50726f6a65637420425443506f6f6c2f01000001bf7e000000000000", }, }, Vout: []bchain.Vout{ - bchain.Vout{ + { N: 0, ScriptPubKey: bchain.ScriptPubKey{ Hex: AddressToPubKeyHex(AddrA, parser), }, ValueSat: *SatB2T4AA, }, - bchain.Vout{ + { N: 1, ScriptPubKey: bchain.ScriptPubKey{}, ValueSat: *SatZero, diff --git a/tests/dbtestdata/fakechain.go b/tests/dbtestdata/fakechain.go index 549e01f9..71515bbb 100644 --- a/tests/dbtestdata/fakechain.go +++ b/tests/dbtestdata/fakechain.go @@ -12,7 +12,8 @@ type fakeBlockChain struct { *bchain.BaseChain } -func NewFakeBlockChain(parser bchain.BlockChainParser) (*fakeBlockChain, error) { +// NewFakeBlockChain returns mocked blockchain RPC interface used for tests +func NewFakeBlockChain(parser bchain.BlockChainParser) (bchain.BlockChain, error) { return &fakeBlockChain{&bchain.BaseChain{Parser: parser}}, nil }